http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-zktreeutil/src/ZkTreeUtil.cc
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-zktreeutil/src/ZkTreeUtil.cc 
b/zookeeper-contrib/zookeeper-contrib-zktreeutil/src/ZkTreeUtil.cc
new file mode 100644
index 0000000..270bf31
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-zktreeutil/src/ZkTreeUtil.cc
@@ -0,0 +1,705 @@
+/**
+ * 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.
+ */
+
+#include "ZkTreeUtil.h"
+
+#include <map>
+#include <iostream>
+#include <log4cxx/logger.h>
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/split.hpp>
+
+namespace zktreeutil
+{
+    using std::map;
+    using std::pair;
+
+    static ZkTreeNodeSptr loadZkTree_ (ZooKeeperAdapterSptr zkHandle,
+            const string& path)
+    {
+        // Extract the node value
+        string value = zkHandle->getNodeData(path);
+
+        // Extract nodename from the path
+        string nodename = "/";
+        if (path != "/")
+        {
+            vector< string > nodes;
+            boost::split(nodes, path, boost::is_any_of ("/") );
+            nodename = nodes[nodes.size()-1];
+        }
+
+        // Create tree-node with name and value
+        ZkTreeNodeSptr nodeSptr = ZkTreeNodeSptr (new ZkTreeNode (nodename, 
value));
+        std::cerr << "[zktreeutil] loaded nodename: "
+            << nodename
+            << " value: "
+            << value
+            << std::endl;
+
+        // Load all the children
+        vector< string > cnodes = zkHandle->getNodeChildren (path);
+        for (unsigned i = 0; i < cnodes.size(); i++)
+            nodeSptr->addChild (loadZkTree_ (zkHandle, cnodes[i]));
+
+        // Return the constructed node
+        return nodeSptr;
+    }
+
+    static ZkTreeNodeSptr loadZkTreeXml_ (xmlNode* xmlNodePtr)
+    {
+        // Null check
+        if (xmlNodePtr == NULL)
+        {
+            std::cerr << "[zktreeutil] empty XML node encountered" << 
std::endl;
+            exit (-1);
+        }
+
+        // Get the node name
+        xmlChar* name = xmlGetProp (xmlNodePtr, BAD_CAST "name");
+        string nameStr = (const char*)name;
+        std::cerr << "[zktreeutil] node name: " << nameStr;
+        xmlFree (name);
+        // Get the node value
+        string valueStr;
+        xmlChar* value = xmlGetProp (xmlNodePtr, BAD_CAST "value");
+        if (value)
+        {
+            valueStr = (const char*)value;
+            std::cerr << " value: " << valueStr;
+        }
+        xmlFree (value);
+        // Get the ignore flag
+        bool doIgnore = false;
+        xmlChar* ignore = xmlGetProp (xmlNodePtr, BAD_CAST "ignore");
+        if (ignore)
+        {
+            string ignoreStr = (const char*) ignore;
+            if (ignoreStr == "true" || ignoreStr == "yes" || ignoreStr == "1")
+            {
+                doIgnore = true;
+                std::cerr << " <ignore:>";
+            }
+        }
+        xmlFree (ignore);
+        std::cerr << std::endl;
+
+        // Create the zk node
+        ZkTreeNodeSptr nodeSptr =
+            ZkTreeNodeSptr (new ZkTreeNode (nameStr,
+                        ZkNodeData (valueStr, doIgnore)));
+
+        // Load the children
+        for (xmlNode* chldNode = xmlNodePtr->children;
+                chldNode;
+                chldNode = chldNode->next)
+            if (chldNode->type == XML_ELEMENT_NODE)
+                nodeSptr->addChild (loadZkTreeXml_ (chldNode));
+
+        // Return the loaded node
+        return nodeSptr;
+    }
+
+    static void writeZkTree_ (ZooKeeperAdapterSptr zkHandle,
+            const ZkTreeNodeSptr zkNodeSptr,
+            const string& path)
+    {
+        // Create the path in zk-tree
+        zkHandle->createNode(path.c_str(), "", 0, false);
+        std::cerr << "[zktreeutil] created key: " << path << std::endl;
+        // Set value for the path
+        string value = zkNodeSptr->getData().value;
+        if (value != "")
+        {
+            zkHandle->setNodeData (path.c_str(), value.c_str());
+            std::cerr << "[zktreeutil] set value: " << std::endl;
+        }
+
+        // Go deep to write the subtree rooted in the node, if not to be 
ignored
+        if (!(zkNodeSptr->getData().ignoreUpdate))
+        {
+            for (unsigned i=0; i < zkNodeSptr->numChildren(); i++)
+            {
+                ZkTreeNodeSptr childNodeSptr = zkNodeSptr->getChild (i);
+                // Add the node name into the path and write in zk-tree
+                string cpath = ((path != "/")? path : "")
+                    + string("/")
+                    + childNodeSptr->getKey();
+                writeZkTree_ (zkHandle, childNodeSptr, cpath);
+            }
+        }
+
+        return;
+    }
+
+    static void addTreeZkAction_ (const ZkTreeNodeSptr zkNodeSptr,
+            const string& path,
+            vector< ZkAction >& actions)
+    {
+        // Create the key
+        actions.push_back (ZkAction (ZkAction::CREATE, path));
+
+        // Set value for the new key
+        if (zkNodeSptr->getData().value != "")
+            actions.push_back (ZkAction (ZkAction::VALUE,
+                        path,
+                        zkNodeSptr->getData().value));
+
+        // Add all the children
+        for (unsigned i=0; i < zkNodeSptr->numChildren(); i++)
+        {
+            ZkTreeNodeSptr childSptr = zkNodeSptr->getChild (i);
+            string cpath = path + string("/") + childSptr->getKey();
+            addTreeZkAction_ (childSptr, cpath, actions);
+        }
+
+        return;
+    }
+
+    static xmlNodePtr dumpZkTreeXml_ (const ZkTreeNodeSptr zkNodeSptr)
+    {
+        // Create xml node with zknode name and value
+        string nodename = zkNodeSptr->getKey ();
+        string value = zkNodeSptr->getData().value;
+        xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "zknode");
+        xmlNewProp (node, BAD_CAST "name", BAD_CAST nodename.c_str());
+        if (value.length())
+            xmlNewProp (node, BAD_CAST "value", BAD_CAST value.c_str());
+
+        // Add all the children rotted at this node
+        for (unsigned i=0; i < zkNodeSptr->numChildren(); i++)
+            xmlAddChild (node, dumpZkTreeXml_ (zkNodeSptr->getChild (i)));
+
+        // Return xml node
+        return node;
+    }
+
+    static void dumpZkTree_ (const ZkTreeNodeSptr zkNodeSptr,
+            int maxLevel,
+            int level,
+            vector< bool >& masks)
+    {
+        // Check the max. dlevel to be dumped
+        if (level > maxLevel)
+            return;
+
+        
+        // Create branch
+        for (int i=0; i < level; i++) 
+        {
+            if ( i== level-1) std::cout << "|   ";
+            else if (masks[i]) std::cout << "    ";
+            else std::cout << "|   ";
+        }
+        std::cout << std::endl;
+        for (int i=0; i < level-1; i++)
+        {
+            if (masks[i]) std::cout << "    ";
+            else std::cout << "|   ";
+        }
+
+        // Dump the node name and value
+        std::cout << "|--[" << zkNodeSptr->getKey();
+        if (zkNodeSptr->getData().value != "")
+            std::cout << " => " << zkNodeSptr->getData().value;
+        std::cout << "]" << std::endl;
+
+        // Dump all the children
+        for (unsigned i=0; i < zkNodeSptr->numChildren(); i++)
+        {
+            // Add mask for last child
+            if (i == zkNodeSptr->numChildren()-1)
+                masks.push_back(true);
+            else
+                masks.push_back(false);
+            dumpZkTree_ (zkNodeSptr->getChild (i), maxLevel, level+1, masks);
+        }
+
+        masks.pop_back();
+        return;
+    }
+
+    static ZkTreeNodeSptr traverseBranch_ (const ZkTreeNodeSptr& zkRootSptr,
+            const string& path)
+    {
+        // Check if the tree is loaded into memory
+        if (zkRootSptr == NULL)
+        {
+            string errMsg = "[zktreeutil] null root passed for traversing";
+            std::cout << errMsg << std::endl;
+            throw std::logic_error (errMsg);
+        }
+
+        // Split the path and add intermediate znodes
+        vector< string > nodes;
+        boost::split(nodes, path, boost::is_any_of ("/") );
+
+        // Start traversing the tree
+        ZkTreeNodeSptr currNodeSptr = zkRootSptr;
+        for (unsigned znode_idx = 1; znode_idx < nodes.size(); znode_idx++)
+        {
+            bool found = false;
+            for (unsigned i=0; i < currNodeSptr->numChildren(); i++)
+            {
+                ZkTreeNodeSptr  childNodeSptr = currNodeSptr->getChild(i);
+                if (childNodeSptr->getKey() == nodes[znode_idx])
+                {
+                    // Found! go to the znode
+                    currNodeSptr = childNodeSptr;
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) // No such znode found; return NULL node-ptr
+            {
+                string errMsg = string("[zktreeutil] unknown znode during 
traversal: ")
+                    + nodes[znode_idx];
+                std::cout << errMsg << std::endl;
+                throw std::logic_error (errMsg);
+            }
+        }
+
+        return currNodeSptr;
+    }
+
+    static ZkTreeNodeSptr createAncestors_ (const string& path)
+    {
+        // Create the root znode
+        ZkTreeNodeSptr zkRootSptr = ZkTreeNodeSptr (new ZkTreeNode ("/"));
+        ZkTreeNodeSptr currNodeSptr = zkRootSptr;
+        // Split the path and add intermediate znodes
+        vector< string > nodes;
+        boost::split(nodes, path, boost::is_any_of ("/") );
+        for (unsigned i=1; i < nodes.size()-1; i++)
+        {
+            ZkTreeNodeSptr childNodeSptr = ZkTreeNodeSptr (new ZkTreeNode 
(nodes[i]));
+            currNodeSptr->addChild (childNodeSptr);
+            currNodeSptr = childNodeSptr;
+        }
+
+        //Return the root of the branch
+        return zkRootSptr;
+    }
+
+    ZooKeeperAdapterSptr ZkTreeUtil::get_zkHandle (const string& zkHosts)
+    {
+        try
+        {
+            // Create an instance of ZK adapter.
+            ZooKeeperConfig config (zkHosts, 10000);
+            ZooKeeperAdapterSptr zkHandleSptr =
+                ZooKeeperAdapterSptr (new ZooKeeperAdapter (config));
+            return zkHandleSptr;
+        }
+        catch (const ZooKeeperException &e)
+        {
+            std::cerr << "[zktreeutil] zooKeeper exception caught: "
+                << e.what()
+                << std::endl;
+            throw;
+        }
+        catch (std::exception &stde)
+        {
+            std::cerr << "[zktreeutil] standard exception caught: "
+                << stde.what()
+                << std::endl;
+            throw;
+        }
+        catch (...)
+        {
+            std::cerr
+                << "[zktreeutil] unknown exception while connecting to 
zookeeper"
+                << std::endl;
+            throw;
+        }
+    }
+
+
+    void ZkTreeUtil::loadZkTree (const string& zkHosts,
+            const string& path,
+            bool force)
+    {
+        // Check if already loaded
+        if (loaded_ && !force)
+        {
+            std::cerr << "[zktreeutil] zk-tree already loaded into memory"
+                << std::endl;
+            return;
+        }
+
+        // Connect to ZK server
+        ZooKeeperAdapterSptr zkHandle = get_zkHandle (zkHosts);
+        std::cerr << "[zktreeutil] connected to ZK serverfor reading"
+            << std::endl;
+
+        // Check the existence of the path to znode
+        if (!zkHandle->nodeExists (path))
+        {
+            string errMsg = string("[zktreeutil] path does not exists : ") + 
path;
+            std::cout << errMsg << std::endl;
+            throw std::logic_error (errMsg);
+        }
+
+        // Load the rooted (sub)tree
+        ZkTreeNodeSptr zkSubrootSptr = loadZkTree_ (zkHandle, path);
+
+        //  Create the ancestors before loading the rooted subtree
+        if (path != "/")
+        {
+            zkRootSptr_ = createAncestors_(path);
+            string ppath = path.substr (0, path.rfind('/'));
+            ZkTreeNodeSptr parentSptr = traverseBranch_( zkRootSptr_, ppath);
+            parentSptr->addChild (zkSubrootSptr);
+        }
+        else // Loaded entire zk-tree
+        {
+            zkRootSptr_ = zkSubrootSptr;
+        }
+
+        // Set load flag
+        loaded_ = true;
+        return;
+    }
+
+    void ZkTreeUtil::loadZkTreeXml (const string& zkXmlConfig,
+            bool force)
+    {
+        // Check if already loaded
+        if (loaded_ && !force)
+        {
+            std::cerr << "[zktreeutil] zk-tree already loaded into memory"
+                << std::endl;
+            return;
+        }
+
+        // Parse the file and get the DOM
+        xmlDocPtr docPtr = xmlReadFile(zkXmlConfig.c_str(), NULL, 0);
+        if (docPtr == NULL) {
+            std::cerr << "[zktreeutil] could not parse XML file "
+                << zkXmlConfig
+                << std::endl;
+            exit (-1);
+        }
+        std::cerr << "[zktreeutil] zk-tree XML parsing successful"
+            << std::endl;
+
+        // Get the root element node
+        xmlNodePtr rootPtr = xmlDocGetRootElement(docPtr);
+        // Create the root zk node
+        zkRootSptr_ = ZkTreeNodeSptr (new ZkTreeNode ("/"));
+        // Load the rooted XML tree
+        for (xmlNode* chldNode = rootPtr->children;
+                chldNode;
+                chldNode = chldNode->next)
+        {
+            if (chldNode->type == XML_ELEMENT_NODE)
+                zkRootSptr_->addChild (loadZkTreeXml_ (chldNode));
+        }
+
+        // set oad flag
+        loaded_ = true;
+        // Cleanup stuff
+        xmlFreeDoc(docPtr);
+        xmlCleanupParser();
+        return;
+    }
+
+    void ZkTreeUtil::writeZkTree (const string& zkHosts,
+            const string& path,
+            bool force) const
+    {
+        // Connect to ZK server
+        ZooKeeperAdapterSptr zkHandle = get_zkHandle (zkHosts);
+        std::cerr << "[zktreeutil] connected to ZK server for writing"
+            << std::endl;
+
+        // Go to the rooted subtree
+        ZkTreeNodeSptr zkRootSptr = traverseBranch_ (zkRootSptr_, path);
+
+        // Cleanup before write if forceful write enabled
+        if (force)
+        {
+            if (path != "/") // remove the subtree rooted at the znode
+            {
+                // Delete the subtree rooted at the znode before write
+                if (zkHandle->nodeExists (path))
+                {
+                    std::cerr << "[zktreeutil] deleting subtree rooted at "
+                        << path
+                        << "..."
+                        << std::endl;
+                    zkHandle->deleteNode (path, true);
+                }
+            }
+            else // remove the rooted znodes
+            {
+                std::cerr << "[zktreeutil] deleting rooted zk-tree"
+                    << "..."
+                    << std::endl;
+                // Get the root's children
+                vector< string > cnodes = zkHandle->getNodeChildren ("/");
+                for (unsigned i=0; i < cnodes.size(); i++)
+                {
+                    if ( cnodes[i] != "/zookeeper") // reserved for zookeeper 
use
+                        zkHandle->deleteNode(cnodes[i], true);
+                }
+            }
+        }
+
+        // Start tree construction
+        writeZkTree_ (zkHandle, zkRootSptr, path);
+        return;
+    }
+
+    void ZkTreeUtil::dumpZkTree (bool xml, int depth) const
+    {
+        if (xml)
+        {
+            // Creates a new document, a node and set it as a root node
+            xmlDocPtr docPtr = xmlNewDoc(BAD_CAST "1.0");
+            xmlNodePtr rootNode = xmlNewNode(NULL, BAD_CAST "root");
+            xmlDocSetRootElement(docPtr, rootNode);
+
+            // Add all the rooted children
+            for (unsigned i=0; i < zkRootSptr_->numChildren(); i++)
+                xmlAddChild (rootNode, dumpZkTreeXml_ (zkRootSptr_->getChild 
(i)));
+
+            // Dumping document to stdio or file
+            xmlSaveFormatFileEnc("-", docPtr, "UTF-8", 1);
+
+            // Cleanup stuff
+            xmlFreeDoc(docPtr);
+            xmlCleanupParser();
+            return;
+        }
+
+        // Dump text
+        std::cout << "/" << std::endl;
+        vector< bool > masks;
+        for (unsigned i=0; i < zkRootSptr_->numChildren(); i++)
+        {
+            if (i == zkRootSptr_->numChildren()-1)
+                masks.push_back(true);
+            else
+                masks.push_back(false);
+            dumpZkTree_ (zkRootSptr_->getChild (i), depth, 1, masks);
+        }
+
+        return;
+    }
+
+    vector< ZkAction > ZkTreeUtil::diffZkTree (const string& zkHosts,
+            const string& path) const
+    {
+        // Action container
+        vector< ZkAction > actions;
+
+        if (!loaded_)
+        {
+            std::cout << "[zktreeutil] zk-tree not loaded for diff"
+                << std::endl;
+            exit (-1);
+        }
+
+        // Load the rooted subtree from zookeeper
+        ZooKeeperAdapterSptr zkHandle = get_zkHandle (zkHosts);
+        std::cerr << "[zktreeutil] connected to ZK server for reading"
+            << std::endl;
+        ZkTreeNodeSptr zkLiveRootSptr = loadZkTree_ (zkHandle, path);
+
+        // Go to the saved rooted subtree
+        ZkTreeNodeSptr zkLoadedRootSptr =
+            traverseBranch_ (zkRootSptr_, path);
+
+        // Check the root value first
+        if (zkLoadedRootSptr->getData().value
+                != zkLiveRootSptr->getData().value)
+        {
+            actions.push_back (ZkAction (ZkAction::VALUE,
+                        path,
+                        zkLoadedRootSptr->getData().value,
+                        zkLiveRootSptr->getData().value));
+        }
+
+        // Start traversal from root
+        vector< string > ppaths;
+        vector< pair< ZkTreeNodeSptr, ZkTreeNodeSptr > > commonNodes;
+        ppaths.push_back ((path != "/")? path : "");
+        commonNodes.push_back (pair< ZkTreeNodeSptr, ZkTreeNodeSptr >
+                (zkLoadedRootSptr, zkLiveRootSptr));
+
+        for (unsigned j=0; j < commonNodes.size(); j++)
+        {
+            // Get children of loaded tree
+            map< string, ZkTreeNodeSptr > loadedChildren;
+            for (unsigned i=0; i < commonNodes[j].first->numChildren(); i++)
+            {
+                ZkTreeNodeSptr childSptr = commonNodes[j].first->getChild (i);
+                loadedChildren[childSptr->getKey()] = childSptr;
+            }
+            // Get children of live tree
+            map< string, ZkTreeNodeSptr > liveChildren;
+            for (unsigned i=0; i < commonNodes[j].second->numChildren(); i++)
+            {
+                ZkTreeNodeSptr childSptr = commonNodes[j].second->getChild (i);
+                liveChildren[childSptr->getKey()] = childSptr;
+            }
+
+            // Start comparing the children
+            for (map< string, ZkTreeNodeSptr >::const_iterator it =
+                    loadedChildren.begin();
+                    it != loadedChildren.end();
+                    it++)
+            {
+                bool ignoreKey = it->second->getData().ignoreUpdate;
+                string loadedVal = it->second->getData().value;
+                // Path to this node
+                string path = ppaths[j] + string("/") + it->first;
+
+                map< string, ZkTreeNodeSptr >::const_iterator jt =
+                    liveChildren.find (it->first);
+                if (jt != liveChildren.end())
+                {
+                    // Key is present in live zk-tree
+                    string liveVal = jt->second->getData().value;
+                    // Check value for the key, if not ignored
+                    if (!ignoreKey)
+                    {
+                        if (loadedVal != liveVal)
+                        {
+                            // Value differs, set the new value for the key
+                            actions.push_back (ZkAction (ZkAction::VALUE,
+                                        path,
+                                        loadedVal,
+                                        liveVal));
+                        }
+
+                        // Add node to common nodes
+                        ppaths.push_back (path);
+                        commonNodes.push_back (pair< ZkTreeNodeSptr, 
ZkTreeNodeSptr >
+                                (it->second, jt->second));
+                    }
+
+                    // Remove the live zk node
+                    liveChildren.erase (it->first);
+                }
+                else
+                {
+                    // Add the subtree rooted to this node, if not ignored
+                    if (!ignoreKey)
+                        addTreeZkAction_ (it->second, path, actions);
+                }
+            }
+
+            // Remaining live zk nodes to be deleted
+            for (map< string, ZkTreeNodeSptr >::const_iterator it = 
liveChildren.begin();
+                    it != liveChildren.end(); it++)
+            {
+                string path = ppaths[j] + string("/") + it->first;
+                actions.push_back (ZkAction (ZkAction::DELETE, path));
+            }
+        }
+        // return the diff actions
+        return actions;
+    }
+
+    void ZkTreeUtil::executeZkActions (const string& zkHosts,
+            const vector< ZkAction >& zkActions,
+            int execFlags) const
+    {
+        // Execute the diff zk actions
+        if (zkActions.size())
+        {
+            // Connect to Zookeeper for writing
+            ZooKeeperAdapterSptr zkHandleSptr;
+            if ((execFlags & EXECUTE)
+                    || (execFlags & INTERACTIVE))
+            {
+                zkHandleSptr = get_zkHandle (zkHosts);
+                std::cerr << "[zktreeutil] connected to ZK server for writing"
+                    << std::endl;
+            }
+
+            for (unsigned i=0; i < zkActions.size(); i++)
+            {
+                if (zkActions[i].action == ZkAction::CREATE)
+                {
+                    if (execFlags & PRINT)
+                        std::cout << "CREAT- key:" << zkActions[i].key << 
std::endl;
+                    if (execFlags & EXECUTE)
+                    {
+                        if (execFlags & INTERACTIVE)
+                        {
+                            string resp;
+                            std::cout << "Execute this action?[yes/no]: ";
+                            std::getline(std::cin, resp);
+                            if (resp != "yes")
+                                continue;
+                        }
+                        zkHandleSptr->createNode(zkActions[i].key.c_str(), "", 
0, false);
+                    }
+                }
+                else if (zkActions[i].action == ZkAction::DELETE)
+                {
+                    if (execFlags & PRINT)
+                        std::cout << "DELET- key:" << zkActions[i].key << 
std::endl;
+                    if (execFlags & EXECUTE)
+                    {
+                        if (execFlags & INTERACTIVE)
+                        {
+                            string resp;
+                            std::cout << "Execute this action?[yes/no]: ";
+                            std::getline(std::cin, resp);
+                            if (resp != "yes")
+                                continue;
+                        }
+                        zkHandleSptr->deleteNode(zkActions[i].key.c_str(), 
true);
+                    }
+                }
+                else if (zkActions[i].action == ZkAction::VALUE)
+                {
+                    if (execFlags & PRINT)
+                    {
+                        std::cout << "VALUE- key:"
+                            << zkActions[i].key
+                            << " value:" << zkActions[i].newval;
+                        if (zkActions[i].oldval != "")
+                            std::cout << " old_value:" << zkActions[i].oldval;
+                        std::cout << std::endl;
+                    }
+                    if (execFlags & EXECUTE)
+                    {
+                        if (execFlags & INTERACTIVE)
+                        {
+                            string resp;
+                            std::cout << "Execute this action?[yes/no]: ";
+                            std::getline(std::cin, resp);
+                            if (resp != "yes")
+                                continue;
+                        }
+                        zkHandleSptr->setNodeData (zkActions[i].key, 
zkActions[i].newval);
+                    }
+                }
+            }
+        }
+
+        return;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-zktreeutil/src/ZkTreeUtil.h
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-zktreeutil/src/ZkTreeUtil.h 
b/zookeeper-contrib/zookeeper-contrib-zktreeutil/src/ZkTreeUtil.h
new file mode 100644
index 0000000..0a9be03
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-zktreeutil/src/ZkTreeUtil.h
@@ -0,0 +1,262 @@
+/**
+ * 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.
+ */
+
+#ifndef __ZK_TREE_UTIL_H__
+#define __ZK_TREE_UTIL_H__
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include "SimpleTree.h"
+#include "ZkAdaptor.h"
+
+namespace zktreeutil
+{
+
+#define ZKTREEUTIL_INF 1000000000
+    /**
+     * \brief A structure containing ZK node data.
+     */
+    struct ZkNodeData
+    {
+        /**
+         * \brief The value string of the ZK node.
+         */
+        string value;
+
+        /**
+         * \brief The flag indicating whether children of the
+         * \brief node shduld be ignored during create/diff/update
+         */
+        bool ignoreUpdate;
+
+        /**
+         * \brief Constructor.
+         *
+         * @param val the value string
+         * @param ignore the flag indicating ignore any update/diff
+         */
+        ZkNodeData (const string& val, bool ignore=false)
+            : value (val), ignoreUpdate (ignore) {}
+
+        /**
+         * \brief Constructor.
+         *
+         * @param ignore the flag indicating ignore any update/diff
+         */
+        ZkNodeData (bool ignore=false)
+            : ignoreUpdate (ignore) {}
+    };
+
+    /**
+     * \brief The type representing a ZK Treenode
+     */
+    typedef SimpleTreeNode< string, ZkNodeData > ZkTreeNode;
+
+    /**
+     * \brief The type representing a ZK Treenode smart-pointer
+     */
+    typedef boost::shared_ptr< ZkTreeNode > ZkTreeNodeSptr;
+
+    /**
+     * \brief The type representing a ZK Adapter smart-pointer
+     */
+    typedef boost::shared_ptr< ZooKeeperAdapter > ZooKeeperAdapterSptr;
+
+    /**
+     * \brief A structure defining a particular action on ZK node;
+     * \brief the action can be any of -
+     * \brief        CREAT- <zknode>                : creates <zknode> 
recussively
+     * \brief        DELET- <zknode>              : deletes <zknode> 
recursively
+     * \brief        VALUE- <zknode> <value>     : sets <value> to <zknode>
+     */
+    struct ZkAction
+    {
+        /**
+         * \brief The action type; any of create/delete/setvalue.
+         */
+        enum ZkActionType
+        {
+            NONE,
+            CREATE,
+            DELETE,
+            VALUE,
+        };
+
+        /**
+         * \brief action of this instance
+         */
+        ZkActionType action;
+
+        /**
+         * \brief ZK node key
+         */
+        string key;
+
+        /**
+         * \brief value to be set, if action is setvalue
+         */
+        string newval;
+
+        /**
+         * \brief existing value of the ZK node key
+         */
+        string oldval;
+
+        /**
+         * \brief Constructor.
+         */
+        ZkAction ()
+            : action (ZkAction::NONE) {}
+
+        /**
+         * \brief Constructor.
+         *
+         * @param act the action to be taken
+         * @param k the key on which action to be taken
+         */
+        ZkAction (ZkActionType act, const string& k)
+            : action(act),
+            key(k) {}
+
+        /**
+         * \brief Constructor.
+         *
+         * @param act the action to be taken
+         * @param k the key on which action to be taken
+         * @param v the value of the ZK node key
+         */
+        ZkAction (ZkActionType act, const string& k, const string& v)
+            : action(act),
+            key(k),
+            newval(v) {}
+
+        /**
+         * \brief Constructor.
+         *
+         * @param act the action to be taken
+         * @param k the key on which action to be taken
+         * @param nv the new value of the ZK node key
+         * @param ov the old value of the ZK node key
+         */
+        ZkAction (ZkActionType act, const string& k, const string& nv, const 
string& ov)
+            : action (act),
+            key(k),
+            newval(nv),
+            oldval(ov) {}
+    };
+
+    /**
+     * \brief The ZK tree utility class; supports loading ZK tree from ZK 
server OR
+     * \brief from saved XML file, saving ZK tree into XML file, dumping the 
ZK tree
+     * \brief on standard output, creting a diff between saved ZK tree and 
live ZK
+     * \brief tree and incremental update of the live ZK tree.
+     */
+    class ZkTreeUtil
+    {
+        public:
+            /**
+             * \brief Execution flag on ZkAction
+             */
+            enum ZkActionExecuteFlag
+            {
+                NONE = 0,
+                PRINT = 1,
+                EXECUTE = 2,
+                INTERACTIVE = 5,
+            };
+
+        public:
+            /**
+             * \brief Connects to zookeeper and returns a valid ZK handle
+             *
+             * @param zkHosts comma separated list of host:port forming ZK 
quorum
+             * @param a valid ZK handle
+             */
+            static ZooKeeperAdapterSptr get_zkHandle (const string& zkHosts);
+
+
+        public:
+            /**
+             * \brief Constructor.
+             */
+            ZkTreeUtil () : loaded_(false) {}
+
+            /**
+             * \brief loads the ZK tree from ZK server into memory
+             *
+             * @param zkHosts comma separated list of host:port forming ZK 
quorum
+             * @param path path to the subtree to be loaded into memory
+             * @param force forces reloading in case tree already loaded into 
memory
+             */
+            void loadZkTree (const string& zkHosts, const string& path="/", 
bool force=false);
+
+            /**
+             * \brief loads the ZK tree from XML file into memory
+             *
+             * @param zkXmlConfig ZK tree XML file
+             * @param force forces reloading in case tree already loaded into 
memory
+             */
+            void loadZkTreeXml (const string& zkXmlConfig, bool force=false);
+
+            /**
+             * \brief writes the in-memory ZK tree on to ZK server
+             *
+             * @param zkHosts comma separated list of host:port forming ZK 
quorum
+             * @param path path to the subtree to be written to ZK tree
+             * @param force forces cleanup of the ZK tree on the ZK server 
before writing
+             */
+            void writeZkTree (const string& zkHosts, const string& path="/", 
bool force=false) const;
+
+            /**
+             * \brief dupms the in-memory ZK tree on the standard output 
device;
+             *
+             * @param xml flag indicates whether tree should be dumped in XML 
format
+             * @param depth the depth of the tree to be dumped for non-xml dump
+             */
+            void dumpZkTree (bool xml=false, int depth=ZKTREEUTIL_INF) const;
+
+            /** 
+             * \brief returns a list of actions after taking a diff of 
in-memory
+             * \brief ZK tree and live ZK tree.
+             *
+             * @param zkHosts comma separated list of host:port forming ZK 
quorum
+             * @param path path to the subtree in consideration while taking 
diff with ZK tree
+             * @return a list of ZKAction instances to be performed on live ZK 
tree
+             */
+            vector< ZkAction > diffZkTree (const string& zkHosts, const 
string& path="/") const;
+
+            /**
+             * \brief performs create/delete/setvalue by executing a set of
+             * ZkActions on a live ZK tree.
+             *
+             * @param zkHosts comma separated list of host:port forming ZK 
quorum
+             * @param zkActions set of ZkActions
+             * @param execFlags flags indicating print/execute/interactive etc
+             */
+            void executeZkActions (const string& zkHosts,
+                    const vector< ZkAction >& zkActions,
+                    int execFlags) const;
+
+        private:
+
+            ZkTreeNodeSptr zkRootSptr_;     // ZK tree root node
+            bool loaded_;                        // Falg indicating whether ZK 
tree loaded into memory
+    };
+}
+
+#endif // __ZK_TREE_UTIL_H__

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-zktreeutil/src/ZkTreeUtilMain.cc
----------------------------------------------------------------------
diff --git 
a/zookeeper-contrib/zookeeper-contrib-zktreeutil/src/ZkTreeUtilMain.cc 
b/zookeeper-contrib/zookeeper-contrib-zktreeutil/src/ZkTreeUtilMain.cc
new file mode 100644
index 0000000..8afebf6
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-zktreeutil/src/ZkTreeUtilMain.cc
@@ -0,0 +1,247 @@
+/**
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <getopt.h>
+#include <iostream>
+#include "ZkTreeUtil.h"
+
+using namespace zktreeutil;
+
+// The set of "long" options accepted by this program.
+static struct option long_options[] = {
+    {"help",         no_argument,             0, 'h'},
+    {"import",        no_argument,             0, 'I'},
+    {"export",     no_argument,             0, 'E'},
+    {"update",     no_argument,             0, 'U'},
+    {"diff",         no_argument,             0, 'F'},
+    {"dump",         no_argument,             0, 'D'},
+    {"force",         no_argument,             0, 'f'},
+    {"xmlfile",     required_argument,     0, 'x'},
+    {"path",         required_argument,     0, 'p'},
+    {"depth",         required_argument,     0, 'd'},
+    {"zookeeper", required_argument,     0, 'z'},
+    {0, 0, 0, 0}
+};
+static char *short_options = "IEUFDfx:p:d:hz:";
+
+static void usage(int argc, char *argv[])
+{
+    std::cout << "ZK-tree utility for managing ZK-tree with XML 
import/export," << std::endl;
+    std::cout << "viewing diff between live and saved ZK-tree and performing" 
<< std::endl;
+    std::cout << "incremental update of the same." << std::endl;
+    std::cout << "Usage: " << argv[0] << " [args-and-values]+" << std::endl;
+    std::cout 
+        << "\t--import or -I: " 
+        << std::endl
+        << "\t  Imports the zookeeper tree from XML file. Must be specified 
with"
+        << std::endl
+        << "\t  --zookeeper AND --xmlfile options. Optionally takes --path for"
+        << std::endl
+        << "\t  importing subtree"
+        << std::endl;
+    std::cout 
+        << "\t--export or -E: " 
+        << std::endl
+        << "\t  Exports the zookeeper tree to XML file. Must be specified with"
+        << std::endl
+        << "\t  --zookeeper option. Optionally takes --path for exporting 
subtree"
+        << std::endl;
+    std::cout
+        << "\t--update or -U: "
+        << std::endl
+        << "\t  Updates zookeeper tree with changes from XML file. Update 
operation"
+        << std::endl
+        << "\t  is interactive unless specified with --force option. Must be 
speci-"
+        << std::endl
+        << "\t  fied with --zookeeper AND --xmlfile options. Optionally takes 
--path"
+        << std::endl
+        << "\t  for updating subtree."
+        << std::endl;
+    std::cout
+        << "\t--diff or -F: "
+        << std::endl
+        << "\t  Creates a list of diff actions on ZK tree based on XML data. 
Must"
+        << std::endl
+        << "\t  be specified with --zookeeper OR --xmlfile options. Optionally 
takes"
+        << std::endl
+        << "\t  --path for subtree diff"
+        << std::endl;
+    std::cout
+        << "\t--dump or -D: "
+        << std::endl
+        << "\t  Dumps the entire ZK (sub)tree to standard output. Must be 
specified"
+        << std::endl
+        << "\t  with --zookeeper OR --xmlfile options. Optionally takes --path 
and"
+        << std::endl
+        << "\t  --depth for dumping subtree."
+        << std::endl;
+    std::cout
+        << "\t--xmlfile=<filename> or -x <filename>: "
+        << std::endl
+        << "\t  Zookeeper tree-data XML file."
+        << std::endl;
+    std::cout
+        << "\t--path=<znodepath> or -p <znodepath>: "
+        << std::endl
+        << "\t  Path to the zookeeper subtree rootnode."
+        << std::endl;
+    std::cout
+        << "\t--depth=<tree-depth> or -d <tree-depth>: "
+        << std::endl
+        << "\t  Depth of the ZK tree to be dumped (ignored for XML dump)."
+        << std::endl;
+    std::cout
+        << "\t--force or -f: Forces cleanup before import; also used for 
forceful"
+        << std::endl
+        << "\t  update. Optionally be specified with --import and --update."
+        << std::endl;
+    std::cout
+        << "\t--help or -h: "
+        << std::endl
+        << "\t  prints this message"
+        << std::endl;
+    std::cout
+        << "\t--zookeeper=<zkhosts> or -z <zkhosts>: "
+        << std::endl
+        << "\t  specifies information to connect to zookeeper."
+        << std::endl;
+}
+
+int main(int argc, char **argv)
+{
+    if (argc == 1) {
+        usage(argc, argv);
+        exit(0);
+    }
+
+    // Parse the arguments.
+     int op = 0;
+     bool force = false;
+     string zkHosts;
+     string xmlFile;
+     string path = "/";
+     int depth = 0;
+     while (1)
+     {
+         int c = getopt_long(argc, argv, short_options, long_options, 0);
+         if (c == -1)
+             break;
+
+         switch (c) {
+             case 'I': op = c;
+                          break;
+             case 'E': op = c;
+                          break;
+             case 'U': op = c;
+                          break;
+             case 'F': op = c;
+                          break;
+             case 'D': op = c;
+                          break;
+             case 'f': force = true;
+                          break;
+             case 'x': xmlFile = optarg;
+                          break;
+             case 'p': path = optarg;
+                          break;
+             case 'd': depth = atoi (optarg);
+                          break;
+             case 'z': zkHosts = optarg;
+                          break;
+             case 'h': usage (argc, argv);
+                          exit(0);
+         }
+     }
+
+     ZkTreeUtil zkTreeUtil;
+     switch (op)
+     {
+         case 'I':    {
+                            if (zkHosts == "" || xmlFile == "")
+                            {
+                                std::cout << "[zktreeutil] missing params; 
please see usage" << std::endl;
+                                exit (-1);
+                            }
+                            zkTreeUtil.loadZkTreeXml (xmlFile);
+                            zkTreeUtil.writeZkTree (zkHosts, path, force);
+                            std::cout << "[zktreeutil] import successful!" << 
std::endl;
+                            break;
+                        }
+         case 'E':    {
+                            if (zkHosts == "")
+                            {
+                                std::cout << "[zktreeutil] missing params; 
please see usage" << std::endl;
+                                exit (-1);
+                            }
+                            zkTreeUtil.loadZkTree (zkHosts, path);
+                            zkTreeUtil.dumpZkTree (true);
+                            break;
+                        }
+         case 'U':    {
+                            if (zkHosts == "" || xmlFile == "")
+                            {
+                                std::cout << "[zktreeutil] missing params; 
please see usage" << std::endl;
+                                exit (-1);
+                            }
+                            zkTreeUtil.loadZkTreeXml (xmlFile);
+                            vector< ZkAction > zkActions = 
zkTreeUtil.diffZkTree (zkHosts, path);
+                            int flags = ZkTreeUtil::EXECUTE;
+                            if (!force) flags |= ZkTreeUtil::INTERACTIVE;
+                            zkTreeUtil.executeZkActions (zkHosts, zkActions, 
flags);
+                            std::cout << "[zktreeutil] update successful!" << 
std::endl;
+                            break;
+                        }
+         case 'F':    {
+                            if (zkHosts == "" || xmlFile == "")
+                            {
+                                std::cout << "[zktreeutil] missing params; 
please see usage" << std::endl;
+                                exit (-1);
+                            }
+                            zkTreeUtil.loadZkTreeXml (xmlFile);
+                            vector< ZkAction > zkActions = 
zkTreeUtil.diffZkTree (zkHosts, path);
+                            zkTreeUtil.executeZkActions (zkHosts, zkActions, 
ZkTreeUtil::PRINT);
+                            break;
+                        }
+         case 'D':    {
+                            if (zkHosts != "")
+                                zkTreeUtil.loadZkTree (zkHosts, path);
+                            else if (xmlFile != "")
+                                zkTreeUtil.loadZkTreeXml (xmlFile);
+                            else
+                            {
+                                std::cout << "[zktreeutil] missing params; 
please see usage" << std::endl;
+                                exit (-1);
+                            }
+                            // Dump the ZK tree
+                            if (depth) zkTreeUtil.dumpZkTree (false, depth);
+                            else zkTreeUtil.dumpZkTree (false);
+                            break;
+                        }
+     }
+
+     exit(0);
+}
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-zktreeutil/tests/zk_sample.xml
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-zktreeutil/tests/zk_sample.xml 
b/zookeeper-contrib/zookeeper-contrib-zktreeutil/tests/zk_sample.xml
new file mode 100644
index 0000000..6e97daa
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-zktreeutil/tests/zk_sample.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   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.
+-->
+
+<root>
+  <zknode name="myapp">
+    <zknode name="version-1.0">
+      <zknode name="clientConfig">
+        <zknode name="testClient" 
value="cluster.id=local;server.host=localhost;server.port=4080"/>
+      </zknode>
+      <zknode name="configuration" value="v4.0">
+        <zknode name="cacheControl" value="on"/>
+        <zknode name="healthCheck" value="on"/>
+      </zknode>
+      <zknode name="distributions">
+        <zknode name="http">
+          <zknode name="goldenShards" 
value="0,4294967296,server,localhost:8085;"/>
+          <zknode name="versionedShards" 
value="33;0,4294967296,server,localhost:8086;"/>
+          <zknode name="shards" value="0,4294967296,server,localhost:8086;"/>
+        </zknode>
+      </zknode>
+      <zknode name="tmp" ignore="yes">
+        <zknode name="alerts" value="test"/>
+        <zknode name="locks"/>
+        <zknode name="transactions"/>
+      </zknode>
+    </zknode>
+  </zknode>
+  <zknode name="zookeeper" ignore="true"/>
+</root>

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-zooinspector/NOTICE.txt
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-zooinspector/NOTICE.txt 
b/zookeeper-contrib/zookeeper-contrib-zooinspector/NOTICE.txt
new file mode 100644
index 0000000..5420ef0
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-zooinspector/NOTICE.txt
@@ -0,0 +1,9 @@
+src/java/com/nitido/utils/toaster/Toaster.java:
+This java file is copyright by Daniele Piras ("danielepiras80", no email 
known) released under the Apache Software License 2.0
+It has been downloaded in december 2009 from the CVS web interface of the 
sourceforge project http://sourceforge.net/projects/jtoaster/ . The web 
interface to CVS is not available anymore on sourceforge.
+
+The icons in src/main/resources/icons are taken from the Tango project
+downloaded from http://tango.freedesktop.org/releases on 2011-09-06.
+The Tango project is public domain.
+
+Distribution packagers should not include the icons in the package but rather 
depend on tango-icon-theme (Debian package name). ZooInspector will then try to 
get the icons from /usr/share/icons/Tango rather then from its jar file.

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-zooinspector/README.txt
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-zooinspector/README.txt 
b/zookeeper-contrib/zookeeper-contrib-zooinspector/README.txt
new file mode 100644
index 0000000..3c2a58f
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-zooinspector/README.txt
@@ -0,0 +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 
+       zookeeper-3.3.0.jar and do not require any classpath changes you can 
run the zookeeper-dev-ZooInspector.jar
+       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.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-zooinspector/TODO
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-zooinspector/TODO 
b/zookeeper-contrib/zookeeper-contrib-zooinspector/TODO
new file mode 100644
index 0000000..404d5c9
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-zooinspector/TODO
@@ -0,0 +1,19 @@
+- replace JToaster with standard notifications, see:
+  http://www.galago-project.org/specs/notification/
+  
http://stackoverflow.com/questions/857154/freedesktop-org-notifications-in-java
+  DBus and Java:
+  http://bolta-gecko.blogspot.com/2009/06/using-d-bus-in-java.html
+  http://dbus.freedesktop.org/doc/dbus-java/ (packaged in Debian)
+
+- properly respect
+  
http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html
+  http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+  http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
+
+- Rename classes to avoid redundand "ZooInspector" prefix.
+
+- Ant build file has hard coded log4j dependency. (ZK will move to maven 
anyways...)
+
+- make directory for config files configurable via commandline parameter
+
+- Clean up the code! :-)

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-zooinspector/build.xml
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-zooinspector/build.xml 
b/zookeeper-contrib/zookeeper-contrib-zooinspector/build.xml
new file mode 100644
index 0000000..68ea9f7
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-zooinspector/build.xml
@@ -0,0 +1,148 @@
+<!--
+   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" />
+               </copy>
+               <mkdir dir="${build.dir}/config" />
+               <copy todir="${build.dir}/config">
+                       <fileset dir="${basedir}/src/main/resources">
+                               <include name="defaultConnectionSettings.cfg" />
+                               <include name="defaultNodeViewers.cfg" />
+                       </fileset>
+               </copy>
+               <copy todir="${build.dir}/lib">
+                       <fileset 
file="${basedir}/src/main/resources/log4j.properties" />
+               </copy>
+               <copy todir="${build.dir}/lib">
+                       <fileset file="../../build/zookeeper-${version}.jar" />
+               </copy>
+               <copy todir="${build.dir}">
+                       <fileset dir="${basedir}" includes="*.*" 
excludes="build.xml,ivy.xml" />
+               </copy>
+       </target>
+
+       <!-- 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">
+                               <exclude name="*.cfg" />
+                               <exclude name="*.properties" />
+                       </fileset>
+                       <fileset dir="${basedir}/src/main/java" 
excludes="**/*.jar, **/*.java"/>
+               </jar>
+       </target>
+
+       <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" encoding="${build.encoding}">
+                       <classpath refid="classpath" />
+                       <classpath>
+                               <pathelement 
location="${zk.root}/build/test/classes" />
+                       </classpath>
+               </javac>
+       </target>
+
+       <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>
+
+       <target name="test-category">
+               <property name="test.category" value="" />
+       </target>
+
+       <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" />
+                       <classpath refid="classpath" />
+                       <classpath>
+                               <pathelement path="${build.test}" />
+                               <pathelement 
location="${zk.root}/build/test/classes" />
+                       </classpath>
+                       <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" />
+                       </batchtest>
+               </junit>
+               <fail if="tests.failed">Tests failed!</fail>
+       </target>
+
+       <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" />
+               </copy>
+               <mkdir dir="${dist.dir}/contrib/${name}/licences" />
+               <copy todir="${dist.dir}/contrib/${name}/licences">
+                       <fileset dir="${basedir}/licences" />
+               </copy>
+               <mkdir dir="${dist.dir}/contrib/${name}/config" />
+               <copy todir="${dist.dir}/contrib/${name}/config">
+                       <fileset dir="${basedir}/src/main/resources">
+                               <include name="defaultConnectionSettings.cfg" />
+                               <include name="defaultNodeViewers.cfg" />
+                       </fileset>
+               </copy>
+       </target>
+</project>

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-zooinspector/ivy.xml
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-zooinspector/ivy.xml 
b/zookeeper-contrib/zookeeper-contrib-zooinspector/ivy.xml
new file mode 100644
index 0000000..d841d18
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-zooinspector/ivy.xml
@@ -0,0 +1,50 @@
+<!--
+   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.
+-->
+
+<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="com.google.guava" name="guava" rev="18.0" />
+
+    <dependency org="org.slf4j" name="slf4j-api" rev="1.7.5"/>
+    <dependency org="org.slf4j" name="slf4j-log4j12" rev="1.7.5" 
transitive="false"/>
+            
+    <dependency org="log4j" name="log4j" rev="1.2.17" transitive="false"/>
+    <dependency org="junit" name="junit" rev="4.12" 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.2.2" conf="releaseaudit->default"/>
+  </dependencies>
+
+</ivy-module>

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-zooinspector/licences/Apache
 Software Licence v2.0.txt
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-zooinspector/licences/Apache 
Software Licence v2.0.txt 
b/zookeeper-contrib/zookeeper-contrib-zooinspector/licences/Apache Software 
Licence v2.0.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-zooinspector/licences/Apache Software 
Licence v2.0.txt        
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-zooinspector/src/main/java/com/nitido/utils/toaster/Toaster.java
----------------------------------------------------------------------
diff --git 
a/zookeeper-contrib/zookeeper-contrib-zooinspector/src/main/java/com/nitido/utils/toaster/Toaster.java
 
b/zookeeper-contrib/zookeeper-contrib-zooinspector/src/main/java/com/nitido/utils/toaster/Toaster.java
new file mode 100644
index 0000000..cc123ba
--- /dev/null
+++ 
b/zookeeper-contrib/zookeeper-contrib-zooinspector/src/main/java/com/nitido/utils/toaster/Toaster.java
@@ -0,0 +1,533 @@
+/**
+ * This java file is copyright by Daniele Piras ("danielepiras80", no email 
known) released under the
+ * Apache Software License 2.0. It has been downloaded in december 2009 from 
the CVS web interface
+ * of the sourceforge project http://sourceforge.net/projects/jtoaster/ . The 
web interface to CVS
+ * is not available anymore on sourceforge.
+ *
+ */
+
+/**
+ * Java Toaster is a java utility class for your swing applications
+ * that show an animate box coming from the bottom of your screen
+ * with a notification message and/or an associated image
+ * (like msn online/offline notifications).
+ *
+ * Toaster panel in windows system follow the taskbar; So if
+ * the taskbar is into the bottom the panel coming from the bottom
+ * and if the taskbar is on the top then the panel coming from the top.
+ *
+ * This is a simple example of utilization:
+ *
+ * import com.nitido.utils.toaster.*;
+ * import javax.swing.*;
+ *
+ * public class ToasterTest
+ * {
+ *
+ *  public static void main(String[] args)
+ *  {
+ *   // Initialize toaster manager...
+ *   Toaster toasterManager = new Toaster();
+ *
+ *   // Show a simple toaster
+ *   toasterManager.showToaster( new ImageIcon( "mylogo.gif" ), "A simple 
toaster with an image" );
+ *  }
+ * }
+ */
+package com.nitido.utils.toaster;
+
+import java.awt.*;
+
+import javax.swing.*;
+import javax.swing.border.*;
+
+/**
+ * Class to show tosters in multiplatform
+ *
+ * @author daniele piras
+ *
+ */
+public class Toaster
+{
+       // Width of the toster
+       private int toasterWidth = 300;
+
+       // Height of the toster
+       private int toasterHeight = 80;
+
+       // Step for the toaster
+       private int step = 20;
+
+       // Step time
+       private int stepTime = 20;
+
+       // Show time
+       private int displayTime = 3000;
+
+       // Current number of toaster...
+       private int currentNumberOfToaster = 0;
+
+       // Last opened toaster
+       private int maxToaster = 0;
+
+       // Max number of toasters for the sceen
+       private int maxToasterInSceen;
+
+       // Font used to display message
+       private Font font;
+
+  // Color for border
+       private Color borderColor;
+
+  // Color for toaster
+       private Color toasterColor;
+
+  // Set message color
+       private Color messageColor;
+
+       // Set the margin
+       int margin;
+
+       // Flag that indicate if use alwaysOnTop or not.
+       // method always on top start only SINCE JDK 5 !
+       boolean useAlwaysOnTop = true;
+
+       private static final long serialVersionUID = 1L;
+
+       /**
+        * Constructor to initialized toaster component...
+        *
+        * @author daniele piras
+        *
+        */
+       public Toaster()
+       {
+               // Set default font...
+               font = new Font("Arial", Font.BOLD, 12);
+               // Border color
+               borderColor = new Color(245, 153, 15);
+               toasterColor = Color.WHITE;
+               messageColor = Color.BLACK;
+               useAlwaysOnTop = true;
+               // Verify AlwaysOnTop Flag...
+               try
+               {
+                 JWindow.class.getMethod( "setAlwaysOnTop", new Class[] { 
Boolean.class } );
+               }
+               catch( Exception e )
+               {
+                       useAlwaysOnTop = false;
+               }
+
+       }
+
+       /**
+        * Class that rappresent a single toaster
+        *
+        * @author daniele piras
+        *
+        */
+       class SingleToaster extends javax.swing.JWindow
+       {
+               private static final long serialVersionUID = 1L;
+
+               // Label to store Icon
+               private JLabel iconLabel = new JLabel();
+
+               // Text area for the message
+               private JTextArea message = new JTextArea();
+
+
+
+
+               /***
+                * Simple costructor that initialized components...
+                */
+               public SingleToaster()
+               {
+                       initComponents();
+               }
+
+               /***
+                * Function to initialized components
+                */
+               private void initComponents()
+               {
+
+                       setSize(toasterWidth, toasterHeight);
+                       message.setFont( getToasterMessageFont() );
+                       JPanel externalPanel = new JPanel(new BorderLayout(1, 
1));
+                       externalPanel.setBackground( getBorderColor() );
+                       JPanel innerPanel = new JPanel(new BorderLayout( 
getMargin(), getMargin() ));
+                       innerPanel.setBackground( getToasterColor() );
+                       message.setBackground( getToasterColor() );
+                       message.setMargin( new Insets( 2,2,2,2 ) );
+                       message.setLineWrap( true );
+                       message.setWrapStyleWord( true );
+
+                       EtchedBorder etchedBorder = (EtchedBorder) BorderFactory
+                                       .createEtchedBorder();
+                       externalPanel.setBorder(etchedBorder);
+
+                       externalPanel.add(innerPanel);
+      message.setForeground( getMessageColor() );
+                       innerPanel.add(iconLabel, BorderLayout.WEST);
+                       innerPanel.add(message, BorderLayout.CENTER);
+                       getContentPane().add(externalPanel);
+               }
+
+
+               /***
+                * Start toaster animation...
+                */
+               public void animate()
+               {
+                       ( new Animation( this ) ).start();
+               }
+
+       }
+
+       /***
+        * Class that manage the animation
+        */
+       class Animation extends Thread
+       {
+               SingleToaster toaster;
+
+               public Animation( SingleToaster toaster )
+               {
+                       this.toaster = toaster;
+               }
+
+
+               /**
+                * Animate vertically the toaster. The toaster could be moved 
from bottom
+                * to upper or to upper to bottom
+                * @param posx
+                * @param fromy
+                * @param toy
+                * @throws InterruptedException
+                */
+               protected void animateVertically( int posx, int fromY, int toY 
) throws InterruptedException
+               {
+
+                       toaster.setLocation( posx, fromY );
+                       if ( toY < fromY )
+                       {
+                               for (int i = fromY; i > toY; i -= step)
+                               {
+                                       toaster.setLocation(posx, i);
+                                       Thread.sleep(stepTime);
+                               }
+                       }
+                       else
+                       {
+                               for (int i = fromY; i < toY; i += step)
+                               {
+                                       toaster.setLocation(posx, i);
+                                       Thread.sleep(stepTime);
+                               }
+                       }
+                       toaster.setLocation( posx, toY );
+               }
+
+               public void run()
+               {
+                       try
+                       {
+                               boolean animateFromBottom = true;
+                               GraphicsEnvironment ge = GraphicsEnvironment
+                                               .getLocalGraphicsEnvironment();
+                               Rectangle screenRect = 
ge.getMaximumWindowBounds();
+
+                               int screenHeight = (int) screenRect.height;
+
+                               int startYPosition;
+                               int stopYPosition;
+
+                               if ( screenRect.y > 0 )
+                               {
+                                 animateFromBottom = false; // Animate from 
top!
+                               }
+
+                               maxToasterInSceen = screenHeight / 
toasterHeight;
+
+
+                               int posx = (int) screenRect.width - 
toasterWidth - 1;
+
+                               toaster.setLocation(posx, screenHeight);
+                               toaster.setVisible(true);
+                               if ( useAlwaysOnTop )
+                               {
+                                 toaster.setAlwaysOnTop(true);
+                               }
+
+                               if ( animateFromBottom )
+                               {
+                                       startYPosition = screenHeight;
+                                       stopYPosition = startYPosition - 
toasterHeight - 1;
+                                       if ( currentNumberOfToaster > 0 )
+                                       {
+                                               stopYPosition = stopYPosition - 
( maxToaster % maxToasterInSceen * toasterHeight );
+                                       }
+                                       else
+                                       {
+                                               maxToaster = 0;
+                                       }
+                               }
+                               else
+                               {
+                                       startYPosition = screenRect.y - 
toasterHeight;
+                                       stopYPosition = screenRect.y;
+
+                                       if ( currentNumberOfToaster > 0 )
+                                       {
+                                               stopYPosition = stopYPosition + 
( maxToaster % maxToasterInSceen * toasterHeight );
+                                       }
+                                       else
+                                       {
+                                               maxToaster = 0;
+                                       }
+                               }
+
+                               currentNumberOfToaster++;
+                               maxToaster++;
+
+
+                               animateVertically( posx, startYPosition, 
stopYPosition );
+                               Thread.sleep(displayTime);
+                               animateVertically( posx, stopYPosition, 
startYPosition );
+
+                               currentNumberOfToaster--;
+                               toaster.setVisible(false);
+                               toaster.dispose();
+                       } catch (Exception e)
+                       {
+                               e.printStackTrace();
+                       }
+               }
+       }
+
+
+
+       /**
+        * Show a toaster with the specified message and the associated icon.
+        */
+       public void showToaster(Icon icon, String msg)
+       {
+    SingleToaster singleToaster = new SingleToaster();
+    if ( icon != null )
+    {
+      singleToaster.iconLabel.setIcon( icon );
+    }
+    singleToaster.message.setText( msg );
+               singleToaster.animate();
+       }
+
+       /**
+        * Show a toaster with the specified message.
+        */
+       public void showToaster( String msg )
+       {
+               showToaster( null, msg );
+       }
+
+       /**
+        * @return Returns the font
+        */
+       public Font getToasterMessageFont()
+       {
+               // TODO Auto-generated method stub
+               return font;
+       }
+
+       /**
+        * Set the font for the message
+        */
+       public void setToasterMessageFont( Font f)
+       {
+    font = f;
+       }
+
+
+       /**
+        * @return Returns the borderColor.
+        */
+       public Color getBorderColor()
+       {
+               return borderColor;
+       }
+
+
+
+       /**
+        * @param borderColor The borderColor to set.
+        */
+       public void setBorderColor(Color borderColor)
+       {
+               this.borderColor = borderColor;
+       }
+
+
+
+       /**
+        * @return Returns the displayTime.
+        */
+       public int getDisplayTime()
+       {
+               return displayTime;
+       }
+
+
+
+       /**
+        * @param displayTime The displayTime to set.
+        */
+       public void setDisplayTime(int displayTime)
+       {
+               this.displayTime = displayTime;
+       }
+
+
+
+       /**
+        * @return Returns the margin.
+        */
+       public int getMargin()
+       {
+               return margin;
+       }
+
+
+
+       /**
+        * @param margin The margin to set.
+        */
+       public void setMargin(int margin)
+       {
+               this.margin = margin;
+       }
+
+
+
+       /**
+        * @return Returns the messageColor.
+        */
+       public Color getMessageColor()
+       {
+               return messageColor;
+       }
+
+
+
+       /**
+        * @param messageColor The messageColor to set.
+        */
+       public void setMessageColor(Color messageColor)
+       {
+               this.messageColor = messageColor;
+       }
+
+
+
+       /**
+        * @return Returns the step.
+        */
+       public int getStep()
+       {
+               return step;
+       }
+
+
+
+       /**
+        * @param step The step to set.
+        */
+       public void setStep(int step)
+       {
+               this.step = step;
+       }
+
+
+
+       /**
+        * @return Returns the stepTime.
+        */
+       public int getStepTime()
+       {
+               return stepTime;
+       }
+
+
+
+       /**
+        * @param stepTime The stepTime to set.
+        */
+       public void setStepTime(int stepTime)
+       {
+               this.stepTime = stepTime;
+       }
+
+
+
+       /**
+        * @return Returns the toasterColor.
+        */
+       public Color getToasterColor()
+       {
+               return toasterColor;
+       }
+
+
+
+       /**
+        * @param toasterColor The toasterColor to set.
+        */
+       public void setToasterColor(Color toasterColor)
+       {
+               this.toasterColor = toasterColor;
+       }
+
+
+
+       /**
+        * @return Returns the toasterHeight.
+        */
+       public int getToasterHeight()
+       {
+               return toasterHeight;
+       }
+
+
+
+       /**
+        * @param toasterHeight The toasterHeight to set.
+        */
+       public void setToasterHeight(int toasterHeight)
+       {
+               this.toasterHeight = toasterHeight;
+       }
+
+
+
+       /**
+        * @return Returns the toasterWidth.
+        */
+       public int getToasterWidth()
+       {
+               return toasterWidth;
+       }
+
+
+
+       /**
+        * @param toasterWidth The toasterWidth to set.
+        */
+       public void setToasterWidth(int toasterWidth)
+       {
+               this.toasterWidth = toasterWidth;
+       }
+
+
+
+}

Reply via email to