From commits-return-6732-archive-asf-public=cust-asf.ponee.io@zookeeper.apache.org Mon Aug 6 14:13:31 2018 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx-eu-01.ponee.io (Postfix) with SMTP id 851BE180797 for ; Mon, 6 Aug 2018 14:13:28 +0200 (CEST) Received: (qmail 44036 invoked by uid 500); 6 Aug 2018 12:13:27 -0000 Mailing-List: contact commits-help@zookeeper.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@zookeeper.apache.org Delivered-To: mailing list commits@zookeeper.apache.org Received: (qmail 43545 invoked by uid 99); 6 Aug 2018 12:13:27 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 06 Aug 2018 12:13:27 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id C14A1E0A96; Mon, 6 Aug 2018 12:13:26 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: andor@apache.org To: commits@zookeeper.apache.org Date: Mon, 06 Aug 2018 12:13:30 -0000 Message-Id: <07ba97cea91545cdb43f5c5b12f7ab7b@git.apache.org> In-Reply-To: <13bf07ba1f73429dae991fd13f50d7a5@git.apache.org> References: <13bf07ba1f73429dae991fd13f50d7a5@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [05/45] zookeeper git commit: ZOOKEEPER-3030: MAVEN MIGRATION - Step 1.3 - move contrib directories http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/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 +#include +#include +#include +#include + +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 << " "; + } + } + 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/b0df8fe1/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 +#include +#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- : creates recussively + * \brief DELET- : deletes recursively + * \brief VALUE- : sets to + */ + 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/b0df8fe1/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 +#endif + +#include +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#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= or -x : " + << std::endl + << "\t Zookeeper tree-data XML file." + << std::endl; + std::cout + << "\t--path= or -p : " + << std::endl + << "\t Path to the zookeeper subtree rootnode." + << std::endl; + std::cout + << "\t--depth= or -d : " + << 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= or -z : " + << 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/b0df8fe1/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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/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/b0df8fe1/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/b0df8fe1/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/b0df8fe1/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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Tests failed! + + + + + + + + + + + + + + + + + + + + + + + http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/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 @@ + + + + + + + + ZooInspector + + + + + + + + + + + + + + + + + + + + + + http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/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/b0df8fe1/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; + } + + + +}