git-svn-id: https://svn.apache.org/repos/asf/zookeeper/trunk@1584497 13f79535-47bb-0310-9956-ffa450edef68
@@ -1,6 +1,6 @@
-This directory contain scripts that allow easy access (classpath in particular)
-to the ZooKeeper server and command line client.
-
-Files ending in .sh are unix and cygwin compatible
-Files ending in .cmd are msdos/windows compatible
+This directory contain scripts that allow easy access (classpath in particular)
+to the ZooKeeper server and command line client.
+
+Files ending in .sh are unix and cygwin compatible
+Files ending in .cmd are msdos/windows compatible
@@ -1,24 +1,24 @@
-@echo off
-REM Licensed to the Apache Software Foundation (ASF) under one or more
-REM contributor license agreements. See the NOTICE file distributed with
-REM this work for additional information regarding copyright ownership.
-REM The ASF licenses this file to You under the Apache License, Version 2.0
-REM (the "License"); you may not use this file except in compliance with
-REM the License. You may obtain a copy of the License at
-REM
-REM http://www.apache.org/licenses/LICENSE-2.0
-REM Unless required by applicable law or agreed to in writing, software
-REM distributed under the License is distributed on an "AS IS" BASIS,
-REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-REM See the License for the specific language governing permissions and
-REM limitations under the License.
-setlocal
-call "%~dp0zkEnv.cmd"
-set ZOOMAIN=org.apache.zookeeper.ZooKeeperMain
-call %JAVA% "-Dzookeeper.log.dir=%ZOO_LOG_DIR%" "-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%" -cp "%CLASSPATH%" %ZOOMAIN% %*
-endlocal
+@echo off
+REM Licensed to the Apache Software Foundation (ASF) under one or more
+REM contributor license agreements. See the NOTICE file distributed with
+REM this work for additional information regarding copyright ownership.
+REM The ASF licenses this file to You under the Apache License, Version 2.0
+REM (the "License"); you may not use this file except in compliance with
+REM the License. You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM Unless required by applicable law or agreed to in writing, software
+REM distributed under the License is distributed on an "AS IS" BASIS,
+REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+REM See the License for the specific language governing permissions and
+REM limitations under the License.
+setlocal
+call "%~dp0zkEnv.cmd"
+set ZOOMAIN=org.apache.zookeeper.ZooKeeperMain
+call %JAVA% "-Dzookeeper.log.dir=%ZOO_LOG_DIR%" "-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%" -cp "%CLASSPATH%" %ZOOMAIN% %*
+endlocal
-set ZOOMAIN=org.apache.zookeeper.server.quorum.QuorumPeerMain
-echo on
-call %JAVA% "-Dzookeeper.log.dir=%ZOO_LOG_DIR%" "-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%" -cp "%CLASSPATH%" %ZOOMAIN% "%ZOOCFG%" %*
+set ZOOMAIN=org.apache.zookeeper.server.quorum.QuorumPeerMain
+echo on
+call %JAVA% "-Dzookeeper.log.dir=%ZOO_LOG_DIR%" "-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%" -cp "%CLASSPATH%" %ZOOMAIN% "%ZOOCFG%" %*
@@ -1,1252 +1,1252 @@
-# Doxyfile 1.4.7
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project
-#
-# All text after a hash (#) is considered a comment and will be ignored
-# The format is:
-# TAG = value [value, ...]
-# For lists items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ")
-#---------------------------------------------------------------------------
-# Project related configuration options
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
-# by quotes) that should identify the project.
-PROJECT_NAME = $(PROJECT)-$(VERSION)
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
-PROJECT_NUMBER =
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
-OUTPUT_DIRECTORY = $(DOCDIR)
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
-# otherwise cause performance problems for the file system.
-CREATE_SUBDIRS = NO
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
-# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
-# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
-# Swedish, and Ukrainian.
-OUTPUT_LANGUAGE = English
-# This tag can be used to specify the encoding used in the generated output.
-# The encoding is not always determined by the language that is chosen,
-# but also whether or not the output is meant for Windows or non-Windows users.
-# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
-# forces the Windows encoding (this is the default for the Windows binary),
-# whereas setting the tag to NO uses a Unix-style encoding (the default for
-# all platforms other than Windows).
-USE_WINDOWS_ENCODING = NO
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
-BRIEF_MEMBER_DESC = YES
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-REPEAT_BRIEF = YES
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
-# "represents" "a" "an" "the"
-ABBREVIATE_BRIEF =
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
-# description.
-ALWAYS_DETAILED_SEC = NO
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-INLINE_INHERITED_MEMB = NO
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
-FULL_PATH_NAMES = YES
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip.
-STRIP_FROM_PATH =
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
-# are normally passed to the compiler using the -I flag.
-STRIP_FROM_INC_PATH =
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful is your file systems
-# doesn't support long names like on DOS, Mac, or CD-ROM.
-SHORT_NAMES = NO
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like the Qt-style comments (thus requiring an
-# explicit @brief command for a brief description.
-JAVADOC_AUTOBRIEF = NO
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
-MULTILINE_CPP_IS_BRIEF = NO
-# If the DETAILS_AT_TOP tag is set to YES then Doxygen
-# will output the detailed description near the top, like JavaDoc.
-# If set to NO, the detailed description appears after the member
-# documentation.
-DETAILS_AT_TOP = NO
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
-INHERIT_DOCS = YES
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
-# a new page for each member. If set to NO, the documentation of a member will
-# be part of the file/class/namespace that contains it.
-SEPARATE_MEMBER_PAGES = NO
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-TAB_SIZE = 8
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
-ALIASES =
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
-# sources only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
-# of all members will be omitted, etc.
-OPTIMIZE_OUTPUT_FOR_C = YES
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
-# sources only. Doxygen will then generate output that is more tailored for Java.
-# For instance, namespaces will be presented as packages, qualified scopes
-# will look different, etc.
-OPTIMIZE_OUTPUT_JAVA = NO
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
-# include (a tag file for) the STL sources as input, then you should
-# set this tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also make the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-BUILTIN_STL_SUPPORT = NO
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-DISTRIBUTE_GROUP_DOC = NO
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
-SUBGROUPING = YES
-# Build related configuration options
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-EXTRACT_ALL = NO
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
-EXTRACT_PRIVATE = NO
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-EXTRACT_STATIC = YES
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
-# If set to NO only classes defined in header files are included.
-EXTRACT_LOCAL_CLASSES = YES
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
-# If set to NO (the default) only methods in the interface are included.
-EXTRACT_LOCAL_METHODS = NO
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
-HIDE_UNDOC_MEMBERS = NO
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-HIDE_UNDOC_CLASSES = NO
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
-HIDE_FRIEND_COMPOUNDS = NO
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
-HIDE_IN_BODY_DOCS = NO
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
-INTERNAL_DOCS = NO
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-CASE_SENSE_NAMES = YES
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
-HIDE_SCOPE_NAMES = NO
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
-SHOW_INCLUDE_FILES = NO
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
-INLINE_INFO = YES
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
-SORT_MEMBER_DOCS = YES
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-SORT_BRIEF_DOCS = NO
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
-# alphabetical list.
-SORT_BY_SCOPE_NAME = NO
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
-GENERATE_TODOLIST = YES
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-GENERATE_TESTLIST = YES
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
-GENERATE_BUGLIST = YES
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
-# \deprecated commands in the documentation.
-GENERATE_DEPRECATEDLIST = YES
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
-ENABLED_SECTIONS =
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or define consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and defines in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
-MAX_INITIALIZER_LINES = 30
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
-# list will mention the files that were used to generate the documentation.
-SHOW_USED_FILES = YES
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-SHOW_DIRECTORIES = NO
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from the
-# version control system). Doxygen will invoke the program by executing (via
-# popen()) the command <command> <input-file>, where <command> is the value of
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
-# provided by doxygen. Whatever the program writes to standard output
-# is used as the file version. See the manual for examples.
-FILE_VERSION_FILTER =
-# configuration options related to warning and progress messages
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
-QUIET = NO
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
-WARNINGS = YES
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
-WARN_IF_UNDOCUMENTED = YES
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
-WARN_IF_DOC_ERROR = YES
-# This WARN_NO_PARAMDOC option can be abled to get warnings for
-# functions that are documented, but have no documentation for their parameters
-# or return value. If set to NO (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
-WARN_NO_PARAMDOC = NO
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text. Optionally the format may contain
-# $version, which will be replaced by the version of the file (if it could
-# be obtained via FILE_VERSION_FILTER)
-WARN_FORMAT = "$file:$line: $text"
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
-WARN_LOGFILE =
-# configuration options related to the input files
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
-INPUT = include/zookeeper.h
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
-# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
-FILE_PATTERNS =
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
-RECURSIVE = NO
-# The EXCLUDE tag can be used to specify files and/or directories that should
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-EXCLUDE =
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
-# directories that are symbolic links (a Unix filesystem feature) are excluded
-# from the input.
-EXCLUDE_SYMLINKS = NO
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories. Note that the wildcards are matched
-# against the file with absolute path, so to exclude all test directories
-# for example use the pattern */test/*
-EXCLUDE_PATTERNS =
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
-EXAMPLE_PATH =
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# blank all files are included.
-EXAMPLE_PATTERNS =
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
-EXAMPLE_RECURSIVE = NO
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
-IMAGE_PATH =
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output. If FILTER_PATTERNS is specified, this tag will be
-# ignored.
-INPUT_FILTER =
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form:
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
-# is applied to all files.
-FILTER_PATTERNS =
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
-FILTER_SOURCE_FILES = NO
-# configuration options related to source browsing
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
-SOURCE_BROWSER = NO
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
-INLINE_SOURCES = NO
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
-STRIP_CODE_COMMENTS = YES
-# If the REFERENCED_BY_RELATION tag is set to YES (the default)
-# then for each documented function all documented
-# functions referencing it will be listed.
-REFERENCED_BY_RELATION = YES
-# If the REFERENCES_RELATION tag is set to YES (the default)
-# then for each documented function all documented entities
-# called/used by that function will be listed.
-REFERENCES_RELATION = YES
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code. Otherwise they will link to the documentstion.
-REFERENCES_LINK_SOURCE = YES
-# If the USE_HTAGS tag is set to YES then the references to source code
-# will point to the HTML generated by the htags(1) tool instead of doxygen
-# built-in source browser. The htags tool is part of GNU's global source
-# tagging system (see http://www.gnu.org/software/global/global.html). You
-# will need version 4.8.6 or higher.
-USE_HTAGS = NO
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
-VERBATIM_HEADERS = YES
-# configuration options related to the alphabetical class index
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
-ALPHABETICAL_INDEX = NO
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
-COLS_IN_ALPHA_INDEX = 5
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
-IGNORE_PREFIX =
-# configuration options related to the HTML output
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
-GENERATE_HTML = $(GENERATE_HTML)
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
-HTML_OUTPUT = html
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
-HTML_FILE_EXTENSION = .html
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header.
-HTML_HEADER =
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# standard footer.
-HTML_FOOTER =
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# stylesheet in the HTML output directory as well, or it will be erased!
-HTML_STYLESHEET =
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-HTML_ALIGN_MEMBERS = YES
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
-# of the generated HTML documentation.
-GENERATE_HTMLHELP = $(GENERATE_HTMLHELP)
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
-# written to the html output directory.
-CHM_FILE = ../$(PROJECT).chm
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
-HHC_LOCATION = $(HHC_PATH)
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
-GENERATE_CHI = $(GENERATE_CHI)
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
-BINARY_TOC = NO
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
-# to the contents of the HTML help documentation and to the tree view.
-TOC_EXPAND = NO
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
-# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
-DISABLE_INDEX = NO
-# This tag can be used to set the number of enum values (range [1..20])
-# that doxygen will group on one line in the generated HTML documentation.
-ENUM_VALUES_PER_LINE = 4
-# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
-# generated containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
-# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
-# probably better off using the HTML help feature.
-GENERATE_TREEVIEW = NO
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
-TREEVIEW_WIDTH = 250
-# configuration options related to the LaTeX output
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
-GENERATE_LATEX = $(GENERATE_LATEX)
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# put in front of it. If left blank `latex' will be used as the default path.
-LATEX_OUTPUT = latex
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-LATEX_CMD_NAME = latex
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
-# default command name.
-MAKEINDEX_CMD_NAME = makeindex
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
-COMPACT_LATEX = NO
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, a4wide, letter, legal and
-# executive. If left blank a4wide will be used.
-PAPER_TYPE = $(PAPER_SIZE)
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
-EXTRA_PACKAGES =
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
-LATEX_HEADER =
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
-PDF_HYPERLINKS = NO
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
-# higher quality PDF documentation.
-USE_PDFLATEX = $(GENERATE_PDF)
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
-LATEX_BATCHMODE = NO
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
-LATEX_HIDE_INDICES = NO
-# configuration options related to the RTF output
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
-GENERATE_RTF = $(GENERATE_RTF)
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# put in front of it. If left blank `rtf' will be used as the default path.
-RTF_OUTPUT = rtf
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-COMPACT_RTF = NO
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
-RTF_HYPERLINKS = NO
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
-# replacements, missing definitions are set to their default value.
-RTF_STYLESHEET_FILE =
-# Set optional variables used in the generation of an rtf document.
-# Syntax is similar to doxygen's config file.
-RTF_EXTENSIONS_FILE =
-# configuration options related to the man page output
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
-GENERATE_MAN = $(GENERATE_MAN)
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# put in front of it. If left blank `man' will be used as the default path.
-MAN_OUTPUT = man
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
-MAN_EXTENSION = .3
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
-MAN_LINKS = NO
-# configuration options related to the XML output
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation.
-GENERATE_XML = $(GENERATE_XML)
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# put in front of it. If left blank `xml' will be used as the default path.
-XML_OUTPUT = xml
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-XML_SCHEMA =
-# The XML_DTD tag can be used to specify an XML DTD,
-XML_DTD =
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
-# enabling this will significantly increase the size of the XML output.
-XML_PROGRAMLISTING = YES
-# configuration options for the AutoGen Definitions output
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
-GENERATE_AUTOGEN_DEF = NO
-# configuration options related to the Perl module output
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
-GENERATE_PERLMOD = NO
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
-# to generate PDF and DVI output from the Perl module output.
-PERLMOD_LATEX = NO
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader. This is useful
-# if you want to understand what is going on. On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
-# and Perl will parse it just the same.
-PERLMOD_PRETTY = YES
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
-# Makefile don't overwrite each other's variables.
-PERLMOD_MAKEVAR_PREFIX =
-# Configuration options related to the preprocessor
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
-ENABLE_PREPROCESSING = YES
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
-MACRO_EXPANSION = NO
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_DEFINED tags.
-EXPAND_ONLY_PREDEF = NO
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
-SEARCH_INCLUDES = YES
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
-INCLUDE_PATH =
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
-INCLUDE_FILE_PATTERNS =
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed. To prevent a macro definition from being
-# undefined via #undef or recursively expanded use the := operator
-# instead of the = operator.
-PREDEFINED =
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition.
-EXPAND_AS_DEFINED =
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all function-like macros that are alone
-# on a line, have an all uppercase name, and do not end with a semicolon. Such
-# function macros are typically used for boiler-plate code, and will confuse
-# the parser if not removed.
-SKIP_FUNCTION_MACROS = YES
-# Configuration::additions related to external references
-# The TAGFILES option can be used to specify one or more tagfiles.
-# Optionally an initial location of the external documentation
-# can be added for each tagfile. The format of a tag file without
-# this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths or
-# URLs. If a location is present for each tag, the installdox tool
-# does not have to be run to correct the links.
-# Note that each tag file must have a unique name
-# (where the name does NOT include the path)
-# If a tag file is not located in the directory in which doxygen
-# is run, you must also specify the path to the tagfile here.
-TAGFILES =
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
-GENERATE_TAGFILE = $(DOCDIR)/$(PROJECT).tag
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
-ALLEXTERNALS = NO
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
-# be listed.
-EXTERNAL_GROUPS = YES
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
-PERL_PATH = /usr/bin/perl
-# Configuration options related to the dot tool
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option is superseded by the HAVE_DOT option below. This is only a
-# fallback. It is recommended to install and use dot, since it yields more
-# powerful graphs.
-CLASS_DIAGRAMS = YES
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
-HIDE_UNDOC_RELATIONS = YES
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
-HAVE_DOT = $(HAVE_DOT)
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# the CLASS_DIAGRAMS tag to NO.
-CLASS_GRAPH = YES
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
-COLLABORATION_GRAPH = YES
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for groups, showing the direct groups dependencies
-GROUP_GRAPHS = YES
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-UML_LOOK = NO
-# If set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
-TEMPLATE_RELATIONS = NO
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
-INCLUDE_GRAPH = YES
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
-INCLUDED_BY_GRAPH = YES
-# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
-# generate a call dependency graph for every global function or class method.
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command.
-CALL_GRAPH = NO
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will
-# generate a caller dependency graph for every global function or class method.
-# So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command.
-CALLER_GRAPH = NO
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will graphical hierarchy of all classes instead of a textual one.
-GRAPHICAL_HIERARCHY = YES
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
-DIRECTORY_GRAPH = YES
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are png, jpg, or gif
-# If left blank png will be used.
-DOT_IMAGE_FORMAT = png
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-DOT_PATH = $(DOT_PATH)
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
-# \dotfile command).
-DOTFILE_DIRS =
-# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than
-# this value, doxygen will try to truncate the graph, so that it fits within
-# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
-MAX_DOT_GRAPH_WIDTH = 1024
-# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
-MAX_DOT_GRAPH_HEIGHT = 1024
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes
-# that lay further from the root node will be omitted. Note that setting this
-# option to 1 or 2 may greatly reduce the computation time needed for large
-# code bases. Also note that a graph may be further truncated if the graph's
-# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
-# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
-# the graph is not depth-constrained.
-MAX_DOT_GRAPH_DEPTH = 0
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, which results in a white background.
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-DOT_TRANSPARENT = NO
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10)
-# support this, this feature is disabled by default.
-DOT_MULTI_TARGETS = NO
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
-GENERATE_LEGEND = YES
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
-DOT_CLEANUP = YES
-# Configuration::additions related to the search engine
-# The SEARCHENGINE tag specifies whether or not a search engine should be
-# used. If set to NO the values of all tags below this one will be ignored.
-SEARCHENGINE = NO
+# Doxyfile 1.4.7
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+#---------------------------------------------------------------------------
+# Project related configuration options
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+PROJECT_NAME = $(PROJECT)-$(VERSION)
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+PROJECT_NUMBER =
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+OUTPUT_DIRECTORY = $(DOCDIR)
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+CREATE_SUBDIRS = NO
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
+# Swedish, and Ukrainian.
+OUTPUT_LANGUAGE = English
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+USE_WINDOWS_ENCODING = NO
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+BRIEF_MEMBER_DESC = YES
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+REPEAT_BRIEF = YES
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+ABBREVIATE_BRIEF =
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+ALWAYS_DETAILED_SEC = NO
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+INLINE_INHERITED_MEMB = NO
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+FULL_PATH_NAMES = YES
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+STRIP_FROM_PATH =
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+STRIP_FROM_INC_PATH =
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+SHORT_NAMES = NO
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+JAVADOC_AUTOBRIEF = NO
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+MULTILINE_CPP_IS_BRIEF = NO
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+DETAILS_AT_TOP = NO
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+INHERIT_DOCS = YES
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+SEPARATE_MEMBER_PAGES = NO
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+TAB_SIZE = 8
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+ALIASES =
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+OPTIMIZE_OUTPUT_FOR_C = YES
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+OPTIMIZE_OUTPUT_JAVA = NO
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+BUILTIN_STL_SUPPORT = NO
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+DISTRIBUTE_GROUP_DOC = NO
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+SUBGROUPING = YES
+# Build related configuration options
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+EXTRACT_ALL = NO
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+EXTRACT_PRIVATE = NO
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+EXTRACT_STATIC = YES
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+EXTRACT_LOCAL_CLASSES = YES
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+EXTRACT_LOCAL_METHODS = NO
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+HIDE_UNDOC_MEMBERS = NO
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+HIDE_UNDOC_CLASSES = NO
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+HIDE_FRIEND_COMPOUNDS = NO
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+HIDE_IN_BODY_DOCS = NO
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+INTERNAL_DOCS = NO
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+CASE_SENSE_NAMES = YES
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+HIDE_SCOPE_NAMES = NO
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+SHOW_INCLUDE_FILES = NO
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+INLINE_INFO = YES
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+SORT_MEMBER_DOCS = YES
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+SORT_BRIEF_DOCS = NO
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+SORT_BY_SCOPE_NAME = NO
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+GENERATE_TODOLIST = YES
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+GENERATE_TESTLIST = YES
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+GENERATE_BUGLIST = YES
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+GENERATE_DEPRECATEDLIST = YES
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+ENABLED_SECTIONS =
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+MAX_INITIALIZER_LINES = 30
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+SHOW_USED_FILES = YES
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+SHOW_DIRECTORIES = NO
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+FILE_VERSION_FILTER =
+# configuration options related to warning and progress messages
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+QUIET = NO
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+WARNINGS = YES
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+WARN_IF_UNDOCUMENTED = YES
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+WARN_IF_DOC_ERROR = YES
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+WARN_NO_PARAMDOC = NO
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+WARN_FORMAT = "$file:$line: $text"
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+WARN_LOGFILE =
+# configuration options related to the input files
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+INPUT = include/zookeeper.h
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+FILE_PATTERNS =
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+RECURSIVE = NO
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+EXCLUDE =
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+EXCLUDE_SYMLINKS = NO
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+EXCLUDE_PATTERNS =
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+EXAMPLE_PATH =
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# blank all files are included.
+EXAMPLE_PATTERNS =
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+EXAMPLE_RECURSIVE = NO
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+IMAGE_PATH =
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+INPUT_FILTER =
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+FILTER_PATTERNS =
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+FILTER_SOURCE_FILES = NO
+# configuration options related to source browsing
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+SOURCE_BROWSER = NO
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+INLINE_SOURCES = NO
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+STRIP_CODE_COMMENTS = YES
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+REFERENCED_BY_RELATION = YES
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+REFERENCES_RELATION = YES
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+REFERENCES_LINK_SOURCE = YES
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+USE_HTAGS = NO
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+VERBATIM_HEADERS = YES
+# configuration options related to the alphabetical class index
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+ALPHABETICAL_INDEX = NO
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+COLS_IN_ALPHA_INDEX = 5
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+IGNORE_PREFIX =
+# configuration options related to the HTML output
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+GENERATE_HTML = $(GENERATE_HTML)
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+HTML_OUTPUT = html
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+HTML_FILE_EXTENSION = .html
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+HTML_HEADER =
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# standard footer.
+HTML_FOOTER =
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+HTML_STYLESHEET =
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+HTML_ALIGN_MEMBERS = YES
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+GENERATE_HTMLHELP = $(GENERATE_HTMLHELP)
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+CHM_FILE = ../$(PROJECT).chm
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+HHC_LOCATION = $(HHC_PATH)
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+GENERATE_CHI = $(GENERATE_CHI)
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+BINARY_TOC = NO
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+TOC_EXPAND = NO
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+DISABLE_INDEX = NO
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+ENUM_VALUES_PER_LINE = 4
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+GENERATE_TREEVIEW = NO
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+TREEVIEW_WIDTH = 250
+# configuration options related to the LaTeX output
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+GENERATE_LATEX = $(GENERATE_LATEX)
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# put in front of it. If left blank `latex' will be used as the default path.
+LATEX_OUTPUT = latex
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+LATEX_CMD_NAME = latex
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+MAKEINDEX_CMD_NAME = makeindex
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+COMPACT_LATEX = NO
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+PAPER_TYPE = $(PAPER_SIZE)
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+EXTRA_PACKAGES =
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+LATEX_HEADER =
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+PDF_HYPERLINKS = NO
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+USE_PDFLATEX = $(GENERATE_PDF)
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+LATEX_BATCHMODE = NO
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+LATEX_HIDE_INDICES = NO
+# configuration options related to the RTF output
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+GENERATE_RTF = $(GENERATE_RTF)
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# put in front of it. If left blank `rtf' will be used as the default path.
+RTF_OUTPUT = rtf
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+COMPACT_RTF = NO
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+RTF_HYPERLINKS = NO
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+RTF_STYLESHEET_FILE =
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+RTF_EXTENSIONS_FILE =
+# configuration options related to the man page output
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+GENERATE_MAN = $(GENERATE_MAN)
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# put in front of it. If left blank `man' will be used as the default path.
+MAN_OUTPUT = man
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+MAN_EXTENSION = .3
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+MAN_LINKS = NO
+# configuration options related to the XML output
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+GENERATE_XML = $(GENERATE_XML)
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# put in front of it. If left blank `xml' will be used as the default path.
+XML_OUTPUT = xml
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+XML_SCHEMA =
+# The XML_DTD tag can be used to specify an XML DTD,
+XML_DTD =
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+XML_PROGRAMLISTING = YES
+# configuration options for the AutoGen Definitions output
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+GENERATE_AUTOGEN_DEF = NO
+# configuration options related to the Perl module output
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+GENERATE_PERLMOD = NO
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+PERLMOD_LATEX = NO
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+PERLMOD_PRETTY = YES
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+PERLMOD_MAKEVAR_PREFIX =
+# Configuration options related to the preprocessor
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+ENABLE_PREPROCESSING = YES
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+MACRO_EXPANSION = NO
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+EXPAND_ONLY_PREDEF = NO
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+SEARCH_INCLUDES = YES
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+INCLUDE_PATH =
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+INCLUDE_FILE_PATTERNS =
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+PREDEFINED =
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+EXPAND_AS_DEFINED =
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+SKIP_FUNCTION_MACROS = YES
+# Configuration::additions related to external references
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+TAGFILES =
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+GENERATE_TAGFILE = $(DOCDIR)/$(PROJECT).tag
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+ALLEXTERNALS = NO
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+EXTERNAL_GROUPS = YES
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+PERL_PATH = /usr/bin/perl
+# Configuration options related to the dot tool
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+CLASS_DIAGRAMS = YES
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+HIDE_UNDOC_RELATIONS = YES
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+HAVE_DOT = $(HAVE_DOT)
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+CLASS_GRAPH = YES
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+COLLABORATION_GRAPH = YES
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+GROUP_GRAPHS = YES
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+UML_LOOK = NO
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+TEMPLATE_RELATIONS = NO
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+INCLUDE_GRAPH = YES
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+INCLUDED_BY_GRAPH = YES
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+CALL_GRAPH = NO
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a caller dependency graph for every global function or class method.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+CALLER_GRAPH = NO
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+GRAPHICAL_HIERARCHY = YES
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+DIRECTORY_GRAPH = YES
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+DOT_IMAGE_FORMAT = png
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+DOT_PATH = $(DOT_PATH)
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+DOTFILE_DIRS =
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+MAX_DOT_GRAPH_WIDTH = 1024
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+MAX_DOT_GRAPH_HEIGHT = 1024
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that a graph may be further truncated if the graph's
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
+# the graph is not depth-constrained.
+MAX_DOT_GRAPH_DEPTH = 0
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+DOT_TRANSPARENT = NO
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+DOT_MULTI_TARGETS = NO
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+GENERATE_LEGEND = YES
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+DOT_CLEANUP = YES
+# Configuration::additions related to the search engine
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+SEARCHENGINE = NO
@@ -1,126 +1,126 @@
-/*
- * Date Format 1.2.3
- * (c) 2007-2009 Steven Levithan <stevenlevithan.com>
- * MIT license
- *
- * Includes enhancements by Scott Trenda <scott.trenda.net>
- * and Kris Kowal <cixar.com/~kris.kowal/>
- * Accepts a date, a mask, or a date and a mask.
- * Returns a formatted version of the given date.
- * The date defaults to the current date/time.
- * The mask defaults to dateFormat.masks.default.
- */
-var dateFormat = function () {
- var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
- timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
- timezoneClip = /[^-+\dA-Z]/g,
- pad = function (val, len) {
- val = String(val);
- len = len || 2;
- while (val.length < len) val = "0" + val;
- return val;
- };
- // Regexes and supporting functions are cached through closure
- return function (date, mask, utc) {
- var dF = dateFormat;
- // You can't provide utc if you skip other args (use the "UTC:" mask prefix)
- if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
- mask = date;
- date = undefined;
- }
- // Passing date through Date applies Date.parse, if necessary
- date = date ? new Date(date) : new Date;
- if (isNaN(date)) throw SyntaxError("invalid date");
- mask = String(dF.masks[mask] || mask || dF.masks["default"]);
- // Allow setting the utc argument via the mask
- if (mask.slice(0, 4) == "UTC:") {
- mask = mask.slice(4);
- utc = true;
- var _ = utc ? "getUTC" : "get",
- d = date[_ + "Date"](),
- D = date[_ + "Day"](),
- m = date[_ + "Month"](),
- y = date[_ + "FullYear"](),
- H = date[_ + "Hours"](),
- M = date[_ + "Minutes"](),
- s = date[_ + "Seconds"](),
- L = date[_ + "Milliseconds"](),
- o = utc ? 0 : date.getTimezoneOffset(),
- flags = {
- d: d,
- dd: pad(d),
- ddd: dF.i18n.dayNames[D],
- dddd: dF.i18n.dayNames[D + 7],
- m: m + 1,
- mm: pad(m + 1),
- mmm: dF.i18n.monthNames[m],
- mmmm: dF.i18n.monthNames[m + 12],
- yy: String(y).slice(2),
- yyyy: y,
- h: H % 12 || 12,
- hh: pad(H % 12 || 12),
- H: H,
- HH: pad(H),
- M: M,
- MM: pad(M),
- s: s,
- ss: pad(s),
- l: pad(L, 3),
- L: pad(L > 99 ? Math.round(L / 10) : L),
- t: H < 12 ? "a" : "p",
- tt: H < 12 ? "am" : "pm",
- T: H < 12 ? "A" : "P",
- TT: H < 12 ? "AM" : "PM",
- Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
- o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
- S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
- return mask.replace(token, function ($0) {
- return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
- });
-}();
-// Some common format strings
-dateFormat.masks = {
- "default": "ddd mmm dd yyyy HH:MM:ss",
- shortDate: "m/d/yy",
- mediumDate: "mmm d, yyyy",
- longDate: "mmmm d, yyyy",
- fullDate: "dddd, mmmm d, yyyy",
- shortTime: "h:MM TT",
- mediumTime: "h:MM:ss TT",
- longTime: "h:MM:ss TT Z",
- isoDate: "yyyy-mm-dd",
- isoTime: "HH:MM:ss",
- isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
- isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
-};
-// Internationalization strings
-dateFormat.i18n = {
- dayNames: [
- "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
- "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
- ],
- monthNames: [
- "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
- "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
- ]
-// For convenience...
-Date.prototype.format = function (mask, utc) {
- return dateFormat(this, mask, utc);
+/*
+ * Date Format 1.2.3
+ * (c) 2007-2009 Steven Levithan <stevenlevithan.com>
+ * MIT license
+ *
+ * Includes enhancements by Scott Trenda <scott.trenda.net>
+ * and Kris Kowal <cixar.com/~kris.kowal/>
+ * Accepts a date, a mask, or a date and a mask.
+ * Returns a formatted version of the given date.
+ * The date defaults to the current date/time.
+ * The mask defaults to dateFormat.masks.default.
+ */
+var dateFormat = function () {
+ var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
+ timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
+ timezoneClip = /[^-+\dA-Z]/g,
+ pad = function (val, len) {
+ val = String(val);
+ len = len || 2;
+ while (val.length < len) val = "0" + val;
+ return val;
+ };
+ // Regexes and supporting functions are cached through closure
+ return function (date, mask, utc) {
+ var dF = dateFormat;
+ // You can't provide utc if you skip other args (use the "UTC:" mask prefix)
+ if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
+ mask = date;
+ date = undefined;
+ }
+ // Passing date through Date applies Date.parse, if necessary
+ date = date ? new Date(date) : new Date;
+ if (isNaN(date)) throw SyntaxError("invalid date");
+ mask = String(dF.masks[mask] || mask || dF.masks["default"]);
+ // Allow setting the utc argument via the mask
+ if (mask.slice(0, 4) == "UTC:") {
+ mask = mask.slice(4);
+ utc = true;
+ var _ = utc ? "getUTC" : "get",
+ d = date[_ + "Date"](),
+ D = date[_ + "Day"](),
+ m = date[_ + "Month"](),
+ y = date[_ + "FullYear"](),
+ H = date[_ + "Hours"](),
+ M = date[_ + "Minutes"](),
+ s = date[_ + "Seconds"](),
+ L = date[_ + "Milliseconds"](),
+ o = utc ? 0 : date.getTimezoneOffset(),
+ flags = {
+ d: d,
+ dd: pad(d),
+ ddd: dF.i18n.dayNames[D],
+ dddd: dF.i18n.dayNames[D + 7],
+ m: m + 1,
+ mm: pad(m + 1),
+ mmm: dF.i18n.monthNames[m],
+ mmmm: dF.i18n.monthNames[m + 12],
+ yy: String(y).slice(2),
+ yyyy: y,
+ h: H % 12 || 12,
+ hh: pad(H % 12 || 12),
+ H: H,
+ HH: pad(H),
+ M: M,
+ MM: pad(M),
+ s: s,
+ ss: pad(s),
+ l: pad(L, 3),
+ L: pad(L > 99 ? Math.round(L / 10) : L),
+ t: H < 12 ? "a" : "p",
+ tt: H < 12 ? "am" : "pm",
+ T: H < 12 ? "A" : "P",
+ TT: H < 12 ? "AM" : "PM",
+ Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
+ o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
+ S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
+ return mask.replace(token, function ($0) {
+ return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
+ });
+}();
+// Some common format strings
+dateFormat.masks = {
+ "default": "ddd mmm dd yyyy HH:MM:ss",
+ shortDate: "m/d/yy",
+ mediumDate: "mmm d, yyyy",
+ longDate: "mmmm d, yyyy",
+ fullDate: "dddd, mmmm d, yyyy",
+ shortTime: "h:MM TT",
+ mediumTime: "h:MM:ss TT",
+ longTime: "h:MM:ss TT Z",
+ isoDate: "yyyy-mm-dd",
+ isoTime: "HH:MM:ss",
+ isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
+ isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
+};
+// Internationalization strings
+dateFormat.i18n = {
+ dayNames: [
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+ ],
+ monthNames: [
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
+ ]
+// For convenience...
+Date.prototype.format = function (mask, utc) {
+ return dateFormat(this, mask, utc);
@@ -1,94 +1,94 @@
-==========================================
-ZooInspector - Browser and Editor for ZooKeeper Instances
-Author: Colin Goodheart-Smithe
-Date: February 2010
-==========================================
-ZooInspector is a Java Swing based application for browsing and editing ZooKeeper instances.
-Contents
---------
- - Features
- - Pre-requisites
- - Build Instructions
- - Using ZooInspector
- - Creating and Using Plugins
-Features
- Below is a list of features in the current release of ZooInspector.
- - Load connection settings from a zookeeper properties file
- - Plugable DataEncryptionManagers to specify how data should be encrypted and decrypted in the Zookeeper instance
- - Browseable tree view of the ZooKeeper instance
- - View the data in a node
- - View the ACL's currently applied to a node
- - View the metadata for a node (Version, Number of Children, Last modified Tiem, etc.)
- - Plugable NodeViewers interface
- - Ability to save/load and set default Node Viewers
-Pre-requisites
---------------
- - The main zookeeper build script must have been run before building this module
-Build Instructions
-------------------
- 1. Open a command line.
- 2. cd into this directory
- 3. Run command: ant
- 4. ZooInspector will be built to ../../../build/contrib/ZooInspector
- 5. Copy zookeeper-3.x.x.jar into the lib sub-directory (if you are using zookeeper-3.3.0.jar it will have been
- copied to this directory during the build
- 6. By default the zookeeper.cmd and zookeeper.sh files expect zookeeper-3.3.0.jar. If you are using another version
- you will need to change these files to point to the zookeeper-3.x.x.jar you copied to the lib directory
- 7. To run ZooInspector run zooInspector.cmd (on Windows) or zooInspector.sh (on Linux). If you are using
- zookeeper-3.3.0.jar and do not require any classpath changes you can run the zookeeper-dev-ZooInspector.jar
- directly
-Using ZooInspector
- To start ZooInspector run zooInspector.cmd (on Windows) or zooInspector.sh (on Linux). If you are using
- directly.
- Click the play button on the toolbar to bring up the connection dialog. From here you can enter connection
- information for your zookeeper instance. You can also load the connection properties from a file. This file can
- have the format as a normal zookeeper properties file (i.e. hosts and timeout key-value pairs) and van optional have
- an encryptionManager key-value pair to specify the DataEncryptionManager to use for this connection
- (DataEncryptionManagers are explained in further detail in the 'Creating and Using Plugins' section below). You can
- also set the entered information as the defaults so that when you first start ZooInspector these settings are
- automatically loaded into this dialog. Pressing the OK button with connect to your ZooKeeper instance and show the
- current node tree on the left of the main panel.
- Clicking a node in the node tree will load the data for that node into the node viewers. Three node viewers are
- currently distributed with ZooInspector:
- 1. Node Data - This enables you to see the data current stored on that node. This data can be modified and
- saved. The data is decrypted and encrypted using the DataEncryptionManager specified on the connection
- dialog.
- 2. Node Metadata - This enables you to see the metadata associiated with this node. This is Essentially the data
- obtained from the Stat object for this node.
- 3. Node ACLs - This allows you to see the ACLs currently applied to this node. Currently there is no ability
- to change the ACLs on a node, but it is a feature I would like to add.
- Other custom Node Viewers can be added, this is explained in the 'Creating and Using Plugins' section below.
-Creating and Using Plugins
---------------------------
- There are two types of plugin which can be used with ZooInspector:
- 1. DataEncryptionManager - This specifies how data should be encrypted and decrypted when working with a
- zookeeper instance.
- 2. ZooInspectorNodeViewer - This is a GUI panel which provides a view of visualisation on a node.
- More information on these interfaces can be found in the javadocs for this module.
- To use a plugin in ZooInspector, build the plugin to a jar and copy the jar to the lib sub-directory. Edit the
- zooInspector.cmd and/or zooInspector.sh files to include your new jar on the classpath and run ZooInspector.
- For DataEncryptionManagers, click the play button to open the connection dialog and enter the full class name of
- your DataEncryptionManager in the 'Data Encryption Manager' field. You can make this Data Encryption Manager the
- default by clicking 'Set As Default'. Click the 'OK' button to instantiate and use your plugin.
- For ZooInspectorNodeViewers, Click the 'Change Node Viewers' button on the toolbar (looks like a tree with a pencil)
- and enter the full classname for your Node Viewer in the field left of the 'Add' button, then click the 'Add'
- button. The Node Viewer will be instantiated and should appear in the list. You can change the order of the Node
- viewers by clicking the up and dpwn buttons and delete a Node Viewer by clicking the delete button. You can save
- to configuration to a file or set it as the default if necessary. Then click the 'OK' button and your Node Viewer
+==========================================
+ZooInspector - Browser and Editor for ZooKeeper Instances
+Author: Colin Goodheart-Smithe
+Date: February 2010
+==========================================
+ZooInspector is a Java Swing based application for browsing and editing ZooKeeper instances.
+Contents
+--------
+ - Features
+ - Pre-requisites
+ - Build Instructions
+ - Using ZooInspector
+ - Creating and Using Plugins
+Features
+ Below is a list of features in the current release of ZooInspector.
+ - Load connection settings from a zookeeper properties file
+ - Plugable DataEncryptionManagers to specify how data should be encrypted and decrypted in the Zookeeper instance
+ - Browseable tree view of the ZooKeeper instance
+ - View the data in a node
+ - View the ACL's currently applied to a node
+ - View the metadata for a node (Version, Number of Children, Last modified Tiem, etc.)
+ - Plugable NodeViewers interface
+ - Ability to save/load and set default Node Viewers
+Pre-requisites
+--------------
+ - The main zookeeper build script must have been run before building this module
+Build Instructions
+------------------
+ 1. Open a command line.
+ 2. cd into this directory
+ 3. Run command: ant
+ 4. ZooInspector will be built to ../../../build/contrib/ZooInspector
+ 5. Copy zookeeper-3.x.x.jar into the lib sub-directory (if you are using zookeeper-3.3.0.jar it will have been
+ copied to this directory during the build
+ 6. By default the zookeeper.cmd and zookeeper.sh files expect zookeeper-3.3.0.jar. If you are using another version
+ you will need to change these files to point to the zookeeper-3.x.x.jar you copied to the lib directory
+ 7. To run ZooInspector run zooInspector.cmd (on Windows) or zooInspector.sh (on Linux). If you are using
+ zookeeper-3.3.0.jar and do not require any classpath changes you can run the zookeeper-dev-ZooInspector.jar
+ directly
+Using ZooInspector
+ To start ZooInspector run zooInspector.cmd (on Windows) or zooInspector.sh (on Linux). If you are using
+ directly.
+ Click the play button on the toolbar to bring up the connection dialog. From here you can enter connection
+ information for your zookeeper instance. You can also load the connection properties from a file. This file can
+ have the format as a normal zookeeper properties file (i.e. hosts and timeout key-value pairs) and van optional have
+ an encryptionManager key-value pair to specify the DataEncryptionManager to use for this connection
+ (DataEncryptionManagers are explained in further detail in the 'Creating and Using Plugins' section below). You can
+ also set the entered information as the defaults so that when you first start ZooInspector these settings are
+ automatically loaded into this dialog. Pressing the OK button with connect to your ZooKeeper instance and show the
+ current node tree on the left of the main panel.
+ Clicking a node in the node tree will load the data for that node into the node viewers. Three node viewers are
+ currently distributed with ZooInspector:
+ 1. Node Data - This enables you to see the data current stored on that node. This data can be modified and
+ saved. The data is decrypted and encrypted using the DataEncryptionManager specified on the connection
+ dialog.
+ 2. Node Metadata - This enables you to see the metadata associiated with this node. This is Essentially the data
+ obtained from the Stat object for this node.
+ 3. Node ACLs - This allows you to see the ACLs currently applied to this node. Currently there is no ability
+ to change the ACLs on a node, but it is a feature I would like to add.
+ Other custom Node Viewers can be added, this is explained in the 'Creating and Using Plugins' section below.
+Creating and Using Plugins
+--------------------------
+ There are two types of plugin which can be used with ZooInspector:
+ 1. DataEncryptionManager - This specifies how data should be encrypted and decrypted when working with a
+ zookeeper instance.
+ 2. ZooInspectorNodeViewer - This is a GUI panel which provides a view of visualisation on a node.
+ More information on these interfaces can be found in the javadocs for this module.
+ To use a plugin in ZooInspector, build the plugin to a jar and copy the jar to the lib sub-directory. Edit the
+ zooInspector.cmd and/or zooInspector.sh files to include your new jar on the classpath and run ZooInspector.
+ For DataEncryptionManagers, click the play button to open the connection dialog and enter the full class name of
+ your DataEncryptionManager in the 'Data Encryption Manager' field. You can make this Data Encryption Manager the
+ default by clicking 'Set As Default'. Click the 'OK' button to instantiate and use your plugin.
+ For ZooInspectorNodeViewers, Click the 'Change Node Viewers' button on the toolbar (looks like a tree with a pencil)
+ and enter the full classname for your Node Viewer in the field left of the 'Add' button, then click the 'Add'
+ button. The Node Viewer will be instantiated and should appear in the list. You can change the order of the Node
+ viewers by clicking the up and dpwn buttons and delete a Node Viewer by clicking the delete button. You can save
+ to configuration to a file or set it as the default if necessary. Then click the 'OK' button and your Node Viewer
should appear in the tabs on the right of the main panel.
@@ -1,139 +1,139 @@
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<project name="ZooInspector" default="jar">
- <import file="../build-contrib.xml" />
- <target name="setjarname">
- <property name="jarname" value="${build.dir}/zookeeper-${version}-${name}.jar" />
- </target>
- <target name="init" depends="checkMainCompiled, zookeeperbuildcontrib.init">
- <mkdir dir="${build.dir}/licences" />
- <copy todir="${build.dir}/licences">
- <fileset dir="${basedir}/licences" />
- </copy>
- <mkdir dir="${build.dir}/icons" />
- <copy todir="${build.dir}/icons">
- <fileset dir="${basedir}/src/main/resources/icons" />
- <mkdir dir="${build.dir}/config" />
- <copy todir="${build.dir}/config">
- <fileset dir="${basedir}/config" />
- <copy todir="${build.dir}/lib">
- <fileset file="${basedir}/lib/log4j.properties" />
- <fileset file="../../../build/zookeeper-${version}.jar" />
- <copy todir="${build.dir}">
- <fileset dir="${basedir}" includes="*.*" excludes="build.xml,ivy.xml" />
- <!-- Override jar target to specify main class -->
- <target name="jar" depends="setjarname, compile">
- <echo message="contrib: ${name}" />
- <jar jarfile="${jarname}">
- <manifest>
- <attribute name="Main-Class" value="org.apache.zookeeper.inspector.ZooInspector" />
- <attribute name="Built-By" value="${user.name}" />
- <attribute name="Built-At" value="${build.time}" />
- <attribute name="Built-On" value="${host.name}" />
- <attribute name="Implementation-Title" value="org.apache.zookeeper" />
- <attribute name="Implementation-Version" value="${revision}" />
- <attribute name="Implementation-Vendor" value="The Apache Software Foundation" />
- </manifest>
- <fileset file="${zk.root}/LICENSE.txt" />
- <fileset dir="${build.classes}" />
- <fileset dir="${basedir}/src/main/resources" />
- <fileset dir="${basedir}/src/java" excludes="**/*.jar, **/*.java"/>
- </jar>
- <target name="compile" depends="ivy-retrieve,zookeeperbuildcontrib.compile" />
- <target name="test" depends="checkMainTestCompiled,compile-test,test-init,test-category,junit.run" />
- <target name="compile-test" depends="ivy-retrieve-test,compile">
- <property name="target.jdk" value="${ant.java.version}" />
- <property name="src.test.local" location="${basedir}/test" />
- <mkdir dir="${build.test}" />
- <javac srcdir="${src.test.local}" destdir="${build.test}" target="${target.jdk}" debug="on">
- <classpath refid="classpath" />
- <classpath>
- <pathelement location="${zk.root}/build/test/classes" />
- </classpath>
- </javac>
- <target name="test-init" depends="jar,compile-test">
- <delete dir="${test.log.dir}" />
- <delete dir="${test.tmp.dir}" />
- <delete dir="${test.data.dir}" />
- <mkdir dir="${test.log.dir}" />
- <mkdir dir="${test.tmp.dir}" />
- <mkdir dir="${test.data.dir}" />
- <target name="test-category">
- <property name="test.category" value="" />
- <target name="junit.run">
- <echo message="${test.src.dir}" />
- <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">
- <sysproperty key="build.test.dir" value="${test.tmp.dir}" />
- <sysproperty key="test.data.dir" value="${test.data.dir}" />
- <sysproperty key="log4j.configuration" value="file:${basedir}/conf/log4j.properties" />
- <pathelement path="${build.test}" />
- <formatter type="${test.junit.output.format}" />
- <batchtest todir="${test.log.dir}" unless="testcase">
- <fileset dir="${test.src.dir}" includes="**/*${test.category}Test.java" />
- </batchtest>
- <batchtest todir="${test.log.dir}" if="testcase">
- <fileset dir="${test.src.dir}" includes="**/${testcase}.java" />
- </junit>
- <fail if="tests.failed">Tests failed!</fail>
- <target name="package" depends="jar, zookeeperbuildcontrib.package" unless="skip.contrib">
- <copy file="${basedir}/build.xml" todir="${dist.dir}/contrib/${name}" />
- <mkdir dir="${dist.dir}/contrib/${name}/src" />
- <copy todir="${dist.dir}/contrib/${name}/src">
- <fileset dir="${basedir}/src" />
- <mkdir dir="${dist.dir}/contrib/${name}/licences" />
- <copy todir="${dist.dir}/contrib/${name}/licences">
- <mkdir dir="${dist.dir}/contrib/${name}/config" />
- <copy todir="${dist.dir}/contrib/${name}/config">
-</project>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project name="ZooInspector" default="jar">
+ <import file="../build-contrib.xml" />
+ <target name="setjarname">
+ <property name="jarname" value="${build.dir}/zookeeper-${version}-${name}.jar" />
+ </target>
+ <target name="init" depends="checkMainCompiled, zookeeperbuildcontrib.init">
+ <mkdir dir="${build.dir}/licences" />
+ <copy todir="${build.dir}/licences">
+ <fileset dir="${basedir}/licences" />
+ </copy>
+ <mkdir dir="${build.dir}/icons" />
+ <copy todir="${build.dir}/icons">
+ <fileset dir="${basedir}/src/main/resources/icons" />
+ <mkdir dir="${build.dir}/config" />
+ <copy todir="${build.dir}/config">
+ <fileset dir="${basedir}/config" />
+ <copy todir="${build.dir}/lib">
+ <fileset file="${basedir}/lib/log4j.properties" />
+ <fileset file="../../../build/zookeeper-${version}.jar" />
+ <copy todir="${build.dir}">
+ <fileset dir="${basedir}" includes="*.*" excludes="build.xml,ivy.xml" />
+ <!-- Override jar target to specify main class -->
+ <target name="jar" depends="setjarname, compile">
+ <echo message="contrib: ${name}" />
+ <jar jarfile="${jarname}">
+ <manifest>
+ <attribute name="Main-Class" value="org.apache.zookeeper.inspector.ZooInspector" />
+ <attribute name="Built-By" value="${user.name}" />
+ <attribute name="Built-At" value="${build.time}" />
+ <attribute name="Built-On" value="${host.name}" />
+ <attribute name="Implementation-Title" value="org.apache.zookeeper" />
+ <attribute name="Implementation-Version" value="${revision}" />
+ <attribute name="Implementation-Vendor" value="The Apache Software Foundation" />
+ </manifest>
+ <fileset file="${zk.root}/LICENSE.txt" />
+ <fileset dir="${build.classes}" />
+ <fileset dir="${basedir}/src/main/resources" />
+ <fileset dir="${basedir}/src/java" excludes="**/*.jar, **/*.java"/>
+ </jar>
+ <target name="compile" depends="ivy-retrieve,zookeeperbuildcontrib.compile" />
+ <target name="test" depends="checkMainTestCompiled,compile-test,test-init,test-category,junit.run" />
+ <target name="compile-test" depends="ivy-retrieve-test,compile">
+ <property name="target.jdk" value="${ant.java.version}" />
+ <property name="src.test.local" location="${basedir}/test" />
+ <mkdir dir="${build.test}" />
+ <javac srcdir="${src.test.local}" destdir="${build.test}" target="${target.jdk}" debug="on">
+ <classpath refid="classpath" />
+ <classpath>
+ <pathelement location="${zk.root}/build/test/classes" />
+ </classpath>
+ </javac>
+ <target name="test-init" depends="jar,compile-test">
+ <delete dir="${test.log.dir}" />
+ <delete dir="${test.tmp.dir}" />
+ <delete dir="${test.data.dir}" />
+ <mkdir dir="${test.log.dir}" />
+ <mkdir dir="${test.tmp.dir}" />
+ <mkdir dir="${test.data.dir}" />
+ <target name="test-category">
+ <property name="test.category" value="" />
+ <target name="junit.run">
+ <echo message="${test.src.dir}" />
+ <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">
+ <sysproperty key="build.test.dir" value="${test.tmp.dir}" />
+ <sysproperty key="test.data.dir" value="${test.data.dir}" />
+ <sysproperty key="log4j.configuration" value="file:${basedir}/conf/log4j.properties" />
+ <pathelement path="${build.test}" />
+ <formatter type="${test.junit.output.format}" />
+ <batchtest todir="${test.log.dir}" unless="testcase">
+ <fileset dir="${test.src.dir}" includes="**/*${test.category}Test.java" />
+ </batchtest>
+ <batchtest todir="${test.log.dir}" if="testcase">
+ <fileset dir="${test.src.dir}" includes="**/${testcase}.java" />
+ </junit>
+ <fail if="tests.failed">Tests failed!</fail>
+ <target name="package" depends="jar, zookeeperbuildcontrib.package" unless="skip.contrib">
+ <copy file="${basedir}/build.xml" todir="${dist.dir}/contrib/${name}" />
+ <mkdir dir="${dist.dir}/contrib/${name}/src" />
+ <copy todir="${dist.dir}/contrib/${name}/src">
+ <fileset dir="${basedir}/src" />
+ <mkdir dir="${dist.dir}/contrib/${name}/licences" />
+ <copy todir="${dist.dir}/contrib/${name}/licences">
+ <mkdir dir="${dist.dir}/contrib/${name}/config" />
+ <copy todir="${dist.dir}/contrib/${name}/config">
+</project>
@@ -1,48 +1,48 @@
-<ivy-module version="2.0"
- xmlns:e="http://ant.apache.org/ivy/extra">
- <info organisation="org.apache.zookeeper"
- module="${name}" revision="${version}">
- <license name="Apache 2.0"/>
- <ivyauthor name="Apache Hadoop" url="http://hadoop.apache.org"/>
- <description>ZooInspector</description>
- </info>
- <configurations defaultconfmapping="default">
- <conf name="default"/>
- <conf name="test"/>
- <conf name="releaseaudit" visibility="private" description="Artifacts required for releaseaudit target"/>
- </configurations>
- <dependencies>
- <dependency org="org.slf4j" name="slf4j-api" rev="1.6.1"/>
- <dependency org="org.slf4j" name="slf4j-log4j12" rev="1.6.1" transitive="false"/>
- <dependency org="log4j" name="log4j" rev="1.2.15" transitive="false"/>
- <dependency org="junit" name="junit" rev="4.7" conf="test->default"/>
- <dependency org="org.apache.rat" name="apache-rat-tasks"
- rev="0.6" conf="releaseaudit->default"/>
- <dependency org="commons-lang" name="commons-lang"
- rev="2.4" conf="releaseaudit->default"/>
- <dependency org="commons-collections" name="commons-collections"
- rev="3.1" conf="releaseaudit->default"/>
- </dependencies>
+<ivy-module version="2.0"
+ xmlns:e="http://ant.apache.org/ivy/extra">
+ <info organisation="org.apache.zookeeper"
+ module="${name}" revision="${version}">
+ <license name="Apache 2.0"/>
+ <ivyauthor name="Apache Hadoop" url="http://hadoop.apache.org"/>
+ <description>ZooInspector</description>
+ </info>
+ <configurations defaultconfmapping="default">
+ <conf name="default"/>
+ <conf name="test"/>
+ <conf name="releaseaudit" visibility="private" description="Artifacts required for releaseaudit target"/>
+ </configurations>
+ <dependencies>
+ <dependency org="org.slf4j" name="slf4j-api" rev="1.6.1"/>
+ <dependency org="org.slf4j" name="slf4j-log4j12" rev="1.6.1" transitive="false"/>
+ <dependency org="log4j" name="log4j" rev="1.2.15" transitive="false"/>
+ <dependency org="junit" name="junit" rev="4.7" conf="test->default"/>
+ <dependency org="org.apache.rat" name="apache-rat-tasks"
+ rev="0.6" conf="releaseaudit->default"/>
+ <dependency org="commons-lang" name="commons-lang"
+ rev="2.4" conf="releaseaudit->default"/>
+ <dependency org="commons-collections" name="commons-collections"
+ rev="3.1" conf="releaseaudit->default"/>
+ </dependencies>
</ivy-module>
@@ -1,9 +1,9 @@
-# ***** Set root logger level to INFO and it appender to stdout.
-log4j.rootLogger=INFO,stdout
-# ***** stdout is set to be a ConsoleAppender.
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-# ***** stdout uses PatternLayout.
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-# ***** Pattern to output the caller's file name and line number.
+# ***** Set root logger level to INFO and it appender to stdout.
+log4j.rootLogger=INFO,stdout
+# ***** stdout is set to be a ConsoleAppender.
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+# ***** stdout uses PatternLayout.
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+# ***** Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
@@ -1,71 +1,71 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-package org.apache.zookeeper.inspector;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import javax.swing.JFrame;
-import javax.swing.JOptionPane;
-import javax.swing.UIManager;
-import org.apache.zookeeper.inspector.gui.IconResource;
-import org.apache.zookeeper.inspector.gui.ZooInspectorPanel;
-import org.apache.zookeeper.inspector.logger.LoggerFactory;
-import org.apache.zookeeper.inspector.manager.ZooInspectorManagerImpl;
-public class ZooInspector {
- public static IconResource iconResource;
- /**
- * @param args
- * - not used. The value of these parameters will have no effect
- * on the application
- public static void main(String[] args) {
- try {
- UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
- JFrame frame = new JFrame("ZooInspector");
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- iconResource = new IconResource();
- final ZooInspectorPanel zooInspectorPanel = new ZooInspectorPanel(
- new ZooInspectorManagerImpl(), iconResource);
- frame.addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosed(WindowEvent e) {
- super.windowClosed(e);
- zooInspectorPanel.disconnect(true);
- frame.setContentPane(zooInspectorPanel);
- frame.setSize(1024, 768);
- frame.setVisible(true);
- } catch (Exception e) {
- LoggerFactory.getLogger().error(
- "Error occurred loading ZooInspector", e);
- JOptionPane.showMessageDialog(null,
- "ZooInspector failed to start: " + e.getMessage(), "Error",
- JOptionPane.ERROR_MESSAGE);
-}
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+package org.apache.zookeeper.inspector;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+import javax.swing.UIManager;
+import org.apache.zookeeper.inspector.gui.IconResource;
+import org.apache.zookeeper.inspector.gui.ZooInspectorPanel;
+import org.apache.zookeeper.inspector.logger.LoggerFactory;
+import org.apache.zookeeper.inspector.manager.ZooInspectorManagerImpl;
+public class ZooInspector {
+ public static IconResource iconResource;
+ /**
+ * @param args
+ * - not used. The value of these parameters will have no effect
+ * on the application
+ public static void main(String[] args) {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ JFrame frame = new JFrame("ZooInspector");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ iconResource = new IconResource();
+ final ZooInspectorPanel zooInspectorPanel = new ZooInspectorPanel(
+ new ZooInspectorManagerImpl(), iconResource);
+ frame.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosed(WindowEvent e) {
+ super.windowClosed(e);
+ zooInspectorPanel.disconnect(true);
+ frame.setContentPane(zooInspectorPanel);
+ frame.setSize(1024, 768);
+ frame.setVisible(true);
+ } catch (Exception e) {
+ LoggerFactory.getLogger().error(
+ "Error occurred loading ZooInspector", e);
+ JOptionPane.showMessageDialog(null,
+ "ZooInspector failed to start: " + e.getMessage(), "Error",
+ JOptionPane.ERROR_MESSAGE);
+}
@@ -1,50 +1,50 @@
-package org.apache.zookeeper.inspector.encryption;
-public class BasicDataEncryptionManager implements DataEncryptionManager {
- /*
- * (non-Javadoc)
- * @see
- * org.apache.zookeeper.inspector.encryption.DataEncryptionManager#decryptData
- * (byte[])
- public String decryptData(byte[] encrypted) throws Exception {
- return new String(encrypted);
- * org.apache.zookeeper.inspector.encryption.DataEncryptionManager#encryptData
- * (java.lang.String)
- public byte[] encryptData(String data) throws Exception {
- if (data == null) {
- return new byte[0];
- return data.getBytes();
+package org.apache.zookeeper.inspector.encryption;
+public class BasicDataEncryptionManager implements DataEncryptionManager {
+ /*
+ * (non-Javadoc)
+ * @see
+ * org.apache.zookeeper.inspector.encryption.DataEncryptionManager#decryptData
+ * (byte[])
+ public String decryptData(byte[] encrypted) throws Exception {
+ return new String(encrypted);
+ * org.apache.zookeeper.inspector.encryption.DataEncryptionManager#encryptData
+ * (java.lang.String)
+ public byte[] encryptData(String data) throws Exception {
+ if (data == null) {
+ return new byte[0];
+ return data.getBytes();
@@ -1,39 +1,39 @@
- * A class which describes how data should be encrypted and decrypted
-public interface DataEncryptionManager {
- * @param data
- * - the data to be encrypted
- * @return the encrypted data
- * @throws Exception
- public byte[] encryptData(String data) throws Exception;
- * @param encrypted
- * - the data to be decrypted
- * @return the decrypted data
- public String decryptData(byte[] encrypted) throws Exception;
+ * A class which describes how data should be encrypted and decrypted
+public interface DataEncryptionManager {
+ * @param data
+ * - the data to be encrypted
+ * @return the encrypted data
+ * @throws Exception
+ public byte[] encryptData(String data) throws Exception;
+ * @param encrypted
+ * - the data to be decrypted
+ * @return the decrypted data
+ public String decryptData(byte[] encrypted) throws Exception;
@@ -1,37 +1,37 @@
-package org.apache.zookeeper.inspector.gui;
-import java.util.List;
-import org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer;
- * A Listener for changes to the configuration of which node viewers are shown
-public interface NodeViewersChangeListener {
- * Called when the node viewers configuration is changed (i.e node viewers
- * are added, removed or the order of the node viewers is changed)
- * @param newViewers
- * - a {@link List} of {@link ZooInspectorNodeViewer}s which are
- * to be shown
- public void nodeViewersChanged(List<ZooInspectorNodeViewer> newViewers);
+package org.apache.zookeeper.inspector.gui;
+import java.util.List;
+import org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer;
+ * A Listener for changes to the configuration of which node viewers are shown
+public interface NodeViewersChangeListener {
+ * Called when the node viewers configuration is changed (i.e node viewers
+ * are added, removed or the order of the node viewers is changed)
+ * @param newViewers
+ * - a {@link List} of {@link ZooInspectorNodeViewer}s which are
+ * to be shown
+ public void nodeViewersChanged(List<ZooInspectorNodeViewer> newViewers);
@@ -1,79 +1,79 @@
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.awt.Frame;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.io.IOException;
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JEditorPane;
-import javax.swing.JPanel;
- * The About Dialog for the application
-public class ZooInspectorAboutDialog extends JDialog {
- * @param frame
- * - the Frame from which the dialog is displayed
- public ZooInspectorAboutDialog(Frame frame, IconResource iconResource) {
- super(frame);
- this.setLayout(new BorderLayout());
- this.setIconImage(iconResource.get(IconResource.ICON_INFORMATION, "About ZooInspector").getImage());
- this.setTitle("About ZooInspector");
- this.setModal(true);
- this.setAlwaysOnTop(true);
- this.setResizable(false);
- JPanel panel = new JPanel();
- panel.setLayout(new BorderLayout());
- JEditorPane aboutPane = new JEditorPane();
- aboutPane.setEditable(false);
- aboutPane.setOpaque(false);
- java.net.URL aboutURL = ZooInspectorAboutDialog.class
- .getResource("about.html");
- aboutPane.setPage(aboutURL);
- } catch (IOException e) {
- "Error loading about.html, file may be corrupt", e);
- panel.add(aboutPane, BorderLayout.CENTER);
- panel.setPreferredSize(new Dimension(600, 200));
- JPanel buttonsPanel = new JPanel();
- buttonsPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));
- JButton okButton = new JButton("OK");
- okButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- ZooInspectorAboutDialog.this.dispose();
- buttonsPanel.add(okButton);
- this.add(panel, BorderLayout.CENTER);
- this.add(buttonsPanel, BorderLayout.SOUTH);
- this.pack();
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JEditorPane;
+import javax.swing.JPanel;
+ * The About Dialog for the application
+public class ZooInspectorAboutDialog extends JDialog {
+ * @param frame
+ * - the Frame from which the dialog is displayed
+ public ZooInspectorAboutDialog(Frame frame, IconResource iconResource) {
+ super(frame);
+ this.setLayout(new BorderLayout());
+ this.setIconImage(iconResource.get(IconResource.ICON_INFORMATION, "About ZooInspector").getImage());
+ this.setTitle("About ZooInspector");
+ this.setModal(true);
+ this.setAlwaysOnTop(true);
+ this.setResizable(false);
+ JPanel panel = new JPanel();
+ panel.setLayout(new BorderLayout());
+ JEditorPane aboutPane = new JEditorPane();
+ aboutPane.setEditable(false);
+ aboutPane.setOpaque(false);
+ java.net.URL aboutURL = ZooInspectorAboutDialog.class
+ .getResource("about.html");
+ aboutPane.setPage(aboutURL);
+ } catch (IOException e) {
+ "Error loading about.html, file may be corrupt", e);
+ panel.add(aboutPane, BorderLayout.CENTER);
+ panel.setPreferredSize(new Dimension(600, 200));
+ JPanel buttonsPanel = new JPanel();
+ buttonsPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));
+ JButton okButton = new JButton("OK");
+ okButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ ZooInspectorAboutDialog.this.dispose();
+ buttonsPanel.add(okButton);
+ this.add(panel, BorderLayout.CENTER);
+ this.add(buttonsPanel, BorderLayout.SOUTH);
+ this.pack();
@@ -1,321 +1,321 @@
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.io.File;
-import java.io.FileReader;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Map.Entry;
-import javax.swing.JComboBox;
-import javax.swing.JComponent;
-import javax.swing.JFileChooser;
-import javax.swing.JLabel;
-import javax.swing.JTextField;
-import org.apache.zookeeper.inspector.manager.Pair;
- * The connection properties dialog. This is used to determine the settings for
- * connecting to a zookeeper instance
-public class ZooInspectorConnectionPropertiesDialog extends JDialog {
- private final HashMap<String, JComponent> components;
- * @param lastConnectionProps
- * - the last connection properties used. if this is the first
- * conneciton since starting the applications this will be the
- * default settings
- * @param connectionPropertiesTemplateAndLabels
- * - the connection properties and labels to show in this dialog
- * @param zooInspectorPanel
- * - the {@link ZooInspectorPanel} linked to this dialog
- public ZooInspectorConnectionPropertiesDialog(
- Properties lastConnectionProps,
- Pair<Map<String, List<String>>, Map<String, String>> connectionPropertiesTemplateAndLabels,
- final ZooInspectorPanel zooInspectorPanel) {
- final Map<String, List<String>> connectionPropertiesTemplate = connectionPropertiesTemplateAndLabels
- .getKey();
- final Map<String, String> connectionPropertiesLabels = connectionPropertiesTemplateAndLabels
- .getValue();
- this.setTitle("Connection Settings");
- final JPanel options = new JPanel();
- final JFileChooser fileChooser = new JFileChooser();
- options.setLayout(new GridBagLayout());
- int i = 0;
- components = new HashMap<String, JComponent>();
- for (Entry<String, List<String>> entry : connectionPropertiesTemplate
- .entrySet()) {
- int rowPos = 2 * i + 1;
- JLabel label = new JLabel(connectionPropertiesLabels.get(entry
- .getKey()));
- GridBagConstraints c1 = new GridBagConstraints();
- c1.gridx = 0;
- c1.gridy = rowPos;
- c1.gridwidth = 1;
- c1.gridheight = 1;
- c1.weightx = 0;
- c1.weighty = 0;
- c1.anchor = GridBagConstraints.WEST;
- c1.fill = GridBagConstraints.HORIZONTAL;
- c1.insets = new Insets(5, 5, 5, 5);
- c1.ipadx = 0;
- c1.ipady = 0;
- options.add(label, c1);
- if (entry.getValue().size() == 0) {
- JTextField text = new JTextField();
- GridBagConstraints c2 = new GridBagConstraints();
- c2.gridx = 2;
- c2.gridy = rowPos;
- c2.gridwidth = 1;
- c2.gridheight = 1;
- c2.weightx = 0;
- c2.weighty = 0;
- c2.anchor = GridBagConstraints.WEST;
- c2.fill = GridBagConstraints.HORIZONTAL;
- c2.insets = new Insets(5, 5, 5, 5);
- c2.ipadx = 0;
- c2.ipady = 0;
- options.add(text, c2);
- components.put(entry.getKey(), text);
- } else if (entry.getValue().size() == 1) {
- JTextField text = new JTextField(entry.getValue().get(0));
- } else {
- List<String> list = entry.getValue();
- JComboBox combo = new JComboBox(list.toArray(new String[list
- .size()]));
- combo.setSelectedItem(list.get(0));
- options.add(combo, c2);
- components.put(entry.getKey(), combo);
- i++;
- loadConnectionProps(lastConnectionProps);
- buttonsPanel.setLayout(new GridBagLayout());
- JButton loadPropsFileButton = new JButton("Load from file");
- loadPropsFileButton.addActionListener(new ActionListener() {
- int result = fileChooser
- .showOpenDialog(ZooInspectorConnectionPropertiesDialog.this);
- if (result == JFileChooser.APPROVE_OPTION) {
- File propsFilePath = fileChooser.getSelectedFile();
- Properties props = new Properties();
- FileReader reader = new FileReader(propsFilePath);
- props.load(reader);
- loadConnectionProps(props);
- } finally {
- reader.close();
- } catch (IOException ex) {
- LoggerFactory
- .getLogger()
- .error(
- "An Error occurred loading connection properties from file",
- ex);
- JOptionPane
- .showMessageDialog(
- ZooInspectorConnectionPropertiesDialog.this,
- "Error", JOptionPane.ERROR_MESSAGE);
- options.revalidate();
- options.repaint();
- GridBagConstraints c3 = new GridBagConstraints();
- c3.gridx = 0;
- c3.gridy = 0;
- c3.gridwidth = 1;
- c3.gridheight = 1;
- c3.weightx = 0;
- c3.weighty = 1;
- c3.anchor = GridBagConstraints.SOUTHWEST;
- c3.fill = GridBagConstraints.NONE;
- c3.insets = new Insets(5, 5, 5, 5);
- c3.ipadx = 0;
- c3.ipady = 0;
- buttonsPanel.add(loadPropsFileButton, c3);
- JButton saveDefaultPropsFileButton = new JButton("Set As Default");
- saveDefaultPropsFileButton.addActionListener(new ActionListener() {
- Properties connectionProps = getConnectionProps();
- zooInspectorPanel
- .setdefaultConnectionProps(connectionProps);
- "An Error occurred saving the default connection properties file",
- GridBagConstraints c6 = new GridBagConstraints();
- c6.gridx = 1;
- c6.gridy = 0;
- c6.gridwidth = 1;
- c6.gridheight = 1;
- c6.weightx = 1;
- c6.weighty = 1;
- c6.anchor = GridBagConstraints.SOUTHWEST;
- c6.fill = GridBagConstraints.NONE;
- c6.insets = new Insets(5, 5, 5, 5);
- c6.ipadx = 0;
- c6.ipady = 0;
- buttonsPanel.add(saveDefaultPropsFileButton, c6);
- ZooInspectorConnectionPropertiesDialog.this.dispose();
- zooInspectorPanel.connect(connectionProps);
- GridBagConstraints c4 = new GridBagConstraints();
- c4.gridx = 2;
- c4.gridy = 0;
- c4.gridwidth = 1;
- c4.gridheight = 1;
- c4.weightx = 0;
- c4.weighty = 1;
- c4.anchor = GridBagConstraints.SOUTH;
- c4.fill = GridBagConstraints.HORIZONTAL;
- c4.insets = new Insets(5, 5, 5, 5);
- c4.ipadx = 0;
- c4.ipady = 0;
- buttonsPanel.add(okButton, c4);
- JButton cancelButton = new JButton("Cancel");
- cancelButton.addActionListener(new ActionListener() {
- GridBagConstraints c5 = new GridBagConstraints();
- c5.gridx = 3;
- c5.gridy = 0;
- c5.gridwidth = 1;
- c5.gridheight = 1;
- c5.weightx = 0;
- c5.weighty = 1;
- c5.anchor = GridBagConstraints.SOUTH;
- c5.fill = GridBagConstraints.HORIZONTAL;
- c5.insets = new Insets(5, 5, 5, 5);
- c5.ipadx = 0;
- c5.ipady = 0;
- buttonsPanel.add(cancelButton, c5);
- this.add(options, BorderLayout.CENTER);
- private void loadConnectionProps(Properties props) {
- if (props != null) {
- for (Object key : props.keySet()) {
- String propsKey = (String) key;
- if (components.containsKey(propsKey)) {
- JComponent component = components.get(propsKey);
- String value = props.getProperty(propsKey);
- if (component instanceof JTextField) {
- ((JTextField) component).setText(value);
- } else if (component instanceof JComboBox) {
- ((JComboBox) component).setSelectedItem(value);
- private Properties getConnectionProps() {
- Properties connectionProps = new Properties();
- for (Entry<String, JComponent> entry : components.entrySet()) {
- String value = null;
- JComponent component = entry.getValue();
- value = ((JTextField) component).getText();
- value = ((JComboBox) component).getSelectedItem().toString();
- connectionProps.put(entry.getKey(), value);
- return connectionProps;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.io.File;
+import java.io.FileReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Map.Entry;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JTextField;
+import org.apache.zookeeper.inspector.manager.Pair;
+ * The connection properties dialog. This is used to determine the settings for
+ * connecting to a zookeeper instance
+public class ZooInspectorConnectionPropertiesDialog extends JDialog {
+ private final HashMap<String, JComponent> components;
+ * @param lastConnectionProps
+ * - the last connection properties used. if this is the first
+ * conneciton since starting the applications this will be the
+ * default settings
+ * @param connectionPropertiesTemplateAndLabels
+ * - the connection properties and labels to show in this dialog
+ * @param zooInspectorPanel
+ * - the {@link ZooInspectorPanel} linked to this dialog
+ public ZooInspectorConnectionPropertiesDialog(
+ Properties lastConnectionProps,
+ Pair<Map<String, List<String>>, Map<String, String>> connectionPropertiesTemplateAndLabels,
+ final ZooInspectorPanel zooInspectorPanel) {
+ final Map<String, List<String>> connectionPropertiesTemplate = connectionPropertiesTemplateAndLabels
+ .getKey();
+ final Map<String, String> connectionPropertiesLabels = connectionPropertiesTemplateAndLabels
+ .getValue();
+ this.setTitle("Connection Settings");
+ final JPanel options = new JPanel();
+ final JFileChooser fileChooser = new JFileChooser();
+ options.setLayout(new GridBagLayout());
+ int i = 0;
+ components = new HashMap<String, JComponent>();
+ for (Entry<String, List<String>> entry : connectionPropertiesTemplate
+ .entrySet()) {
+ int rowPos = 2 * i + 1;
+ JLabel label = new JLabel(connectionPropertiesLabels.get(entry
+ .getKey()));
+ GridBagConstraints c1 = new GridBagConstraints();
+ c1.gridx = 0;
+ c1.gridy = rowPos;
+ c1.gridwidth = 1;
+ c1.gridheight = 1;
+ c1.weightx = 0;
+ c1.weighty = 0;
+ c1.anchor = GridBagConstraints.WEST;
+ c1.fill = GridBagConstraints.HORIZONTAL;
+ c1.insets = new Insets(5, 5, 5, 5);
+ c1.ipadx = 0;
+ c1.ipady = 0;
+ options.add(label, c1);
+ if (entry.getValue().size() == 0) {
+ JTextField text = new JTextField();
+ GridBagConstraints c2 = new GridBagConstraints();
+ c2.gridx = 2;
+ c2.gridy = rowPos;
+ c2.gridwidth = 1;
+ c2.gridheight = 1;
+ c2.weightx = 0;
+ c2.weighty = 0;
+ c2.anchor = GridBagConstraints.WEST;
+ c2.fill = GridBagConstraints.HORIZONTAL;
+ c2.insets = new Insets(5, 5, 5, 5);
+ c2.ipadx = 0;
+ c2.ipady = 0;
+ options.add(text, c2);
+ components.put(entry.getKey(), text);
+ } else if (entry.getValue().size() == 1) {
+ JTextField text = new JTextField(entry.getValue().get(0));
+ } else {
+ List<String> list = entry.getValue();
+ JComboBox combo = new JComboBox(list.toArray(new String[list
+ .size()]));
+ combo.setSelectedItem(list.get(0));
+ options.add(combo, c2);
+ components.put(entry.getKey(), combo);
+ i++;
+ loadConnectionProps(lastConnectionProps);
+ buttonsPanel.setLayout(new GridBagLayout());
+ JButton loadPropsFileButton = new JButton("Load from file");
+ loadPropsFileButton.addActionListener(new ActionListener() {
+ int result = fileChooser
+ .showOpenDialog(ZooInspectorConnectionPropertiesDialog.this);
+ if (result == JFileChooser.APPROVE_OPTION) {
+ File propsFilePath = fileChooser.getSelectedFile();
+ Properties props = new Properties();
+ FileReader reader = new FileReader(propsFilePath);
+ props.load(reader);
+ loadConnectionProps(props);
+ } finally {
+ reader.close();
+ } catch (IOException ex) {
+ LoggerFactory
+ .getLogger()
+ .error(
+ "An Error occurred loading connection properties from file",
+ ex);
+ JOptionPane
+ .showMessageDialog(
+ ZooInspectorConnectionPropertiesDialog.this,
+ "Error", JOptionPane.ERROR_MESSAGE);
+ options.revalidate();
+ options.repaint();
+ GridBagConstraints c3 = new GridBagConstraints();
+ c3.gridx = 0;
+ c3.gridy = 0;
+ c3.gridwidth = 1;
+ c3.gridheight = 1;
+ c3.weightx = 0;
+ c3.weighty = 1;
+ c3.anchor = GridBagConstraints.SOUTHWEST;
+ c3.fill = GridBagConstraints.NONE;
+ c3.insets = new Insets(5, 5, 5, 5);
+ c3.ipadx = 0;
+ c3.ipady = 0;
+ buttonsPanel.add(loadPropsFileButton, c3);
+ JButton saveDefaultPropsFileButton = new JButton("Set As Default");
+ saveDefaultPropsFileButton.addActionListener(new ActionListener() {
+ Properties connectionProps = getConnectionProps();
+ zooInspectorPanel
+ .setdefaultConnectionProps(connectionProps);
+ "An Error occurred saving the default connection properties file",
+ GridBagConstraints c6 = new GridBagConstraints();
+ c6.gridx = 1;
+ c6.gridy = 0;
+ c6.gridwidth = 1;
+ c6.gridheight = 1;
+ c6.weightx = 1;
+ c6.weighty = 1;
+ c6.anchor = GridBagConstraints.SOUTHWEST;
+ c6.fill = GridBagConstraints.NONE;
+ c6.insets = new Insets(5, 5, 5, 5);
+ c6.ipadx = 0;
+ c6.ipady = 0;
+ buttonsPanel.add(saveDefaultPropsFileButton, c6);
+ ZooInspectorConnectionPropertiesDialog.this.dispose();
+ zooInspectorPanel.connect(connectionProps);
+ GridBagConstraints c4 = new GridBagConstraints();
+ c4.gridx = 2;
+ c4.gridy = 0;
+ c4.gridwidth = 1;
+ c4.gridheight = 1;
+ c4.weightx = 0;
+ c4.weighty = 1;
+ c4.anchor = GridBagConstraints.SOUTH;
+ c4.fill = GridBagConstraints.HORIZONTAL;
+ c4.insets = new Insets(5, 5, 5, 5);
+ c4.ipadx = 0;
+ c4.ipady = 0;
+ buttonsPanel.add(okButton, c4);
+ JButton cancelButton = new JButton("Cancel");
+ cancelButton.addActionListener(new ActionListener() {
+ GridBagConstraints c5 = new GridBagConstraints();
+ c5.gridx = 3;
+ c5.gridy = 0;
+ c5.gridwidth = 1;
+ c5.gridheight = 1;
+ c5.weightx = 0;
+ c5.weighty = 1;
+ c5.anchor = GridBagConstraints.SOUTH;
+ c5.fill = GridBagConstraints.HORIZONTAL;
+ c5.insets = new Insets(5, 5, 5, 5);
+ c5.ipadx = 0;
+ c5.ipady = 0;
+ buttonsPanel.add(cancelButton, c5);
+ this.add(options, BorderLayout.CENTER);
+ private void loadConnectionProps(Properties props) {
+ if (props != null) {
+ for (Object key : props.keySet()) {
+ String propsKey = (String) key;
+ if (components.containsKey(propsKey)) {
+ JComponent component = components.get(propsKey);
+ String value = props.getProperty(propsKey);
+ if (component instanceof JTextField) {
+ ((JTextField) component).setText(value);
+ } else if (component instanceof JComboBox) {
+ ((JComboBox) component).setSelectedItem(value);
+ private Properties getConnectionProps() {
+ Properties connectionProps = new Properties();
+ for (Entry<String, JComponent> entry : components.entrySet()) {
+ String value = null;
+ JComponent component = entry.getValue();
+ value = ((JTextField) component).getText();
+ value = ((JComboBox) component).getSelectedItem().toString();
+ connectionProps.put(entry.getKey(), value);
+ return connectionProps;
@@ -1,631 +1,631 @@
-import java.awt.Component;
-import java.awt.datatransfer.Transferable;
-import java.util.ArrayList;
-import java.util.Collection;
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.DefaultListModel;
-import javax.swing.DropMode;
-import javax.swing.ImageIcon;
-import javax.swing.JList;
-import javax.swing.JScrollPane;
-import javax.swing.ListSelectionModel;
-import javax.swing.TransferHandler;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import org.apache.zookeeper.inspector.gui.Toolbar.Button;
-import org.apache.zookeeper.inspector.manager.ZooInspectorManager;
- * A {@link JDialog} for configuring which {@link ZooInspectorNodeViewer}s to
- * show in the application
-public class ZooInspectorNodeViewersDialog extends JDialog implements
- ListSelectionListener {
- private final JList viewersList;
- private final JFileChooser fileChooser = new JFileChooser(new File("."));
- private final Map<Button, JButton> buttons = new HashMap<Button, JButton>();
- * @param currentViewers
- * - the {@link ZooInspectorNodeViewer}s to show
- * @param listeners
- * - the {@link NodeViewersChangeListener}s which need to be
- * notified of changes to the node viewers configuration
- * @param manager
- * - the {@link ZooInspectorManager} for the application
- public ZooInspectorNodeViewersDialog(Frame frame,
- final List<ZooInspectorNodeViewer> currentViewers,
- final Collection<NodeViewersChangeListener> listeners,
- final ZooInspectorManager manager,
- final IconResource iconResource) {
- final List<ZooInspectorNodeViewer> newViewers = new ArrayList<ZooInspectorNodeViewer>(
- currentViewers);
- this.setIconImage(iconResource.get(IconResource.ICON_ChangeNodeViewers,"")
- .getImage());
- this.setResizable(true);
- final JPanel panel = new JPanel();
- panel.setLayout(new GridBagLayout());
- viewersList = new JList();
- DefaultListModel model = new DefaultListModel();
- for (ZooInspectorNodeViewer viewer : newViewers) {
- model.addElement(viewer);
- viewersList.setModel(model);
- viewersList.setCellRenderer(new DefaultListCellRenderer() {
- public Component getListCellRendererComponent(JList list,
- Object value, int index, boolean isSelected,
- boolean cellHasFocus) {
- ZooInspectorNodeViewer viewer = (ZooInspectorNodeViewer) value;
- JLabel label = (JLabel) super.getListCellRendererComponent(
- list, value, index, isSelected, cellHasFocus);
- label.setText(viewer.getTitle());
- return label;
- viewersList.setDropMode(DropMode.INSERT);
- viewersList.enableInputMethods(true);
- viewersList.setDragEnabled(true);
- viewersList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- viewersList.getSelectionModel().addListSelectionListener(this);
- viewersList.setTransferHandler(new TransferHandler() {
- public boolean canImport(TransferHandler.TransferSupport info) {
- // we only import NodeViewers
- if (!info
- .isDataFlavorSupported(ZooInspectorNodeViewer.nodeViewerDataFlavor)) {
- return false;
- JList.DropLocation dl = (JList.DropLocation) info
- .getDropLocation();
- if (dl.getIndex() == -1) {
- return true;
- public boolean importData(TransferHandler.TransferSupport info) {
- DefaultListModel listModel = (DefaultListModel) viewersList
- .getModel();
- int index = dl.getIndex();
- boolean insert = dl.isInsert();
- // Get the string that is being dropped.
- Transferable t = info.getTransferable();
- String data;
- data = (String) t
- .getTransferData(ZooInspectorNodeViewer.nodeViewerDataFlavor);
- ZooInspectorNodeViewer viewer = (ZooInspectorNodeViewer) Class
- .forName(data).newInstance();
- if (listModel.contains(viewer)) {
- listModel.removeElement(viewer);
- if (insert) {
- listModel.add(index, viewer);
- listModel.set(index, viewer);
- "Error instantiating class: " + data, e);
- public int getSourceActions(JComponent c) {
- return MOVE;
- protected Transferable createTransferable(JComponent c) {
- JList list = (JList) c;
- ZooInspectorNodeViewer value = (ZooInspectorNodeViewer) list
- .getSelectedValue();
- return value;
- JScrollPane scroller = new JScrollPane(viewersList);
- c1.gridy = 0;
- c1.gridwidth = 3;
- c1.gridheight = 3;
- c1.weighty = 1;
- c1.anchor = GridBagConstraints.CENTER;
- c1.fill = GridBagConstraints.BOTH;
- panel.add(scroller, c1);
- final JTextField newViewerTextField = new JTextField();
- for(Button button : Button.values()) {
- JButton jbutton = button.createJButton(iconResource);
- buttons.put(button, jbutton);
- c2.gridx = 3;
- c2.gridy = 0;
- c2.anchor = GridBagConstraints.NORTH;
- panel.add(buttons.get(Button.up), c2);
- c3.gridx = 3;
- c3.gridy = 2;
- c3.weighty = 0;
- c3.anchor = GridBagConstraints.NORTH;
- c3.fill = GridBagConstraints.HORIZONTAL;
- panel.add(buttons.get(Button.down), c3);
- c4.gridx = 3;
- c4.gridy = 1;
- c4.weighty = 0;
- c4.anchor = GridBagConstraints.NORTH;
- panel.add(buttons.get(Button.remove), c4);
- c5.gridx = 0;
- c5.gridy = 3;
- c5.gridwidth = 3;
- c5.weighty = 0;
- c5.anchor = GridBagConstraints.CENTER;
- c5.fill = GridBagConstraints.BOTH;
- panel.add(newViewerTextField, c5);
- c6.gridx = 3;
- c6.gridy = 3;
- c6.weightx = 0;
- c6.weighty = 0;
- c6.anchor = GridBagConstraints.CENTER;
- c6.fill = GridBagConstraints.BOTH;
- panel.add(buttons.get(Button.add), c6);
- buttons.get(Button.up).addActionListener(new ActionListener() {
- ZooInspectorNodeViewer viewer = (ZooInspectorNodeViewer) viewersList
- int index = viewersList.getSelectedIndex();
- listModel.removeElementAt(index);
- listModel.insertElementAt(viewer, index - 1);
- viewersList.setSelectedValue(viewer, true);
- buttons.get(Button.down).addActionListener(new ActionListener() {
- listModel.insertElementAt(viewer, index + 1);
- buttons.get(Button.remove).addActionListener(new ActionListener() {
- viewersList
- .setSelectedIndex(index == listModel.size() ? index - 1
- : index);
- buttons.get(Button.add).addActionListener(new ActionListener() {
- String className = newViewerTextField.getText();
- if (className == null || className.length() == 0) {
- ZooInspectorNodeViewersDialog.this,
- "Please enter the full class name for a Node Viewer and click the add button",
- "Input Error", JOptionPane.ERROR_MESSAGE);
- .forName(className).newInstance();
- "Node viewer already exists. Each node viewer can only be added once.",
- "Input Error",
- listModel.addElement(viewer);
- } catch (Exception ex) {
- "An error occurred while instaniating the node viewer. ",
- JOptionPane.showMessageDialog(
- "An error occurred while instaniating the node viewer: "
- + ex.getMessage(), "Error",
- GridBagConstraints c7 = new GridBagConstraints();
- c7.gridx = 0;
- c7.gridy = 4;
- c7.gridwidth = 1;
- c7.gridheight = 1;
- c7.weightx = 1;
- c7.weighty = 0;
- c7.anchor = GridBagConstraints.WEST;
- c7.fill = GridBagConstraints.VERTICAL;
- c7.insets = new Insets(5, 5, 5, 5);
- c7.ipadx = 0;
- c7.ipady = 0;
- panel.add(buttons.get(Button.save), c7);
- GridBagConstraints c8 = new GridBagConstraints();
- c8.gridx = 1;
- c8.gridy = 4;
- c8.gridwidth = 1;
- c8.gridheight = 1;
- c8.weightx = 0;
- c8.weighty = 0;
- c8.anchor = GridBagConstraints.WEST;
- c8.fill = GridBagConstraints.VERTICAL;
- c8.insets = new Insets(5, 5, 5, 5);
- c8.ipadx = 0;
- c8.ipady = 0;
- panel.add(buttons.get(Button.load), c8);
- GridBagConstraints c9 = new GridBagConstraints();
- c9.gridx = 2;
- c9.gridy = 4;
- c9.gridwidth = 1;
- c9.gridheight = 1;
- c9.weightx = 0;
- c9.weighty = 0;
- c9.anchor = GridBagConstraints.WEST;
- c9.fill = GridBagConstraints.VERTICAL;
- c9.insets = new Insets(5, 5, 5, 5);
- c9.ipadx = 0;
- c9.ipady = 0;
- panel.add(buttons.get(Button.setDefaults), c9);
- buttons.get(Button.save).addActionListener(new ActionListener() {
- .showSaveDialog(ZooInspectorNodeViewersDialog.this);
- File selectedFile = fileChooser.getSelectedFile();
- int answer = JOptionPane.YES_OPTION;
- if (selectedFile.exists()) {
- answer = JOptionPane
- .showConfirmDialog(
- "The specified file already exists. do you want to overwrite it?",
- "Confirm Overwrite",
- JOptionPane.YES_NO_OPTION,
- JOptionPane.WARNING_MESSAGE);
- if (answer == JOptionPane.YES_OPTION) {
- List<String> nodeViewersClassNames = new ArrayList<String>();
- Object[] modelContents = listModel.toArray();
- for (Object o : modelContents) {
- nodeViewersClassNames
- .add(((ZooInspectorNodeViewer) o)
- .getClass().getCanonicalName());
- manager.saveNodeViewersFile(selectedFile,
- nodeViewersClassNames);
- "Error saving node viewer configuration from file.",
- "Error saving node viewer configuration from file: "
- buttons.get(Button.load).addActionListener(new ActionListener() {
- .showOpenDialog(ZooInspectorNodeViewersDialog.this);
- List<String> nodeViewersClassNames = manager
- .loadNodeViewersFile(fileChooser
- .getSelectedFile());
- List<ZooInspectorNodeViewer> nodeViewers = new ArrayList<ZooInspectorNodeViewer>();
- for (String nodeViewersClassName : nodeViewersClassNames) {
- .forName(nodeViewersClassName)
- .newInstance();
- nodeViewers.add(viewer);
- for (ZooInspectorNodeViewer viewer : nodeViewers) {
- panel.revalidate();
- panel.repaint();
- "Error loading node viewer configuration from file.",
- "Error loading node viewer configuration from file: "
- buttons.get(Button.setDefaults).addActionListener(new ActionListener() {
- int answer = JOptionPane
- "Are you sure you want to save this configuration as the default?",
- "Confirm Set Defaults",
- nodeViewersClassNames.add(((ZooInspectorNodeViewer) o)
- manager
- .setDefaultNodeViewerConfiguration(nodeViewersClassNames);
- "Error setting default node viewer configuration.",
- "Error setting default node viewer configuration: "
- ZooInspectorNodeViewersDialog.this.dispose();
- newViewers.clear();
- newViewers.add((ZooInspectorNodeViewer) o);
- currentViewers.clear();
- currentViewers.addAll(newViewers);
- for (NodeViewersChangeListener listener : listeners) {
- listener.nodeViewersChanged(currentViewers);
- buttonsPanel.add(cancelButton);
- * javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event
- * .ListSelectionEvent)
- public void valueChanged(ListSelectionEvent e) {
- JButton removeButton = buttons.get(Button.remove);
- JButton upButton = buttons.get(Button.up);
- JButton downButton = buttons.get(Button.down);
- if (index == -1) {
- removeButton.setEnabled(false);
- upButton.setEnabled(false);
- downButton.setEnabled(false);
- removeButton.setEnabled(true);
- if (index == 0) {
- upButton.setEnabled(true);
- if (index == ((DefaultListModel) viewersList.getModel()).getSize()) {
- downButton.setEnabled(true);
- public static enum Button {
- up("Move currently selected node viewer up",IconResource.ICON_UP,false),
- down("Move currently selected node viewer down",IconResource.ICON_DOWN,false),
- add("Add node viewer",IconResource.ICON_ADD,true),
- remove("Remove currently selected node viewer",IconResource.ICON_REMOVE,false),
- save("Save current node viewer configuration to file","Save"),
- load("Load node viewer configuration from file","Load"),
- setDefaults("Set current configuration asd defaults","Set as defaults");
- private String toolTip;
- private String icon;
- private boolean enabled;
- Button(String toolTip, String icon, boolean enabled) {
- this.toolTip = toolTip;
- this.icon = icon;
- this.enabled = enabled;
- Button(String toolTip, String icon) {
- this(toolTip, icon, true);
- public JButton createJButton(IconResource iconResource) {
- ImageIcon imageIcon = iconResource.get(icon, toolTip);
- JButton jbutton;
- if(imageIcon == null) {
- jbutton = new JButton(icon);
- jbutton = new JButton(imageIcon);
- jbutton.setEnabled(enabled);
- jbutton.setToolTipText(toolTip);
- return jbutton;
+import java.awt.Component;
+import java.awt.datatransfer.Transferable;
+import java.util.ArrayList;
+import java.util.Collection;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.DefaultListModel;
+import javax.swing.DropMode;
+import javax.swing.ImageIcon;
+import javax.swing.JList;
+import javax.swing.JScrollPane;
+import javax.swing.ListSelectionModel;
+import javax.swing.TransferHandler;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import org.apache.zookeeper.inspector.gui.Toolbar.Button;
+import org.apache.zookeeper.inspector.manager.ZooInspectorManager;
+ * A {@link JDialog} for configuring which {@link ZooInspectorNodeViewer}s to
+ * show in the application
+public class ZooInspectorNodeViewersDialog extends JDialog implements
+ ListSelectionListener {
+ private final JList viewersList;
+ private final JFileChooser fileChooser = new JFileChooser(new File("."));
+ private final Map<Button, JButton> buttons = new HashMap<Button, JButton>();
+ * @param currentViewers
+ * - the {@link ZooInspectorNodeViewer}s to show
+ * @param listeners
+ * - the {@link NodeViewersChangeListener}s which need to be
+ * notified of changes to the node viewers configuration
+ * @param manager
+ * - the {@link ZooInspectorManager} for the application
+ public ZooInspectorNodeViewersDialog(Frame frame,
+ final List<ZooInspectorNodeViewer> currentViewers,
+ final Collection<NodeViewersChangeListener> listeners,
+ final ZooInspectorManager manager,
+ final IconResource iconResource) {
+ final List<ZooInspectorNodeViewer> newViewers = new ArrayList<ZooInspectorNodeViewer>(
+ currentViewers);
+ this.setIconImage(iconResource.get(IconResource.ICON_ChangeNodeViewers,"")
+ .getImage());
+ this.setResizable(true);
+ final JPanel panel = new JPanel();
+ panel.setLayout(new GridBagLayout());
+ viewersList = new JList();
+ DefaultListModel model = new DefaultListModel();
+ for (ZooInspectorNodeViewer viewer : newViewers) {
+ model.addElement(viewer);
+ viewersList.setModel(model);
+ viewersList.setCellRenderer(new DefaultListCellRenderer() {
+ public Component getListCellRendererComponent(JList list,
+ Object value, int index, boolean isSelected,
+ boolean cellHasFocus) {
+ ZooInspectorNodeViewer viewer = (ZooInspectorNodeViewer) value;
+ JLabel label = (JLabel) super.getListCellRendererComponent(
+ list, value, index, isSelected, cellHasFocus);
+ label.setText(viewer.getTitle());
+ return label;
+ viewersList.setDropMode(DropMode.INSERT);
+ viewersList.enableInputMethods(true);
+ viewersList.setDragEnabled(true);
+ viewersList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ viewersList.getSelectionModel().addListSelectionListener(this);
+ viewersList.setTransferHandler(new TransferHandler() {
+ public boolean canImport(TransferHandler.TransferSupport info) {
+ // we only import NodeViewers
+ if (!info
+ .isDataFlavorSupported(ZooInspectorNodeViewer.nodeViewerDataFlavor)) {
+ return false;
+ JList.DropLocation dl = (JList.DropLocation) info
+ .getDropLocation();
+ if (dl.getIndex() == -1) {
+ return true;
+ public boolean importData(TransferHandler.TransferSupport info) {
+ DefaultListModel listModel = (DefaultListModel) viewersList
+ .getModel();
+ int index = dl.getIndex();
+ boolean insert = dl.isInsert();
+ // Get the string that is being dropped.
+ Transferable t = info.getTransferable();
+ String data;
+ data = (String) t
+ .getTransferData(ZooInspectorNodeViewer.nodeViewerDataFlavor);
+ ZooInspectorNodeViewer viewer = (ZooInspectorNodeViewer) Class
+ .forName(data).newInstance();
+ if (listModel.contains(viewer)) {
+ listModel.removeElement(viewer);
+ if (insert) {
+ listModel.add(index, viewer);
+ listModel.set(index, viewer);
+ "Error instantiating class: " + data, e);
+ public int getSourceActions(JComponent c) {
+ return MOVE;
+ protected Transferable createTransferable(JComponent c) {
+ JList list = (JList) c;
+ ZooInspectorNodeViewer value = (ZooInspectorNodeViewer) list
+ .getSelectedValue();
+ return value;
+ JScrollPane scroller = new JScrollPane(viewersList);
+ c1.gridy = 0;
+ c1.gridwidth = 3;
+ c1.gridheight = 3;
+ c1.weighty = 1;
+ c1.anchor = GridBagConstraints.CENTER;
+ c1.fill = GridBagConstraints.BOTH;
+ panel.add(scroller, c1);
+ final JTextField newViewerTextField = new JTextField();
+ for(Button button : Button.values()) {
+ JButton jbutton = button.createJButton(iconResource);
+ buttons.put(button, jbutton);
+ c2.gridx = 3;
+ c2.gridy = 0;
+ c2.anchor = GridBagConstraints.NORTH;
+ panel.add(buttons.get(Button.up), c2);
+ c3.gridx = 3;
+ c3.gridy = 2;
+ c3.weighty = 0;
+ c3.anchor = GridBagConstraints.NORTH;
+ c3.fill = GridBagConstraints.HORIZONTAL;
+ panel.add(buttons.get(Button.down), c3);
+ c4.gridx = 3;
+ c4.gridy = 1;
+ c4.weighty = 0;
+ c4.anchor = GridBagConstraints.NORTH;
+ panel.add(buttons.get(Button.remove), c4);
+ c5.gridx = 0;
+ c5.gridy = 3;
+ c5.gridwidth = 3;
+ c5.weighty = 0;
+ c5.anchor = GridBagConstraints.CENTER;
+ c5.fill = GridBagConstraints.BOTH;
+ panel.add(newViewerTextField, c5);
+ c6.gridx = 3;
+ c6.gridy = 3;
+ c6.weightx = 0;
+ c6.weighty = 0;
+ c6.anchor = GridBagConstraints.CENTER;
+ c6.fill = GridBagConstraints.BOTH;
+ panel.add(buttons.get(Button.add), c6);
+ buttons.get(Button.up).addActionListener(new ActionListener() {
+ ZooInspectorNodeViewer viewer = (ZooInspectorNodeViewer) viewersList
+ int index = viewersList.getSelectedIndex();
+ listModel.removeElementAt(index);
+ listModel.insertElementAt(viewer, index - 1);
+ viewersList.setSelectedValue(viewer, true);
+ buttons.get(Button.down).addActionListener(new ActionListener() {
+ listModel.insertElementAt(viewer, index + 1);
+ buttons.get(Button.remove).addActionListener(new ActionListener() {
+ viewersList
+ .setSelectedIndex(index == listModel.size() ? index - 1
+ : index);
+ buttons.get(Button.add).addActionListener(new ActionListener() {
+ String className = newViewerTextField.getText();
+ if (className == null || className.length() == 0) {
+ ZooInspectorNodeViewersDialog.this,
+ "Please enter the full class name for a Node Viewer and click the add button",
+ "Input Error", JOptionPane.ERROR_MESSAGE);
+ .forName(className).newInstance();
+ "Node viewer already exists. Each node viewer can only be added once.",
+ "Input Error",
+ listModel.addElement(viewer);
+ } catch (Exception ex) {
+ "An error occurred while instaniating the node viewer. ",
+ JOptionPane.showMessageDialog(
+ "An error occurred while instaniating the node viewer: "
+ + ex.getMessage(), "Error",
+ GridBagConstraints c7 = new GridBagConstraints();
+ c7.gridx = 0;
+ c7.gridy = 4;
+ c7.gridwidth = 1;
+ c7.gridheight = 1;
+ c7.weightx = 1;
+ c7.weighty = 0;
+ c7.anchor = GridBagConstraints.WEST;
+ c7.fill = GridBagConstraints.VERTICAL;
+ c7.insets = new Insets(5, 5, 5, 5);
+ c7.ipadx = 0;
+ c7.ipady = 0;
+ panel.add(buttons.get(Button.save), c7);
+ GridBagConstraints c8 = new GridBagConstraints();
+ c8.gridx = 1;
+ c8.gridy = 4;
+ c8.gridwidth = 1;
+ c8.gridheight = 1;
+ c8.weightx = 0;
+ c8.weighty = 0;
+ c8.anchor = GridBagConstraints.WEST;
+ c8.fill = GridBagConstraints.VERTICAL;
+ c8.insets = new Insets(5, 5, 5, 5);
+ c8.ipadx = 0;
+ c8.ipady = 0;
+ panel.add(buttons.get(Button.load), c8);
+ GridBagConstraints c9 = new GridBagConstraints();
+ c9.gridx = 2;
+ c9.gridy = 4;
+ c9.gridwidth = 1;
+ c9.gridheight = 1;
+ c9.weightx = 0;
+ c9.weighty = 0;
+ c9.anchor = GridBagConstraints.WEST;
+ c9.fill = GridBagConstraints.VERTICAL;
+ c9.insets = new Insets(5, 5, 5, 5);
+ c9.ipadx = 0;
+ c9.ipady = 0;
+ panel.add(buttons.get(Button.setDefaults), c9);
+ buttons.get(Button.save).addActionListener(new ActionListener() {
+ .showSaveDialog(ZooInspectorNodeViewersDialog.this);
+ File selectedFile = fileChooser.getSelectedFile();
+ int answer = JOptionPane.YES_OPTION;
+ if (selectedFile.exists()) {
+ answer = JOptionPane
+ .showConfirmDialog(
+ "The specified file already exists. do you want to overwrite it?",
+ "Confirm Overwrite",
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.WARNING_MESSAGE);
+ if (answer == JOptionPane.YES_OPTION) {
+ List<String> nodeViewersClassNames = new ArrayList<String>();
+ Object[] modelContents = listModel.toArray();
+ for (Object o : modelContents) {
+ nodeViewersClassNames
+ .add(((ZooInspectorNodeViewer) o)
+ .getClass().getCanonicalName());
+ manager.saveNodeViewersFile(selectedFile,
+ nodeViewersClassNames);
+ "Error saving node viewer configuration from file.",
+ "Error saving node viewer configuration from file: "
+ buttons.get(Button.load).addActionListener(new ActionListener() {
+ .showOpenDialog(ZooInspectorNodeViewersDialog.this);
+ List<String> nodeViewersClassNames = manager
+ .loadNodeViewersFile(fileChooser
+ .getSelectedFile());
+ List<ZooInspectorNodeViewer> nodeViewers = new ArrayList<ZooInspectorNodeViewer>();
+ for (String nodeViewersClassName : nodeViewersClassNames) {
+ .forName(nodeViewersClassName)
+ .newInstance();
+ nodeViewers.add(viewer);
+ for (ZooInspectorNodeViewer viewer : nodeViewers) {
+ panel.revalidate();
+ panel.repaint();
+ "Error loading node viewer configuration from file.",
+ "Error loading node viewer configuration from file: "
+ buttons.get(Button.setDefaults).addActionListener(new ActionListener() {
+ int answer = JOptionPane
+ "Are you sure you want to save this configuration as the default?",
+ "Confirm Set Defaults",
+ nodeViewersClassNames.add(((ZooInspectorNodeViewer) o)
+ manager
+ .setDefaultNodeViewerConfiguration(nodeViewersClassNames);
+ "Error setting default node viewer configuration.",
+ "Error setting default node viewer configuration: "
+ ZooInspectorNodeViewersDialog.this.dispose();
+ newViewers.clear();
+ newViewers.add((ZooInspectorNodeViewer) o);
+ currentViewers.clear();
+ currentViewers.addAll(newViewers);
+ for (NodeViewersChangeListener listener : listeners) {
+ listener.nodeViewersChanged(currentViewers);
+ buttonsPanel.add(cancelButton);
+ * javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event
+ * .ListSelectionEvent)
+ public void valueChanged(ListSelectionEvent e) {
+ JButton removeButton = buttons.get(Button.remove);
+ JButton upButton = buttons.get(Button.up);
+ JButton downButton = buttons.get(Button.down);
+ if (index == -1) {
+ removeButton.setEnabled(false);
+ upButton.setEnabled(false);
+ downButton.setEnabled(false);
+ removeButton.setEnabled(true);
+ if (index == 0) {
+ upButton.setEnabled(true);
+ if (index == ((DefaultListModel) viewersList.getModel()).getSize()) {
+ downButton.setEnabled(true);
+ public static enum Button {
+ up("Move currently selected node viewer up",IconResource.ICON_UP,false),
+ down("Move currently selected node viewer down",IconResource.ICON_DOWN,false),
+ add("Add node viewer",IconResource.ICON_ADD,true),
+ remove("Remove currently selected node viewer",IconResource.ICON_REMOVE,false),
+ save("Save current node viewer configuration to file","Save"),
+ load("Load node viewer configuration from file","Load"),
+ setDefaults("Set current configuration asd defaults","Set as defaults");
+ private String toolTip;
+ private String icon;
+ private boolean enabled;
+ Button(String toolTip, String icon, boolean enabled) {
+ this.toolTip = toolTip;
+ this.icon = icon;
+ this.enabled = enabled;
+ Button(String toolTip, String icon) {
+ this(toolTip, icon, true);
+ public JButton createJButton(IconResource iconResource) {
+ ImageIcon imageIcon = iconResource.get(icon, toolTip);
+ JButton jbutton;
+ if(imageIcon == null) {
+ jbutton = new JButton(icon);
+ jbutton = new JButton(imageIcon);
+ jbutton.setEnabled(enabled);
+ jbutton.setToolTipText(toolTip);
+ return jbutton;
@@ -1,140 +1,140 @@
-import javax.swing.JTabbedPane;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.tree.TreePath;
-import org.apache.zookeeper.inspector.manager.ZooInspectorNodeManager;
- * This is the {@link JPanel} which contains the {@link ZooInspectorNodeViewer}s
-public class ZooInspectorNodeViewersPanel extends JPanel implements
- TreeSelectionListener, ChangeListener {
- private final List<ZooInspectorNodeViewer> nodeVeiwers = new ArrayList<ZooInspectorNodeViewer>();
- private final List<Boolean> needsReload = new ArrayList<Boolean>();
- private final JTabbedPane tabbedPane;
- private final List<String> selectedNodes = new ArrayList<String>();
- private final ZooInspectorNodeManager zooInspectorManager;
- * @param zooInspectorManager
- * @param nodeVeiwers
- public ZooInspectorNodeViewersPanel(
- ZooInspectorNodeManager zooInspectorManager,
- List<ZooInspectorNodeViewer> nodeVeiwers) {
- this.zooInspectorManager = zooInspectorManager;
- tabbedPane = new JTabbedPane(JTabbedPane.TOP,
- JTabbedPane.WRAP_TAB_LAYOUT);
- setNodeViewers(nodeVeiwers);
- tabbedPane.addChangeListener(this);
- this.add(tabbedPane, BorderLayout.CENTER);
- reloadSelectedViewer();
- * @param nodeViewers
- public void setNodeViewers(List<ZooInspectorNodeViewer> nodeViewers) {
- this.nodeVeiwers.clear();
- this.nodeVeiwers.addAll(nodeViewers);
- needsReload.clear();
- tabbedPane.removeAll();
- for (ZooInspectorNodeViewer nodeViewer : nodeVeiwers) {
- nodeViewer.setZooInspectorManager(zooInspectorManager);
- needsReload.add(true);
- tabbedPane.add(nodeViewer.getTitle(), nodeViewer);
- this.revalidate();
- this.repaint();
- private void reloadSelectedViewer() {
- int index = this.tabbedPane.getSelectedIndex();
- if (index != -1 && this.needsReload.get(index)) {
- ZooInspectorNodeViewer viewer = this.nodeVeiwers.get(index);
- viewer.nodeSelectionChanged(selectedNodes);
- this.needsReload.set(index, false);
- * javax.swing.event.TreeSelectionListener#valueChanged(javax.swing.event
- * .TreeSelectionEvent)
- public void valueChanged(TreeSelectionEvent e) {
- TreePath[] paths = e.getPaths();
- selectedNodes.clear();
- for (TreePath path : paths) {
- boolean appended = false;
- StringBuilder sb = new StringBuilder();
- Object[] pathArray = path.getPath();
- for (Object o : pathArray) {
- if (o != null) {
- String nodeName = o.toString();
- if (nodeName != null) {
- if (nodeName.length() > 0) {
- appended = true;
- sb.append("/"); //$NON-NLS-1$
- sb.append(o.toString());
- if (appended) {
- selectedNodes.add(sb.toString());
- for (int i = 0; i < needsReload.size(); i++) {
- this.needsReload.set(i, true);
- * javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent
- * )
- public void stateChanged(ChangeEvent e) {
+import javax.swing.JTabbedPane;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.TreePath;
+import org.apache.zookeeper.inspector.manager.ZooInspectorNodeManager;
+ * This is the {@link JPanel} which contains the {@link ZooInspectorNodeViewer}s
+public class ZooInspectorNodeViewersPanel extends JPanel implements
+ TreeSelectionListener, ChangeListener {
+ private final List<ZooInspectorNodeViewer> nodeVeiwers = new ArrayList<ZooInspectorNodeViewer>();
+ private final List<Boolean> needsReload = new ArrayList<Boolean>();
+ private final JTabbedPane tabbedPane;
+ private final List<String> selectedNodes = new ArrayList<String>();
+ private final ZooInspectorNodeManager zooInspectorManager;
+ * @param zooInspectorManager
+ * @param nodeVeiwers
+ public ZooInspectorNodeViewersPanel(
+ ZooInspectorNodeManager zooInspectorManager,
+ List<ZooInspectorNodeViewer> nodeVeiwers) {
+ this.zooInspectorManager = zooInspectorManager;
+ tabbedPane = new JTabbedPane(JTabbedPane.TOP,
+ JTabbedPane.WRAP_TAB_LAYOUT);
+ setNodeViewers(nodeVeiwers);
+ tabbedPane.addChangeListener(this);
+ this.add(tabbedPane, BorderLayout.CENTER);
+ reloadSelectedViewer();
+ * @param nodeViewers
+ public void setNodeViewers(List<ZooInspectorNodeViewer> nodeViewers) {
+ this.nodeVeiwers.clear();
+ this.nodeVeiwers.addAll(nodeViewers);
+ needsReload.clear();
+ tabbedPane.removeAll();
+ for (ZooInspectorNodeViewer nodeViewer : nodeVeiwers) {
+ nodeViewer.setZooInspectorManager(zooInspectorManager);
+ needsReload.add(true);
+ tabbedPane.add(nodeViewer.getTitle(), nodeViewer);
+ this.revalidate();
+ this.repaint();
+ private void reloadSelectedViewer() {
+ int index = this.tabbedPane.getSelectedIndex();
+ if (index != -1 && this.needsReload.get(index)) {
+ ZooInspectorNodeViewer viewer = this.nodeVeiwers.get(index);
+ viewer.nodeSelectionChanged(selectedNodes);
+ this.needsReload.set(index, false);
+ * javax.swing.event.TreeSelectionListener#valueChanged(javax.swing.event
+ * .TreeSelectionEvent)
+ public void valueChanged(TreeSelectionEvent e) {
+ TreePath[] paths = e.getPaths();
+ selectedNodes.clear();
+ for (TreePath path : paths) {
+ boolean appended = false;
+ StringBuilder sb = new StringBuilder();
+ Object[] pathArray = path.getPath();
+ for (Object o : pathArray) {
+ if (o != null) {
+ String nodeName = o.toString();
+ if (nodeName != null) {
+ if (nodeName.length() > 0) {
+ appended = true;
+ sb.append("/"); //$NON-NLS-1$
+ sb.append(o.toString());
+ if (appended) {
+ selectedNodes.add(sb.toString());
+ for (int i = 0; i < needsReload.size(); i++) {
+ this.needsReload.set(i, true);
+ * javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent
+ * )
+ public void stateChanged(ChangeEvent e) {
@@ -1,318 +1,318 @@
-import java.util.concurrent.ExecutionException;
-import javax.swing.JSplitPane;
-import javax.swing.JToolBar;
-import javax.swing.SwingWorker;
- * The parent {@link JPanel} for the whole application
-public class ZooInspectorPanel extends JPanel implements
- NodeViewersChangeListener {
- private final IconResource iconResource;
- private final Toolbar toolbar;
- private final ZooInspectorNodeViewersPanel nodeViewersPanel;
- private final ZooInspectorTreeViewer treeViewer;
- private final ZooInspectorManager zooInspectorManager;
- private final List<NodeViewersChangeListener> listeners = new ArrayList<NodeViewersChangeListener>();
- {
- listeners.add(this);
- public ZooInspectorPanel(final ZooInspectorManager zooInspectorManager, final IconResource iconResource) {
- this.iconResource = iconResource;
- toolbar = new Toolbar(iconResource);
- final ArrayList<ZooInspectorNodeViewer> nodeViewers = new ArrayList<ZooInspectorNodeViewer>();
- List<String> defaultNodeViewersClassNames = this.zooInspectorManager
- .getDefaultNodeViewerConfiguration();
- for (String className : defaultNodeViewersClassNames) {
- nodeViewers.add((ZooInspectorNodeViewer) Class.forName(
- className).newInstance());
- "Error loading default node viewers.", ex);
- JOptionPane.showMessageDialog(ZooInspectorPanel.this,
- "Error loading default node viewers: " + ex.getMessage(),
- nodeViewersPanel = new ZooInspectorNodeViewersPanel(
- zooInspectorManager, nodeViewers);
- treeViewer = new ZooInspectorTreeViewer(zooInspectorManager,
- nodeViewersPanel, iconResource);
- toolbar.addActionListener(Toolbar.Button.connect, new ActionListener() {
- ZooInspectorConnectionPropertiesDialog zicpd = new ZooInspectorConnectionPropertiesDialog(
- zooInspectorManager.getLastConnectionProps(),
- zooInspectorManager.getConnectionPropertiesTemplate(),
- ZooInspectorPanel.this);
- zicpd.setVisible(true);
- toolbar.addActionListener(Toolbar.Button.disconnect, new ActionListener() {
- disconnect();
- toolbar.addActionListener(Toolbar.Button.refresh, new ActionListener() {
- treeViewer.refreshView();
- toolbar.addActionListener(Toolbar.Button.addNode, new ActionListener() {
- final List<String> selectedNodes = treeViewer
- .getSelectedNodes();
- if (selectedNodes.size() == 1) {
- final String nodeName = JOptionPane.showInputDialog(
- ZooInspectorPanel.this,
- "Please Enter a name for the new node",
- "Create Node", JOptionPane.INFORMATION_MESSAGE);
- if (nodeName != null && nodeName.length() > 0) {
- SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
- protected Boolean doInBackground() throws Exception {
- return ZooInspectorPanel.this.zooInspectorManager
- .createNode(selectedNodes.get(0),
- nodeName);
- protected void done() {
- worker.execute();
- "Please select 1 parent node for the new node.");
- toolbar.addActionListener(Toolbar.Button.deleteNode, new ActionListener() {
- if (selectedNodes.size() == 0) {
- "Please select at least 1 node to be deleted");
- int answer = JOptionPane.showConfirmDialog(
- "Are you sure you want to delete the selected nodes?"
- + "(This action cannot be reverted)",
- "Confirm Delete", JOptionPane.YES_NO_OPTION,
- for (String nodePath : selectedNodes) {
- ZooInspectorPanel.this.zooInspectorManager
- .deleteNode(nodePath);
- toolbar.addActionListener(Toolbar.Button.nodeViewers, new ActionListener() {
- ZooInspectorNodeViewersDialog nvd = new ZooInspectorNodeViewersDialog(
- JOptionPane.getRootFrame(), nodeViewers, listeners,
- zooInspectorManager, iconResource);
- nvd.setVisible(true);
- toolbar.addActionListener(Toolbar.Button.about, new ActionListener() {
- ZooInspectorAboutDialog zicpd = new ZooInspectorAboutDialog(
- JOptionPane.getRootFrame(), iconResource);
- JScrollPane treeScroller = new JScrollPane(treeViewer);
- JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
- treeScroller, nodeViewersPanel);
- splitPane.setResizeWeight(0.25);
- this.add(splitPane, BorderLayout.CENTER);
- this.add(toolbar.getJToolBar(), BorderLayout.NORTH);
- * @param connectionProps
- * the {@link Properties} for connecting to the zookeeper
- * instance
- public void connect(final Properties connectionProps) {
- zooInspectorManager.setLastConnectionProps(connectionProps);
- return zooInspectorManager.connect(connectionProps);
- if (get()) {
- toolbar.toggleButtons(true);
- "Unable to connect to zookeeper", "Error",
- } catch (InterruptedException e) {
- "Error occurred while connecting to ZooKeeper server",
- e);
- } catch (ExecutionException e) {
- public void disconnect() {
- disconnect(false);
- * @param wait
- * - set this to true if the method should only return once the
- * application has successfully disconnected
- public void disconnect(boolean wait) {
- return ZooInspectorPanel.this.zooInspectorManager.disconnect();
- treeViewer.clearView();
- toolbar.toggleButtons(false);
- "Error occurred while disconnecting from ZooKeeper server",
- if (wait) {
- while (!worker.isDone()) {
- Thread.sleep(100);
- * @seeorg.apache.zookeeper.inspector.gui.NodeViewersChangeListener#
- * nodeViewersChanged(java.util.List)
- public void nodeViewersChanged(List<ZooInspectorNodeViewer> newViewers) {
- this.nodeViewersPanel.setNodeViewers(newViewers);
- * @throws IOException
- public void setdefaultConnectionProps(Properties connectionProps)
- throws IOException {
- this.zooInspectorManager.saveDefaultConnectionFile(connectionProps);
+import java.util.concurrent.ExecutionException;
+import javax.swing.JSplitPane;
+import javax.swing.JToolBar;
+import javax.swing.SwingWorker;
+ * The parent {@link JPanel} for the whole application
+public class ZooInspectorPanel extends JPanel implements
+ NodeViewersChangeListener {
+ private final IconResource iconResource;
+ private final Toolbar toolbar;
+ private final ZooInspectorNodeViewersPanel nodeViewersPanel;
+ private final ZooInspectorTreeViewer treeViewer;
+ private final ZooInspectorManager zooInspectorManager;
+ private final List<NodeViewersChangeListener> listeners = new ArrayList<NodeViewersChangeListener>();
+ {
+ listeners.add(this);
+ public ZooInspectorPanel(final ZooInspectorManager zooInspectorManager, final IconResource iconResource) {
+ this.iconResource = iconResource;
+ toolbar = new Toolbar(iconResource);
+ final ArrayList<ZooInspectorNodeViewer> nodeViewers = new ArrayList<ZooInspectorNodeViewer>();
+ List<String> defaultNodeViewersClassNames = this.zooInspectorManager
+ .getDefaultNodeViewerConfiguration();
+ for (String className : defaultNodeViewersClassNames) {
+ nodeViewers.add((ZooInspectorNodeViewer) Class.forName(
+ className).newInstance());
+ "Error loading default node viewers.", ex);
+ JOptionPane.showMessageDialog(ZooInspectorPanel.this,
+ "Error loading default node viewers: " + ex.getMessage(),
+ nodeViewersPanel = new ZooInspectorNodeViewersPanel(
+ zooInspectorManager, nodeViewers);
+ treeViewer = new ZooInspectorTreeViewer(zooInspectorManager,
+ nodeViewersPanel, iconResource);
+ toolbar.addActionListener(Toolbar.Button.connect, new ActionListener() {
+ ZooInspectorConnectionPropertiesDialog zicpd = new ZooInspectorConnectionPropertiesDialog(
+ zooInspectorManager.getLastConnectionProps(),
+ zooInspectorManager.getConnectionPropertiesTemplate(),
+ ZooInspectorPanel.this);
+ zicpd.setVisible(true);
+ toolbar.addActionListener(Toolbar.Button.disconnect, new ActionListener() {
+ disconnect();
+ toolbar.addActionListener(Toolbar.Button.refresh, new ActionListener() {
+ treeViewer.refreshView();
+ toolbar.addActionListener(Toolbar.Button.addNode, new ActionListener() {
+ final List<String> selectedNodes = treeViewer
+ .getSelectedNodes();
+ if (selectedNodes.size() == 1) {
+ final String nodeName = JOptionPane.showInputDialog(
+ ZooInspectorPanel.this,
+ "Please Enter a name for the new node",
+ "Create Node", JOptionPane.INFORMATION_MESSAGE);
+ if (nodeName != null && nodeName.length() > 0) {
+ SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
+ protected Boolean doInBackground() throws Exception {
+ return ZooInspectorPanel.this.zooInspectorManager
+ .createNode(selectedNodes.get(0),
+ nodeName);
+ protected void done() {
+ worker.execute();
+ "Please select 1 parent node for the new node.");
+ toolbar.addActionListener(Toolbar.Button.deleteNode, new ActionListener() {
+ if (selectedNodes.size() == 0) {
+ "Please select at least 1 node to be deleted");
+ int answer = JOptionPane.showConfirmDialog(
+ "Are you sure you want to delete the selected nodes?"
+ + "(This action cannot be reverted)",
+ "Confirm Delete", JOptionPane.YES_NO_OPTION,
+ for (String nodePath : selectedNodes) {
+ ZooInspectorPanel.this.zooInspectorManager
+ .deleteNode(nodePath);
+ toolbar.addActionListener(Toolbar.Button.nodeViewers, new ActionListener() {
+ ZooInspectorNodeViewersDialog nvd = new ZooInspectorNodeViewersDialog(
+ JOptionPane.getRootFrame(), nodeViewers, listeners,
+ zooInspectorManager, iconResource);
+ nvd.setVisible(true);
+ toolbar.addActionListener(Toolbar.Button.about, new ActionListener() {
+ ZooInspectorAboutDialog zicpd = new ZooInspectorAboutDialog(
+ JOptionPane.getRootFrame(), iconResource);
+ JScrollPane treeScroller = new JScrollPane(treeViewer);
+ JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+ treeScroller, nodeViewersPanel);
+ splitPane.setResizeWeight(0.25);
+ this.add(splitPane, BorderLayout.CENTER);
+ this.add(toolbar.getJToolBar(), BorderLayout.NORTH);
+ * @param connectionProps
+ * the {@link Properties} for connecting to the zookeeper
+ * instance
+ public void connect(final Properties connectionProps) {
+ zooInspectorManager.setLastConnectionProps(connectionProps);
+ return zooInspectorManager.connect(connectionProps);
+ if (get()) {
+ toolbar.toggleButtons(true);
+ "Unable to connect to zookeeper", "Error",
+ } catch (InterruptedException e) {
+ "Error occurred while connecting to ZooKeeper server",
+ e);
+ } catch (ExecutionException e) {
+ public void disconnect() {
+ disconnect(false);
+ * @param wait
+ * - set this to true if the method should only return once the
+ * application has successfully disconnected
+ public void disconnect(boolean wait) {
+ return ZooInspectorPanel.this.zooInspectorManager.disconnect();
+ treeViewer.clearView();
+ toolbar.toggleButtons(false);
+ "Error occurred while disconnecting from ZooKeeper server",
+ if (wait) {
+ while (!worker.isDone()) {
+ Thread.sleep(100);
+ * @seeorg.apache.zookeeper.inspector.gui.NodeViewersChangeListener#
+ * nodeViewersChanged(java.util.List)
+ public void nodeViewersChanged(List<ZooInspectorNodeViewer> newViewers) {
+ this.nodeViewersPanel.setNodeViewers(newViewers);
+ * @throws IOException
+ public void setdefaultConnectionProps(Properties connectionProps)
+ throws IOException {
+ this.zooInspectorManager.saveDefaultConnectionFile(connectionProps);
@@ -1,356 +1,356 @@
-import java.awt.Color;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.LinkedHashSet;
-import java.util.Set;
-import javax.swing.JMenuItem;
-import javax.swing.JPopupMenu;
-import javax.swing.JTree;
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.DefaultTreeCellRenderer;
-import javax.swing.tree.DefaultTreeModel;
-import javax.swing.tree.TreeNode;
-import org.apache.zookeeper.inspector.manager.NodeListener;
-import com.nitido.utils.toaster.Toaster;
- * A {@link JPanel} for showing the tree view of all the nodes in the zookeeper
-public class ZooInspectorTreeViewer extends JPanel implements NodeListener {
- private final JTree tree;
- private final Toaster toasterManager;
- private final ImageIcon toasterIcon;
- * @param listener
- * - the {@link TreeSelectionListener} to listen for changes in
- * the selected node on the node tree
- public ZooInspectorTreeViewer(
- final ZooInspectorManager zooInspectorManager,
- TreeSelectionListener listener, IconResource iconResource) {
- final JPopupMenu popupMenu = new JPopupMenu();
- final JMenuItem addNotify = new JMenuItem("Add Change Notification");
- this.toasterManager = new Toaster();
- this.toasterManager.setBorderColor(Color.BLACK);
- this.toasterManager.setMessageColor(Color.BLACK);
- this.toasterManager.setToasterColor(Color.WHITE);
- toasterIcon = iconResource.get(IconResource.ICON_INFORMATION,"");
- addNotify.addActionListener(new ActionListener() {
- List<String> selectedNodes = getSelectedNodes();
- zooInspectorManager.addWatchers(selectedNodes,
- ZooInspectorTreeViewer.this);
- final JMenuItem removeNotify = new JMenuItem(
- "Remove Change Notification");
- removeNotify.addActionListener(new ActionListener() {
- zooInspectorManager.removeWatchers(selectedNodes);
- tree = new JTree(new DefaultMutableTreeNode());
- tree.setCellRenderer(new ZooInspectorTreeCellRenderer(iconResource));
- tree.setEditable(false);
- tree.getSelectionModel().addTreeSelectionListener(listener);
- tree.addMouseListener(new MouseAdapter() {
- public void mouseClicked(MouseEvent e) {
- if (e.isPopupTrigger() || e.getButton() == MouseEvent.BUTTON3) {
- // TODO only show add if a selected node isn't being
- // watched, and only show remove if a selected node is being
- // watched
- popupMenu.removeAll();
- popupMenu.add(addNotify);
- popupMenu.add(removeNotify);
- popupMenu.show(ZooInspectorTreeViewer.this, e.getX(), e
- .getY());
- this.add(tree, BorderLayout.CENTER);
- * Refresh the tree view
- public void refreshView() {
- final Set<TreePath> expandedNodes = new LinkedHashSet<TreePath>();
- int rowCount = tree.getRowCount();
- for (int i = 0; i < rowCount; i++) {
- TreePath path = tree.getPathForRow(i);
- if (tree.isExpanded(path)) {
- expandedNodes.add(path);
- final TreePath[] selectedNodes = tree.getSelectionPaths();
- tree.setModel(new DefaultTreeModel(new ZooInspectorTreeNode(
- "/", null)));
- for (TreePath path : expandedNodes) {
- tree.expandPath(path);
- tree.getSelectionModel().setSelectionPaths(selectedNodes);
- * clear the tree view of all nodes
- public void clearView() {
- tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode()));
- private static class ZooInspectorTreeCellRenderer extends
- DefaultTreeCellRenderer {
- public ZooInspectorTreeCellRenderer(IconResource iconResource) {
- setLeafIcon(iconResource.get(IconResource.ICON_TREE_LEAF,""));
- setOpenIcon(iconResource.get(IconResource.ICON_TREE_OPEN,""));
- setClosedIcon(iconResource.get(IconResource.ICON_TREE_CLOSE,""));
- private class ZooInspectorTreeNode implements TreeNode {
- private final String nodePath;
- private final String nodeName;
- private final ZooInspectorTreeNode parent;
- public ZooInspectorTreeNode(String nodePath, ZooInspectorTreeNode parent) {
- this.parent = parent;
- this.nodePath = nodePath;
- int index = nodePath.lastIndexOf("/");
- throw new IllegalArgumentException("Invalid node path"
- + nodePath);
- this.nodeName = nodePath.substring(index + 1);
- * @see javax.swing.tree.TreeNode#children()
- public Enumeration<TreeNode> children() {
- List<String> children = zooInspectorManager
- .getChildren(this.nodePath);
- Collections.sort(children);
- List<TreeNode> returnChildren = new ArrayList<TreeNode>();
- for (String child : children) {
- returnChildren.add(new ZooInspectorTreeNode((this.nodePath
- .equals("/") ? "" : this.nodePath)
- + "/" + child, this));
- return Collections.enumeration(returnChildren);
- * @see javax.swing.tree.TreeNode#getAllowsChildren()
- public boolean getAllowsChildren() {
- return zooInspectorManager.isAllowsChildren(this.nodePath);
- * @see javax.swing.tree.TreeNode#getChildAt(int)
- public TreeNode getChildAt(int childIndex) {
- String child = zooInspectorManager.getNodeChild(this.nodePath,
- childIndex);
- if (child != null) {
- return new ZooInspectorTreeNode((this.nodePath.equals("/") ? ""
- : this.nodePath)
- + "/" + child, this);
- return null;
- * @see javax.swing.tree.TreeNode#getChildCount()
- public int getChildCount() {
- return zooInspectorManager.getNumChildren(this.nodePath);
- * @see javax.swing.tree.TreeNode#getIndex(javax.swing.tree.TreeNode)
- public int getIndex(TreeNode node) {
- return zooInspectorManager.getNodeIndex(this.nodePath);
- * @see javax.swing.tree.TreeNode#getParent()
- public TreeNode getParent() {
- return this.parent;
- * @see javax.swing.tree.TreeNode#isLeaf()
- public boolean isLeaf() {
- return !zooInspectorManager.hasChildren(this.nodePath);
- public String toString() {
- return this.nodeName;
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + getOuterType().hashCode();
- result = prime * result
- + ((nodePath == null) ? 0 : nodePath.hashCode());
- + ((parent == null) ? 0 : parent.hashCode());
- return result;
- public boolean equals(Object obj) {
- if (this == obj)
- if (obj == null)
- if (getClass() != obj.getClass())
- ZooInspectorTreeNode other = (ZooInspectorTreeNode) obj;
- if (!getOuterType().equals(other.getOuterType()))
- if (nodePath == null) {
- if (other.nodePath != null)
- } else if (!nodePath.equals(other.nodePath))
- if (parent == null) {
- if (other.parent != null)
- } else if (!parent.equals(other.parent))
- private ZooInspectorTreeViewer getOuterType() {
- return ZooInspectorTreeViewer.this;
- * @return {@link List} of the currently selected nodes
- public List<String> getSelectedNodes() {
- TreePath[] paths = tree.getSelectionPaths();
- List<String> selectedNodes = new ArrayList<String>();
- if (paths != null) {
- sb.append("/");
- return selectedNodes;
- * org.apache.zookeeper.inspector.manager.NodeListener#processEvent(java
- * .lang.String, java.lang.String, java.util.Map)
- public void processEvent(String nodePath, String eventType,
- Map<String, String> eventInfo) {
- sb.append("Node: ");
- sb.append(nodePath);
- sb.append("\nEvent: ");
- sb.append(eventType);
- if (eventInfo != null) {
- for (Map.Entry<String, String> entry : eventInfo.entrySet()) {
- sb.append("\n");
- sb.append(entry.getKey());
- sb.append(": ");
- sb.append(entry.getValue());
- this.toasterManager.showToaster(toasterIcon, sb.toString());
+import java.awt.Color;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.JTree;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeNode;
+import org.apache.zookeeper.inspector.manager.NodeListener;
+import com.nitido.utils.toaster.Toaster;
+ * A {@link JPanel} for showing the tree view of all the nodes in the zookeeper
+public class ZooInspectorTreeViewer extends JPanel implements NodeListener {
+ private final JTree tree;
+ private final Toaster toasterManager;
+ private final ImageIcon toasterIcon;
+ * @param listener
+ * - the {@link TreeSelectionListener} to listen for changes in
+ * the selected node on the node tree
+ public ZooInspectorTreeViewer(
+ final ZooInspectorManager zooInspectorManager,
+ TreeSelectionListener listener, IconResource iconResource) {
+ final JPopupMenu popupMenu = new JPopupMenu();
+ final JMenuItem addNotify = new JMenuItem("Add Change Notification");
+ this.toasterManager = new Toaster();
+ this.toasterManager.setBorderColor(Color.BLACK);
+ this.toasterManager.setMessageColor(Color.BLACK);
+ this.toasterManager.setToasterColor(Color.WHITE);
+ toasterIcon = iconResource.get(IconResource.ICON_INFORMATION,"");
+ addNotify.addActionListener(new ActionListener() {
+ List<String> selectedNodes = getSelectedNodes();
+ zooInspectorManager.addWatchers(selectedNodes,
+ ZooInspectorTreeViewer.this);
+ final JMenuItem removeNotify = new JMenuItem(
+ "Remove Change Notification");
+ removeNotify.addActionListener(new ActionListener() {
+ zooInspectorManager.removeWatchers(selectedNodes);
+ tree = new JTree(new DefaultMutableTreeNode());
+ tree.setCellRenderer(new ZooInspectorTreeCellRenderer(iconResource));
+ tree.setEditable(false);
+ tree.getSelectionModel().addTreeSelectionListener(listener);
+ tree.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ if (e.isPopupTrigger() || e.getButton() == MouseEvent.BUTTON3) {
+ // TODO only show add if a selected node isn't being
+ // watched, and only show remove if a selected node is being
+ // watched
+ popupMenu.removeAll();
+ popupMenu.add(addNotify);
+ popupMenu.add(removeNotify);
+ popupMenu.show(ZooInspectorTreeViewer.this, e.getX(), e
+ .getY());
+ this.add(tree, BorderLayout.CENTER);
+ * Refresh the tree view
+ public void refreshView() {
+ final Set<TreePath> expandedNodes = new LinkedHashSet<TreePath>();
+ int rowCount = tree.getRowCount();
+ for (int i = 0; i < rowCount; i++) {
+ TreePath path = tree.getPathForRow(i);
+ if (tree.isExpanded(path)) {
+ expandedNodes.add(path);
+ final TreePath[] selectedNodes = tree.getSelectionPaths();
+ tree.setModel(new DefaultTreeModel(new ZooInspectorTreeNode(
+ "/", null)));
+ for (TreePath path : expandedNodes) {
+ tree.expandPath(path);
+ tree.getSelectionModel().setSelectionPaths(selectedNodes);
+ * clear the tree view of all nodes
+ public void clearView() {
+ tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode()));
+ private static class ZooInspectorTreeCellRenderer extends
+ DefaultTreeCellRenderer {
+ public ZooInspectorTreeCellRenderer(IconResource iconResource) {
+ setLeafIcon(iconResource.get(IconResource.ICON_TREE_LEAF,""));
+ setOpenIcon(iconResource.get(IconResource.ICON_TREE_OPEN,""));
+ setClosedIcon(iconResource.get(IconResource.ICON_TREE_CLOSE,""));
+ private class ZooInspectorTreeNode implements TreeNode {
+ private final String nodePath;
+ private final String nodeName;
+ private final ZooInspectorTreeNode parent;
+ public ZooInspectorTreeNode(String nodePath, ZooInspectorTreeNode parent) {
+ this.parent = parent;
+ this.nodePath = nodePath;
+ int index = nodePath.lastIndexOf("/");
+ throw new IllegalArgumentException("Invalid node path"
+ + nodePath);
+ this.nodeName = nodePath.substring(index + 1);
+ * @see javax.swing.tree.TreeNode#children()
+ public Enumeration<TreeNode> children() {
+ List<String> children = zooInspectorManager
+ .getChildren(this.nodePath);
+ Collections.sort(children);
+ List<TreeNode> returnChildren = new ArrayList<TreeNode>();
+ for (String child : children) {
+ returnChildren.add(new ZooInspectorTreeNode((this.nodePath
+ .equals("/") ? "" : this.nodePath)
+ + "/" + child, this));
+ return Collections.enumeration(returnChildren);
+ * @see javax.swing.tree.TreeNode#getAllowsChildren()
+ public boolean getAllowsChildren() {
+ return zooInspectorManager.isAllowsChildren(this.nodePath);
+ * @see javax.swing.tree.TreeNode#getChildAt(int)
+ public TreeNode getChildAt(int childIndex) {
+ String child = zooInspectorManager.getNodeChild(this.nodePath,
+ childIndex);
+ if (child != null) {
+ return new ZooInspectorTreeNode((this.nodePath.equals("/") ? ""
+ : this.nodePath)
+ + "/" + child, this);
+ return null;
+ * @see javax.swing.tree.TreeNode#getChildCount()
+ public int getChildCount() {
+ return zooInspectorManager.getNumChildren(this.nodePath);
+ * @see javax.swing.tree.TreeNode#getIndex(javax.swing.tree.TreeNode)
+ public int getIndex(TreeNode node) {
+ return zooInspectorManager.getNodeIndex(this.nodePath);
+ * @see javax.swing.tree.TreeNode#getParent()
+ public TreeNode getParent() {
+ return this.parent;
+ * @see javax.swing.tree.TreeNode#isLeaf()
+ public boolean isLeaf() {
+ return !zooInspectorManager.hasChildren(this.nodePath);
+ public String toString() {
+ return this.nodeName;
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + getOuterType().hashCode();
+ result = prime * result
+ + ((nodePath == null) ? 0 : nodePath.hashCode());
+ + ((parent == null) ? 0 : parent.hashCode());
+ return result;
+ public boolean equals(Object obj) {
+ if (this == obj)
+ if (obj == null)
+ if (getClass() != obj.getClass())
+ ZooInspectorTreeNode other = (ZooInspectorTreeNode) obj;
+ if (!getOuterType().equals(other.getOuterType()))
+ if (nodePath == null) {
+ if (other.nodePath != null)
+ } else if (!nodePath.equals(other.nodePath))
+ if (parent == null) {
+ if (other.parent != null)
+ } else if (!parent.equals(other.parent))
+ private ZooInspectorTreeViewer getOuterType() {
+ return ZooInspectorTreeViewer.this;
+ * @return {@link List} of the currently selected nodes
+ public List<String> getSelectedNodes() {
+ TreePath[] paths = tree.getSelectionPaths();
+ List<String> selectedNodes = new ArrayList<String>();
+ if (paths != null) {
+ sb.append("/");
+ return selectedNodes;
+ * org.apache.zookeeper.inspector.manager.NodeListener#processEvent(java
+ * .lang.String, java.lang.String, java.util.Map)
+ public void processEvent(String nodePath, String eventType,
+ Map<String, String> eventInfo) {
+ sb.append("Node: ");
+ sb.append(nodePath);
+ sb.append("\nEvent: ");
+ sb.append(eventType);
+ if (eventInfo != null) {
+ for (Map.Entry<String, String> entry : eventInfo.entrySet()) {
+ sb.append("\n");
+ sb.append(entry.getKey());
+ sb.append(": ");
+ sb.append(entry.getValue());
+ this.toasterManager.showToaster(toasterIcon, sb.toString());
@@ -1,21 +1,21 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-<title>ZooInspector v0.1</title>
-</head>
-<body>
-<p>ZooInspector was developed by Colin Goodheart-Smithe and is
-available under the Apache Software Licence v2.0.</p>
-<p>The Icons used were sourced from the Eclipse project (<a
- href="http://www.eclipse.org">http://www.eclipse.org</a>) and licensed
-under the Eclipse Public Licence v1.0. [<a
- href="http://www.eclipse.org/org/documents/epl-v10.php">http://www.eclipse.org/org/documents/epl-v10.php</a>]
-</p>
-<p>ZooKeeper is available from <a
- href="http://zookeeper.apache.org/">http://zookeeper.apache.org/</a>
-and is licensed under an Apache Software Licence v2.0</p>
-<p>The ApacheSoftware Licence v2.0 can be found at <a
- href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a></p>
-</body>
-</html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>ZooInspector v0.1</title>
+</head>
+<body>
+<p>ZooInspector was developed by Colin Goodheart-Smithe and is
+available under the Apache Software Licence v2.0.</p>
+<p>The Icons used were sourced from the Eclipse project (<a
+ href="http://www.eclipse.org">http://www.eclipse.org</a>) and licensed
+under the Eclipse Public Licence v1.0. [<a
+ href="http://www.eclipse.org/org/documents/epl-v10.php">http://www.eclipse.org/org/documents/epl-v10.php</a>]
+</p>
+<p>ZooKeeper is available from <a
+ href="http://zookeeper.apache.org/">http://zookeeper.apache.org/</a>
+and is licensed under an Apache Software Licence v2.0</p>
+<p>The ApacheSoftware Licence v2.0 can be found at <a
+ href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a></p>
+</body>
+</html>
@@ -1,187 +1,187 @@
-package org.apache.zookeeper.inspector.gui.nodeviewer;
-import javax.swing.BorderFactory;
- * A node viewer for displaying the ACLs currently applied to the selected node
-public class NodeViewerACL extends ZooInspectorNodeViewer {
- private ZooInspectorNodeManager zooInspectorManager;
- private final JPanel aclDataPanel;
- private String selectedNode;
- public NodeViewerACL() {
- this.aclDataPanel = new JPanel();
- this.aclDataPanel.setBackground(Color.WHITE);
- JScrollPane scroller = new JScrollPane(this.aclDataPanel);
- this.add(scroller, BorderLayout.CENTER);
- * org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer#
- * getTitle()
- public String getTitle() {
- return "Node ACLs";
- * nodeSelectionChanged(java.util.Set)
- public void nodeSelectionChanged(List<String> selectedNodes) {
- this.aclDataPanel.removeAll();
- if (selectedNodes.size() > 0) {
- this.selectedNode = selectedNodes.get(0);
- SwingWorker<List<Map<String, String>>, Void> worker = new SwingWorker<List<Map<String, String>>, Void>() {
- protected List<Map<String, String>> doInBackground()
- throws Exception {
- return NodeViewerACL.this.zooInspectorManager
- .getACLs(NodeViewerACL.this.selectedNode);
- List<Map<String, String>> acls = null;
- acls = get();
- acls = new ArrayList<Map<String, String>>();
- "Error retrieving ACL Information for node: "
- + NodeViewerACL.this.selectedNode, e);
- aclDataPanel.setLayout(new GridBagLayout());
- int j = 0;
- for (Map<String, String> data : acls) {
- int rowPos = 2 * j + 1;
- JPanel aclPanel = new JPanel();
- aclPanel.setBorder(BorderFactory
- .createLineBorder(Color.BLACK));
- aclPanel.setBackground(Color.WHITE);
- aclPanel.setLayout(new GridBagLayout());
- for (Map.Entry<String, String> entry : data.entrySet()) {
- int rowPosACL = 2 * i + 1;
- JLabel label = new JLabel(entry.getKey());
- JTextField text = new JTextField(entry.getValue());
- text.setEditable(false);
- c1.gridx = 1;
- c1.gridy = rowPosACL;
- c1.anchor = GridBagConstraints.NORTHWEST;
- aclPanel.add(label, c1);
- c2.gridy = rowPosACL;
- c2.anchor = GridBagConstraints.NORTHWEST;
- c2.fill = GridBagConstraints.BOTH;
- aclPanel.add(text, c2);
- GridBagConstraints c = new GridBagConstraints();
- c.gridx = 1;
- c.gridy = rowPos;
- c.gridwidth = 1;
- c.gridheight = 1;
- c.weightx = 1;
- c.weighty = 1;
- c.anchor = GridBagConstraints.NORTHWEST;
- c.fill = GridBagConstraints.NONE;
- c.insets = new Insets(5, 5, 5, 5);
- c.ipadx = 0;
- c.ipady = 0;
- aclDataPanel.add(aclPanel, c);
- NodeViewerACL.this.aclDataPanel.revalidate();
- NodeViewerACL.this.aclDataPanel.repaint();
- * setZooInspectorManager
- * (org.apache.zookeeper.inspector.manager.ZooInspectorNodeManager)
- public void setZooInspectorManager(
- ZooInspectorNodeManager zooInspectorManager) {
+package org.apache.zookeeper.inspector.gui.nodeviewer;
+import javax.swing.BorderFactory;
+ * A node viewer for displaying the ACLs currently applied to the selected node
+public class NodeViewerACL extends ZooInspectorNodeViewer {
+ private ZooInspectorNodeManager zooInspectorManager;
+ private final JPanel aclDataPanel;
+ private String selectedNode;
+ public NodeViewerACL() {
+ this.aclDataPanel = new JPanel();
+ this.aclDataPanel.setBackground(Color.WHITE);
+ JScrollPane scroller = new JScrollPane(this.aclDataPanel);
+ this.add(scroller, BorderLayout.CENTER);
+ * org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer#
+ * getTitle()
+ public String getTitle() {
+ return "Node ACLs";
+ * nodeSelectionChanged(java.util.Set)
+ public void nodeSelectionChanged(List<String> selectedNodes) {
+ this.aclDataPanel.removeAll();
+ if (selectedNodes.size() > 0) {
+ this.selectedNode = selectedNodes.get(0);
+ SwingWorker<List<Map<String, String>>, Void> worker = new SwingWorker<List<Map<String, String>>, Void>() {
+ protected List<Map<String, String>> doInBackground()
+ throws Exception {
+ return NodeViewerACL.this.zooInspectorManager
+ .getACLs(NodeViewerACL.this.selectedNode);
+ List<Map<String, String>> acls = null;
+ acls = get();
+ acls = new ArrayList<Map<String, String>>();
+ "Error retrieving ACL Information for node: "
+ + NodeViewerACL.this.selectedNode, e);
+ aclDataPanel.setLayout(new GridBagLayout());
+ int j = 0;
+ for (Map<String, String> data : acls) {
+ int rowPos = 2 * j + 1;
+ JPanel aclPanel = new JPanel();
+ aclPanel.setBorder(BorderFactory
+ .createLineBorder(Color.BLACK));
+ aclPanel.setBackground(Color.WHITE);
+ aclPanel.setLayout(new GridBagLayout());
+ for (Map.Entry<String, String> entry : data.entrySet()) {
+ int rowPosACL = 2 * i + 1;
+ JLabel label = new JLabel(entry.getKey());
+ JTextField text = new JTextField(entry.getValue());
+ text.setEditable(false);
+ c1.gridx = 1;
+ c1.gridy = rowPosACL;
+ c1.anchor = GridBagConstraints.NORTHWEST;
+ aclPanel.add(label, c1);
+ c2.gridy = rowPosACL;
+ c2.anchor = GridBagConstraints.NORTHWEST;
+ c2.fill = GridBagConstraints.BOTH;
+ aclPanel.add(text, c2);
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 1;
+ c.gridy = rowPos;
+ c.gridwidth = 1;
+ c.gridheight = 1;
+ c.weightx = 1;
+ c.weighty = 1;
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.fill = GridBagConstraints.NONE;
+ c.insets = new Insets(5, 5, 5, 5);
+ c.ipadx = 0;
+ c.ipady = 0;
+ aclDataPanel.add(aclPanel, c);
+ NodeViewerACL.this.aclDataPanel.revalidate();
+ NodeViewerACL.this.aclDataPanel.repaint();
+ * setZooInspectorManager
+ * (org.apache.zookeeper.inspector.manager.ZooInspectorNodeManager)
+ public void setZooInspectorManager(
+ ZooInspectorNodeManager zooInspectorManager) {
@@ -1,143 +1,143 @@
-import javax.swing.JTextPane;
-import org.apache.zookeeper.inspector.ZooInspector;
- * A node viewer for displaying the data for the currently selected node
-public class NodeViewerData extends ZooInspectorNodeViewer {
- private final JTextPane dataArea;
- private final JToolBar toolbar;
- public NodeViewerData() {
- this.dataArea = new JTextPane();
- this.toolbar = new JToolBar();
- this.toolbar.setFloatable(false);
- JScrollPane scroller = new JScrollPane(this.dataArea);
- scroller
- .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
- this.add(this.toolbar, BorderLayout.NORTH);
- JButton saveButton = new JButton(ZooInspector.iconResource.get(IconResource.ICON_SAVE,""));
- saveButton.addActionListener(new ActionListener() {
- if (selectedNode != null) {
- if (JOptionPane.showConfirmDialog(NodeViewerData.this,
- "Are you sure you want to save this node?"
- + " (this action cannot be reverted)",
- "Confirm Save", JOptionPane.YES_NO_OPTION,
- JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) {
- zooInspectorManager.setData(selectedNode, dataArea
- .getText());
- this.toolbar.add(saveButton);
- return "Node Data";
- SwingWorker<String, Void> worker = new SwingWorker<String, Void>() {
- protected String doInBackground() throws Exception {
- return NodeViewerData.this.zooInspectorManager
- .getData(NodeViewerData.this.selectedNode);
- String data = "";
- data = get();
- "Error retrieving data for node: "
- + NodeViewerData.this.selectedNode, e);
- NodeViewerData.this.dataArea.setText(data);
+import javax.swing.JTextPane;
+import org.apache.zookeeper.inspector.ZooInspector;
+ * A node viewer for displaying the data for the currently selected node
+public class NodeViewerData extends ZooInspectorNodeViewer {
+ private final JTextPane dataArea;
+ private final JToolBar toolbar;
+ public NodeViewerData() {
+ this.dataArea = new JTextPane();
+ this.toolbar = new JToolBar();
+ this.toolbar.setFloatable(false);
+ JScrollPane scroller = new JScrollPane(this.dataArea);
+ scroller
+ .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ this.add(this.toolbar, BorderLayout.NORTH);
+ JButton saveButton = new JButton(ZooInspector.iconResource.get(IconResource.ICON_SAVE,""));
+ saveButton.addActionListener(new ActionListener() {
+ if (selectedNode != null) {
+ if (JOptionPane.showConfirmDialog(NodeViewerData.this,
+ "Are you sure you want to save this node?"
+ + " (this action cannot be reverted)",
+ "Confirm Save", JOptionPane.YES_NO_OPTION,
+ JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) {
+ zooInspectorManager.setData(selectedNode, dataArea
+ .getText());
+ this.toolbar.add(saveButton);
+ return "Node Data";
+ SwingWorker<String, Void> worker = new SwingWorker<String, Void>() {
+ protected String doInBackground() throws Exception {
+ return NodeViewerData.this.zooInspectorManager
+ .getData(NodeViewerData.this.selectedNode);
+ String data = "";
+ data = get();
+ "Error retrieving data for node: "
+ + NodeViewerData.this.selectedNode, e);
+ NodeViewerData.this.dataArea.setText(data);
@@ -1,186 +1,186 @@
-import org.apache.zookeeper.data.Stat;
- * A node viewer for displaying the meta data for the currently selected node.
- * The meta data is essentially the information from the {@link Stat} for the
- * node
-public class NodeViewerMetaData extends ZooInspectorNodeViewer {
- private final JPanel metaDataPanel;
- public NodeViewerMetaData() {
- this.metaDataPanel = new JPanel();
- this.metaDataPanel.setBackground(Color.WHITE);
- JScrollPane scroller = new JScrollPane(this.metaDataPanel);
- return "Node Metadata";
- this.metaDataPanel.removeAll();
- SwingWorker<Map<String, String>, Void> worker = new SwingWorker<Map<String, String>, Void>() {
- protected Map<String, String> doInBackground() throws Exception {
- return NodeViewerMetaData.this.zooInspectorManager
- .getNodeMeta(NodeViewerMetaData.this.selectedNode);
- Map<String, String> data = null;
- data = new HashMap<String, String>();
- "Error retrieving meta data for node: "
- + NodeViewerMetaData.this.selectedNode,
- NodeViewerMetaData.this.metaDataPanel
- .setLayout(new GridBagLayout());
- JPanel infoPanel = new JPanel();
- infoPanel.setBackground(Color.WHITE);
- infoPanel.setLayout(new GridBagLayout());
- int rowPos = 0;
- rowPos = 2 * i + 1;
- infoPanel.add(label, c1);
- infoPanel.add(text, c2);
- NodeViewerMetaData.this.metaDataPanel.add(infoPanel, c);
- NodeViewerMetaData.this.metaDataPanel.revalidate();
- NodeViewerMetaData.this.metaDataPanel.repaint();
+import org.apache.zookeeper.data.Stat;
+ * A node viewer for displaying the meta data for the currently selected node.
+ * The meta data is essentially the information from the {@link Stat} for the
+ * node
+public class NodeViewerMetaData extends ZooInspectorNodeViewer {
+ private final JPanel metaDataPanel;
+ public NodeViewerMetaData() {
+ this.metaDataPanel = new JPanel();
+ this.metaDataPanel.setBackground(Color.WHITE);
+ JScrollPane scroller = new JScrollPane(this.metaDataPanel);
+ return "Node Metadata";
+ this.metaDataPanel.removeAll();
+ SwingWorker<Map<String, String>, Void> worker = new SwingWorker<Map<String, String>, Void>() {
+ protected Map<String, String> doInBackground() throws Exception {
+ return NodeViewerMetaData.this.zooInspectorManager
+ .getNodeMeta(NodeViewerMetaData.this.selectedNode);
+ Map<String, String> data = null;
+ data = new HashMap<String, String>();
+ "Error retrieving meta data for node: "
+ + NodeViewerMetaData.this.selectedNode,
+ NodeViewerMetaData.this.metaDataPanel
+ .setLayout(new GridBagLayout());
+ JPanel infoPanel = new JPanel();
+ infoPanel.setBackground(Color.WHITE);
+ infoPanel.setLayout(new GridBagLayout());
+ int rowPos = 0;
+ rowPos = 2 * i + 1;
+ infoPanel.add(label, c1);
+ infoPanel.add(text, c2);
+ NodeViewerMetaData.this.metaDataPanel.add(infoPanel, c);
+ NodeViewerMetaData.this.metaDataPanel.revalidate();
+ NodeViewerMetaData.this.metaDataPanel.repaint();
@@ -1,138 +1,138 @@
-import java.awt.datatransfer.DataFlavor;
-import java.awt.datatransfer.UnsupportedFlavorException;
- * A {@link JPanel} for displaying information about the currently selected
- * node(s)
-public abstract class ZooInspectorNodeViewer extends JPanel implements
- Transferable {
- * The {@link DataFlavor} used for DnD in the node viewer configuration
- * dialog
- public static final DataFlavor nodeViewerDataFlavor = new DataFlavor(
- ZooInspectorNodeViewer.class, "nodeviewer");
- public abstract void setZooInspectorManager(
- ZooInspectorNodeManager zooInspectorManager);
- * Called whenever the selected nodes in the tree view changes.
- * @param selectedNodes
- * - the nodes currently selected in the tree view
- public abstract void nodeSelectionChanged(List<String> selectedNodes);
- * @return the title of the node viewer. this will be shown on the tab for
- * this node viewer.
- public abstract String getTitle();
- * java.awt.datatransfer.Transferable#getTransferData(java.awt.datatransfer
- * .DataFlavor)
- public Object getTransferData(DataFlavor flavor)
- throws UnsupportedFlavorException, IOException {
- if (flavor.equals(nodeViewerDataFlavor)) {
- return this.getClass().getCanonicalName();
- * @see java.awt.datatransfer.Transferable#getTransferDataFlavors()
- public DataFlavor[] getTransferDataFlavors() {
- return new DataFlavor[] { nodeViewerDataFlavor };
- * @seejava.awt.datatransfer.Transferable#isDataFlavorSupported(java.awt.
- * datatransfer.DataFlavor)
- public boolean isDataFlavorSupported(DataFlavor flavor) {
- return flavor.equals(nodeViewerDataFlavor);
- * @see java.lang.Object#hashCode()
- + ((getTitle() == null) ? 0 : getTitle().hashCode());
- * @see java.lang.Object#equals(java.lang.Object)
- ZooInspectorNodeViewer other = (ZooInspectorNodeViewer) obj;
- if (getClass().getCanonicalName() != other.getClass()
- .getCanonicalName()) {
- if (getTitle() == null) {
- if (other.getTitle() != null)
- } else if (!getTitle().equals(other.getTitle()))
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.UnsupportedFlavorException;
+ * A {@link JPanel} for displaying information about the currently selected
+ * node(s)
+public abstract class ZooInspectorNodeViewer extends JPanel implements
+ Transferable {
+ * The {@link DataFlavor} used for DnD in the node viewer configuration
+ * dialog
+ public static final DataFlavor nodeViewerDataFlavor = new DataFlavor(
+ ZooInspectorNodeViewer.class, "nodeviewer");
+ public abstract void setZooInspectorManager(
+ ZooInspectorNodeManager zooInspectorManager);
+ * Called whenever the selected nodes in the tree view changes.
+ * @param selectedNodes
+ * - the nodes currently selected in the tree view
+ public abstract void nodeSelectionChanged(List<String> selectedNodes);
+ * @return the title of the node viewer. this will be shown on the tab for
+ * this node viewer.
+ public abstract String getTitle();
+ * java.awt.datatransfer.Transferable#getTransferData(java.awt.datatransfer
+ * .DataFlavor)
+ public Object getTransferData(DataFlavor flavor)
+ throws UnsupportedFlavorException, IOException {
+ if (flavor.equals(nodeViewerDataFlavor)) {
+ return this.getClass().getCanonicalName();
+ * @see java.awt.datatransfer.Transferable#getTransferDataFlavors()
+ public DataFlavor[] getTransferDataFlavors() {
+ return new DataFlavor[] { nodeViewerDataFlavor };
+ * @seejava.awt.datatransfer.Transferable#isDataFlavorSupported(java.awt.
+ * datatransfer.DataFlavor)
+ public boolean isDataFlavorSupported(DataFlavor flavor) {
+ return flavor.equals(nodeViewerDataFlavor);
+ * @see java.lang.Object#hashCode()
+ + ((getTitle() == null) ? 0 : getTitle().hashCode());
+ * @see java.lang.Object#equals(java.lang.Object)
+ ZooInspectorNodeViewer other = (ZooInspectorNodeViewer) obj;
+ if (getClass().getCanonicalName() != other.getClass()
+ .getCanonicalName()) {
+ if (getTitle() == null) {
+ if (other.getTitle() != null)
+ } else if (!getTitle().equals(other.getTitle()))
@@ -1,36 +1,36 @@
-package org.apache.zookeeper.inspector.logger;
- * Provides a {@link Logger} for use across the entire application
-public class LoggerFactory
-{
- private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger("org.apache.zookeeper.inspector"); //$NON-NLS-1$
- * @return {@link Logger} for ZooInspector
- public static org.slf4j.Logger getLogger()
- return logger;
+package org.apache.zookeeper.inspector.logger;
+ * Provides a {@link Logger} for use across the entire application
+public class LoggerFactory
+{
+ private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger("org.apache.zookeeper.inspector"); //$NON-NLS-1$
+ * @return {@link Logger} for ZooInspector
+ public static org.slf4j.Logger getLogger()
+ return logger;
-package org.apache.zookeeper.inspector.manager;
- * A Listener for Events on zookeeper nodes
-public interface NodeListener {
- * @param nodePath
- * - the path of the node
- * @param eventType
- * - the event type
- * @param eventInfo
- * - a {@link Map} containing any other information about this
- * event
- Map<String, String> eventInfo);
+package org.apache.zookeeper.inspector.manager;
+ * A Listener for Events on zookeeper nodes
+public interface NodeListener {
+ * @param nodePath
+ * - the path of the node
+ * @param eventType
+ * - the event type
+ * @param eventInfo
+ * - a {@link Map} containing any other information about this
+ * event
+ Map<String, String> eventInfo);
@@ -1,120 +1,120 @@
- * A utility class for storing a pair of objects
- * @param <K>
- * @param <V>
-public class Pair<K, V> {
- private K key;
- private V value;
- * @param key
- * @param value
- public Pair(K key, V value) {
- this.key = key;
- this.value = value;
- public Pair() {
- // Do Nothing
- * @return key
- public K getKey() {
- return key;
- public void setKey(K key) {
- * @return value
- public V getValue() {
- public void setValue(V value) {
- return "Pair [" + key + ", " + value + "]";
- result = prime * result + ((key == null) ? 0 : key.hashCode());
- result = prime * result + ((value == null) ? 0 : value.hashCode());
- Pair<?, ?> other = (Pair<?, ?>) obj;
- if (key == null) {
- if (other.key != null)
- } else if (!key.equals(other.key))
- if (value == null) {
- if (other.value != null)
- } else if (!value.equals(other.value))
+ * A utility class for storing a pair of objects
+ * @param <K>
+ * @param <V>
+public class Pair<K, V> {
+ private K key;
+ private V value;
+ * @param key
+ * @param value
+ public Pair(K key, V value) {
+ this.key = key;
+ this.value = value;
+ public Pair() {
+ // Do Nothing
+ * @return key
+ public K getKey() {
+ return key;
+ public void setKey(K key) {
+ * @return value
+ public V getValue() {
+ public void setValue(V value) {
+ return "Pair [" + key + ", " + value + "]";
+ result = prime * result + ((key == null) ? 0 : key.hashCode());
+ result = prime * result + ((value == null) ? 0 : value.hashCode());
+ Pair<?, ?> other = (Pair<?, ?>) obj;
+ if (key == null) {
+ if (other.key != null)
+ } else if (!key.equals(other.key))
+ if (value == null) {
+ if (other.value != null)
+ } else if (!value.equals(other.value))
- * A Manager for all interactions between the application and the Zookeeper
-public interface ZooInspectorManager extends ZooInspectorNodeManager,
- ZooInspectorNodeTreeManager {
- * @return true if successfully connected
- public boolean connect(Properties connectionProps);
- * @return true if successfully disconnected
- public boolean disconnect();
- * @return a {@link Pair} containing the following:
- * <ul>
- * <li>a {@link Map} of property keys to list of possible values. If
- * the list size is 1 the value is taken to be the default value for
- * a {@link JTextField}. If the list size is greater than 1, the
- * values are taken to be the possible options to show in a
- * {@link JComboBox} with the first selected as default.</li>
- * <li>a {@link Map} of property keys to the label to show on the UI
- * </li>
- public Pair<Map<String, List<String>>, Map<String, String>> getConnectionPropertiesTemplate();
- * - the nodes to add the watcher to
- * @param nodeListener
- * - the node listener for this watcher
- public void addWatchers(Collection<String> selectedNodes,
- NodeListener nodeListener);
- * - the nodes to remove the watchers from
- public void removeWatchers(Collection<String> selectedNodes);
- * @param selectedFile
- * - the file to load which contains the node viewers
- * configuration
- * @return nodeViewers - the class names of the node viewers from the
- * - if the configuration file cannot be loaded
- public List<String> loadNodeViewersFile(File selectedFile)
- throws IOException;
- * - the file to save the configuration to
- * @param nodeViewersClassNames
- * - the class names of the node viewers
- * - if the configuration file cannot be saved
- public void saveNodeViewersFile(File selectedFile,
- List<String> nodeViewersClassNames) throws IOException;
- * - if the default configuration file cannot be loaded
- public void setDefaultNodeViewerConfiguration(
- List<String> getDefaultNodeViewerConfiguration() throws IOException;
- * - the connection properties last used to connect to the
- * zookeeeper instance
- public void setLastConnectionProps(Properties connectionProps);
- * @return last connection Properties - the connection properties last used
- * to connect to the zookeeeper instance
- public Properties getLastConnectionProps();
- * @param props
- * - the properties to use as the default connection settings
- * - if the default configuration file cannot be saved
- public void saveDefaultConnectionFile(Properties props) throws IOException;
+ * A Manager for all interactions between the application and the Zookeeper
+public interface ZooInspectorManager extends ZooInspectorNodeManager,
+ ZooInspectorNodeTreeManager {
+ * @return true if successfully connected
+ public boolean connect(Properties connectionProps);
+ * @return true if successfully disconnected
+ public boolean disconnect();
+ * @return a {@link Pair} containing the following:
+ * <ul>
+ * <li>a {@link Map} of property keys to list of possible values. If
+ * the list size is 1 the value is taken to be the default value for
+ * a {@link JTextField}. If the list size is greater than 1, the
+ * values are taken to be the possible options to show in a
+ * {@link JComboBox} with the first selected as default.</li>
+ * <li>a {@link Map} of property keys to the label to show on the UI
+ * </li>
+ public Pair<Map<String, List<String>>, Map<String, String>> getConnectionPropertiesTemplate();
+ * - the nodes to add the watcher to
+ * @param nodeListener
+ * - the node listener for this watcher
+ public void addWatchers(Collection<String> selectedNodes,
+ NodeListener nodeListener);
+ * - the nodes to remove the watchers from
+ public void removeWatchers(Collection<String> selectedNodes);
+ * @param selectedFile
+ * - the file to load which contains the node viewers
+ * configuration
+ * @return nodeViewers - the class names of the node viewers from the
+ * - if the configuration file cannot be loaded
+ public List<String> loadNodeViewersFile(File selectedFile)
+ throws IOException;
+ * - the file to save the configuration to
+ * @param nodeViewersClassNames
+ * - the class names of the node viewers
+ * - if the configuration file cannot be saved
+ public void saveNodeViewersFile(File selectedFile,
+ List<String> nodeViewersClassNames) throws IOException;
+ * - if the default configuration file cannot be loaded
+ public void setDefaultNodeViewerConfiguration(
+ List<String> getDefaultNodeViewerConfiguration() throws IOException;
+ * - the connection properties last used to connect to the
+ * zookeeeper instance
+ public void setLastConnectionProps(Properties connectionProps);
+ * @return last connection Properties - the connection properties last used
+ * to connect to the zookeeeper instance
+ public Properties getLastConnectionProps();
+ * @param props
+ * - the properties to use as the default connection settings
+ * - if the default configuration file cannot be saved
+ public void saveDefaultConnectionFile(Properties props) throws IOException;
@@ -1,885 +1,885 @@
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.FileWriter;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import org.apache.zookeeper.CreateMode;
-import org.apache.zookeeper.KeeperException;
-import org.apache.zookeeper.WatchedEvent;
-import org.apache.zookeeper.Watcher;
-import org.apache.zookeeper.ZooKeeper;
-import org.apache.zookeeper.Watcher.Event.EventType;
-import org.apache.zookeeper.Watcher.Event.KeeperState;
-import org.apache.zookeeper.ZooDefs.Ids;
-import org.apache.zookeeper.ZooDefs.Perms;
-import org.apache.zookeeper.data.ACL;
-import org.apache.zookeeper.inspector.encryption.BasicDataEncryptionManager;
-import org.apache.zookeeper.inspector.encryption.DataEncryptionManager;
-import org.apache.zookeeper.retry.ZooKeeperRetry;
- * A default implementation of {@link ZooInspectorManager} for connecting to
- * zookeeper instances
-public class ZooInspectorManagerImpl implements ZooInspectorManager {
- private static final String A_VERSION = "ACL Version";
- private static final String C_TIME = "Creation Time";
- private static final String C_VERSION = "Children Version";
- private static final String CZXID = "Creation ID";
- private static final String DATA_LENGTH = "Data Length";
- private static final String EPHEMERAL_OWNER = "Ephemeral Owner";
- private static final String M_TIME = "Last Modified Time";
- private static final String MZXID = "Modified ID";
- private static final String NUM_CHILDREN = "Number of Children";
- private static final String PZXID = "Node ID";
- private static final String VERSION = "Data Version";
- private static final String ACL_PERMS = "Permissions";
- private static final String ACL_SCHEME = "Scheme";
- private static final String ACL_ID = "Id";
- private static final String SESSION_STATE = "Session State";
- private static final String SESSION_ID = "Session ID";
- * The key used for the connect string in the connection properties file
- public static final String CONNECT_STRING = "hosts";
- * The key used for the session timeout in the connection properties file
- public static final String SESSION_TIMEOUT = "timeout";
- * The key used for the data encryption manager in the connection properties
- * file
- public static final String DATA_ENCRYPTION_MANAGER = "encryptionManager";
- * The key used for the authentication scheme in the connection properties file
- public static final String AUTH_SCHEME_KEY = "authScheme";
- * The key used for the authentication data in the connection properties file
- public static final String AUTH_DATA_KEY = "authData";
- private static final File defaultNodeViewersFile = new File(
- "./config/defaultNodeViewers.cfg");
- private static final File defaultConnectionFile = new File(
- "./config/defaultConnectionSettings.cfg");
- private DataEncryptionManager encryptionManager;
- private String connectString;
- private int sessionTimeout;
- private ZooKeeper zooKeeper;
- private final Map<String, NodeWatcher> watchers = new HashMap<String, NodeWatcher>();
- protected boolean connected = true;
- private Properties lastConnectionProps;
- private String defaultEncryptionManager;
- private String defaultTimeout;
- private String defaultHosts;
- private String defaultAuthScheme;
- private String defaultAuthValue;
- * - thrown if the default connection settings cannot be loaded
- public ZooInspectorManagerImpl() throws IOException {
- loadDefaultConnectionFile();
- * org.apache.zookeeper.inspector.manager.ZooInspectorManager#connect(java
- * .util.Properties)
- public boolean connect(Properties connectionProps) {
- if (this.zooKeeper == null) {
- String connectString = connectionProps
- .getProperty(CONNECT_STRING);
- String sessionTimeout = connectionProps
- .getProperty(SESSION_TIMEOUT);
- String encryptionManager = connectionProps
- .getProperty(DATA_ENCRYPTION_MANAGER);
- String authScheme = connectionProps
- .getProperty(AUTH_SCHEME_KEY);
- String authData = connectionProps
- .getProperty(AUTH_DATA_KEY);
- if (connectString == null || sessionTimeout == null) {
- throw new IllegalArgumentException(
- "Both connect string and session timeout are required.");
- if (encryptionManager == null) {
- this.encryptionManager = new BasicDataEncryptionManager();
- Class<?> clazz = Class.forName(encryptionManager);
- if (Arrays.asList(clazz.getInterfaces()).contains(
- DataEncryptionManager.class)) {
- this.encryptionManager = (DataEncryptionManager) Class
- .forName(encryptionManager).newInstance();
- "Data encryption manager must implement DataEncryptionManager interface");
- this.connectString = connectString;
- this.sessionTimeout = Integer.valueOf(sessionTimeout);
- this.zooKeeper = new ZooKeeperRetry(connectString, Integer
- .valueOf(sessionTimeout), new Watcher() {
- public void process(WatchedEvent event) {
- if (event.getState() == KeeperState.Expired) {
- connected = false;
- if (authData != null && authData.length() > 0){
- this.zooKeeper.addAuthInfo(authScheme, authData.getBytes());
- ((ZooKeeperRetry) this.zooKeeper).setRetryLimit(10);
- connected = ((ZooKeeperRetry) this.zooKeeper).testConnection();
- e.printStackTrace();
- if (!connected){
- return connected;
- * org.apache.zookeeper.inspector.manager.ZooInspectorManager#disconnect()
- public boolean disconnect() {
- if (this.zooKeeper != null) {
- this.zooKeeper.close();
- this.zooKeeper = null;
- removeWatchers(this.watchers.keySet());
- * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorReadOnlyManager#
- * getChildren(java.lang.String)
- public List<String> getChildren(String nodePath) {
- if (connected) {
- return zooKeeper.getChildren(nodePath, false);
- "Error occurred retrieving children of node: "
- + nodePath, e);
- * org.apache.zookeeper.inspector.manager.ZooInspectorReadOnlyManager#getData
- public String getData(String nodePath) {
- if (nodePath.length() == 0) {
- nodePath = "/";
- Stat s = zooKeeper.exists(nodePath, false);
- if (s != null) {
- return this.encryptionManager.decryptData(zooKeeper
- .getData(nodePath, false, s));
- "Error occurred getting data for node: " + nodePath, e);
- * getNodeChild(java.lang.String, int)
- public String getNodeChild(String nodePath, int childIndex) {
- return this.zooKeeper.getChildren(nodePath, false).get(
- "Error occurred retrieving child " + childIndex
- + " of node: " + nodePath, e);
- * getNodeIndex(java.lang.String)
- public int getNodeIndex(String nodePath) {
- if (index == -1
- || (!nodePath.equals("/") && nodePath.charAt(nodePath
- .length() - 1) == '/')) {
- throw new IllegalArgumentException("Invalid node path: "
- String parentPath = nodePath.substring(0, index);
- String child = nodePath.substring(index + 1);
- if (parentPath != null && parentPath.length() > 0) {
- List<String> children = this.getChildren(parentPath);
- if (children != null) {
- return children.indexOf(child);
- return -1;
- * org.apache.zookeeper.inspector.manager.ZooInspectorReadOnlyManager#getACLs
- public List<Map<String, String>> getACLs(String nodePath) {
- List<Map<String, String>> returnACLs = new ArrayList<Map<String, String>>();
- List<ACL> acls = zooKeeper.getACL(nodePath, s);
- for (ACL acl : acls) {
- Map<String, String> aclMap = new LinkedHashMap<String, String>();
- aclMap.put(ACL_SCHEME, acl.getId().getScheme());
- aclMap.put(ACL_ID, acl.getId().getId());
- int perms = acl.getPerms();
- boolean addedPerm = false;
- if ((perms & Perms.READ) == Perms.READ) {
- sb.append("Read");
- addedPerm = true;
- if (addedPerm) {
- sb.append(", ");
- if ((perms & Perms.WRITE) == Perms.WRITE) {
- sb.append("Write");
- if ((perms & Perms.CREATE) == Perms.CREATE) {
- sb.append("Create");
- if ((perms & Perms.DELETE) == Perms.DELETE) {
- sb.append("Delete");
- if ((perms & Perms.ADMIN) == Perms.ADMIN) {
- sb.append("Admin");
- aclMap.put(ACL_PERMS, sb.toString());
- returnACLs.add(aclMap);
- "Error occurred retrieving ACLs of node: " + nodePath,
- } catch (KeeperException e) {
- return returnACLs;
- * getNodeMeta(java.lang.String)
- public Map<String, String> getNodeMeta(String nodePath) {
- Map<String, String> nodeMeta = new LinkedHashMap<String, String>();
- nodeMeta.put(A_VERSION, String.valueOf(s.getAversion()));
- nodeMeta.put(C_TIME, String.valueOf(s.getCtime()));
- nodeMeta.put(C_VERSION, String.valueOf(s.getCversion()));
- nodeMeta.put(CZXID, String.valueOf(s.getCzxid()));
- nodeMeta
- .put(DATA_LENGTH, String.valueOf(s.getDataLength()));
- nodeMeta.put(EPHEMERAL_OWNER, String.valueOf(s
- .getEphemeralOwner()));
- nodeMeta.put(M_TIME, String.valueOf(s.getMtime()));
- nodeMeta.put(MZXID, String.valueOf(s.getMzxid()));
- nodeMeta.put(NUM_CHILDREN, String.valueOf(s
- .getNumChildren()));
- nodeMeta.put(PZXID, String.valueOf(s.getPzxid()));
- nodeMeta.put(VERSION, String.valueOf(s.getVersion()));
- "Error occurred retrieving meta data for node: "
- return nodeMeta;
- * getNumChildren(java.lang.String)
- public int getNumChildren(String nodePath) {
- return s.getNumChildren();
- "Error occurred getting the number of children of node: "
- * hasChildren(java.lang.String)
- public boolean hasChildren(String nodePath) {
- return getNumChildren(nodePath) > 0;
- * isAllowsChildren(java.lang.String)
- public boolean isAllowsChildren(String nodePath) {
- return s.getEphemeralOwner() == 0;
- "Error occurred determining whether node is allowed children: "
- * getSessionMeta()
- public Map<String, String> getSessionMeta() {
- Map<String, String> sessionMeta = new LinkedHashMap<String, String>();
- if (zooKeeper != null) {
- sessionMeta.put(SESSION_ID, String.valueOf(zooKeeper
- .getSessionId()));
- sessionMeta.put(SESSION_STATE, String.valueOf(zooKeeper
- .getState().toString()));
- sessionMeta.put(CONNECT_STRING, this.connectString);
- sessionMeta.put(SESSION_TIMEOUT, String
- .valueOf(this.sessionTimeout));
- "Error occurred retrieving session meta data.", e);
- return sessionMeta;
- * org.apache.zookeeper.inspector.manager.ZooInspectorNodeTreeManager#createNode
- * (java.lang.String, java.lang.String)
- public boolean createNode(String parent, String nodeName) {
- String[] nodeElements = nodeName.split("/");
- for (String nodeElement : nodeElements) {
- String node = parent + "/" + nodeElement;
- Stat s = zooKeeper.exists(node, false);
- if (s == null) {
- zooKeeper.create(node, this.encryptionManager
- .encryptData(null), Ids.OPEN_ACL_UNSAFE,
- CreateMode.PERSISTENT);
- parent = node;
- "Error occurred creating node: " + parent + "/"
- + nodeName, e);
- * org.apache.zookeeper.inspector.manager.ZooInspectorNodeTreeManager#deleteNode
- public boolean deleteNode(String nodePath) {
- List<String> children = zooKeeper.getChildren(nodePath,
- false);
- String node = nodePath + "/" + child;
- deleteNode(node);
- zooKeeper.delete(nodePath, -1);
- "Error occurred deleting node: " + nodePath, e);
- * org.apache.zookeeper.inspector.manager.ZooInspectorNodeManager#setData
- public boolean setData(String nodePath, String data) {
- zooKeeper.setData(nodePath, this.encryptionManager
- .encryptData(data), -1);
- "Error occurred setting data for node: " + nodePath, e);
- * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorManager#
- * getConnectionPropertiesTemplate()
- public Pair<Map<String, List<String>>, Map<String, String>> getConnectionPropertiesTemplate() {
- Map<String, List<String>> template = new LinkedHashMap<String, List<String>>();
- template.put(CONNECT_STRING, Arrays
- .asList(new String[] { defaultHosts }));
- template.put(SESSION_TIMEOUT, Arrays
- .asList(new String[] { defaultTimeout }));
- template.put(DATA_ENCRYPTION_MANAGER, Arrays
- .asList(new String[] { defaultEncryptionManager }));
- template.put(AUTH_SCHEME_KEY, Arrays
- .asList(new String[] { defaultAuthScheme }));
- template.put(AUTH_DATA_KEY, Arrays
- .asList(new String[] { defaultAuthValue }));
- Map<String, String> labels = new LinkedHashMap<String, String>();
- labels.put(CONNECT_STRING, "Connect String");
- labels.put(SESSION_TIMEOUT, "Session Timeout");
- labels.put(DATA_ENCRYPTION_MANAGER, "Data Encryption Manager");
- labels.put(AUTH_SCHEME_KEY, "Authentication Scheme");
- labels.put(AUTH_DATA_KEY, "Authentication Data");
- return new Pair<Map<String, List<String>>, Map<String, String>>(
- template, labels);
- * org.apache.zookeeper.inspector.manager.ZooInspectorManager#addWatchers
- * (java.util.Collection,
- * org.apache.zookeeper.inspector.manager.NodeListener)
- NodeListener nodeListener) {
- // add watcher for each node and add node to collection of
- // watched nodes
- for (String node : selectedNodes) {
- if (!watchers.containsKey(node)) {
- watchers.put(node, new NodeWatcher(node, nodeListener,
- zooKeeper));
- "Error occured adding node watcher for node: "
- + node, e);
- * org.apache.zookeeper.inspector.manager.ZooInspectorManager#removeWatchers
- * (java.util.Collection)
- public void removeWatchers(Collection<String> selectedNodes) {
- // remove watcher for each node and remove node from
- // collection of watched nodes
- if (watchers.containsKey(node)) {
- NodeWatcher watcher = watchers.remove(node);
- if (watcher != null) {
- watcher.stop();
- * A Watcher which will re-add itself every time an event is fired
- public class NodeWatcher implements Watcher {
- private final NodeListener nodeListener;
- private final ZooKeeper zookeeper;
- private boolean closed = false;
- * - the path to the node to watch
- * the {@link NodeListener} for this node
- * @param zookeeper
- * - a {@link ZooKeeper} to use to access zookeeper
- * @throws InterruptedException
- * @throws KeeperException
- public NodeWatcher(String nodePath, NodeListener nodeListener,
- ZooKeeper zookeeper) throws KeeperException,
- InterruptedException {
- this.nodeListener = nodeListener;
- this.zookeeper = zookeeper;
- Stat s = zooKeeper.exists(nodePath, this);
- zookeeper.getChildren(nodePath, this);
- if (!closed) {
- if (event.getType() != EventType.NodeDeleted) {
- "Error occured re-adding node watcherfor node "
- nodeListener.processEvent(event.getPath(), event.getType()
- .name(), null);
- public void stop() {
- this.closed = true;
- * loadNodeViewersFile(java.io.File)
- List<String> result = new ArrayList<String>();
- if (defaultNodeViewersFile.exists()) {
- FileReader reader = new FileReader(selectedFile);
- BufferedReader buff = new BufferedReader(reader);
- while (buff.ready()) {
- String line = buff.readLine();
- if (line != null && line.length() > 0 && !line.startsWith("#")) {
- result.add(line);
- buff.close();
- private void loadDefaultConnectionFile() throws IOException {
- if (defaultConnectionFile.exists()) {
- FileReader reader = new FileReader(defaultConnectionFile);
- defaultEncryptionManager = props
- .getProperty(DATA_ENCRYPTION_MANAGER) == null ? "org.apache.zookeeper.inspector.encryption.BasicDataEncryptionManager"
- : props.getProperty(DATA_ENCRYPTION_MANAGER);
- defaultTimeout = props.getProperty(SESSION_TIMEOUT) == null ? "5000"
- : props.getProperty(SESSION_TIMEOUT);
- defaultHosts = props.getProperty(CONNECT_STRING) == null ? "localhost:2181"
- : props.getProperty(CONNECT_STRING);
- defaultAuthScheme = props.getProperty(AUTH_SCHEME_KEY) == null ? ""
- : props.getProperty(AUTH_SCHEME_KEY);
- defaultAuthValue = props.getProperty(AUTH_DATA_KEY) == null ? ""
- : props.getProperty(AUTH_DATA_KEY);
- defaultEncryptionManager = "org.apache.zookeeper.inspector.encryption.BasicDataEncryptionManager";
- defaultTimeout = "5000";
- defaultHosts = "localhost:2181";
- defaultAuthScheme = "";
- defaultAuthValue = "";
- * saveDefaultConnectionFile(java.util.Properties)
- public void saveDefaultConnectionFile(Properties props) throws IOException {
- File defaultDir = defaultConnectionFile.getParentFile();
- if (!defaultDir.exists()) {
- if (!defaultDir.mkdirs()) {
- throw new IOException(
- "Failed to create configuration directory: "
- + defaultDir.getAbsolutePath());
- if (!defaultConnectionFile.exists()) {
- if (!defaultConnectionFile.createNewFile()) {
- "Failed to create default connection file: "
- + defaultConnectionFile.getAbsolutePath());
- FileWriter writer = new FileWriter(defaultConnectionFile);
- props.store(writer, "Default connection for ZooInspector");
- writer.close();
- * saveNodeViewersFile(java.io.File, java.util.List)
- List<String> nodeViewersClassNames) throws IOException {
- if (!selectedFile.exists()) {
- if (!selectedFile.createNewFile()) {
- "Failed to create node viewers configuration file: "
- + selectedFile.getAbsolutePath());
- FileWriter writer = new FileWriter(selectedFile);
- BufferedWriter buff = new BufferedWriter(writer);
- buff.append(nodeViewersClassName);
- buff.append("\n");
- buff.flush();
- * setDefaultNodeViewerConfiguration(java.io.File, java.util.List)
- File defaultDir = defaultNodeViewersFile.getParentFile();
- saveNodeViewersFile(defaultNodeViewersFile, nodeViewersClassNames);
- public List<String> getDefaultNodeViewerConfiguration() throws IOException {
- return loadNodeViewersFile(defaultNodeViewersFile);
- * getLastConnectionProps()
- public Properties getLastConnectionProps() {
- return this.lastConnectionProps;
- * setLastConnectionProps(java.util.Properties)
- public void setLastConnectionProps(Properties connectionProps) {
- this.lastConnectionProps = connectionProps;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.Watcher.Event.EventType;
+import org.apache.zookeeper.Watcher.Event.KeeperState;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.ZooDefs.Perms;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.inspector.encryption.BasicDataEncryptionManager;
+import org.apache.zookeeper.inspector.encryption.DataEncryptionManager;
+import org.apache.zookeeper.retry.ZooKeeperRetry;
+ * A default implementation of {@link ZooInspectorManager} for connecting to
+ * zookeeper instances
+public class ZooInspectorManagerImpl implements ZooInspectorManager {
+ private static final String A_VERSION = "ACL Version";
+ private static final String C_TIME = "Creation Time";
+ private static final String C_VERSION = "Children Version";
+ private static final String CZXID = "Creation ID";
+ private static final String DATA_LENGTH = "Data Length";
+ private static final String EPHEMERAL_OWNER = "Ephemeral Owner";
+ private static final String M_TIME = "Last Modified Time";
+ private static final String MZXID = "Modified ID";
+ private static final String NUM_CHILDREN = "Number of Children";
+ private static final String PZXID = "Node ID";
+ private static final String VERSION = "Data Version";
+ private static final String ACL_PERMS = "Permissions";
+ private static final String ACL_SCHEME = "Scheme";
+ private static final String ACL_ID = "Id";
+ private static final String SESSION_STATE = "Session State";
+ private static final String SESSION_ID = "Session ID";
+ * The key used for the connect string in the connection properties file
+ public static final String CONNECT_STRING = "hosts";
+ * The key used for the session timeout in the connection properties file
+ public static final String SESSION_TIMEOUT = "timeout";
+ * The key used for the data encryption manager in the connection properties
+ * file
+ public static final String DATA_ENCRYPTION_MANAGER = "encryptionManager";
+ * The key used for the authentication scheme in the connection properties file
+ public static final String AUTH_SCHEME_KEY = "authScheme";
+ * The key used for the authentication data in the connection properties file
+ public static final String AUTH_DATA_KEY = "authData";
+ private static final File defaultNodeViewersFile = new File(
+ "./config/defaultNodeViewers.cfg");
+ private static final File defaultConnectionFile = new File(
+ "./config/defaultConnectionSettings.cfg");
+ private DataEncryptionManager encryptionManager;
+ private String connectString;
+ private int sessionTimeout;
+ private ZooKeeper zooKeeper;
+ private final Map<String, NodeWatcher> watchers = new HashMap<String, NodeWatcher>();
+ protected boolean connected = true;
+ private Properties lastConnectionProps;
+ private String defaultEncryptionManager;
+ private String defaultTimeout;
+ private String defaultHosts;
+ private String defaultAuthScheme;
+ private String defaultAuthValue;
+ * - thrown if the default connection settings cannot be loaded
+ public ZooInspectorManagerImpl() throws IOException {
+ loadDefaultConnectionFile();
+ * org.apache.zookeeper.inspector.manager.ZooInspectorManager#connect(java
+ * .util.Properties)
+ public boolean connect(Properties connectionProps) {
+ if (this.zooKeeper == null) {
+ String connectString = connectionProps
+ .getProperty(CONNECT_STRING);
+ String sessionTimeout = connectionProps
+ .getProperty(SESSION_TIMEOUT);
+ String encryptionManager = connectionProps
+ .getProperty(DATA_ENCRYPTION_MANAGER);
+ String authScheme = connectionProps
+ .getProperty(AUTH_SCHEME_KEY);
+ String authData = connectionProps
+ .getProperty(AUTH_DATA_KEY);
+ if (connectString == null || sessionTimeout == null) {
+ throw new IllegalArgumentException(
+ "Both connect string and session timeout are required.");
+ if (encryptionManager == null) {
+ this.encryptionManager = new BasicDataEncryptionManager();
+ Class<?> clazz = Class.forName(encryptionManager);
+ if (Arrays.asList(clazz.getInterfaces()).contains(
+ DataEncryptionManager.class)) {
+ this.encryptionManager = (DataEncryptionManager) Class
+ .forName(encryptionManager).newInstance();
+ "Data encryption manager must implement DataEncryptionManager interface");
+ this.connectString = connectString;
+ this.sessionTimeout = Integer.valueOf(sessionTimeout);
+ this.zooKeeper = new ZooKeeperRetry(connectString, Integer
+ .valueOf(sessionTimeout), new Watcher() {
+ public void process(WatchedEvent event) {
+ if (event.getState() == KeeperState.Expired) {
+ connected = false;
+ if (authData != null && authData.length() > 0){
+ this.zooKeeper.addAuthInfo(authScheme, authData.getBytes());
+ ((ZooKeeperRetry) this.zooKeeper).setRetryLimit(10);
+ connected = ((ZooKeeperRetry) this.zooKeeper).testConnection();
+ e.printStackTrace();
+ if (!connected){
+ return connected;
+ * org.apache.zookeeper.inspector.manager.ZooInspectorManager#disconnect()
+ public boolean disconnect() {
+ if (this.zooKeeper != null) {
+ this.zooKeeper.close();
+ this.zooKeeper = null;
+ removeWatchers(this.watchers.keySet());
+ * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorReadOnlyManager#
+ * getChildren(java.lang.String)
+ public List<String> getChildren(String nodePath) {
+ if (connected) {
+ return zooKeeper.getChildren(nodePath, false);
+ "Error occurred retrieving children of node: "
+ + nodePath, e);
+ * org.apache.zookeeper.inspector.manager.ZooInspectorReadOnlyManager#getData
+ public String getData(String nodePath) {
+ if (nodePath.length() == 0) {
+ nodePath = "/";
+ Stat s = zooKeeper.exists(nodePath, false);
+ if (s != null) {
+ return this.encryptionManager.decryptData(zooKeeper
+ .getData(nodePath, false, s));
+ "Error occurred getting data for node: " + nodePath, e);
+ * getNodeChild(java.lang.String, int)
+ public String getNodeChild(String nodePath, int childIndex) {
+ return this.zooKeeper.getChildren(nodePath, false).get(
+ "Error occurred retrieving child " + childIndex
+ + " of node: " + nodePath, e);
+ * getNodeIndex(java.lang.String)
+ public int getNodeIndex(String nodePath) {
+ if (index == -1
+ || (!nodePath.equals("/") && nodePath.charAt(nodePath
+ .length() - 1) == '/')) {
+ throw new IllegalArgumentException("Invalid node path: "
+ String parentPath = nodePath.substring(0, index);
+ String child = nodePath.substring(index + 1);
+ if (parentPath != null && parentPath.length() > 0) {
+ List<String> children = this.getChildren(parentPath);
+ if (children != null) {
+ return children.indexOf(child);
+ return -1;
+ * org.apache.zookeeper.inspector.manager.ZooInspectorReadOnlyManager#getACLs
+ public List<Map<String, String>> getACLs(String nodePath) {
+ List<Map<String, String>> returnACLs = new ArrayList<Map<String, String>>();
+ List<ACL> acls = zooKeeper.getACL(nodePath, s);
+ for (ACL acl : acls) {
+ Map<String, String> aclMap = new LinkedHashMap<String, String>();
+ aclMap.put(ACL_SCHEME, acl.getId().getScheme());
+ aclMap.put(ACL_ID, acl.getId().getId());
+ int perms = acl.getPerms();
+ boolean addedPerm = false;
+ if ((perms & Perms.READ) == Perms.READ) {
+ sb.append("Read");
+ addedPerm = true;
+ if (addedPerm) {
+ sb.append(", ");
+ if ((perms & Perms.WRITE) == Perms.WRITE) {
+ sb.append("Write");
+ if ((perms & Perms.CREATE) == Perms.CREATE) {
+ sb.append("Create");
+ if ((perms & Perms.DELETE) == Perms.DELETE) {
+ sb.append("Delete");
+ if ((perms & Perms.ADMIN) == Perms.ADMIN) {
+ sb.append("Admin");
+ aclMap.put(ACL_PERMS, sb.toString());
+ returnACLs.add(aclMap);
+ "Error occurred retrieving ACLs of node: " + nodePath,
+ } catch (KeeperException e) {
+ return returnACLs;
+ * getNodeMeta(java.lang.String)
+ public Map<String, String> getNodeMeta(String nodePath) {
+ Map<String, String> nodeMeta = new LinkedHashMap<String, String>();
+ nodeMeta.put(A_VERSION, String.valueOf(s.getAversion()));
+ nodeMeta.put(C_TIME, String.valueOf(s.getCtime()));
+ nodeMeta.put(C_VERSION, String.valueOf(s.getCversion()));
+ nodeMeta.put(CZXID, String.valueOf(s.getCzxid()));
+ nodeMeta
+ .put(DATA_LENGTH, String.valueOf(s.getDataLength()));
+ nodeMeta.put(EPHEMERAL_OWNER, String.valueOf(s
+ .getEphemeralOwner()));
+ nodeMeta.put(M_TIME, String.valueOf(s.getMtime()));
+ nodeMeta.put(MZXID, String.valueOf(s.getMzxid()));
+ nodeMeta.put(NUM_CHILDREN, String.valueOf(s
+ .getNumChildren()));
+ nodeMeta.put(PZXID, String.valueOf(s.getPzxid()));
+ nodeMeta.put(VERSION, String.valueOf(s.getVersion()));
+ "Error occurred retrieving meta data for node: "
+ return nodeMeta;
+ * getNumChildren(java.lang.String)
+ public int getNumChildren(String nodePath) {
+ return s.getNumChildren();
+ "Error occurred getting the number of children of node: "
+ * hasChildren(java.lang.String)
+ public boolean hasChildren(String nodePath) {
+ return getNumChildren(nodePath) > 0;
+ * isAllowsChildren(java.lang.String)
+ public boolean isAllowsChildren(String nodePath) {
+ return s.getEphemeralOwner() == 0;
+ "Error occurred determining whether node is allowed children: "
+ * getSessionMeta()
+ public Map<String, String> getSessionMeta() {
+ Map<String, String> sessionMeta = new LinkedHashMap<String, String>();
+ if (zooKeeper != null) {
+ sessionMeta.put(SESSION_ID, String.valueOf(zooKeeper
+ .getSessionId()));
+ sessionMeta.put(SESSION_STATE, String.valueOf(zooKeeper
+ .getState().toString()));
+ sessionMeta.put(CONNECT_STRING, this.connectString);
+ sessionMeta.put(SESSION_TIMEOUT, String
+ .valueOf(this.sessionTimeout));
+ "Error occurred retrieving session meta data.", e);
+ return sessionMeta;
+ * org.apache.zookeeper.inspector.manager.ZooInspectorNodeTreeManager#createNode
+ * (java.lang.String, java.lang.String)
+ public boolean createNode(String parent, String nodeName) {
+ String[] nodeElements = nodeName.split("/");
+ for (String nodeElement : nodeElements) {
+ String node = parent + "/" + nodeElement;
+ Stat s = zooKeeper.exists(node, false);
+ if (s == null) {
+ zooKeeper.create(node, this.encryptionManager
+ .encryptData(null), Ids.OPEN_ACL_UNSAFE,
+ CreateMode.PERSISTENT);
+ parent = node;
+ "Error occurred creating node: " + parent + "/"
+ + nodeName, e);
+ * org.apache.zookeeper.inspector.manager.ZooInspectorNodeTreeManager#deleteNode
+ public boolean deleteNode(String nodePath) {
+ List<String> children = zooKeeper.getChildren(nodePath,
+ false);
+ String node = nodePath + "/" + child;
+ deleteNode(node);
+ zooKeeper.delete(nodePath, -1);
+ "Error occurred deleting node: " + nodePath, e);
+ * org.apache.zookeeper.inspector.manager.ZooInspectorNodeManager#setData
+ public boolean setData(String nodePath, String data) {
+ zooKeeper.setData(nodePath, this.encryptionManager
+ .encryptData(data), -1);
+ "Error occurred setting data for node: " + nodePath, e);
+ * @seeorg.apache.zookeeper.inspector.manager.ZooInspectorManager#
+ * getConnectionPropertiesTemplate()
+ public Pair<Map<String, List<String>>, Map<String, String>> getConnectionPropertiesTemplate() {
+ Map<String, List<String>> template = new LinkedHashMap<String, List<String>>();
+ template.put(CONNECT_STRING, Arrays
+ .asList(new String[] { defaultHosts }));
+ template.put(SESSION_TIMEOUT, Arrays
+ .asList(new String[] { defaultTimeout }));
+ template.put(DATA_ENCRYPTION_MANAGER, Arrays
+ .asList(new String[] { defaultEncryptionManager }));
+ template.put(AUTH_SCHEME_KEY, Arrays
+ .asList(new String[] { defaultAuthScheme }));
+ template.put(AUTH_DATA_KEY, Arrays
+ .asList(new String[] { defaultAuthValue }));
+ Map<String, String> labels = new LinkedHashMap<String, String>();
+ labels.put(CONNECT_STRING, "Connect String");
+ labels.put(SESSION_TIMEOUT, "Session Timeout");
+ labels.put(DATA_ENCRYPTION_MANAGER, "Data Encryption Manager");
+ labels.put(AUTH_SCHEME_KEY, "Authentication Scheme");
+ labels.put(AUTH_DATA_KEY, "Authentication Data");
+ return new Pair<Map<String, List<String>>, Map<String, String>>(
+ template, labels);
+ * org.apache.zookeeper.inspector.manager.ZooInspectorManager#addWatchers
+ * (java.util.Collection,
+ * org.apache.zookeeper.inspector.manager.NodeListener)
+ NodeListener nodeListener) {
+ // add watcher for each node and add node to collection of
+ // watched nodes
+ for (String node : selectedNodes) {
+ if (!watchers.containsKey(node)) {
+ watchers.put(node, new NodeWatcher(node, nodeListener,
+ zooKeeper));
+ "Error occured adding node watcher for node: "
+ + node, e);
+ * org.apache.zookeeper.inspector.manager.ZooInspectorManager#removeWatchers
+ * (java.util.Collection)
+ public void removeWatchers(Collection<String> selectedNodes) {
+ // remove watcher for each node and remove node from
+ // collection of watched nodes
+ if (watchers.containsKey(node)) {
+ NodeWatcher watcher = watchers.remove(node);
+ if (watcher != null) {
+ watcher.stop();
+ * A Watcher which will re-add itself every time an event is fired
+ public class NodeWatcher implements Watcher {
+ private final NodeListener nodeListener;
+ private final ZooKeeper zookeeper;
+ private boolean closed = false;
+ * - the path to the node to watch
+ * the {@link NodeListener} for this node
+ * @param zookeeper
+ * - a {@link ZooKeeper} to use to access zookeeper
+ * @throws InterruptedException
+ * @throws KeeperException
+ public NodeWatcher(String nodePath, NodeListener nodeListener,
+ ZooKeeper zookeeper) throws KeeperException,
+ InterruptedException {
+ this.nodeListener = nodeListener;
+ this.zookeeper = zookeeper;
+ Stat s = zooKeeper.exists(nodePath, this);
+ zookeeper.getChildren(nodePath, this);
+ if (!closed) {
+ if (event.getType() != EventType.NodeDeleted) {
+ "Error occured re-adding node watcherfor node "
+ nodeListener.processEvent(event.getPath(), event.getType()
+ .name(), null);
+ public void stop() {
+ this.closed = true;
+ * loadNodeViewersFile(java.io.File)
+ List<String> result = new ArrayList<String>();
+ if (defaultNodeViewersFile.exists()) {
+ FileReader reader = new FileReader(selectedFile);
+ BufferedReader buff = new BufferedReader(reader);
+ while (buff.ready()) {
+ String line = buff.readLine();
+ if (line != null && line.length() > 0 && !line.startsWith("#")) {
+ result.add(line);
+ buff.close();
+ private void loadDefaultConnectionFile() throws IOException {
+ if (defaultConnectionFile.exists()) {
+ FileReader reader = new FileReader(defaultConnectionFile);
+ defaultEncryptionManager = props
+ .getProperty(DATA_ENCRYPTION_MANAGER) == null ? "org.apache.zookeeper.inspector.encryption.BasicDataEncryptionManager"
+ : props.getProperty(DATA_ENCRYPTION_MANAGER);
+ defaultTimeout = props.getProperty(SESSION_TIMEOUT) == null ? "5000"
+ : props.getProperty(SESSION_TIMEOUT);
+ defaultHosts = props.getProperty(CONNECT_STRING) == null ? "localhost:2181"
+ : props.getProperty(CONNECT_STRING);
+ defaultAuthScheme = props.getProperty(AUTH_SCHEME_KEY) == null ? ""
+ : props.getProperty(AUTH_SCHEME_KEY);
+ defaultAuthValue = props.getProperty(AUTH_DATA_KEY) == null ? ""
+ : props.getProperty(AUTH_DATA_KEY);
+ defaultEncryptionManager = "org.apache.zookeeper.inspector.encryption.BasicDataEncryptionManager";
+ defaultTimeout = "5000";
+ defaultHosts = "localhost:2181";
+ defaultAuthScheme = "";
+ defaultAuthValue = "";
+ * saveDefaultConnectionFile(java.util.Properties)
+ public void saveDefaultConnectionFile(Properties props) throws IOException {
+ File defaultDir = defaultConnectionFile.getParentFile();
+ if (!defaultDir.exists()) {
+ if (!defaultDir.mkdirs()) {
+ throw new IOException(
+ "Failed to create configuration directory: "
+ + defaultDir.getAbsolutePath());
+ if (!defaultConnectionFile.exists()) {
+ if (!defaultConnectionFile.createNewFile()) {
+ "Failed to create default connection file: "
+ + defaultConnectionFile.getAbsolutePath());
+ FileWriter writer = new FileWriter(defaultConnectionFile);
+ props.store(writer, "Default connection for ZooInspector");
+ writer.close();
+ * saveNodeViewersFile(java.io.File, java.util.List)
+ List<String> nodeViewersClassNames) throws IOException {
+ if (!selectedFile.exists()) {
+ if (!selectedFile.createNewFile()) {
+ "Failed to create node viewers configuration file: "
+ + selectedFile.getAbsolutePath());
+ FileWriter writer = new FileWriter(selectedFile);
+ BufferedWriter buff = new BufferedWriter(writer);
+ buff.append(nodeViewersClassName);
+ buff.append("\n");
+ buff.flush();
+ * setDefaultNodeViewerConfiguration(java.io.File, java.util.List)
+ File defaultDir = defaultNodeViewersFile.getParentFile();
+ saveNodeViewersFile(defaultNodeViewersFile, nodeViewersClassNames);
+ public List<String> getDefaultNodeViewerConfiguration() throws IOException {
+ return loadNodeViewersFile(defaultNodeViewersFile);
+ * getLastConnectionProps()
+ public Properties getLastConnectionProps() {
+ return this.lastConnectionProps;
+ * setLastConnectionProps(java.util.Properties)
+ public void setLastConnectionProps(Properties connectionProps) {
+ this.lastConnectionProps = connectionProps;
@@ -1,33 +1,33 @@
- * A Manager for all interactions between the application and the nodes in a
- * Zookeeper instance
- * */
-public interface ZooInspectorNodeManager extends ZooInspectorReadOnlyManager {
- * - the path to the node on which to set the data
- * - the data to set on the this node
- * @return true if the data for the node was successfully updated
- public boolean setData(String nodePath, String data);
+ * A Manager for all interactions between the application and the nodes in a
+ * Zookeeper instance
+ * */
+public interface ZooInspectorNodeManager extends ZooInspectorReadOnlyManager {
+ * - the path to the node on which to set the data
+ * - the data to set on the this node
+ * @return true if the data for the node was successfully updated
+ public boolean setData(String nodePath, String data);
@@ -1,288 +1,288 @@
-package org.apache.zookeeper.retry;
- * A Class which extends {@link ZooKeeper} and will automatically retry calls to
- * zookeeper if a {@link KeeperException.ConnectionLossException} occurs
-public class ZooKeeperRetry extends ZooKeeper {
- private final Watcher watcher;
- private int limit = -1;
- * @param connectString
- * @param sessionTimeout
- * @param watcher
- public ZooKeeperRetry(String connectString, int sessionTimeout,
- Watcher watcher) throws IOException {
- super(connectString, sessionTimeout, watcher);
- this.watcher = watcher;
- * @param sessionId
- * @param sessionPasswd
- Watcher watcher, long sessionId, byte[] sessionPasswd)
- super(connectString, sessionTimeout, watcher, sessionId, sessionPasswd);
- public synchronized void close() throws InterruptedException {
- super.close();
- public String create(String path, byte[] data, List<ACL> acl,
- CreateMode createMode) throws KeeperException, InterruptedException {
- int count = 0;
- do {
- return super.create(path, data, acl, createMode);
- } catch (KeeperException.ConnectionLossException e) {
- LoggerFactory.getLogger().warn(
- "ZooKeeper connection lost. Trying to reconnect.");
- if (exists(path, false) != null) {
- return path;
- } catch (KeeperException.NodeExistsException e) {
- } while (!closed && (limit == -1 || count++ < limit));
- public void delete(String path, int version) throws InterruptedException,
- KeeperException {
- super.delete(path, version);
- if (exists(path, false) == null) {
- return;
- } catch (KeeperException.NoNodeException e) {
- break;
- public Stat exists(String path, boolean watch) throws KeeperException,
- return super.exists(path, watch ? watcher : null);
- public Stat exists(String path, Watcher watcher) throws KeeperException,
- return super.exists(path, watcher);
- public List<ACL> getACL(String path, Stat stat) throws KeeperException,
- return super.getACL(path, stat);
- public List<String> getChildren(String path, boolean watch)
- throws KeeperException, InterruptedException {
- return super.getChildren(path, watch ? watcher : null);
- return new ArrayList<String>();
- public List<String> getChildren(String path, Watcher watcher)
- return super.getChildren(path, watcher);
- public byte[] getData(String path, boolean watch, Stat stat)
- return super.getData(path, watch ? watcher : null, stat);
- public byte[] getData(String path, Watcher watcher, Stat stat)
- return super.getData(path, watcher, stat);
- public Stat setACL(String path, List<ACL> acl, int version)
- return super.setACL(path, acl, version);
- Stat s = exists(path, false);
- if (getACL(path, s).equals(acl)) {
- return s;
- public Stat setData(String path, byte[] data, int version)
- return super.setData(path, data, version);
- if (getData(path, false, s) == data) {
- * @param limit
- public void setRetryLimit(int limit) {
- this.limit = limit;
- * @return true if successfully connected to zookeeper
- public boolean testConnection() {
- return super.exists("/", null) != null;
- } while (count++ < 5);
+package org.apache.zookeeper.retry;
+ * A Class which extends {@link ZooKeeper} and will automatically retry calls to
+ * zookeeper if a {@link KeeperException.ConnectionLossException} occurs
+public class ZooKeeperRetry extends ZooKeeper {
+ private final Watcher watcher;
+ private int limit = -1;
+ * @param connectString
+ * @param sessionTimeout
+ * @param watcher
+ public ZooKeeperRetry(String connectString, int sessionTimeout,
+ Watcher watcher) throws IOException {
+ super(connectString, sessionTimeout, watcher);
+ this.watcher = watcher;
+ * @param sessionId
+ * @param sessionPasswd
+ Watcher watcher, long sessionId, byte[] sessionPasswd)
+ super(connectString, sessionTimeout, watcher, sessionId, sessionPasswd);
+ public synchronized void close() throws InterruptedException {
+ super.close();
+ public String create(String path, byte[] data, List<ACL> acl,
+ CreateMode createMode) throws KeeperException, InterruptedException {
+ int count = 0;
+ do {
+ return super.create(path, data, acl, createMode);
+ } catch (KeeperException.ConnectionLossException e) {
+ LoggerFactory.getLogger().warn(
+ "ZooKeeper connection lost. Trying to reconnect.");
+ if (exists(path, false) != null) {
+ return path;
+ } catch (KeeperException.NodeExistsException e) {
+ } while (!closed && (limit == -1 || count++ < limit));
+ public void delete(String path, int version) throws InterruptedException,
+ KeeperException {
+ super.delete(path, version);
+ if (exists(path, false) == null) {
+ return;
+ } catch (KeeperException.NoNodeException e) {
+ break;
+ public Stat exists(String path, boolean watch) throws KeeperException,
+ return super.exists(path, watch ? watcher : null);
+ public Stat exists(String path, Watcher watcher) throws KeeperException,
+ return super.exists(path, watcher);
+ public List<ACL> getACL(String path, Stat stat) throws KeeperException,
+ return super.getACL(path, stat);
+ public List<String> getChildren(String path, boolean watch)
+ throws KeeperException, InterruptedException {
+ return super.getChildren(path, watch ? watcher : null);
+ return new ArrayList<String>();
+ public List<String> getChildren(String path, Watcher watcher)
+ return super.getChildren(path, watcher);
+ public byte[] getData(String path, boolean watch, Stat stat)
+ return super.getData(path, watch ? watcher : null, stat);
+ public byte[] getData(String path, Watcher watcher, Stat stat)
+ return super.getData(path, watcher, stat);
+ public Stat setACL(String path, List<ACL> acl, int version)
+ return super.setACL(path, acl, version);
+ Stat s = exists(path, false);
+ if (getACL(path, s).equals(acl)) {
+ return s;
+ public Stat setData(String path, byte[] data, int version)
+ return super.setData(path, data, version);
+ if (getData(path, false, s) == data) {
+ * @param limit
+ public void setRetryLimit(int limit) {
+ this.limit = limit;
+ * @return true if successfully connected to zookeeper
+ public boolean testConnection() {
+ return super.exists("/", null) != null;
+ } while (count++ < 5);
@@ -1,18 +1,18 @@
-#!/bin/sh
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-# http://www.apache.org/licenses/LICENSE-2.0
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-java -cp "zookeeper-dev-ZooInspector.jar;lib\*;lib" org.apache.zookeeper.inspector.ZooInspector
+#!/bin/sh
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+java -cp "zookeeper-dev-ZooInspector.jar;lib\*;lib" org.apache.zookeeper.inspector.ZooInspector
@@ -1,128 +1,128 @@
-package org.apache.zookeeper.server;
-import java.io.BufferedInputStream;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.util.Date;
-import java.util.zip.Adler32;
-import java.util.zip.CheckedInputStream;
-import org.apache.jute.BinaryInputArchive;
-import org.apache.jute.InputArchive;
-import org.apache.zookeeper.data.StatPersisted;
-import org.apache.zookeeper.server.persistence.FileSnap;
- * Dump a snapshot file to stdout.
-public class SnapshotFormatter {
- * USAGE: SnapshotFormatter snapshot_file
- public static void main(String[] args) throws Exception {
- if (args.length != 1) {
- System.err.println("USAGE: SnapshotFormatter snapshot_file");
- System.exit(2);
- new SnapshotFormatter().run(args[0]);
- public void run(String snapshotFileName) throws IOException {
- InputStream is = new CheckedInputStream(
- new BufferedInputStream(new FileInputStream(snapshotFileName)),
- new Adler32());
- InputArchive ia = BinaryInputArchive.getArchive(is);
- FileSnap fileSnap = new FileSnap(null);
- DataTree dataTree = new DataTree();
- Map<Long, Integer> sessions = new HashMap<Long, Integer>();
- fileSnap.deserialize(dataTree, sessions, ia);
- printDetails(dataTree, sessions);
- private void printDetails(DataTree dataTree, Map<Long, Integer> sessions) {
- printZnodeDetails(dataTree);
- printSessionDetails(dataTree, sessions);
- private void printZnodeDetails(DataTree dataTree) {
- System.out.println(String.format("ZNode Details (count=%d):",
- dataTree.getNodeCount()));
- printZnode(dataTree, "/");
- System.out.println("----");
- private void printZnode(DataTree dataTree, String name) {
- DataNode n = dataTree.getNode(name);
- Set<String> children;
- synchronized(n) { // keep findbugs happy
- System.out.println(name);
- printStat(n.stat);
- if (n.data != null) {
- System.out.println(" dataLength = " + n.data.length);
- System.out.println(" no data");
- children = n.getChildren();
- printZnode(dataTree, name + (name.equals("/") ? "" : "/") + child);
- private void printSessionDetails(DataTree dataTree, Map<Long, Integer> sessions) {
- System.out.println("Session Details (sid, timeout, ephemeralCount):");
- for (Map.Entry<Long, Integer> e : sessions.entrySet()) {
- long sid = e.getKey();
- System.out.println(String.format("%#016x, %d, %d",
- sid, e.getValue(), dataTree.getEphemerals(sid).size()));
- private void printStat(StatPersisted stat) {
- printHex("cZxid", stat.getCzxid());
- System.out.println(" ctime = " + new Date(stat.getCtime()).toString());
- printHex("mZxid", stat.getMzxid());
- System.out.println(" mtime = " + new Date(stat.getMtime()).toString());
- printHex("pZxid", stat.getPzxid());
- System.out.println(" cversion = " + stat.getCversion());
- System.out.println(" dataVersion = " + stat.getVersion());
- System.out.println(" aclVersion = " + stat.getAversion());
- printHex("ephemeralOwner", stat.getEphemeralOwner());
- private void printHex(String prefix, long value) {
- System.out.println(String.format(" %s = %#016x", prefix, value));
+package org.apache.zookeeper.server;
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.Date;
+import java.util.zip.Adler32;
+import java.util.zip.CheckedInputStream;
+import org.apache.jute.BinaryInputArchive;
+import org.apache.jute.InputArchive;
+import org.apache.zookeeper.data.StatPersisted;
+import org.apache.zookeeper.server.persistence.FileSnap;
+ * Dump a snapshot file to stdout.
+public class SnapshotFormatter {
+ * USAGE: SnapshotFormatter snapshot_file
+ public static void main(String[] args) throws Exception {
+ if (args.length != 1) {
+ System.err.println("USAGE: SnapshotFormatter snapshot_file");
+ System.exit(2);
+ new SnapshotFormatter().run(args[0]);
+ public void run(String snapshotFileName) throws IOException {
+ InputStream is = new CheckedInputStream(
+ new BufferedInputStream(new FileInputStream(snapshotFileName)),
+ new Adler32());
+ InputArchive ia = BinaryInputArchive.getArchive(is);
+ FileSnap fileSnap = new FileSnap(null);
+ DataTree dataTree = new DataTree();
+ Map<Long, Integer> sessions = new HashMap<Long, Integer>();
+ fileSnap.deserialize(dataTree, sessions, ia);
+ printDetails(dataTree, sessions);
+ private void printDetails(DataTree dataTree, Map<Long, Integer> sessions) {
+ printZnodeDetails(dataTree);
+ printSessionDetails(dataTree, sessions);
+ private void printZnodeDetails(DataTree dataTree) {
+ System.out.println(String.format("ZNode Details (count=%d):",
+ dataTree.getNodeCount()));
+ printZnode(dataTree, "/");
+ System.out.println("----");
+ private void printZnode(DataTree dataTree, String name) {
+ DataNode n = dataTree.getNode(name);
+ Set<String> children;
+ synchronized(n) { // keep findbugs happy
+ System.out.println(name);
+ printStat(n.stat);
+ if (n.data != null) {
+ System.out.println(" dataLength = " + n.data.length);
+ System.out.println(" no data");
+ children = n.getChildren();
+ printZnode(dataTree, name + (name.equals("/") ? "" : "/") + child);
+ private void printSessionDetails(DataTree dataTree, Map<Long, Integer> sessions) {
+ System.out.println("Session Details (sid, timeout, ephemeralCount):");
+ for (Map.Entry<Long, Integer> e : sessions.entrySet()) {
+ long sid = e.getKey();
+ System.out.println(String.format("%#016x, %d, %d",
+ sid, e.getValue(), dataTree.getEphemerals(sid).size()));
+ private void printStat(StatPersisted stat) {
+ printHex("cZxid", stat.getCzxid());
+ System.out.println(" ctime = " + new Date(stat.getCtime()).toString());
+ printHex("mZxid", stat.getMzxid());
+ System.out.println(" mtime = " + new Date(stat.getMtime()).toString());
+ printHex("pZxid", stat.getPzxid());
+ System.out.println(" cversion = " + stat.getCversion());
+ System.out.println(" dataVersion = " + stat.getVersion());
+ System.out.println(" aclVersion = " + stat.getAversion());
+ printHex("ephemeralOwner", stat.getEphemeralOwner());
+ private void printHex(String prefix, long value) {
+ System.out.println(String.format(" %s = %#016x", prefix, value));
@@ -1,149 +1,149 @@
-import static org.junit.Assert.*;
-import java.io.PrintWriter;
-import java.nio.ByteBuffer;
-import java.util.concurrent.CountDownLatch;
-import org.apache.zookeeper.PortAssignment;
-import org.apache.zookeeper.KeeperException.Code;
-import org.apache.zookeeper.KeeperException.SessionExpiredException;
-import org.apache.zookeeper.KeeperException.SessionMovedException;
-import org.apache.zookeeper.ZooDefs.OpCode;
-import org.apache.zookeeper.server.PrepRequestProcessor;
-import org.apache.zookeeper.server.Request;
-import org.apache.zookeeper.server.RequestProcessor;
-import org.apache.zookeeper.server.ServerCnxnFactory;
-import org.apache.zookeeper.server.SyncRequestProcessor;
-import org.apache.zookeeper.server.ZooKeeperServer;
-import org.apache.zookeeper.test.ClientBase;
-import org.apache.zookeeper.txn.ErrorTxn;
-import org.junit.Assert;
-import org.junit.Test;
-public class PrepRequestProcessorTest extends ClientBase {
- private static String HOSTPORT = "127.0.0.1:" + PortAssignment.unique();
- private static final int CONNECTION_TIMEOUT = 3000;
- private final CountDownLatch testEnd = new CountDownLatch(1);
- @Test
- public void testPRequest() throws Exception {
- File tmpDir = ClientBase.createTmpDir();
- ClientBase.setupTestEnv();
- ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);
- SyncRequestProcessor.setSnapCount(100);
- final int PORT = Integer.parseInt(HOSTPORT.split(":")[1]);
- ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);
- f.startup(zks);
- Assert.assertTrue("waiting for server being up ",
- ClientBase.waitForServerUp(HOSTPORT,CONNECTION_TIMEOUT));
- zks.sessionTracker = new MySessionTracker();
- PrepRequestProcessor processor = new PrepRequestProcessor(zks, new MyRequestProcessor());
- Request foo = new Request(null, 1l, 1, OpCode.create, ByteBuffer.allocate(3), null);
- processor.pRequest(foo);
- testEnd.await(5, java.util.concurrent.TimeUnit.SECONDS);
- f.shutdown();
- zks.shutdown();
- private class MyRequestProcessor implements RequestProcessor {
- public void processRequest(Request request) {
- Assert.assertEquals("Request should have marshalling error", new ErrorTxn(Code.MARSHALLINGERROR.intValue()), request.getTxn());
- testEnd.countDown();
- public void shutdown() {
- // TODO Auto-generated method stub
- private class MySessionTracker implements SessionTracker {
- public boolean addGlobalSession(long id, int to) {
- public boolean addSession(long id, int to) {
- public void checkSession(long sessionId, Object owner)
- throws SessionExpiredException, SessionMovedException {
- public long createSession(int sessionTimeout) {
- return 0;
- public void dumpSessions(PrintWriter pwriter) {
- public void removeSession(long sessionId) {
- public int upgradeSession(long sessionId) {
- public void setOwner(long id, Object owner)
- throws SessionExpiredException {
- public boolean touchSession(long sessionId, int sessionTimeout) {
- public void setSessionClosing(long sessionId) {
- public boolean isTrackingSession(long sessionId) {
- public void checkGlobalSession(long sessionId, Object owner)
+import static org.junit.Assert.*;
+import java.io.PrintWriter;
+import java.nio.ByteBuffer;
+import java.util.concurrent.CountDownLatch;
+import org.apache.zookeeper.PortAssignment;
+import org.apache.zookeeper.KeeperException.Code;
+import org.apache.zookeeper.KeeperException.SessionExpiredException;
+import org.apache.zookeeper.KeeperException.SessionMovedException;
+import org.apache.zookeeper.ZooDefs.OpCode;
+import org.apache.zookeeper.server.PrepRequestProcessor;
+import org.apache.zookeeper.server.Request;
+import org.apache.zookeeper.server.RequestProcessor;
+import org.apache.zookeeper.server.ServerCnxnFactory;
+import org.apache.zookeeper.server.SyncRequestProcessor;
+import org.apache.zookeeper.server.ZooKeeperServer;
+import org.apache.zookeeper.test.ClientBase;
+import org.apache.zookeeper.txn.ErrorTxn;
+import org.junit.Assert;
+import org.junit.Test;
+public class PrepRequestProcessorTest extends ClientBase {
+ private static String HOSTPORT = "127.0.0.1:" + PortAssignment.unique();
+ private static final int CONNECTION_TIMEOUT = 3000;
+ private final CountDownLatch testEnd = new CountDownLatch(1);
+ @Test
+ public void testPRequest() throws Exception {
+ File tmpDir = ClientBase.createTmpDir();
+ ClientBase.setupTestEnv();
+ ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);
+ SyncRequestProcessor.setSnapCount(100);
+ final int PORT = Integer.parseInt(HOSTPORT.split(":")[1]);
+ ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);
+ f.startup(zks);
+ Assert.assertTrue("waiting for server being up ",
+ ClientBase.waitForServerUp(HOSTPORT,CONNECTION_TIMEOUT));
+ zks.sessionTracker = new MySessionTracker();
+ PrepRequestProcessor processor = new PrepRequestProcessor(zks, new MyRequestProcessor());
+ Request foo = new Request(null, 1l, 1, OpCode.create, ByteBuffer.allocate(3), null);
+ processor.pRequest(foo);
+ testEnd.await(5, java.util.concurrent.TimeUnit.SECONDS);
+ f.shutdown();
+ zks.shutdown();
+ private class MyRequestProcessor implements RequestProcessor {
+ public void processRequest(Request request) {
+ Assert.assertEquals("Request should have marshalling error", new ErrorTxn(Code.MARSHALLINGERROR.intValue()), request.getTxn());
+ testEnd.countDown();
+ public void shutdown() {
+ // TODO Auto-generated method stub
+ private class MySessionTracker implements SessionTracker {
+ public boolean addGlobalSession(long id, int to) {
+ public boolean addSession(long id, int to) {
+ public void checkSession(long sessionId, Object owner)
+ throws SessionExpiredException, SessionMovedException {
+ public long createSession(int sessionTimeout) {
+ return 0;
+ public void dumpSessions(PrintWriter pwriter) {
+ public void removeSession(long sessionId) {
+ public int upgradeSession(long sessionId) {
+ public void setOwner(long id, Object owner)
+ throws SessionExpiredException {
+ public boolean touchSession(long sessionId, int sessionTimeout) {
+ public void setSessionClosing(long sessionId) {
+ public boolean isTrackingSession(long sessionId) {
+ public void checkGlobalSession(long sessionId, Object owner)
@@ -1,107 +1,107 @@
-package org.apache.zookeeper.test;
-import java.net.InetSocketAddress;
-import org.apache.zookeeper.server.quorum.FastLeaderElection;
-import org.apache.zookeeper.server.quorum.QuorumCnxManager;
-import org.apache.zookeeper.server.quorum.QuorumPeer;
-import org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;
-import org.apache.zookeeper.ZKTestCase;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-public class FLEPredicateTest extends ZKTestCase {
- protected static final Logger LOG = LoggerFactory.getLogger(FLEPredicateTest.class);
- class MockFLE extends FastLeaderElection {
- MockFLE(QuorumPeer peer){
- super(peer, new QuorumCnxManager(peer));
- boolean predicate(long newId, long newZxid, long newEpoch, long curId, long curZxid, long curEpoch){
- return this.totalOrderPredicate(newId, newZxid, newEpoch, curId, curZxid, curEpoch);
- HashMap<Long,QuorumServer> peers;
- public void testPredicate() throws IOException {
- peers = new HashMap<Long,QuorumServer>(3);
- * Creates list of peers.
- for(int i = 0; i < 3; i++) {
- peers.put(Long.valueOf(i),
- new QuorumServer(i,
- new InetSocketAddress(
- "127.0.0.1", PortAssignment.unique()),
- "127.0.0.1", PortAssignment.unique())));
- * Creating peer.
- try{
- QuorumPeer peer = new QuorumPeer(peers, tmpDir, tmpDir,
- PortAssignment.unique(), 3, 0, 1000, 2, 2);
- MockFLE mock = new MockFLE(peer);
- * Lower epoch must return false
- Assert.assertFalse (mock.predicate(4L, 0L, 0L, 3L, 0L, 2L));
- * Later epoch
- Assert.assertTrue (mock.predicate(0L, 0L, 1L, 1L, 0L, 0L));
- * Higher zxid
- Assert.assertTrue(mock.predicate(0L, 1L, 0L, 1L, 0L, 0L));
- * Higher id
- Assert.assertTrue(mock.predicate(1L, 1L, 0L, 0L, 1L, 0L));
- LOG.error("Exception while creating quorum peer", e);
- Assert.fail("Exception while creating quorum peer");
+package org.apache.zookeeper.test;
+import java.net.InetSocketAddress;
+import org.apache.zookeeper.server.quorum.FastLeaderElection;
+import org.apache.zookeeper.server.quorum.QuorumCnxManager;
+import org.apache.zookeeper.server.quorum.QuorumPeer;
+import org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;
+import org.apache.zookeeper.ZKTestCase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+public class FLEPredicateTest extends ZKTestCase {
+ protected static final Logger LOG = LoggerFactory.getLogger(FLEPredicateTest.class);
+ class MockFLE extends FastLeaderElection {
+ MockFLE(QuorumPeer peer){
+ super(peer, new QuorumCnxManager(peer));
+ boolean predicate(long newId, long newZxid, long newEpoch, long curId, long curZxid, long curEpoch){
+ return this.totalOrderPredicate(newId, newZxid, newEpoch, curId, curZxid, curEpoch);
+ HashMap<Long,QuorumServer> peers;
+ public void testPredicate() throws IOException {
+ peers = new HashMap<Long,QuorumServer>(3);
+ * Creates list of peers.
+ for(int i = 0; i < 3; i++) {
+ peers.put(Long.valueOf(i),
+ new QuorumServer(i,
+ new InetSocketAddress(
+ "127.0.0.1", PortAssignment.unique()),
+ "127.0.0.1", PortAssignment.unique())));
+ * Creating peer.
+ try{
+ QuorumPeer peer = new QuorumPeer(peers, tmpDir, tmpDir,
+ PortAssignment.unique(), 3, 0, 1000, 2, 2);
+ MockFLE mock = new MockFLE(peer);
+ * Lower epoch must return false
+ Assert.assertFalse (mock.predicate(4L, 0L, 0L, 3L, 0L, 2L));
+ * Later epoch
+ Assert.assertTrue (mock.predicate(0L, 0L, 1L, 1L, 0L, 0L));
+ * Higher zxid
+ Assert.assertTrue(mock.predicate(0L, 1L, 0L, 1L, 0L, 0L));
+ * Higher id
+ Assert.assertTrue(mock.predicate(1L, 1L, 0L, 0L, 1L, 0L));
+ LOG.error("Exception while creating quorum peer", e);
+ Assert.fail("Exception while creating quorum peer");
@@ -1,736 +1,736 @@
-import java.util.LinkedList;
-import org.apache.zookeeper.ZooDefs;
-import org.apache.zookeeper.AsyncCallback.DataCallback;
-import org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;
-import org.apache.zookeeper.server.quorum.flexible.QuorumHierarchical;
-import org.apache.zookeeper.server.quorum.flexible.QuorumMaj;
-import org.apache.zookeeper.server.quorum.flexible.QuorumVerifier;
-import org.junit.After;
-public class ReconfigTest extends ZKTestCase implements DataCallback{
- private static final Logger LOG = LoggerFactory
- .getLogger(ReconfigTest.class);
- private QuorumUtil qu;
- @After
- public void tearDown() throws Exception {
- if (qu != null) {
- qu.tearDown();
- public static String reconfig(ZooKeeper zk, List<String> joiningServers,
- List<String> leavingServers, List<String> newMembers, long fromConfig)
- byte[] config = null;
- for (int j = 0; j < 30; j++) {
- config = zk.reconfig(joiningServers, leavingServers,
- newMembers, fromConfig, new Stat());
- if (j < 29) {
- Thread.sleep(1000);
- // test fails if we still can't connect to the quorum after
- // 30 seconds.
- Assert.fail("client could not connect to reestablished quorum: giving up after 30+ seconds.");
- String configStr = new String(config);
- if (joiningServers != null) {
- for (String joiner : joiningServers)
- Assert.assertTrue(configStr.contains(joiner));
- if (leavingServers != null) {
- for (String leaving : leavingServers)
- Assert.assertFalse(configStr.contains("server.".concat(leaving)));
- return configStr;
- public static String testServerHasConfig(ZooKeeper zk,
- List<String> joiningServers, List<String> leavingServers)
- zk.sync("/", null, null);
- config = zk.getConfig(false, new Stat());
- for (String joiner : joiningServers) {
- public static void testNormalOperation(ZooKeeper writer, ZooKeeper reader)
- boolean testNodeExists = false;
- if (!testNodeExists) {
- writer.create("/test", "test".getBytes(),
- ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
- testNodeExists = true;
- String data = "test" + j;
- writer.setData("/test", data.getBytes(), -1);
- reader.sync("/", null, null);
- byte[] res = reader.getData("/test", null, new Stat());
- Assert.assertEquals(data, new String(res));
- private int getLeaderId(QuorumUtil qu) {
- int leaderId = 1;
- while (qu.getPeer(leaderId).peer.leader == null)
- leaderId++;
- return leaderId;
- private ZooKeeper[] createHandles(QuorumUtil qu) throws IOException {
- // create an extra handle, so we can index the handles from 1 to qu.ALL
- // using the server id.
- ZooKeeper[] zkArr = new ZooKeeper[qu.ALL + 1];
- zkArr[0] = null; // not used.
- for (int i = 1; i <= qu.ALL; i++) {
- // server ids are 1, 2 and 3
- zkArr[i] = new ZooKeeper("127.0.0.1:"
- + qu.getPeer(i).peer.getClientPort(),
- ClientBase.CONNECTION_TIMEOUT, new Watcher() {
- }});
- return zkArr;
- private void closeAllHandles(ZooKeeper[] zkArr) throws InterruptedException {
- for (ZooKeeper zk : zkArr)
- if (zk != null)
- zk.close();
- public void testRemoveAddOne() throws Exception {
- qu = new QuorumUtil(1); // create 3 servers
- qu.disableJMXTest = true;
- qu.startAll();
- ZooKeeper[] zkArr = createHandles(qu);
- List<String> leavingServers = new ArrayList<String>();
- List<String> joiningServers = new ArrayList<String>();
- int leaderIndex = getLeaderId(qu);
- // during first iteration, leavingIndex will correspond to a follower
- // during second iteration leavingIndex will be the index of the leader
- int leavingIndex = (leaderIndex == 1) ? 2 : 1;
- for (int i = 0; i < 2; i++) {
- // some of the operations will be executed by a client connected to
- // the removed server
- // while others are invoked by a client connected to some other
- // server.
- // when we're removing the leader, zk1 will be the client connected
- // to removed server
- ZooKeeper zk1 = (leavingIndex == leaderIndex) ? zkArr[leaderIndex]
- : zkArr[(leaderIndex % qu.ALL) + 1];
- ZooKeeper zk2 = (leavingIndex == leaderIndex) ? zkArr[(leaderIndex % qu.ALL) + 1]
- : zkArr[leaderIndex];
- leavingServers.add(Integer.toString(leavingIndex));
- // remember this server so we can add it back later
- joiningServers.add("server."
- + leavingIndex
- + "=localhost:"
- + qu.getPeer(leavingIndex).peer.getQuorumAddress()
- .getPort()
- + ":"
- + qu.getPeer(leavingIndex).peer.getElectionAddress()
- .getPort() + ":participant;localhost:"
- + qu.getPeer(leavingIndex).peer.getClientPort());
- String configStr = reconfig(zk1, null, leavingServers, null, -1);
- testServerHasConfig(zk2, null, leavingServers);
- testNormalOperation(zk2, zk1);
- QuorumVerifier qv = qu.getPeer(1).peer.configFromString(configStr);
- long version = qv.getVersion();
- // checks that conditioning on version works properly
- reconfig(zk2, joiningServers, null, null, version + 1);
- Assert.fail("reconfig succeeded even though version condition was incorrect!");
- } catch (KeeperException.BadVersionException e) {
- reconfig(zk2, joiningServers, null, null, version);
- testNormalOperation(zk1, zk2);
- testServerHasConfig(zk1, joiningServers, null);
- // second iteration of the loop will remove the leader
- // and add it back (as follower)
- leavingIndex = leaderIndex = getLeaderId(qu);
- leavingServers.clear();
- joiningServers.clear();
- closeAllHandles(zkArr);
- * 1. removes and adds back two servers (incl leader). One of the servers is added back as observer
- * 2. tests that reconfig fails if quorum of new config is not up
- * 3. tests that a server that's not up during reconfig learns the new config when it comes up
- public void testRemoveAddTwo() throws Exception {
- qu = new QuorumUtil(2); // create 5 servers
- // lets remove the leader and some other server
- int leavingIndex1 = leaderIndex;
- int leavingIndex2 = (leaderIndex == 1) ? 2 : 1;
- // find some server that's staying
- int stayingIndex1 = 1, stayingIndex2 = 1, stayingIndex3 = 1;
- while (stayingIndex1 == leavingIndex1 || stayingIndex1 == leavingIndex2)
- stayingIndex1++;
- while (stayingIndex2 == leavingIndex1 || stayingIndex2 == leavingIndex2
- || stayingIndex2 == stayingIndex1)
- stayingIndex2++;
- while (stayingIndex3 == leavingIndex1 || stayingIndex3 == leavingIndex2
- || stayingIndex3 == stayingIndex1
- || stayingIndex3 == stayingIndex2)
- stayingIndex3++;
- leavingServers.add(Integer.toString(leavingIndex1));
- leavingServers.add(Integer.toString(leavingIndex2));
- // remember these servers so we can add them back later
- joiningServers.add("server." + leavingIndex1 + "=localhost:"
- + qu.getPeer(leavingIndex1).peer.getQuorumAddress().getPort()
- + qu.getPeer(leavingIndex1).peer.getElectionAddress().getPort()
- + ":participant;localhost:"
- + qu.getPeer(leavingIndex1).peer.getClientPort());
- // this server will be added back as an observer
- joiningServers.add("server." + leavingIndex2 + "=localhost:"
- + qu.getPeer(leavingIndex2).peer.getQuorumAddress().getPort()
- + qu.getPeer(leavingIndex2).peer.getElectionAddress().getPort()
- + ":observer;localhost:"
- + qu.getPeer(leavingIndex2).peer.getClientPort());
- qu.shutdown(leavingIndex1);
- qu.shutdown(leavingIndex2);
- // 3 servers still up so this should work
- reconfig(zkArr[stayingIndex2], null, leavingServers, null, -1);
- qu.shutdown(stayingIndex2);
- // the following commands would not work in the original
- // cluster of 5, but now that we've removed 2 servers
- // we have a cluster of 3 servers and one of them is allowed to fail
- testServerHasConfig(zkArr[stayingIndex1], null, leavingServers);
- testServerHasConfig(zkArr[stayingIndex3], null, leavingServers);
- testNormalOperation(zkArr[stayingIndex1], zkArr[stayingIndex3]);
- // this is a test that a reconfig will only succeed
- // if there is a quorum up in new config. Below there is no
- // quorum so it should fail
- // the sleep is necessary so that the leader figures out
- // that the switched off servers are down
- Thread.sleep(10000);
- reconfig(zkArr[stayingIndex1], joiningServers, null, null, -1);
- Assert.fail("reconfig completed successfully even though there is no quorum up in new config!");
- } catch (KeeperException.NewConfigNoQuorum e) {
- // now start the third server so that new config has quorum
- qu.restart(stayingIndex2);
- testNormalOperation(zkArr[stayingIndex2], zkArr[stayingIndex3]);
- testServerHasConfig(zkArr[stayingIndex2], joiningServers, null);
- // this server wasn't around during the configuration change
- // we should check that it is able to connect, finds out
- // about the change and becomes an observer.
- qu.restart(leavingIndex2);
- Assert.assertTrue(qu.getPeer(leavingIndex2).peer.getPeerState() == ServerState.OBSERVING);
- testNormalOperation(zkArr[stayingIndex2], zkArr[leavingIndex2]);
- testServerHasConfig(zkArr[leavingIndex2], joiningServers, null);
- public void testBulkReconfig() throws Exception {
- qu = new QuorumUtil(3); // create 7 servers
- // new config will have three of the servers as followers
- // two of the servers as observers, and all ports different
- ArrayList<String> newServers = new ArrayList<String>();
- for (int i = 1; i <= 5; i++) {
- String server = "server." + i + "=localhost:" + PortAssignment.unique()
- + ":" + PortAssignment.unique() + ":"
- + ((i == 4 || i == 5) ? "observer" : "participant")
- + ";localhost:" + qu.getPeer(i).peer.getClientPort();
- newServers.add(server);
- qu.shutdown(3);
- qu.shutdown(6);
- qu.shutdown(7);
- reconfig(zkArr[1], null, null, newServers, -1);
- testNormalOperation(zkArr[1], zkArr[2]);
- testServerHasConfig(zkArr[1], newServers, null);
- testServerHasConfig(zkArr[2], newServers, null);
- testServerHasConfig(zkArr[4], newServers, null);
- testServerHasConfig(zkArr[5], newServers, null);
- qu.shutdown(5);
- qu.shutdown(4);
- public void testRemoveOneAsynchronous() throws Exception {
- qu = new QuorumUtil(2);
- // lets remove someone who's not the leader
- leavingServers.add(getLeaderId(qu) == 5 ? "4": "5");
- LinkedList<Integer> results = new LinkedList<Integer>();
- zkArr[1].reconfig(null, leavingServers, null, -1, this, results);
- synchronized (results) {
- while (results.size() < 1) {
- results.wait();
- Assert.assertEquals(0, (int) results.get(0));
- for (int i=1; i<=5; i++)
- testServerHasConfig(zkArr[i], null, leavingServers);
- @SuppressWarnings("unchecked")
- public void processResult(int rc, String path, Object ctx, byte[] data,
- Stat stat) {
- synchronized(ctx) {
- ((LinkedList<Integer>)ctx).add(rc);
- ctx.notifyAll();
- public void testRoleChange() throws Exception {
- // changing a server's role / port is done by "adding" it with the same
- // id but different role / port
- // during first and second iteration, leavingIndex will correspond to a
- // follower
- // during third and fouth iteration leavingIndex will be the index of
- // the leader
- int changingIndex = (leaderIndex == 1) ? 2 : 1;
- // first convert participant to observer, then observer to participant,
- // and so on
- String newRole = "observer";
- for (int i = 0; i < 4; i++) {
- ZooKeeper zk1 = (changingIndex == leaderIndex) ? zkArr[leaderIndex]
- // exactly as it is now, except for role change
- + changingIndex
- + qu.getPeer(changingIndex).peer.getQuorumAddress()
- + qu.getPeer(changingIndex).peer.getElectionAddress()
- .getPort() + ":" + newRole + ";localhost:"
- + qu.getPeer(changingIndex).peer.getClientPort());
- reconfig(zk1, joiningServers, null, null, -1);
- testNormalOperation(zkArr[changingIndex], zk1);
- if (newRole.equals("observer")) {
- Assert.assertTrue(qu.getPeer(changingIndex).peer.observer != null
- && qu.getPeer(changingIndex).peer.follower == null
- && qu.getPeer(changingIndex).peer.leader == null);
- Assert.assertTrue(qu.getPeer(changingIndex).peer.getPeerState() == ServerState.OBSERVING);
- Assert.assertTrue(qu.getPeer(changingIndex).peer.observer == null
- && (qu.getPeer(changingIndex).peer.follower != null || qu
- .getPeer(changingIndex).peer.leader != null));
- Assert.assertTrue(qu.getPeer(changingIndex).peer.getPeerState() == ServerState.FOLLOWING
- || qu.getPeer(changingIndex).peer.getPeerState() == ServerState.LEADING);
- newRole = "participant";
- // lets change leader to observer
- newRole = "observer";
- leaderIndex = getLeaderId(qu);
- changingIndex = leaderIndex;
- public void testPortChange() throws Exception {
- int followerIndex = leaderIndex == 1 ? 2 : 1;
- // change leader into observer, and modify all its ports at the same
- // time
- int observerIndex = leaderIndex;
- // new ports
- int port1 = PortAssignment.unique();
- int port2 = PortAssignment.unique();
- int port3 = PortAssignment.unique();
- joiningServers.add("server." + observerIndex + "=localhost:" + port1
- + ":" + port2 + ":observer;localhost:" + port3);
- // create a /test znode and check that read/write works before
- // any reconfig is invoked
- testNormalOperation(zkArr[observerIndex], zkArr[followerIndex]);
- reconfig(zkArr[followerIndex], joiningServers, null, null, -1);
- // the change of port may not be immediate -- we repeatedly
- // invoke an operation expecting it to eventually fail once
- // the client port of observerIndex changes. If it didn't
- // change -- that's an error.
- for (int i=0; i < 30; i++) {
- zkArr[observerIndex].setData("/test", "teststr".getBytes(), -1);
- Assert.fail("client port didn't change");
- zkArr[observerIndex] = new ZooKeeper("127.0.0.1:"
- + qu.getPeer(observerIndex).peer.getClientPort(),
- public void process(WatchedEvent event) {}});
- followerIndex = 1;
- while (followerIndex == leaderIndex || followerIndex == observerIndex)
- followerIndex++;
- testServerHasConfig(zkArr[observerIndex], joiningServers, null);
- Assert.assertTrue(qu.getPeer(observerIndex).peer.getQuorumAddress()
- .getPort() == port1);
- Assert.assertTrue(qu.getPeer(observerIndex).peer.getElectionAddress()
- .getPort() == port2);
- Assert.assertTrue(qu.getPeer(observerIndex).peer.getClientPort() == port3);
- Assert.assertTrue(qu.getPeer(observerIndex).peer.getPeerState() == ServerState.OBSERVING);
- // change leader's leading port - should renounce leadership
- port1 = PortAssignment.unique();
- joiningServers.add("server." + leaderIndex + "=localhost:" + port1
- + qu.getPeer(leaderIndex).peer.getElectionAddress().getPort()
- + qu.getPeer(leaderIndex).peer.getClientPort());
- Assert.assertTrue(qu.getPeer(leaderIndex).peer.getQuorumAddress()
- Assert.assertTrue(qu.getPeer(leaderIndex).peer.leader == null
- && qu.getPeer(leaderIndex).peer.follower != null);
- Assert.assertTrue(qu.getPeer(followerIndex).peer.leader != null
- && qu.getPeer(followerIndex).peer.follower == null);
- // change in leader election port
- for (int i = 1; i <= 3; i++) {
- joiningServers.add("server." + i + "=localhost:"
- + qu.getPeer(i).peer.getQuorumAddress().getPort() + ":"
- + PortAssignment.unique() + ":participant;localhost:"
- + qu.getPeer(i).peer.getClientPort());
- reconfig(zkArr[1], joiningServers, null, null, -1);
- int follower1 = leaderIndex == 1 ? 2 : 1;
- int follower2 = 1;
- while (follower2 == leaderIndex || follower2 == follower1)
- follower2++;
- // lets kill the leader and see if a new one is elected
- qu.shutdown(getLeaderId(qu));
- testNormalOperation(zkArr[follower2], zkArr[follower1]);
- testServerHasConfig(zkArr[follower1], joiningServers, null);
- testServerHasConfig(zkArr[follower2], joiningServers, null);
- public void testUnspecifiedClientAddress() throws Exception {
- int[] ports = new int[3];
- for (int port : ports) {
- port = PortAssignment.unique();
- String server = "server.0=localhost:" + ports[0] + ":" + ports[1] + ";" + ports[2];
- QuorumServer qs = new QuorumServer(0, server);
- Assert.assertEquals(qs.clientAddr.getHostName(), "0.0.0.0");
- Assert.assertEquals(qs.clientAddr.getPort(), ports[2]);
- public void testQuorumSystemChange() throws Exception {
- ArrayList<String> members = new ArrayList<String>();
- members.add("group.1=3:4:5");
- members.add("group.2=1:2");
- members.add("weight.1=0");
- members.add("weight.2=0");
- members.add("weight.3=1");
- members.add("weight.4=1");
- members.add("weight.5=1");
- members.add("server." + i + "=127.0.0.1:"
- + qu.getPeer(i).peer.getElectionAddress().getPort() + ";"
- + "127.0.0.1:" + qu.getPeer(i).peer.getClientPort());
- reconfig(zkArr[1], null, null, members, -1);
- // this should flush the config to servers 2, 3, 4 and 5
- testNormalOperation(zkArr[2], zkArr[3]);
- testNormalOperation(zkArr[4], zkArr[5]);
- if (!(qu.getPeer(i).peer.quorumVerifier instanceof QuorumHierarchical))
- Assert.fail("peer " + i
- + " doesn't think the quorum system is Hieararchical!");
- qu.shutdown(1);
- qu.shutdown(2);
- // servers 4 and 5 should be able to work independently
- qu.restart(1);
- qu.restart(2);
- members.clear();
- // flush the config to server 2
- // servers 1 and 2 should be able to work independently
- for (int i = 1; i <= 2; i++) {
- if (!(qu.getPeer(i).peer.quorumVerifier instanceof QuorumMaj))
- Assert.fail("peer "
- + i
- + " doesn't think the quorum system is a majority quorum system!");
- public void testInitialConfigHasPositiveVersion() throws Exception {
- for (int i=1; i<4; i++) {
- String configStr = testServerHasConfig(zkArr[i], null, null);
- QuorumVerifier qv = qu.getPeer(i).peer.configFromString(configStr);
- Assert.assertTrue(version == 0x100000000L);
+import java.util.LinkedList;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.AsyncCallback.DataCallback;
+import org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;
+import org.apache.zookeeper.server.quorum.flexible.QuorumHierarchical;
+import org.apache.zookeeper.server.quorum.flexible.QuorumMaj;
+import org.apache.zookeeper.server.quorum.flexible.QuorumVerifier;
+import org.junit.After;
+public class ReconfigTest extends ZKTestCase implements DataCallback{
+ private static final Logger LOG = LoggerFactory
+ .getLogger(ReconfigTest.class);
+ private QuorumUtil qu;
+ @After
+ public void tearDown() throws Exception {
+ if (qu != null) {
+ qu.tearDown();
+ public static String reconfig(ZooKeeper zk, List<String> joiningServers,
+ List<String> leavingServers, List<String> newMembers, long fromConfig)
+ byte[] config = null;
+ for (int j = 0; j < 30; j++) {
+ config = zk.reconfig(joiningServers, leavingServers,
+ newMembers, fromConfig, new Stat());
+ if (j < 29) {
+ Thread.sleep(1000);
+ // test fails if we still can't connect to the quorum after
+ // 30 seconds.
+ Assert.fail("client could not connect to reestablished quorum: giving up after 30+ seconds.");
+ String configStr = new String(config);
+ if (joiningServers != null) {
+ for (String joiner : joiningServers)
+ Assert.assertTrue(configStr.contains(joiner));
+ if (leavingServers != null) {
+ for (String leaving : leavingServers)
+ Assert.assertFalse(configStr.contains("server.".concat(leaving)));
+ return configStr;
+ public static String testServerHasConfig(ZooKeeper zk,
+ List<String> joiningServers, List<String> leavingServers)
+ zk.sync("/", null, null);
+ config = zk.getConfig(false, new Stat());
+ for (String joiner : joiningServers) {
+ public static void testNormalOperation(ZooKeeper writer, ZooKeeper reader)
+ boolean testNodeExists = false;
+ if (!testNodeExists) {
+ writer.create("/test", "test".getBytes(),
+ ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+ testNodeExists = true;
+ String data = "test" + j;
+ writer.setData("/test", data.getBytes(), -1);
+ reader.sync("/", null, null);
+ byte[] res = reader.getData("/test", null, new Stat());
+ Assert.assertEquals(data, new String(res));
+ private int getLeaderId(QuorumUtil qu) {
+ int leaderId = 1;
+ while (qu.getPeer(leaderId).peer.leader == null)
+ leaderId++;
+ return leaderId;
+ private ZooKeeper[] createHandles(QuorumUtil qu) throws IOException {
+ // create an extra handle, so we can index the handles from 1 to qu.ALL
+ // using the server id.
+ ZooKeeper[] zkArr = new ZooKeeper[qu.ALL + 1];
+ zkArr[0] = null; // not used.
+ for (int i = 1; i <= qu.ALL; i++) {
+ // server ids are 1, 2 and 3
+ zkArr[i] = new ZooKeeper("127.0.0.1:"
+ + qu.getPeer(i).peer.getClientPort(),
+ ClientBase.CONNECTION_TIMEOUT, new Watcher() {
+ }});
+ return zkArr;
+ private void closeAllHandles(ZooKeeper[] zkArr) throws InterruptedException {
+ for (ZooKeeper zk : zkArr)
+ if (zk != null)
+ zk.close();
+ public void testRemoveAddOne() throws Exception {
+ qu = new QuorumUtil(1); // create 3 servers
+ qu.disableJMXTest = true;
+ qu.startAll();
+ ZooKeeper[] zkArr = createHandles(qu);
+ List<String> leavingServers = new ArrayList<String>();
+ List<String> joiningServers = new ArrayList<String>();
+ int leaderIndex = getLeaderId(qu);
+ // during first iteration, leavingIndex will correspond to a follower
+ // during second iteration leavingIndex will be the index of the leader
+ int leavingIndex = (leaderIndex == 1) ? 2 : 1;
+ for (int i = 0; i < 2; i++) {
+ // some of the operations will be executed by a client connected to
+ // the removed server
+ // while others are invoked by a client connected to some other
+ // server.
+ // when we're removing the leader, zk1 will be the client connected
+ // to removed server
+ ZooKeeper zk1 = (leavingIndex == leaderIndex) ? zkArr[leaderIndex]
+ : zkArr[(leaderIndex % qu.ALL) + 1];
+ ZooKeeper zk2 = (leavingIndex == leaderIndex) ? zkArr[(leaderIndex % qu.ALL) + 1]
+ : zkArr[leaderIndex];
+ leavingServers.add(Integer.toString(leavingIndex));
+ // remember this server so we can add it back later
+ joiningServers.add("server."
+ + leavingIndex
+ + "=localhost:"
+ + qu.getPeer(leavingIndex).peer.getQuorumAddress()
+ .getPort()
+ + ":"
+ + qu.getPeer(leavingIndex).peer.getElectionAddress()
+ .getPort() + ":participant;localhost:"
+ + qu.getPeer(leavingIndex).peer.getClientPort());
+ String configStr = reconfig(zk1, null, leavingServers, null, -1);
+ testServerHasConfig(zk2, null, leavingServers);
+ testNormalOperation(zk2, zk1);
+ QuorumVerifier qv = qu.getPeer(1).peer.configFromString(configStr);
+ long version = qv.getVersion();
+ // checks that conditioning on version works properly
+ reconfig(zk2, joiningServers, null, null, version + 1);
+ Assert.fail("reconfig succeeded even though version condition was incorrect!");
+ } catch (KeeperException.BadVersionException e) {
+ reconfig(zk2, joiningServers, null, null, version);
+ testNormalOperation(zk1, zk2);
+ testServerHasConfig(zk1, joiningServers, null);
+ // second iteration of the loop will remove the leader
+ // and add it back (as follower)
+ leavingIndex = leaderIndex = getLeaderId(qu);
+ leavingServers.clear();
+ joiningServers.clear();
+ closeAllHandles(zkArr);
+ * 1. removes and adds back two servers (incl leader). One of the servers is added back as observer
+ * 2. tests that reconfig fails if quorum of new config is not up
+ * 3. tests that a server that's not up during reconfig learns the new config when it comes up
+ public void testRemoveAddTwo() throws Exception {
+ qu = new QuorumUtil(2); // create 5 servers
+ // lets remove the leader and some other server
+ int leavingIndex1 = leaderIndex;
+ int leavingIndex2 = (leaderIndex == 1) ? 2 : 1;
+ // find some server that's staying
+ int stayingIndex1 = 1, stayingIndex2 = 1, stayingIndex3 = 1;
+ while (stayingIndex1 == leavingIndex1 || stayingIndex1 == leavingIndex2)
+ stayingIndex1++;
+ while (stayingIndex2 == leavingIndex1 || stayingIndex2 == leavingIndex2
+ || stayingIndex2 == stayingIndex1)
+ stayingIndex2++;
+ while (stayingIndex3 == leavingIndex1 || stayingIndex3 == leavingIndex2
+ || stayingIndex3 == stayingIndex1
+ || stayingIndex3 == stayingIndex2)
+ stayingIndex3++;
+ leavingServers.add(Integer.toString(leavingIndex1));
+ leavingServers.add(Integer.toString(leavingIndex2));
+ // remember these servers so we can add them back later
+ joiningServers.add("server." + leavingIndex1 + "=localhost:"
+ + qu.getPeer(leavingIndex1).peer.getQuorumAddress().getPort()
+ + qu.getPeer(leavingIndex1).peer.getElectionAddress().getPort()
+ + ":participant;localhost:"
+ + qu.getPeer(leavingIndex1).peer.getClientPort());
+ // this server will be added back as an observer
+ joiningServers.add("server." + leavingIndex2 + "=localhost:"
+ + qu.getPeer(leavingIndex2).peer.getQuorumAddress().getPort()
+ + qu.getPeer(leavingIndex2).peer.getElectionAddress().getPort()
+ + ":observer;localhost:"
+ + qu.getPeer(leavingIndex2).peer.getClientPort());
+ qu.shutdown(leavingIndex1);
+ qu.shutdown(leavingIndex2);
+ // 3 servers still up so this should work
+ reconfig(zkArr[stayingIndex2], null, leavingServers, null, -1);
+ qu.shutdown(stayingIndex2);
+ // the following commands would not work in the original
+ // cluster of 5, but now that we've removed 2 servers
+ // we have a cluster of 3 servers and one of them is allowed to fail
+ testServerHasConfig(zkArr[stayingIndex1], null, leavingServers);
+ testServerHasConfig(zkArr[stayingIndex3], null, leavingServers);
+ testNormalOperation(zkArr[stayingIndex1], zkArr[stayingIndex3]);
+ // this is a test that a reconfig will only succeed
+ // if there is a quorum up in new config. Below there is no
+ // quorum so it should fail
+ // the sleep is necessary so that the leader figures out
+ // that the switched off servers are down
+ Thread.sleep(10000);
+ reconfig(zkArr[stayingIndex1], joiningServers, null, null, -1);
+ Assert.fail("reconfig completed successfully even though there is no quorum up in new config!");
+ } catch (KeeperException.NewConfigNoQuorum e) {
+ // now start the third server so that new config has quorum
+ qu.restart(stayingIndex2);
+ testNormalOperation(zkArr[stayingIndex2], zkArr[stayingIndex3]);
+ testServerHasConfig(zkArr[stayingIndex2], joiningServers, null);
+ // this server wasn't around during the configuration change
+ // we should check that it is able to connect, finds out
+ // about the change and becomes an observer.
+ qu.restart(leavingIndex2);
+ Assert.assertTrue(qu.getPeer(leavingIndex2).peer.getPeerState() == ServerState.OBSERVING);
+ testNormalOperation(zkArr[stayingIndex2], zkArr[leavingIndex2]);
+ testServerHasConfig(zkArr[leavingIndex2], joiningServers, null);
+ public void testBulkReconfig() throws Exception {
+ qu = new QuorumUtil(3); // create 7 servers
+ // new config will have three of the servers as followers
+ // two of the servers as observers, and all ports different
+ ArrayList<String> newServers = new ArrayList<String>();
+ for (int i = 1; i <= 5; i++) {
+ String server = "server." + i + "=localhost:" + PortAssignment.unique()
+ + ":" + PortAssignment.unique() + ":"
+ + ((i == 4 || i == 5) ? "observer" : "participant")
+ + ";localhost:" + qu.getPeer(i).peer.getClientPort();
+ newServers.add(server);
+ qu.shutdown(3);
+ qu.shutdown(6);
+ qu.shutdown(7);
+ reconfig(zkArr[1], null, null, newServers, -1);
+ testNormalOperation(zkArr[1], zkArr[2]);
+ testServerHasConfig(zkArr[1], newServers, null);
+ testServerHasConfig(zkArr[2], newServers, null);
+ testServerHasConfig(zkArr[4], newServers, null);
+ testServerHasConfig(zkArr[5], newServers, null);
+ qu.shutdown(5);
+ qu.shutdown(4);
+ public void testRemoveOneAsynchronous() throws Exception {
+ qu = new QuorumUtil(2);
+ // lets remove someone who's not the leader
+ leavingServers.add(getLeaderId(qu) == 5 ? "4": "5");
+ LinkedList<Integer> results = new LinkedList<Integer>();
+ zkArr[1].reconfig(null, leavingServers, null, -1, this, results);
+ synchronized (results) {
+ while (results.size() < 1) {
+ results.wait();
+ Assert.assertEquals(0, (int) results.get(0));
+ for (int i=1; i<=5; i++)
+ testServerHasConfig(zkArr[i], null, leavingServers);
+ @SuppressWarnings("unchecked")
+ public void processResult(int rc, String path, Object ctx, byte[] data,
+ Stat stat) {
+ synchronized(ctx) {
+ ((LinkedList<Integer>)ctx).add(rc);
+ ctx.notifyAll();
+ public void testRoleChange() throws Exception {
+ // changing a server's role / port is done by "adding" it with the same
+ // id but different role / port
+ // during first and second iteration, leavingIndex will correspond to a
+ // follower
+ // during third and fouth iteration leavingIndex will be the index of
+ // the leader
+ int changingIndex = (leaderIndex == 1) ? 2 : 1;
+ // first convert participant to observer, then observer to participant,
+ // and so on
+ String newRole = "observer";
+ for (int i = 0; i < 4; i++) {
+ ZooKeeper zk1 = (changingIndex == leaderIndex) ? zkArr[leaderIndex]
+ // exactly as it is now, except for role change
+ + changingIndex
+ + qu.getPeer(changingIndex).peer.getQuorumAddress()
+ + qu.getPeer(changingIndex).peer.getElectionAddress()
+ .getPort() + ":" + newRole + ";localhost:"
+ + qu.getPeer(changingIndex).peer.getClientPort());
+ reconfig(zk1, joiningServers, null, null, -1);
+ testNormalOperation(zkArr[changingIndex], zk1);
+ if (newRole.equals("observer")) {
+ Assert.assertTrue(qu.getPeer(changingIndex).peer.observer != null
+ && qu.getPeer(changingIndex).peer.follower == null
+ && qu.getPeer(changingIndex).peer.leader == null);
+ Assert.assertTrue(qu.getPeer(changingIndex).peer.getPeerState() == ServerState.OBSERVING);
+ Assert.assertTrue(qu.getPeer(changingIndex).peer.observer == null
+ && (qu.getPeer(changingIndex).peer.follower != null || qu
+ .getPeer(changingIndex).peer.leader != null));
+ Assert.assertTrue(qu.getPeer(changingIndex).peer.getPeerState() == ServerState.FOLLOWING
+ || qu.getPeer(changingIndex).peer.getPeerState() == ServerState.LEADING);
+ newRole = "participant";
+ // lets change leader to observer
+ newRole = "observer";
+ leaderIndex = getLeaderId(qu);
+ changingIndex = leaderIndex;
+ public void testPortChange() throws Exception {
+ int followerIndex = leaderIndex == 1 ? 2 : 1;
+ // change leader into observer, and modify all its ports at the same
+ // time
+ int observerIndex = leaderIndex;
+ // new ports
+ int port1 = PortAssignment.unique();
+ int port2 = PortAssignment.unique();
+ int port3 = PortAssignment.unique();
+ joiningServers.add("server." + observerIndex + "=localhost:" + port1
+ + ":" + port2 + ":observer;localhost:" + port3);
+ // create a /test znode and check that read/write works before
+ // any reconfig is invoked
+ testNormalOperation(zkArr[observerIndex], zkArr[followerIndex]);
+ reconfig(zkArr[followerIndex], joiningServers, null, null, -1);
+ // the change of port may not be immediate -- we repeatedly
+ // invoke an operation expecting it to eventually fail once
+ // the client port of observerIndex changes. If it didn't
+ // change -- that's an error.
+ for (int i=0; i < 30; i++) {
+ zkArr[observerIndex].setData("/test", "teststr".getBytes(), -1);
+ Assert.fail("client port didn't change");
+ zkArr[observerIndex] = new ZooKeeper("127.0.0.1:"
+ + qu.getPeer(observerIndex).peer.getClientPort(),
+ public void process(WatchedEvent event) {}});
+ followerIndex = 1;
+ while (followerIndex == leaderIndex || followerIndex == observerIndex)
+ followerIndex++;
+ testServerHasConfig(zkArr[observerIndex], joiningServers, null);
+ Assert.assertTrue(qu.getPeer(observerIndex).peer.getQuorumAddress()
+ .getPort() == port1);
+ Assert.assertTrue(qu.getPeer(observerIndex).peer.getElectionAddress()
+ .getPort() == port2);
+ Assert.assertTrue(qu.getPeer(observerIndex).peer.getClientPort() == port3);
+ Assert.assertTrue(qu.getPeer(observerIndex).peer.getPeerState() == ServerState.OBSERVING);
+ // change leader's leading port - should renounce leadership
+ port1 = PortAssignment.unique();
+ joiningServers.add("server." + leaderIndex + "=localhost:" + port1
+ + qu.getPeer(leaderIndex).peer.getElectionAddress().getPort()
+ + qu.getPeer(leaderIndex).peer.getClientPort());
+ Assert.assertTrue(qu.getPeer(leaderIndex).peer.getQuorumAddress()
+ Assert.assertTrue(qu.getPeer(leaderIndex).peer.leader == null
+ && qu.getPeer(leaderIndex).peer.follower != null);
+ Assert.assertTrue(qu.getPeer(followerIndex).peer.leader != null
+ && qu.getPeer(followerIndex).peer.follower == null);
+ // change in leader election port
+ for (int i = 1; i <= 3; i++) {
+ joiningServers.add("server." + i + "=localhost:"
+ + qu.getPeer(i).peer.getQuorumAddress().getPort() + ":"
+ + PortAssignment.unique() + ":participant;localhost:"
+ + qu.getPeer(i).peer.getClientPort());
+ reconfig(zkArr[1], joiningServers, null, null, -1);
+ int follower1 = leaderIndex == 1 ? 2 : 1;
+ int follower2 = 1;
+ while (follower2 == leaderIndex || follower2 == follower1)
+ follower2++;
+ // lets kill the leader and see if a new one is elected
+ qu.shutdown(getLeaderId(qu));
+ testNormalOperation(zkArr[follower2], zkArr[follower1]);
+ testServerHasConfig(zkArr[follower1], joiningServers, null);
+ testServerHasConfig(zkArr[follower2], joiningServers, null);
+ public void testUnspecifiedClientAddress() throws Exception {
+ int[] ports = new int[3];
+ for (int port : ports) {
+ port = PortAssignment.unique();
+ String server = "server.0=localhost:" + ports[0] + ":" + ports[1] + ";" + ports[2];
+ QuorumServer qs = new QuorumServer(0, server);
+ Assert.assertEquals(qs.clientAddr.getHostName(), "0.0.0.0");
+ Assert.assertEquals(qs.clientAddr.getPort(), ports[2]);
+ public void testQuorumSystemChange() throws Exception {
+ ArrayList<String> members = new ArrayList<String>();
+ members.add("group.1=3:4:5");
+ members.add("group.2=1:2");
+ members.add("weight.1=0");
+ members.add("weight.2=0");
+ members.add("weight.3=1");
+ members.add("weight.4=1");
+ members.add("weight.5=1");
+ members.add("server." + i + "=127.0.0.1:"
+ + qu.getPeer(i).peer.getElectionAddress().getPort() + ";"
+ + "127.0.0.1:" + qu.getPeer(i).peer.getClientPort());
+ reconfig(zkArr[1], null, null, members, -1);
+ // this should flush the config to servers 2, 3, 4 and 5
+ testNormalOperation(zkArr[2], zkArr[3]);
+ testNormalOperation(zkArr[4], zkArr[5]);
+ if (!(qu.getPeer(i).peer.quorumVerifier instanceof QuorumHierarchical))
+ Assert.fail("peer " + i
+ + " doesn't think the quorum system is Hieararchical!");
+ qu.shutdown(1);
+ qu.shutdown(2);
+ // servers 4 and 5 should be able to work independently
+ qu.restart(1);
+ qu.restart(2);
+ members.clear();
+ // flush the config to server 2
+ // servers 1 and 2 should be able to work independently
+ for (int i = 1; i <= 2; i++) {
+ if (!(qu.getPeer(i).peer.quorumVerifier instanceof QuorumMaj))
+ Assert.fail("peer "
+ + i
+ + " doesn't think the quorum system is a majority quorum system!");
+ public void testInitialConfigHasPositiveVersion() throws Exception {
+ for (int i=1; i<4; i++) {
+ String configStr = testServerHasConfig(zkArr[i], null, null);
+ QuorumVerifier qv = qu.getPeer(i).peer.configFromString(configStr);
+ Assert.assertTrue(version == 0x100000000L);
@@ -1,105 +1,105 @@
-import java.io.ByteArrayOutputStream;
-import java.io.OutputStream;
-import java.net.Socket;
-import junit.framework.Assert;
-import org.apache.jute.BinaryOutputArchive;
-import org.apache.zookeeper.proto.ConnectRequest;
-import org.apache.zookeeper.proto.CreateRequest;
-import org.apache.zookeeper.proto.RequestHeader;
-public class SessionInvalidationTest extends ClientBase {
- * Test solution for ZOOKEEPER-1208. Verify that operations are not
- * accepted after a close session.
- * We're using our own marshalling here in order to force an operation
- * after the session is closed (ZooKeeper.class will not allow this). Also
- * by filling the pipe with operations it increases the likelyhood that
- * the server will process the create before FinalRequestProcessor
- * removes the session from the tracker.
- public void testCreateAfterCloseShouldFail() throws Exception {
- for (int i = 0; i < 10; i++) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);
- // open a connection
- boa.writeInt(44, "len");
- ConnectRequest conReq = new ConnectRequest(0, 0, 30000, 0, new byte[16]);
- conReq.serialize(boa, "connect");
- // close connection
- boa.writeInt(8, "len");
- RequestHeader h = new RequestHeader(1, ZooDefs.OpCode.closeSession);
- h.serialize(boa, "header");
- // create ephemeral znode
- boa.writeInt(52, "len"); // We'll fill this in later
- RequestHeader header = new RequestHeader(2, OpCode.create);
- header.serialize(boa, "header");
- CreateRequest createReq = new CreateRequest("/foo" + i, new byte[0],
- Ids.OPEN_ACL_UNSAFE, 1);
- createReq.serialize(boa, "request");
- baos.close();
- System.out.println("Length:" + baos.toByteArray().length);
- String hp[] = hostPort.split(":");
- Socket sock = new Socket(hp[0], Integer.parseInt(hp[1]));
- InputStream resultStream = null;
- OutputStream outstream = sock.getOutputStream();
- byte[] data = baos.toByteArray();
- outstream.write(data);
- outstream.flush();
- resultStream = sock.getInputStream();
- byte[] b = new byte[10000];
- int len;
- while ((len = resultStream.read(b)) >= 0) {
- // got results
- System.out.println("gotlen:" + len);
- if (resultStream != null) {
- resultStream.close();
- sock.close();
- ZooKeeper zk = createClient();
- Assert.assertEquals(1, zk.getChildren("/", false).size());
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import junit.framework.Assert;
+import org.apache.jute.BinaryOutputArchive;
+import org.apache.zookeeper.proto.ConnectRequest;
+import org.apache.zookeeper.proto.CreateRequest;
+import org.apache.zookeeper.proto.RequestHeader;
+public class SessionInvalidationTest extends ClientBase {
+ * Test solution for ZOOKEEPER-1208. Verify that operations are not
+ * accepted after a close session.
+ * We're using our own marshalling here in order to force an operation
+ * after the session is closed (ZooKeeper.class will not allow this). Also
+ * by filling the pipe with operations it increases the likelyhood that
+ * the server will process the create before FinalRequestProcessor
+ * removes the session from the tracker.
+ public void testCreateAfterCloseShouldFail() throws Exception {
+ for (int i = 0; i < 10; i++) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);
+ // open a connection
+ boa.writeInt(44, "len");
+ ConnectRequest conReq = new ConnectRequest(0, 0, 30000, 0, new byte[16]);
+ conReq.serialize(boa, "connect");
+ // close connection
+ boa.writeInt(8, "len");
+ RequestHeader h = new RequestHeader(1, ZooDefs.OpCode.closeSession);
+ h.serialize(boa, "header");
+ // create ephemeral znode
+ boa.writeInt(52, "len"); // We'll fill this in later
+ RequestHeader header = new RequestHeader(2, OpCode.create);
+ header.serialize(boa, "header");
+ CreateRequest createReq = new CreateRequest("/foo" + i, new byte[0],
+ Ids.OPEN_ACL_UNSAFE, 1);
+ createReq.serialize(boa, "request");
+ baos.close();
+ System.out.println("Length:" + baos.toByteArray().length);
+ String hp[] = hostPort.split(":");
+ Socket sock = new Socket(hp[0], Integer.parseInt(hp[1]));
+ InputStream resultStream = null;
+ OutputStream outstream = sock.getOutputStream();
+ byte[] data = baos.toByteArray();
+ outstream.write(data);
+ outstream.flush();
+ resultStream = sock.getInputStream();
+ byte[] b = new byte[10000];
+ int len;
+ while ((len = resultStream.read(b)) >= 0) {
+ // got results
+ System.out.println("gotlen:" + len);
+ if (resultStream != null) {
+ resultStream.close();
+ sock.close();
+ ZooKeeper zk = createClient();
+ Assert.assertEquals(1, zk.getChildren("/", false).size());