You are viewing a plain text version of this content. The canonical link for it is here.
Posted to solr-commits@lucene.apache.org by yo...@apache.org on 2009/12/31 23:17:23 UTC

svn commit: r894948 - in /lucene/solr/branches/cloud/src: java/org/apache/solr/core/ZooKeeperController.java webapp/web/admin/solr-admin.css webapp/web/admin/zookeeper.jsp

Author: yonik
Date: Thu Dec 31 22:17:23 2009
New Revision: 894948

URL: http://svn.apache.org/viewvc?rev=894948&view=rev
Log:
SOLR-1277: basic zookeeper browser for admin pages

Added:
    lucene/solr/branches/cloud/src/webapp/web/admin/zookeeper.jsp   (with props)
Modified:
    lucene/solr/branches/cloud/src/java/org/apache/solr/core/ZooKeeperController.java
    lucene/solr/branches/cloud/src/webapp/web/admin/solr-admin.css

Modified: lucene/solr/branches/cloud/src/java/org/apache/solr/core/ZooKeeperController.java
URL: http://svn.apache.org/viewvc/lucene/solr/branches/cloud/src/java/org/apache/solr/core/ZooKeeperController.java?rev=894948&r1=894947&r2=894948&view=diff
==============================================================================
--- lucene/solr/branches/cloud/src/java/org/apache/solr/core/ZooKeeperController.java (original)
+++ lucene/solr/branches/cloud/src/java/org/apache/solr/core/ZooKeeperController.java Thu Dec 31 22:17:23 2009
@@ -37,21 +37,25 @@
 
   private String shardAddress;
 
+  private String zooKeeperHost;
+
   /**
-   * @param zookeeperHost ZooKeeper host service
+   * @param zooKeeperHost ZooKeeper host service
    * @param shardAddress
    * @param zkClientTimeout
    * @param zkSolrPathPrefix Solr ZooKeeper node (default is /solr)
    */
-  public ZooKeeperController(String zookeeperHost, String collection,
+  public ZooKeeperController(String zooKeeperHost, String collection,
       String shardAddress, int zkClientTimeout) {
     this.collectionName = collection;
     this.shardAddress = shardAddress;
+    this.zooKeeperHost = zooKeeperHost;
+    
     CountdownWatcher countdownWatcher = new CountdownWatcher(
         "ZooKeeperController");
     System.out.println("timeout:" + zkClientTimeout);
     try {
-      keeper = new ZooKeeper(zookeeperHost, zkClientTimeout, countdownWatcher);
+      keeper = new ZooKeeper(zooKeeperHost, zkClientTimeout, countdownWatcher);
 
       countdownWatcher.waitForConnected(5000);
 
@@ -193,4 +197,12 @@
       // nocommit: handle
     }
   }
+
+  public ZooKeeper getZooKeeper() {
+    return keeper;
+  }
+
+  public String getZooKeeperHost() {
+    return zooKeeperHost;
+  }
 }

Modified: lucene/solr/branches/cloud/src/webapp/web/admin/solr-admin.css
URL: http://svn.apache.org/viewvc/lucene/solr/branches/cloud/src/webapp/web/admin/solr-admin.css?rev=894948&r1=894947&r2=894948&view=diff
==============================================================================
--- lucene/solr/branches/cloud/src/webapp/web/admin/solr-admin.css (original)
+++ lucene/solr/branches/cloud/src/webapp/web/admin/solr-admin.css Thu Dec 31 22:17:23 2009
@@ -36,6 +36,13 @@
    max-width:450px;
 }
 
