zookeeper-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From an...@apache.org
Subject [23/45] zookeeper git commit: ZOOKEEPER-3030: MAVEN MIGRATION - Step 1.3 - move contrib directories
Date Mon, 06 Aug 2018 12:14:32 GMT
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/build-contrib.xml
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/build-contrib.xml b/zookeeper-contrib/build-contrib.xml
new file mode 100644
index 0000000..4b81f8a
--- /dev/null
+++ b/zookeeper-contrib/build-contrib.xml
@@ -0,0 +1,233 @@
+<?xml version="1.0"?>
+
+<!--
+   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.
+-->
+
+<!-- Imported by contrib/*/build.xml files to share generic targets. -->
+
+<project name="zookeeperbuildcontrib" xmlns:ivy="antlib:org.apache.ivy.ant">
+
+  <property name="name" value="${ant.project.name}"/>
+  <property name="version" value="dev"/>
+  <property name="root" value="${basedir}"/>
+
+  <property name="zk.root" location="${root}/../../"/>
+
+  <property name="src.dir"  location="${root}/src/main/java"/>
+  <property name="src.test" location="${root}/src/test"/>
+
+  <property name="lib.dir"  location="${zk.root}/src/java/lib"/>
+
+  <property name="build.dir" location="${zk.root}/build/contrib/${name}"/>
+  <property name="build.classes" location="${build.dir}/classes"/>
+  <property name="build.test" location="${build.dir}/test"/>
+
+  <property name="javac.deprecation" value="on"/>
+  <property name="javac.debug" value="on"/>
+
+  <property name="build.encoding" value="utf8"/>
+
+  <property name="ivy.version" value="2.4.0"/>
+  <property name="ivy.url"
+            value="https://repo1.maven.org/maven2/org/apache/ivy/ivy" />
+  <property name="ivy.home" value="${user.home}/.ant" />
+  <property name="ivy.lib" value="${build.dir}/lib"/>
+  <property name="ivy.test.lib" value="${build.test}/lib"/>
+  <property name="ivysettings.xml" value="${zk.root}/ivysettings.xml"/>
+
+  <!-- to be overridden by sub-projects -->
+  <target name="check-contrib"/>
+  <target name="init-contrib"/>
+
+  <property name="lib.jars.includes" value="lib/*.jar" />
+  <property name="lib.jars.excludes" value="" />
+
+  <!-- prior to ant 1.7.1 fileset always fails if dir doesn't exist
+       so just point to bin directory and provide settings that exclude
+       everything - user can change as appropriate -->
+  <property name="additional.lib.dir" value="${zk.root}/bin" />
+  <property name="additional.lib.dir.includes" value="**/*.jar" />
+  <property name="additional.lib.dir.excludes" value="**/*.jar" />
+
+  <fileset id="lib.jars" dir="${root}">
+    <include name="${lib.jars.includes}" />
+    <exclude name="${lib.jars.excludes}" />
+  </fileset>
+
+  <path id="classpath">
+    <pathelement location="${build.classes}"/>
+    <!-- allow the user to override (e.g. if there are local versions) -->
+    <fileset dir="${additional.lib.dir}">
+      <include name="${additional.lib.dir.includes}" />
+      <exclude name="${additional.lib.dir.excludes}" />
+    </fileset>
+    <fileset refid="lib.jars"/>
+    <pathelement location="${zk.root}/build/classes"/>
+    <fileset dir="${ivy.lib}">
+      <include name="**/*.jar" />
+    </fileset>
+    <fileset dir="${ivy.test.lib}">
+      <include name="**/*.jar" />
+    </fileset>
+    <fileset dir="${zk.root}/src/java/lib">
+      <include name="**/*.jar" />
+    </fileset>
+    <fileset dir="${ant.home}/lib">
+      <include name="ant.jar" />
+    </fileset>
+  </path>
+
+  <!-- ====================================================== -->
+  <!-- Stuff needed by all targets                            -->
+  <!-- ====================================================== -->
+  <target name="init" depends="check-contrib" unless="skip.contrib">
+    <echo message="contrib: ${name}"/>
+    <mkdir dir="${build.dir}"/>
+    <mkdir dir="${build.classes}"/>
+    <mkdir dir="${build.test}"/>
+
+    <mkdir dir="${ivy.lib}"/>
+    <mkdir dir="${ivy.test.lib}"/>
+    <condition property="ivy.jar.exists">
+      <available file="${lib.dir}/ivy-${ivy.version}.jar"/>
+    </condition>
+
+    <antcall target="init-contrib"/>
+  </target>
+
+  <!-- ====================================================== -->
+  <!-- Compile a contrib's files                              -->
+  <!-- ====================================================== -->
+  <target name="compile" depends="init"
+          unless="skip.contrib">
+    <echo message="contrib: ${name}"/>
+
+    <javac
+     encoding="${build.encoding}"
+     srcdir="${src.dir}"
+     includes="**/*.java"
+     destdir="${build.classes}"
+     debug="${javac.debug}"
+     deprecation="${javac.deprecation}">
+      <classpath refid="classpath"/>
+    </javac>
+  </target>
+
+  <!-- ====================================================== -->
+  <!-- Make a contrib's jar                                   -->
+  <!-- ====================================================== -->
+  <target name="jar" depends="compile" unless="skip.contrib">
+    <echo message="contrib: ${name}"/>
+    <jar
+      jarfile="${build.dir}/zookeeper-${version}-${name}.jar"
+      basedir="${build.classes}"      
+    />
+  </target>
+
+  <!-- ====================================================== -->
+  <!-- Package a contrib's files                              -->
+  <!-- ====================================================== -->
+  <target name="package" depends="jar" unless="skip.contrib"> 
+    <echo message="contrib: ${name}"/>
+
+    <mkdir dir="${dist.dir}${package.share}/contrib/${name}"/>
+    <copy todir="${dist.dir}${package.share}/contrib/${name}" includeEmptyDirs="false"
+          flatten="true">
+      <fileset dir="${build.dir}">
+        <include name="zookeeper-${version}-${name}.jar" />
+      </fileset>
+    </copy>
+  </target>
+
+  <!-- ====================================================== -->
+  <!-- Package a contrib's files                              -->
+  <!-- ====================================================== -->
+  <target name="package-native" depends="jar" unless="skip.contrib">
+    <echo message="contrib: ${name}"/>
+  </target>
+
+  <!-- ================================================================== -->
+  <!-- Clean.  Delete the build files, and their directories              -->
+  <!-- ================================================================== -->
+  <target name="clean">
+    <echo message="contrib: ${name}"/>
+    <delete dir="${build.dir}"/>
+  </target>
+
+
+  <!-- ================================================================== -->
+  <!-- Utility features                                                   -->
+  <!-- ================================================================== -->
+
+  <target name="checkMainIsAvailable">
+    <available classname="org.apache.zookeeper.ZooKeeperMain"
+               property="mainIsCompiled">
+      <!-- we can't use id=classpath, because available fails if fileset directory
+           doesn't exist -->
+      <classpath>
+        <pathelement location="${zk.root}/build/classes"/>
+      </classpath>
+    </available>
+  </target>
+
+  <target name="checkMainCompiled" unless="mainIsCompiled" depends="checkMainIsAvailable">
+    <fail message="ZooKeeper main must first be compiled (toplevel build.xml)"/>
+  </target>
+
+
+  <target name="checkMainTestIsAvailable">
+    <available file="${zk.root}/build/test/classes/org/apache/zookeeper/test/ClientBase.class"
+               property="mainTestIsCompiled">
+    </available>
+  </target>
+
+  <target name="checkMainTestCompiled" unless="mainTestIsCompiled" depends="checkMainTestIsAvailable">
+    <fail message="ZooKeeper test must first be compiled (toplevel build.xml) using 'ant compile-test'"/>
+  </target>
+
+  <!-- ====================================================== -->
+  <!-- Ivy                                                    -->
+  <!-- ====================================================== -->
+  <target name="ivy-download" unless="ivy.jar.exists" depends="init">
+    <delete dir="${lib.dir}"
+            includes="ivy-*.jar" excludes="ivy-${ivy.version}.jar"/>
+    <get src="${ivy.url}/${ivy.version}/ivy-${ivy.version}.jar"
+         dest="${lib.dir}/ivy-${ivy.version}.jar" usetimestamp="true"/>
+  </target>
+
+  <target name="ivy-init" depends="ivy-download" unless="ivy.initialized">
+    <taskdef resource="org/apache/ivy/ant/antlib.xml"
+             uri="antlib:org.apache.ivy.ant" classpathref="classpath"/>
+    <!-- ensure that ivy taskdef is only run once, otw ant will error -->
+    <property name="ivy.initialized" value="true"/>
+    <ivy:settings id="${ant.project.name}" file="${ivysettings.xml}"/> 
+  </target>
+
+  <target name="ivy-retrieve" depends="init,ivy-init">
+    <ivy:retrieve settingsRef="${ant.project.name}" type="jar" conf="default"
+                  pattern="${ivy.lib}/[artifact]-[revision].[ext]"/>
+    <ivy:retrieve settingsRef="${ant.project.name}" type="bundle" conf="default"
+  				  pattern="${ivy.lib}/[artifact]-[revision].[ext]"/>
+  </target>
+
+  <target name="ivy-retrieve-test" depends="init,ivy-init">
+    <ivy:retrieve settingsRef="${ant.project.name}" type="jar" conf="test"
+                  pattern="${ivy.test.lib}/[artifact]-[revision].[ext]"/>
+  </target>
+
+
+</project>

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/build.xml
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/build.xml b/zookeeper-contrib/build.xml
new file mode 100644
index 0000000..bfb6f66
--- /dev/null
+++ b/zookeeper-contrib/build.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+
+<!--
+   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="zookeepercontrib" default="compile" basedir=".">
+
+  <property name="contribfilesetincludes" value="*/build.xml" />
+  <property name="contribfilesetexcludes" value="zookeeper-contrib-fatjar/build.xml" />
+
+  <fileset id="contribfileset" dir=".">
+    <include name="${contribfilesetincludes}"/>
+    <exclude name="${contribfilesetexcludes}"/>
+  </fileset>
+
+  <!-- In case one of the contrib subdirectories -->
+  <!-- fails the build or test targets and you cannot fix it: -->
+  <!-- Then add to fileset: excludes="badcontrib/build.xml" -->
+
+  <!-- ====================================================== -->
+  <!-- Compile contribs.                                      -->
+  <!-- ====================================================== -->
+  <target name="compile">
+    <subant target="jar">
+      <fileset refid="contribfileset" />
+    </subant>
+  </target>
+  
+  <!-- ====================================================== -->
+  <!-- Package contrib jars.                                  -->
+  <!-- ====================================================== -->
+  <target name="package">
+    <subant target="package">
+      <fileset refid="contribfileset" />
+    </subant>
+  </target>
+
+  <!-- ====================================================== -->
+  <!-- Test all the contribs.                               -->
+  <!-- ====================================================== -->
+  <target name="test">
+    <subant target="test">
+      <fileset refid="contribfileset" />
+    </subant>
+  </target>
+  
+  
+  <!-- ====================================================== -->
+  <!-- Clean all the contribs.                              -->
+  <!-- ====================================================== -->
+  <target name="clean">
+    <subant target="clean">
+      <fileset refid="contribfileset" />
+    </subant>
+  </target>
+</project>

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-fatjar/README.txt
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-fatjar/README.txt b/zookeeper-contrib/zookeeper-contrib-fatjar/README.txt
new file mode 100644
index 0000000..f8027ae
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-fatjar/README.txt
@@ -0,0 +1,2 @@
+This package contains build to create a fat zookeeper jar. You need to run ant to create the fat jar.
+To run the fatjar you can use. java -jar zoookeeper-*fatjar.jar 

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-fatjar/build.xml
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-fatjar/build.xml b/zookeeper-contrib/zookeeper-contrib-fatjar/build.xml
new file mode 100644
index 0000000..6f34a92
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-fatjar/build.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0"?>
+
+<!--
+   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="fatjar" default="jar">
+  <import file="../build-contrib.xml"/>
+
+  <target name="setjarname">
+    <property name="jarname"
+              value="${build.dir}/zookeeper-${version}-${name}.jar"/>
+  </target>
+
+  <!-- Override jar target to specify main class -->
+  <target name="jar" depends="checkMainCompiled, setjarname, compile">
+    <echo message="contrib: ${name}"/>
+    <jar jarfile="${jarname}">
+      <manifest>
+        <attribute name="Main-Class" value="org.apache.zookeeper.util.FatJarMain" />
+        <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="${basedir}/src/main/resources/mainClasses" />
+      <fileset dir="${build.classes}"/>
+      <fileset dir="${build.test}"/>
+      <fileset file="${zk.root}/LICENSE.txt" />
+      <fileset file="${zk.root}/conf/log4j.properties" />
+      <fileset dir="${zk.root}/build/classes" excludes="**/.generated"/>
+      <fileset dir="${zk.root}/build/test/classes"/>
+      <zipgroupfileset dir="${zk.root}/build/lib" includes="*.jar" />
+      <zipgroupfileset dir="${zk.root}/build/test/lib" includes="*.jar" />
+      <zipgroupfileset dir="${zk.root}/src/java/lib" includes="*.jar" />
+    </jar>
+  </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}/conf"/>
+    <copy todir="${dist.dir}/contrib/${name}/conf">
+      <fileset dir="${basedir}/src/main/resources"/>
+    </copy>
+
+    <mkdir dir="${dist.dir}/contrib/${name}/src"/>
+    <copy todir="${dist.dir}/contrib/${name}/src">
+      <fileset dir="${basedir}/src"/>
+    </copy>
+  </target>
+
+	<target name="test">
+		<echo message="No test target defined for this package" />
+	</target>
+</project>
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-fatjar/src/main/java/org/apache/zookeeper/util/FatJarMain.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-fatjar/src/main/java/org/apache/zookeeper/util/FatJarMain.java b/zookeeper-contrib/zookeeper-contrib-fatjar/src/main/java/org/apache/zookeeper/util/FatJarMain.java
new file mode 100644
index 0000000..bdf0eae
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-fatjar/src/main/java/org/apache/zookeeper/util/FatJarMain.java
@@ -0,0 +1,126 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * This is a generic Main class that is completely driven by the
+ * /mainClasses resource on the class path. This resource has the
+ * format:
+ * <pre>
+ * cmd:mainClass:Description
+ * </pre>
+ * Any lines starting with # will be skipped
+ *
+ */
+public class FatJarMain {
+    static class Cmd {
+        Cmd(String cmd, String clazz, String desc) {
+            this.cmd = cmd;
+            this.clazz = clazz;
+            this.desc = desc;
+        }
+        String cmd;
+        String clazz;
+        String desc;
+    }
+    static HashMap<String, Cmd> cmds = new HashMap<String, Cmd>();
+    static ArrayList<String> order = new ArrayList<String>();
+    
+    /**
+     * @param args the first parameter of args will be used as an
+     * index into the /mainClasses resource. The rest will be passed
+     * to the mainClass to run.
+     * @throws IOException 
+     * @throws ClassNotFoundException 
+     * @throws NoSuchMethodException 
+     * @throws SecurityException 
+     * @throws IllegalAccessException 
+     * @throws IllegalArgumentException 
+     */
+    public static void main(String[] args) throws IOException, ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException {
+        InputStream is = FatJarMain.class.getResourceAsStream("/mainClasses");
+        if (is == null) {
+            System.err.println("Couldn't find /mainClasses in classpath.");
+            System.exit(3);
+        }
+        BufferedReader br = new BufferedReader(new InputStreamReader(is));
+        String line;
+        while((line = br.readLine()) != null) {
+            String parts[] = line.split(":", 3);
+            if (parts.length != 3 || (parts[0].length() > 0 && parts[0].charAt(0) == '#')) {
+                continue;
+            }
+            if (parts[0].length() > 0) {
+                cmds.put(parts[0], new Cmd(parts[0], parts[1], parts[2]));
+                // We use the order array to preserve the order of the commands
+                // for help. The hashmap will not preserver order. (It may be overkill.)
+                order.add(parts[0]);
+            } else {
+                // Just put the description in
+                order.add(parts[2]);
+            }
+        }
+        if (args.length == 0) {
+            doHelp();
+            return;
+        }
+        Cmd cmd = cmds.get(args[0]);
+        if (cmd == null) {
+            doHelp();
+            return;
+        }
+        Class<?> clazz = Class.forName(cmd.clazz);
+        Method main = clazz.getMethod("main", String[].class);
+        String newArgs[] = new String[args.length-1];
+        System.arraycopy(args, 1, newArgs, 0, newArgs.length);
+        try {
+            main.invoke(null, (Object)newArgs);
+        } catch(InvocationTargetException e) {
+            if (e.getCause() != null) {
+                e.getCause().printStackTrace();
+            } else {
+                e.printStackTrace();
+            }
+        }
+    }
+    
+    private static void doHelp() {
+        System.err.println("USAGE: FatJarMain cmd args");
+        System.err.println("Available cmds:");
+        for(String c: order) {
+            Cmd cmd = cmds.get(c);
+            if (cmd != null) {
+                System.err.println("  " + c + " " + cmd.desc);
+            } else {
+                System.err.println(c);
+            }
+        }
+        System.exit(2);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-fatjar/src/main/resources/mainClasses
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-fatjar/src/main/resources/mainClasses b/zookeeper-contrib/zookeeper-contrib-fatjar/src/main/resources/mainClasses
new file mode 100644
index 0000000..2b0fc83
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-fatjar/src/main/resources/mainClasses
@@ -0,0 +1,10 @@
+::Client Commands
+client:org.apache.zookeeper.ZooKeeperMain:Client shell to ZooKeeper
+::Server Commands
+server:org.apache.zookeeper.server.quorum.QuorumPeerMain:Start ZooKeeper server
+::Test Commands
+generateLoad:org.apache.zookeeper.test.system.GenerateLoad:A distributed load generator for testing
+quorumBench:org.apache.zookeeper.server.QuorumBenchmark:A benchmark of just the quorum protocol
+abBench:org.apache.zookeeper.server.quorum.AtomicBroadcastBenchmark:A benchmark of just the atomic broadcast
+ic:org.apache.zookeeper.test.system.InstanceContainer:A container that will instantiate classes as directed by an instance manager
+systest:org.apache.zookeeper.test.system.BaseSysTest:Start system test

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/README
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/README b/zookeeper-contrib/zookeeper-contrib-huebrowser/README
new file mode 100644
index 0000000..c03ea90
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/README
@@ -0,0 +1,62 @@
+
+ZooKeeper Browser - Hue Application
+===================================
+
+The ZooKeeper Browser application allows you to see how the cluster nodes are working and also allows you to do CRUD operations on the znode hierarchy.
+
+Requirements
+------------
+
+Hue-1.0:
+  * http://github.com/downloads/cloudera/hue/hue-1.0.tgz
+  * http://github.com/downloads/cloudera/hue/release-notes-1.0.html
+
+ZooKeeper REST gateway:
+  * available as contrib: contrib/rest
+
+How to install?
+---------------
+
+First of all you need to install Hue 1.0 release:
+
+  * http://archive.cloudera.com/cdh/3/hue/sdk/sdk.html
+  * http://github.com/cloudera/hue/tree/release-1.0
+
+After you finish the previous step you should copy the zkui/ folder to apps/ and register the new application:
+
+  * $ ./build/env/bin/python tools/app_reg/app_reg.py --install apps/zkui
+  * $ ./build/env/bin/python tools/app_reg/app_reg.py --list 2>&1 | grep zkui
+    zkui           0.1     /Users/philip/src/hue/apps/zkui
+
+
+And restart the Hue application server.
+
+Configuration
+-------------
+
+Edit zkui/src/zkui/settings.py:
+
+CLUSTERS = [{
+        'nice_name': 'Default',
+        'hostport': 'localhost:2181,localhost:2182,localhost:2183',
+        'rest_gateway': 'http://localhost:9998'
+    }, {
+      # ... and more clusters
+    }
+]
+
+What is Hue?
+------------
+
+Wiki: http://wiki.github.com/cloudera/hue/
+Main Repo: http://github.com/cloudera/hue 
+
+Hue is both a web UI for Hadoop and a framework to create interactive web applications. It features a FileBrowser for accessing HDFS, JobSub and JobBrowser applications for submitting and viewing MapReduce jobs, a Beeswax application for interacting with Hive. On top of that, the web frontend is mostly built from declarative widgets that require no JavaScript and are easy to learn.
+
+What is ZooKeeper?
+------------------
+
+http://zookeeper.apache.org/
+
+ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. All of these kinds of services are used in some form or another by distributed applications. Each time they are implemented there is a lot of work that goes into fixing the bugs and race conditions that are inevitable. Because of the difficulty of implementing these kinds of services, applications initially usually skimp on them ,which make them brittle in the presence of change and difficult to manage. Even when done correctly, different implementations of these services lead to management complexity when the applications are deployed.
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/Makefile
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/Makefile b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/Makefile
new file mode 100644
index 0000000..9c22d1c
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/Makefile
@@ -0,0 +1,21 @@
+#  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.
+
+ifeq ($(ROOT),)
+  $(error "Error: Expect the environment variable $$ROOT to point to the Desktop installation")
+endif
+
+include $(ROOT)/Makefile.sdk

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/setup.py
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/setup.py b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/setup.py
new file mode 100644
index 0000000..68d1352
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/setup.py
@@ -0,0 +1,46 @@
+#  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.
+from setuptools import setup, find_packages
+import os
+
+def expand_package_data(src_dirs, strip=""):
+  ret = []
+  for src_dir in src_dirs:
+    for path, dnames, fnames in os.walk(src_dir):
+      for fname in fnames:
+        ret.append(os.path.join(path, fname).replace(strip, ""))
+  return ret
+
+os.chdir(os.path.dirname(os.path.abspath(__file__)))
+setup(
+  name = "zkui",
+  version = "0.1",
+  url = 'http://zookeeper.apache.org/',
+  description = 'ZooKeeper Browser',
+  packages = find_packages('src'),
+  package_dir = {'': 'src'},
+  install_requires = ['setuptools', 'desktop'],
+  entry_points = { 'desktop.sdk.application': 'zkui=zkui' },
+  zip_safe = False,
+  package_data = {
+    # Include static resources.  Package_data doesn't
+    # deal well with directory globs, so we enumerate
+    # the files manually.
+    'zkui': expand_package_data(
+      ["src/zkui/templates", "src/zkui/static"],
+      "src/zkui/")
+  }
+)

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/__init__.py
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/__init__.py b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/__init__.py
new file mode 100644
index 0000000..eccc881
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/__init__.py
@@ -0,0 +1,16 @@
+#  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.
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/forms.py
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/forms.py b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/forms.py
new file mode 100644
index 0000000..6b1f178
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/forms.py
@@ -0,0 +1,29 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+
+#     http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from django import forms
+from django.forms.widgets import Textarea, HiddenInput
+
+class CreateZNodeForm(forms.Form):
+  name = forms.CharField(max_length=64)
+  data = forms.CharField(required=False, widget=Textarea)
+  sequence = forms.BooleanField(required=False)
+
+class EditZNodeForm(forms.Form):
+  data = forms.CharField(required=False, widget=Textarea)
+  version = forms.IntegerField(required=False, widget=HiddenInput)
+  
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/models.py
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/models.py b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/models.py
new file mode 100644
index 0000000..a46696b
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/models.py
@@ -0,0 +1,17 @@
+#  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.
+
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/rest.py
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/rest.py b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/rest.py
new file mode 100644
index 0000000..e4874a1
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/rest.py
@@ -0,0 +1,230 @@
+
+# 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.
+
+import urllib2
+import urllib
+import simplejson
+
+from contextlib import contextmanager
+
+class RequestWithMethod(urllib2.Request):
+    """ Request class that know how to set the method name """
+    def __init__(self, *args, **kwargs):
+        urllib2.Request.__init__(self, *args, **kwargs)
+        self._method = None
+
+    def get_method(self):
+        return self._method or \
+            urllib2.Request.get_method(self)
+
+    def set_method(self, method):
+        self._method = method
+
+class ZooKeeper(object):
+
+    class Error(Exception): pass
+
+    class NotFound(Error): pass
+
+    class ZNodeExists(Error): pass
+
+    class InvalidSession(Error): pass
+
+    class WrongVersion(Error): pass
+
+    def __init__(self, uri = 'http://localhost:9998'):
+        self._base = uri
+        self._session = None
+
+    def start_session(self, expire=5, id=None):
+        """ Create a session and return the ID """
+        if id is None:
+            url = "%s/sessions/v1/?op=create&expire=%d" % (self._base, expire)
+            self._session = self._do_post(url)['id']
+        else:
+            self._session = id
+        return self._session
+
+    def close_session(self):
+        """ Close the session on the server """
+        if self._session is not None:
+            url = '%s/sessions/v1/%s' % (self._base, self._session)
+            self._do_delete(url)
+            self._session = None
+
+    def heartbeat(self):
+        """ Send a heartbeat request. This is needed in order to keep a session alive """
+        if self._session is not None:
+            url = '%s/sessions/v1/%s' % (self._base, self._session)
+            self._do_put(url, '')
+
+    @contextmanager
+    def session(self, *args, **kwargs):
+        """ Session handling using a context manager """
+        yield self.start_session(*args, **kwargs)
+        self.close_session()
+
+    def get(self, path):
+        """ Get a node """
+        url = "%s/znodes/v1%s" % (self._base, path)
+        return self._do_get(url)
+
+    def get_children(self, path):
+        """ Get all the children for a given path. This function creates a generator """
+        for child_path in self.get_children_paths(path, uris=True):
+            try:
+                yield self._do_get(child_path)
+            except ZooKeeper.NotFound:
+                continue
+
+    def get_children_paths(self, path, uris=False):
+        """ Get the paths for children nodes """
+        url = "%s/znodes/v1%s?view=children" % (self._base, path)
+        resp = self._do_get(url)
+        for child in resp.get('children', []):
+            yield child if not uris else resp['child_uri_template']\
+              .replace('{child}', urllib2.quote(child))
+       
+    def create(self, path, data=None, sequence=False, ephemeral=False):
+        """ Create a new node. By default this call creates a persistent znode.
+
+        You can also create an ephemeral or a sequential znode.
+        """
+        ri = path.rindex('/')
+        head, name = path[:ri+1], path[ri+1:]
+        if head != '/': head = head[:-1]
+
+        flags = {
+            'null': 'true' if data is None else 'false',
+            'ephemeral': 'true' if ephemeral else 'false',
+            'sequence': 'true' if sequence else 'false'
+        }
+        if ephemeral:
+            if self._session:
+                flags['session'] = self._session
+            else:
+                raise ZooKeeper.Error, 'You need a session '\
+                    'to create an ephemeral node'
+        flags = urllib.urlencode(flags)
+
+        url = "%s/znodes/v1%s?op=create&name=%s&%s" % \
+            (self._base, head, name, flags)
+
+        return self._do_post(url, data)
+
+    def set(self, path, data=None, version=-1, null=False):
+        """ Set the value of node """
+        url = "%s/znodes/v1%s?%s" % (self._base, path, \
+            urllib.urlencode({
+                'version': version,
+                'null': 'true' if null else 'false'
+        }))
+        return self._do_put(url, data)
+
+    def delete(self, path, version=-1):
+        """ Delete a znode """
+        if type(path) is list:
+            map(lambda el: self.delete(el, version), path)
+            return
+
+        url = '%s/znodes/v1%s?%s' % (self._base, path, \
+            urllib.urlencode({
+                'version':version
+        }))
+        try:
+            return self._do_delete(url)
+        except urllib2.HTTPError, e:
+            if e.code == 412:
+                raise ZooKeeper.WrongVersion(path)
+            elif e.code == 404:
+                raise ZooKeeper.NotFound(path)
+            raise
+
+    def recursive_delete(self, path):
+        """ Delete all the nodes from the tree """
+        for child in self.get_children_paths(path):
+            fp = ("%s/%s" % (path, child)).replace('//', '/')
+            self.recursive_delete(fp)
+        self.delete(path)
+
+    def exists(self, path):
+        """ Do a znode exists """
+        try:
+            self.get(path)
+            return True
+        except ZooKeeper.NotFound:
+            return False
+
+    def _do_get(self, uri):
+        """ Send a GET request and convert errors to exceptions """
+        try:
+            req = urllib2.urlopen(uri)
+            resp = simplejson.load(req)
+
+            if 'Error' in resp:
+               raise ZooKeeper.Error(resp['Error'])
+
+            return resp
+        except urllib2.HTTPError, e:
+            if e.code == 404:
+                raise ZooKeeper.NotFound(uri)
+            raise
+
+    def _do_post(self, uri, data=None):
+        """ Send a POST request and convert errors to exceptions """
+        try:
+            req = urllib2.Request(uri, {})
+            req.add_header('Content-Type', 'application/octet-stream')
+            if data is not None:
+                req.add_data(data)
+
+            resp = simplejson.load(urllib2.urlopen(req))
+            if 'Error' in resp:
+                raise ZooKeeper.Error(resp['Error'])
+            return resp
+
+        except urllib2.HTTPError, e:
+            if e.code == 201:
+                return True
+            elif e.code == 409:
+                raise ZooKeeper.ZNodeExists(uri)
+            elif e.code == 401:
+                raise ZooKeeper.InvalidSession(uri)
+            raise
+
+    def _do_delete(self, uri):
+        """ Send a DELETE request """
+        req = RequestWithMethod(uri)
+        req.set_method('DELETE')
+        req.add_header('Content-Type', 'application/octet-stream')
+        return urllib2.urlopen(req).read()
+
+    def _do_put(self, uri, data):
+        """ Send a PUT request """
+        try:
+            req = RequestWithMethod(uri)
+            req.set_method('PUT')
+            req.add_header('Content-Type', 'application/octet-stream')
+            if data is not None:
+                req.add_data(data)
+
+            return urllib2.urlopen(req).read()
+        except urllib2.HTTPError, e:
+            if e.code == 412: # precondition failed
+                raise ZooKeeper.WrongVersion(uri)
+            raise
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/settings.py
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/settings.py b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/settings.py
new file mode 100644
index 0000000..844c695
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/settings.py
@@ -0,0 +1,30 @@
+#  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.
+
+DJANGO_APPS = [ "zkui" ]
+NICE_NAME = "ZooKeeper Browser"
+REQUIRES_HADOOP = False
+
+CLUSTERS = [{
+        'nice_name': 'Default',
+        'hostport': 'localhost:2181,localhost:2182,localhost:2183',
+        'rest_gateway': 'http://localhost:9998'
+    }
+]
+
+DEPENDER_PACKAGE_YMLS = [
+    "src/zkui/static/js/package.yml",
+]

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/art/line_icons.png
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/art/line_icons.png b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/art/line_icons.png
new file mode 100644
index 0000000..1da4a29
Binary files /dev/null and b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/art/line_icons.png differ

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/art/zkui.png
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/art/zkui.png b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/art/zkui.png
new file mode 100644
index 0000000..cb40df3
Binary files /dev/null and b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/art/zkui.png differ

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/bootstrap.js
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/bootstrap.js b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/bootstrap.js
new file mode 100644
index 0000000..8e3fbfb
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/bootstrap.js
@@ -0,0 +1,32 @@
+// 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.
+CCS.Desktop.register({
+	Zkui : {
+		name : 'ZooKeeper Browser',
+		css : '/zkui/static/css/zkui.css',
+		require: [ 'Zkui' ],
+		launch: function(path, options){
+			return new Zkui(path || '/zkui/', options);
+		},
+		menu: {
+			id: 'ccs-zkui-menu',
+			img: {
+				src: '/zkui/static/art/zkui.png'
+			}
+		},
+		help: '/help/zkui/'
+	}
+});

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/css/zkui.css
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/css/zkui.css b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/css/zkui.css
new file mode 100644
index 0000000..c49f392
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/css/zkui.css
@@ -0,0 +1,56 @@
+/*
+ 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.
+*/
+
+.zkui img.zkui_icon {
+	width: 55px;
+	height: 55px;
+	position: absolute;
+	top: 27px;
+	left: 3px;
+}
+
+div.zkui .left_col li {
+    margin: 5px 0px;
+    font-size: 16px;
+    background-color: white;
+    color: black;
+    padding: 2px 1px 1px 5px;
+    -moz-border-radius: 3px;
+    -webkit-border-radius: 3px;
+    border: solid black 1px;
+}
+
+div.zkui .left_col li:hover {
+    background-color: lightBlue;
+    color: white;
+}
+
+div.zkui .left_col li a {
+    color: black;
+    display: block;
+}
+
+div.zkui .left_col li a:hover {
+    text-decoration: none;
+}
+
+div.zkui .createZnodeForm td,
+div.zkui .editZnodeForm td {
+  padding: 5px;
+}
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/help/index.html
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/help/index.html b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/help/index.html
new file mode 100644
index 0000000..355c8cd
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/help/index.html
@@ -0,0 +1,26 @@
+<!--
+   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.
+-->
+
+<h1>ZooKeeper Browser</h1>
+
+
+<p>ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services</p>
+
+<h2>About</h2>
+
+<p>The ZooKeeper Browser application allows you to see how the cluster nodes are working and also allows you to do CRUD operations on the znode hierarchy.</p>
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/js/Source/Zkui/Zkui.js
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/js/Source/Zkui/Zkui.js b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/js/Source/Zkui/Zkui.js
new file mode 100644
index 0000000..c8bf383
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/js/Source/Zkui/Zkui.js
@@ -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.
+
+/*
+---
+
+script: Zkui.js
+
+description: Defines Zkui; a Hue application that extends CCS.JBrowser.
+
+authors:
+- Unknown
+
+requires:
+- ccs-shared/CCS.JBrowser
+
+provides: [Zkui]
+
+...
+*/
+ART.Sheet.define('window.art.browser.zkui', {
+	'min-width': 620
+});
+
+var Zkui = new Class({
+
+	Extends: CCS.JBrowser,
+
+	options: {
+		className: 'art browser logo_header zkui'
+	},
+
+	initialize: function(path, options){
+		this.parent(path || '/zkui/', options);
+	}
+
+});

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/js/package.yml
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/js/package.yml b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/js/package.yml
new file mode 100644
index 0000000..c2c07ad
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/static/js/package.yml
@@ -0,0 +1,19 @@
+# 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.
+copyright: Apache License v2.0
+version: 0.1
+description: ZooKeeper Browser
+name: ZooKeeper Browser
+sources: [Source/Zkui/Zkui.js]

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/stats.py
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/stats.py b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/stats.py
new file mode 100644
index 0000000..48f35dd
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/stats.py
@@ -0,0 +1,170 @@
+#  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.
+
+import socket
+import re
+
+from StringIO import StringIO
+
+class Session(object):
+
+  class BrokenLine(Exception): pass
+
+  def __init__(self, session):
+    m = re.search('/(\d+\.\d+\.\d+\.\d+):(\d+)\[(\d+)\]\((.*)\)', session)
+    if m:
+        self.host = m.group(1)
+        self.port = m.group(2)
+        self.interest_ops = m.group(3)
+        for d in m.group(4).split(","):
+            k,v = d.split("=")
+            self.__dict__[k] = v
+    else:
+        raise Session.BrokenLine() 
+
+class ZooKeeperStats(object):
+
+    def __init__(self, host='localhost', port='2181', timeout=1):
+        self._address = (host, int(port))
+        self._timeout = timeout
+
+    def get_stats(self):
+        """ Get ZooKeeper server stats as a map """
+        data = self._send_cmd('mntr')
+        if data:
+            return self._parse(data)
+        else:
+            data = self._send_cmd('stat')
+            return self._parse_stat(data)
+
+    def get_clients(self):
+      """ Get ZooKeeper server clients """
+      clients = []
+
+      stat = self._send_cmd('stat')
+      if not stat:
+        return clients
+
+      sio = StringIO(stat)
+
+      #skip two lines
+      sio.readline()
+      sio.readline()
+
+      for line in sio:
+        if not line.strip():
+          break
+        try:
+          clients.append(Session(line.strip()))
+        except Session.BrokenLine:
+          continue
+
+      return clients
+
+    def _create_socket(self):
+        return socket.socket()
+
+    def _send_cmd(self, cmd):
+        """ Send a 4letter word command to the server """
+        s = self._create_socket()
+        s.settimeout(self._timeout)
+
+        s.connect(self._address)
+        s.send(cmd)
+
+        data = s.recv(2048)
+        s.close()
+
+        return data
+
+    def _parse(self, data):
+        """ Parse the output from the 'mntr' 4letter word command """
+        h = StringIO(data)
+        
+        result = {}
+        for line in h.readlines():
+            try:
+                key, value = self._parse_line(line)
+                result[key] = value
+            except ValueError:
+                pass # ignore broken lines
+
+        return result
+
+    def _parse_stat(self, data):
+        """ Parse the output from the 'stat' 4letter word command """
+        h = StringIO(data)
+
+        result = {}
+        
+        version = h.readline()
+        if version:
+            result['zk_version'] = version[version.index(':')+1:].strip()
+
+        # skip all lines until we find the empty one
+        while h.readline().strip(): pass
+
+        for line in h.readlines():
+            m = re.match('Latency min/avg/max: (\d+)/(\d+)/(\d+)', line)
+            if m is not None:
+                result['zk_min_latency'] = int(m.group(1))
+                result['zk_avg_latency'] = int(m.group(2))
+                result['zk_max_latency'] = int(m.group(3))
+                continue
+
+            m = re.match('Received: (\d+)', line)
+            if m is not None:
+                result['zk_packets_received'] = int(m.group(1))
+                continue
+
+            m = re.match('Sent: (\d+)', line)
+            if m is not None:
+                result['zk_packets_sent'] = int(m.group(1))
+                continue
+
+            m = re.match('Outstanding: (\d+)', line)
+            if m is not None:
+                result['zk_outstanding_requests'] = int(m.group(1))
+                continue
+
+            m = re.match('Mode: (.*)', line)
+            if m is not None:
+                result['zk_server_state'] = m.group(1)
+                continue
+
+            m = re.match('Node count: (\d+)', line)
+            if m is not None:
+                result['zk_znode_count'] = int(m.group(1))
+                continue
+
+        return result 
+
+    def _parse_line(self, line):
+        try:
+            key, value = map(str.strip, line.split('\t'))
+        except ValueError:
+            raise ValueError('Found invalid line: %s' % line)
+
+        if not key:
+            raise ValueError('The key is mandatory and should not be empty')
+
+        try:
+            value = int(value)
+        except (TypeError, ValueError):
+            pass
+
+        return key, value
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/clients.mako
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/clients.mako b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/clients.mako
new file mode 100644
index 0000000..2bee9a7
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/clients.mako
@@ -0,0 +1,51 @@
+<%!
+#  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.
+%>
+
+<%namespace name="shared" file="shared_components.mako" />
+
+${shared.header("ZooKeeper Browser > Clients > %s:%s" % (host, port))}
+
+<h1>${host}:${port} :: client connections</h1>
+<br />
+
+% if clients:
+  <table data-filters="HtmlTable"> 
+  <thead>
+    <tr>
+      <th>Host</th>
+      <th>Port</th>
+      <th>Interest Ops</th>
+      <th>Queued</th>
+      <th>Received</th>
+      <th>Sent</th>
+  </thead>
+  % for client in clients:
+    <tr>
+      <td>${client.host}</td>
+      <td>${client.port}</td>
+      <td>${client.interest_ops}</td>
+      <td>${client.queued}</td>
+      <td>${client.recved}</td>
+      <td>${client.sent}</td>
+    </tr>
+  % endfor
+  </table>
+% endif
+
+${shared.footer()}
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/create.mako
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/create.mako b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/create.mako
new file mode 100644
index 0000000..2a8b8cc
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/create.mako
@@ -0,0 +1,34 @@
+<%!
+#  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.
+%>
+<%namespace name="shared" file="shared_components.mako" />
+
+${shared.header("ZooKeeper Browser > Create Znode")}
+
+<h2>Create New Znode :: ${path}</h2>
+<hr /><br />
+
+<form class="createZnodeForm" action="" method="POST">
+<table align="center">
+  ${form.as_table()|n}
+<tr><td colspan="2" align="right">
+  <button type="submit">Create</button>
+</td></tr>
+</table>
+</form>
+
+${shared.footer()}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/edit.mako
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/edit.mako b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/edit.mako
new file mode 100644
index 0000000..997bd07
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/edit.mako
@@ -0,0 +1,34 @@
+<%!
+#  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.
+%>
+<%namespace name="shared" file="shared_components.mako" />
+
+${shared.header("ZooKeeper Browser > Edit Znode > %s" % path)}
+
+<h2>Edit Znode Data :: ${path}</h2>
+<hr /><br />
+
+<form class="editZnodeForm" action="" method="POST">
+<table align="center">
+  ${form.as_table()|n}
+<tr><td colspan="2" align="right">
+  <button type="submit">Save</button>
+</td></tr>
+</table>
+</form>
+
+${shared.footer()}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/index.mako
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/index.mako b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/index.mako
new file mode 100644
index 0000000..567919d
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/index.mako
@@ -0,0 +1,54 @@
+<%!
+#  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.
+%>
+<%namespace name="shared" file="shared_components.mako" />
+
+${shared.header("ZooKeeper Browser")}
+
+<h2>Overview</h2>
+
+<br />
+
+% for i, c in enumerate(overview):
+  <h3> ${i+1}. <a href="${url('zkui.views.view', id=i)}">${c['nice_name']} Cluster Overview</a></h3><br />
+
+  <table data-filters="HtmlTable">
+  <thead>
+    <tr>
+      <th>Node</th>
+      <th>Role</th>
+      <th>Avg Latency</th>
+      <th>Watch Count</th>
+      <th>Version</th>
+    </tr>
+  </thead>
+  % for host, stats in c['stats'].items():
+    <tr>
+      <td>${host}</td>
+      <td>${stats.get('zk_server_state', '')}</td>
+      <td>${stats.get('zk_avg_latency', '')}</td>
+      <td>${stats.get('zk_watch_count', '')}</td>
+      <td>${stats.get('zk_version', '')}</td>
+    </tr>
+  % endfor
+  </table>
+
+  <br /><br />
+% endfor 
+
+${shared.footer()}
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/shared_components.mako
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/shared_components.mako b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/shared_components.mako
new file mode 100644
index 0000000..f9a4589
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/shared_components.mako
@@ -0,0 +1,66 @@
+<%!
+#  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.
+%>
+
+<%!
+import datetime
+from django.template.defaultfilters import urlencode, escape
+from zkui import settings
+%>
+
+<%def name="header(title='ZooKeeper Browser', toolbar=True)">
+  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
+  <html>
+    <head>
+      <title>${title}</title>
+    </head>
+    <body>
+      % if toolbar:
+      <div class="toolbar">
+        <a href="${url('zkui.views.index')}"><img src="/zkui/static/art/zkui.png" class="zkui_icon"/></a>
+      </div>
+      % endif
+
+    <div data-filters="SplitView">
+    <div class="left_col jframe_padded" style="width:150px;">
+        <ul>
+          <li><a href="${url("zkui.views.index")}">Overview</a></li>
+        </ul>
+        <br />
+
+        <h2>Clusters</h2>
+        <ul>
+            % for id, c in enumerate(settings.CLUSTERS):
+                <li><a href="${url("zkui.views.view", id=id)}">
+                    ${c['nice_name']}</a></li>
+            % endfor
+        </ul>
+    </div>
+
+    <div class="right_col jframe_padded">
+</%def>
+
+<%def name="info_button(url, text)">
+  <a data-filters="ArtButton" href="${url}" style="background: url(/static/art/info.png) left 50%; padding: 6px 6px 6px 20px; margin: 10px;" data-icon-styles="{'width': 14, 'height': 14}">${text}</a>
+</%def>
+
+<%def name="footer()">
+        </div>
+    </div>
+    </body>
+  </html>
+</%def>

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/tree.mako
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/tree.mako b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/tree.mako
new file mode 100644
index 0000000..c74c202
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/tree.mako
@@ -0,0 +1,75 @@
+<%!
+#  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.
+%>
+<%namespace name="shared" file="shared_components.mako" />
+
+${shared.header("ZooKeeper Browser > Tree > %s > %s" % (cluster['nice_name'], path))}
+
+<h1>${cluster['nice_name'].lower()} :: ${path}</h1>
+<br />
+
+<table data-filters="HtmlTable">
+  <thead>
+  <th colspan="2">Children</th>
+  </thead>
+  % for child in children:
+    <tr><td width="100%">
+      <a href="${url('zkui.views.tree', id=cluster['id'], \
+          path=("%s/%s" % (path, child)).replace('//', '/'))}">
+      ${child}</a>
+    </td><td>
+      <a title="Delete ${child}" class="delete frame_tip confirm_and_post" alt="Are you sure you want to delete ${child}?" href="${url('zkui.views.delete', id=cluster['id'], \
+          path=("%s/%s" % (path, child)).replace('//', '/'))}">Delete</a>
+    </td></tr>
+  % endfor
+</table>
+<br />
+<span style="float: right">
+  ${shared.info_button(url('zkui.views.create', id=cluster['id'], path=path), 'Create New')}
+</span>
+
+<div style="clear: both"></div>
+
+<h2>data :: base64 :: length :: ${znode.get('dataLength', 0)}</h2>
+<br />
+
+<textarea name="data64" style="width: 100%;" rows="5" readonly="readonly">${znode.get('data64', '')}</textarea>
+<div style="clear: both"></div>
+<span style="float: right">
+  ${shared.info_button(url('zkui.views.edit_as_base64', id=cluster['id'], path=path), 'Edit as Base64')}
+  ${shared.info_button(url('zkui.views.edit_as_text', id=cluster['id'], path=path), 'Edit as Text')}
+</span>
+<div style="clear: both"></div>
+<br />
+
+<h2>stat information</h2>
+<br />
+
+<table data-filters="HtmlTable">
+  <thead><tr><th>Key</th>
+    <th width="80%">Value</th></tr></thead>
+  % for key in ('pzxid', 'ctime', 'aversion', 'mzxid', \
+      'ephemeralOwner', 'version', 'mtime', 'cversion', 'czxid'):
+    <tr><td>${key}</td><td>${znode[key]}</td></tr> 
+  % endfor
+</table>
+
+<br />
+<a target="_blank" href="http://zookeeper.apache.org/docs/current/zookeeperProgrammers.html#sc_zkStatStructure">Details on stat information.</a>
+
+${shared.footer()}
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/view.mako
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/view.mako b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/view.mako
new file mode 100644
index 0000000..e046afc
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/templates/view.mako
@@ -0,0 +1,128 @@
+<%!
+#  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.
+%>
+<%namespace name="shared" file="shared_components.mako" />
+
+${shared.header("ZooKeeper Browser > %s" % cluster['nice_name'])}
+
+<%def name="show_stats(stats)">
+    <thead>
+      <tr><th>Key</th>
+      <th width="100%">Value</th></tr>
+    </thead>
+
+    <tr><td>Version</td>
+      <td>${stats.get('zk_version')}</td>
+    </tr>
+
+    <tr><td>Latency</td><td>
+      Min: ${stats.get('zk_min_latency', '')}
+      Avg: ${stats.get('zk_avg_latency', '')}
+      Max: ${stats.get('zk_max_latency', '')}
+    </td></tr>
+
+    <tr><td>Packets</td>
+      <td>Sent: ${stats.get('zk_packets_sent', '')}
+      Received: ${stats.get('zk_packets_received', '')}
+      </td>
+    </tr>
+
+    <tr><td>Outstanding Requests</td>
+      <td>${stats.get('zk_outstanding_requests', '')}</td>
+    </tr>
+
+    <tr><td>Watch Count</td>
+      <td>${stats.get('zk_watch_count', '')}</td>
+    </tr>
+
+    <tr><td>Open FD Count</td>
+      <td>${stats.get('zk_open_file_descriptor_count', '')}</td>
+    </tr>
+
+    <tr><td>Max FD Count</td>
+      <td>${stats.get('zk_max_file_descriptor_count', '')}</td>
+    </tr>
+
+</%def> 
+
+<h2> ${cluster['nice_name']} Cluster Overview </h2>
+
+${shared.info_button(url('zkui.views.tree', id=cluster['id'], path='/'), 'View Znode Hierarchy')}
+
+<br /><br />
+
+% if leader:
+<h2>General</h2>
+
+<table data-filters="HtmlTable">
+  <thead>
+    <tr><th>Key</th><th width="100%">Value</th></tr>
+  </thead>
+
+  <tr><td>ZNode Count</td>
+    <td>${leader.get('zk_znode_count', '')}</td></tr>
+
+  <tr><td>Ephemerals Count</td>
+    <td>${leader.get('zk_ephemerals_count', '')}</td></tr>
+
+  <tr><td>Approximate Data Size</td>
+    <td>${leader.get('zk_approximate_data_size', '')} bytes</td></tr>
+
+</table>
+<br /><br />
+% endif
+
+% if leader:
+  <h2>node :: ${leader['host']} :: leader</h2>
+
+  ${shared.info_button(url('zkui.views.clients', host=leader['host']), 'View Client Connections')}
+
+  <br /><br />
+  <table data-filters="HtmlTable">
+    ${show_stats(leader)}
+    
+    <tr><td>Followers</td>
+      <td>${leader.get('zk_followers', '')}</td>
+    </tr>
+
+    <tr><td>Synced Followers</td>
+      <td>${leader.get('zk_synced_followers', '')}</td>
+    </tr>
+
+    <tr><td>Pending Syncs</td>
+      <td>${leader.get('zk_pending_syncs', '')}</td>
+    </tr>
+  
+  </table>
+<br /><br />
+% endif
+
+% for stats in followers:
+  <h2>node :: ${stats['host']} :: follower</h2>
+  <br />
+
+  ${shared.info_button(url('zkui.views.clients', host=stats['host']), 'View Client Connections')}
+
+  <br /><br />
+  <table data-filters="HtmlTable">
+    ${show_stats(stats)}
+  </table>
+  <br /><br />
+% endfor
+
+${shared.footer()}
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/urls.py
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/urls.py b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/urls.py
new file mode 100644
index 0000000..f795f7e
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/urls.py
@@ -0,0 +1,28 @@
+#  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.
+
+from django.conf.urls.defaults import patterns, url
+
+urlpatterns = patterns('zkui',
+  url(r'^$', 'views.index'),
+  url(r'view/(?P<id>\d+)$', 'views.view'),
+  url(r'clients/(?P<host>.+)$', 'views.clients'),
+  url(r'tree/(?P<id>\d+)(?P<path>.+)$', 'views.tree'),
+  url(r'create/(?P<id>\d+)(?P<path>.*)$', 'views.create'),
+  url(r'delete/(?P<id>\d+)(?P<path>.*)$', 'views.delete'),
+  url(r'edit/base64/(?P<id>\d+)(?P<path>.*)$', 'views.edit_as_base64'),
+  url(r'edit/text/(?P<id>\d+)(?P<path>.*)$', 'views.edit_as_text')
+)

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/utils.py
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/utils.py b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/utils.py
new file mode 100644
index 0000000..fb01317
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/utils.py
@@ -0,0 +1,33 @@
+#  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.
+
+from zkui import settings
+
+from django.http import Http404
+
+def get_cluster_or_404(id):
+  try:
+    id = int(id)
+    if not (0 <= id < len(settings.CLUSTERS)):
+      raise ValueError, 'Undefined cluster id.'
+  except (TypeError, ValueError):
+    raise Http404()
+
+  cluster = settings.CLUSTERS[id]
+  cluster['id'] = id
+
+  return cluster
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/views.py
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/views.py b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/views.py
new file mode 100644
index 0000000..64d926b
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/views.py
@@ -0,0 +1,165 @@
+#  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.
+
+from desktop.lib.django_util import render
+from django.http import Http404
+
+from zkui import settings
+from zkui.stats import ZooKeeperStats
+from zkui.rest import ZooKeeper
+from zkui.utils import get_cluster_or_404
+from zkui.forms import CreateZNodeForm, EditZNodeForm
+
+def _get_global_overview():
+  overview = []
+  for c in settings.CLUSTERS:
+    overview.append(_get_overview(c))
+  return overview
+
+def _get_overview(cluster):
+  stats = {}
+  for s in cluster['hostport'].split(','):
+    host, port = map(str.strip, s.split(':'))
+
+    zks = ZooKeeperStats(host, port)
+    stats[s] = zks.get_stats() or {}
+
+  cluster['stats'] = stats
+  return cluster
+
+def _group_stats_by_role(cluster):
+  leader, followers = None, []
+  for host, stats in cluster['stats'].items():
+    stats['host'] = host
+
+    if stats.get('zk_server_state') == 'leader':
+      leader = stats
+
+    elif stats.get('zk_server_state') == 'follower':
+      followers.append(stats) 
+
+  return leader, followers           
+ 
+def index(request):
+  overview = _get_global_overview()  
+  return render('index.mako', request, 
+    dict(overview=overview))
+
+def view(request, id):
+  cluster = get_cluster_or_404(id)
+
+  cluster = _get_overview(cluster)
+  leader, followers = _group_stats_by_role(cluster)
+
+  return render('view.mako', request, 
+    dict(cluster=cluster, leader=leader, followers=followers))
+
+def clients(request, host):
+  parts = host.split(':')  
+  if len(parts) != 2:
+    raise Http404
+
+  host, port = parts
+  zks = ZooKeeperStats(host, port)
+  clients = zks.get_clients()
+
+  return render('clients.mako', request,
+    dict(host=host, port=port, clients=clients))
+
+def tree(request, id, path):
+  cluster = get_cluster_or_404(id)
+  zk = ZooKeeper(cluster['rest_gateway'])
+
+  znode = zk.get(path)
+  children = sorted(zk.get_children_paths(path))
+  
+  return render('tree.mako', request,
+    dict(cluster=cluster, path=path, \
+      znode=znode, children=children))
+
+def delete(request, id, path):
+  cluster = get_cluster_or_404(id)
+  if request.method == 'POST':
+    zk = ZooKeeper(cluster['rest_gateway'])
+    try:
+      zk.recursive_delete(path)
+    except ZooKeeper.NotFound:
+      pass
+
+  return tree(request, id, path[:path.rindex('/')] or '/')
+
+def create(request, id, path):
+  cluster = get_cluster_or_404(id)
+
+  if request.method == 'POST':
+    form = CreateZNodeForm(request.POST)
+    if form.is_valid():
+      zk = ZooKeeper(cluster['rest_gateway'])
+
+      full_path = ("%s/%s" % (path, form.cleaned_data['name']))\
+        .replace('//', '/')
+
+      zk.create(full_path, \
+        form.cleaned_data['data'], \
+        sequence = form.cleaned_data['sequence'])
+      return tree(request, id, path)
+  else:
+    form = CreateZNodeForm()
+
+  return render('create.mako', request, 
+    dict(path=path, form=form))
+
+def edit_as_base64(request, id, path):
+  cluster = get_cluster_or_404(id)
+  zk = ZooKeeper(cluster['rest_gateway'])
+  node = zk.get(path)
+
+  if request.method == 'POST':
+    form = EditZNodeForm(request.POST)
+    if form.is_valid():
+      # TODO is valid base64 string?
+      data = form.cleaned_data['data'].decode('base64')
+      zk.set(path, data, form.cleaned_data['version'])
+
+    return tree(request, id, path)
+  else:
+    form = EditZNodeForm(dict(\
+      data=node.get('data64', ''), 
+      version=node.get('version', '-1')))
+
+  return render('edit.mako', request,
+    dict(path=path, form=form))
+
+def edit_as_text(request, id, path):
+  cluster = get_cluster_or_404(id)
+  zk = ZooKeeper(cluster['rest_gateway'])
+  node = zk.get(path)
+
+  if request.method == 'POST':
+    form = EditZNodeForm(request.POST)
+    if form.is_valid():
+      zk.set(path, form.cleaned_data['data'])
+
+    return tree(request, id, path)
+  else:
+    form = EditZNodeForm(dict(data=node.get('data64', '')\
+      .decode('base64').strip(), 
+      version=node.get('version', '-1')))
+
+  return render('edit.mako', request,
+    dict(path=path, form=form))
+
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eab8c1eb/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/windmilltests.py
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/windmilltests.py b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/windmilltests.py
new file mode 100644
index 0000000..ba44e26
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-huebrowser/zkui/src/zkui/windmilltests.py
@@ -0,0 +1,23 @@
+#  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.
+
+from desktop.lib.windmill_util import logged_in_client
+
+def test_zkui():
+  """ launches the default view for zkui """
+  client = logged_in_client()
+  client.click(id='ccs-zkui-menu')
+  client.waits.forElement(classname='CCS-ZKUI', timeout='2000')  


Mime
View raw message