+input.big, textarea.big {
+   color: black;
+   border: 2px inset #ff9933;
+   background-color: #ffffff;
+   width:100%;
+}
+
 input.stdbutton {
    font-family: ITC Officina Sans Book, Helvetica, Arial, sans-serif;
    font-style: bold;

Added: lucene/solr/branches/cloud/src/webapp/web/admin/zookeeper.jsp
URL: http://svn.apache.org/viewvc/lucene/solr/branches/cloud/src/webapp/web/admin/zookeeper.jsp?rev=894948&view=auto
==============================================================================
--- lucene/solr/branches/cloud/src/webapp/web/admin/zookeeper.jsp (added)
+++ lucene/solr/branches/cloud/src/webapp/web/admin/zookeeper.jsp Thu Dec 31 22:17:23 2009
@@ -0,0 +1,424 @@
+<%@ page contentType="text/html; charset=utf-8" pageEncoding="UTF-8"%>
+<%--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+--%>
+<%@ page import="javax.servlet.jsp.JspWriter,java.io.IOException,org.apache.zookeeper.*,org.apache.zookeeper.data.Stat,org.apache.solr.core.*,org.apache.solr.common.util.*
+                "%>
+<%@ page import="java.io.*"%>
+<%@ page import="java.util.*"%>
+<%@ page import="java.net.URLEncoder"%>
+
+<%@include file="header.jsp" %>
+
+<br clear="all">
+<h2>Zookeeper Browser</h2>
+
+<%
+  String path = request.getParameter("path");
+  String addr = request.getParameter("addr");
+  if (addr!=null && addr.length()==0) addr=null;
+  String detailS = request.getParameter("detail");
+  boolean detail = detailS!=null && detailS.equals("true");
+
+  ZKPrinter printer = new ZKPrinter(out, core, addr);
+  printer.detail = detail;
+  String tryAddr = printer.keeperAddr!=null ? printer.keeperAddr : "localhost:2181";
+%>
+
+<form method="GET" action="zookeeper.jsp" accept-charset="UTF-8">
+<table>
+<tr>
+  <td>
+     <strong>   <% XML.escapeCharData(printer.keeper==null ? "Disconnected" : ("Connected to zookeeper "+printer.keeperAddr), out); %>  </strong>
+  </td>
+  <td>
+        <strong>Connect to different zookeeper</strong>
+	<input class="std" name="addr" type="text" value="<% XML.escapeCharData(tryAddr, out); %>">
+  </td>
+    <td>
+	<input class="stdbutton" type="submit" value="CONNECT">
+  </td>
+</tr>
+<tr>
+</form>
+
+
+<%
+  printer.print(path);
+%>
+
+</body>
+</html>
+
+<%!
+
+
+  static class ZKPrinter {
+    static boolean FULLPATH_DEFAULT=true;
+    boolean fullpath=FULLPATH_DEFAULT;
+    boolean detail=false;
+    String addr;        // the address passed to us
+    String keeperAddr;  // the address we're connected to
+
+    ZooKeeper keeper;
+    JspWriter out;
+    int level;
+    int maxData = 60;
+
+    private boolean levelchange;
+
+    public ZKPrinter(JspWriter out, SolrCore core, String addr) throws IOException {
+      this.out = out;
+      this.addr = addr;
+
+      //   ZooKeeperController controller = core.getCoreDescriptor().getCoreContainer().getZooKeeperController();
+      ZooKeeperController controller = null;
+
+      if (controller == null) {
+        keeperAddr = addr;
+        if (addr == null) {
+          out.println("Zookeeper is not configured for this Solr Core.  Please try connecting to an alternate zookeeper address.");
+          return;
+        }
+
+        try {
+          keeper = new ZooKeeper(addr, 10000, null);
+        } catch (IOException e) {
+          out.println("Could not connect to zookeeper at " + addr);
+          return;
+        }
+
+        try {
+          Thread.sleep(2000);  // temporary hack to wait until connected
+        } catch (InterruptedException e) {
+          exception(e);
+        }
+
+        if (keeper.getState() != ZooKeeper.States.CONNECTED) {
+          out.println("Could not connect to zookeeper at " + addr);
+          keeper = null;
+          return;
+        }
+      } else {
+        keeper = controller.getZooKeeper();
+        keeperAddr = controller.getZooKeeperHost();
+      }
+
+    }
+
+
+    // main entry point
+    void print(String path) throws IOException {
+      if (keeper==null) return;
+
+      out.print("<table>");
+      out.print("<tr><td>");
+      out.print("[");
+      url("ROOT","/",false);
+      out.print("]");
+
+      // normalize path
+      if (path==null) path="/";
+      else {
+        path.trim();
+        if (path.length()==0) path="/";
+      }
+      if (path.endsWith("/") && path.length()>1) {
+        path = path.substring(0, path.length()-1);
+      }
+
+      int idx = path.lastIndexOf('/');
+      String parent = idx >= 0 ? path.substring(0, idx) : path;
+      if (parent.length()==0) parent="/";
+
+      out.print(" [");
+      url("PARENT",parent,detail);
+      out.print("]");
+      out.print("</td></tr>");
+
+      if (detail) {
+        out.print("<tr><td>");
+        printZnode(path);
+        out.print("</td></tr>");
+      }
+
+      out.print("<tr><td>");
+      printTree(path);
+      out.print("</td></tr>");
+
+      out.print("</table>");
+    }
+
+
+
+    void exception(Exception e) {
+      try {
+        out.println(e.toString());
+      } catch (IOException e1) {
+        // nothing we can do
+      }
+    }
+
+    void xmlescape(String s) {
+      try {
+        XML.escapeCharData(s, out);
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+    }
+
+
+    void up() throws IOException {
+      level++;
+      if (!fullpath) out.println("<BLOCKQUOTE>");
+      levelchange=true;
+    }
+
+    void down() throws IOException {
+      level--;
+      if (!fullpath) out.println("</BLOCKQUOTE>");
+      levelchange=true;
+    }
+
+    void indent() throws IOException {
+      // if we are using blockquote and just changed indent levels, don't output a break
+      if (fullpath || !levelchange) out.println("<br>");
+      levelchange = false;
+      // if fullpath, no indent is needed
+      // if not, we are currently using blockquote which the browser
+      // will take care of indenting.
+    }
+
+
+    // collapse all whitespace to a single space or escaped newline
+    String compress(String str) {
+      StringBuilder sb = new StringBuilder();
+      for (int i=0; i<str.length(); i++) {
+        char ch = str.charAt(i);
+        boolean whitespace = false;
+        boolean newline = false;
+        while (Character.isWhitespace(ch)) {
+          whitespace = true;
+          if (ch=='\n') newline=true;
+          if (++i >=str.length()) return sb.toString();
+          ch = str.charAt(i);
+        }
+
+        if (newline) {
+          sb.append("\\n");
+        } else if (whitespace) {
+          sb.append(' ');
+        }
+
+        // TODO: handle non-printable chars
+        sb.append(ch);
+
+        if (sb.length() >= maxData) return sb.toString() + "...";
+      }
+      return sb.toString();
+    }
+
+    void url(String label, String path, boolean detail) throws IOException {
+      try {
+        out.print("<a href=\"zookeeper.jsp?");
+        if (path != null) {
+          out.print("path=");
+          out.print(URLEncoder.encode(path,"UTF-8"));
+        }
+        if (detail) {
+          out.print("&detail="+detail);
+        }
+        if (fullpath != FULLPATH_DEFAULT) {
+          out.print("&fullpath="+fullpath);
+        }
+        if (addr != null) {
+          out.print("&addr=");
+          out.print(URLEncoder.encode(addr,"UTF-8"));
+        }
+
+        out.print("\">");
+        xmlescape(label);
+        out.print("</a>");
+
+      } catch (UnsupportedEncodingException e) {
+        exception(e);
+      }
+    }
+
+
+
+    void printTree(String path) throws IOException {
+
+      indent();
+
+      // TODO: make a link from the path
+
+      String label = path;
+      if (!fullpath) {
+        int idx = path.lastIndexOf('/');
+        label = idx > 0 ? path.substring(idx+1) : path;
+      }
+
+      url(label, path, true);
+
+      out.print(" [");
+
+      Stat stat = new Stat();
+      try {
+        byte[] data = keeper.getData(path, null, stat);
+
+        out.print("v=" + stat.getVersion());
+        if (stat.getNumChildren() != 0) {
+          out.print(" children=" + stat.getNumChildren());
+        }
+
+        if (data != null) {
+          String str;
+          try {
+            str = new String(data, "UTF-8");
+            out.print(" d=\"");
+            xmlescape(compress(str));
+            out.print("\"");
+          } catch (UnsupportedEncodingException e) {
+            // not UTF8
+            StringBuilder sb = new StringBuilder("BIN(");
+            sb.append("len="+data.length);
+            sb.append("hex=");
+            int limit = Math.min(data.length, maxData/2);
+            for (int i=0; i<limit; i++) {
+              byte b = data[i];
+              sb.append(StrUtils.HEX_DIGITS[(b>>4)&0xf]);
+              sb.append(StrUtils.HEX_DIGITS[b&0xf]);
+            }
+            if (limit != data.length) sb.append("...");
+            sb.append(")");
+            str = sb.toString();
+            out.print(" d="+str);
+          }
+
+        }
+
+      } catch (IllegalArgumentException e) {
+        // path doesn't exist (must have been removed)
+        out.println("(path gone)");
+      }
+      catch (KeeperException e) {
+        e.printStackTrace();
+      } catch (InterruptedException e) {
+        e.printStackTrace();
+      }
+
+      out.println("]");
+
+      if (stat.getNumChildren() <= 0) return;
+
+      List<String> children = null;
+      try {
+        children = keeper.getChildren(path, null);
+      } catch (KeeperException e) {
+        exception(e);
+        return;
+      } catch (InterruptedException e) {
+        exception(e);
+      } catch (IllegalArgumentException e) {
+        // path doesn't exist (must have been removed)
+        out.println("(children gone)");
+      }
+
+      up();
+      for (String child : children) {
+        String childPath = path + (path.endsWith("/")?"":"/") + child;
+        printTree(childPath);
+      }
+      down();
+    }
+
+    void printZnode(String path) throws IOException {
+      try {
+
+        Stat stat = new Stat();
+        byte[] data = keeper.getData(path, null, stat);
+
+        out.print("<h2>");
+        xmlescape(path);
+        out.print("</h2>");
+
+        up();
+        indent(); out.print("version=" + stat.getVersion());
+        indent(); out.print("aversion=" + stat.getAversion());
+        indent(); out.print("cversion=" + stat.getCversion());
+        indent(); out.print("ctime=" + stat.getCtime());
+        indent(); out.print("mtime=" + stat.getMtime());
+        indent(); out.print("czxid=" + stat.getCzxid());
+        indent(); out.print("mzxid=" + stat.getMzxid());
+        indent(); out.print("pzxid=" + stat.getPzxid());
+        indent(); out.print("numChildren=" + stat.getNumChildren());
+        indent(); out.print("ephemeralOwner=" + stat.getEphemeralOwner());
+        indent(); out.print("dataLength=" + stat.getDataLength());
+
+        if (data != null) {
+          boolean isBinary = false;
+          String str;
+          try {
+            str = new String(data, "UTF-8");
+          } catch (UnsupportedEncodingException e) {
+            // not UTF8
+            StringBuilder sb = new StringBuilder(data.length*2);
+            for (int i=0; i<data.length; i++) {
+              byte b = data[i];
+              sb.append(StrUtils.HEX_DIGITS[(b>>4)&0xf]);
+              sb.append(StrUtils.HEX_DIGITS[b&0xf]);
+              if ((i&0x3f)==0x3f) sb.append("\n");
+            }
+            str = sb.toString();
+          }
+
+          int nLines = 1;
+          int lineLen = 0;
+          int maxLineLen = 10;  // the minimum
+          for (int i=0; i<str.length(); i++) {
+            if (str.charAt(i)=='\n') {
+              nLines++;
+              maxLineLen = Math.max(maxLineLen, lineLen);
+              lineLen = 0;
+            } else {
+              lineLen++;
+            }
+          }
+
+          indent();
+          out.println("<form method='post' action=''>");
+          out.println("<textarea class='big' wrap='off' readonly rows='" + Math.min(20,nLines)
+//                  + "' cols='" + Math.min(80, maxLineLen+1)
+//                  + "' cols='" + (maxLineLen+1)
+                  + "' name='data'>");
+
+          xmlescape(str);
+
+          out.println("</textarea></form>");
+        }
+
+        down();
+
+      } catch (KeeperException e) {
+        exception(e);
+        return;
+      } catch (InterruptedException e) {
+        exception(e);
+      }
+    }
+  }
+%>
\ No newline at end of file

Propchange: lucene/solr/branches/cloud/src/webapp/web/admin/zookeeper.jsp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/solr/branches/cloud/src/webapp/web/admin/zookeeper.jsp
------------------------------------------------------------------------------
    svn:executable = *

Propchange: lucene/solr/branches/cloud/src/webapp/web/admin/zookeeper.jsp
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL