diff --git a/solr/core/src/java/org/apache/solr/servlet/ZookeeperInfoServlet.java b/solr/core/src/java/org/apache/solr/servlet/ZookeeperInfoServlet.java
index c736580d852..008ec76727e 100644
--- a/solr/core/src/java/org/apache/solr/servlet/ZookeeperInfoServlet.java
+++ b/solr/core/src/java/org/apache/solr/servlet/ZookeeperInfoServlet.java
@@ -17,6 +17,21 @@
package org.apache.solr.servlet;
+import org.apache.noggit.CharArr;
+import org.apache.noggit.JSONWriter;
+import org.apache.solr.cloud.ZkController;
+import org.apache.solr.common.cloud.SolrZkClient;
+import org.apache.solr.common.util.StrUtils;
+import org.apache.solr.core.CoreContainer;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.data.Stat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
@@ -25,19 +40,6 @@ import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeoutException;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.solr.cloud.ZkController;
-import org.apache.solr.common.cloud.SolrZkClient;
-import org.apache.solr.common.util.StrUtils;
-import org.apache.solr.common.util.XML;
-import org.apache.solr.core.CoreContainer;
-import org.apache.zookeeper.KeeperException;
-import org.apache.zookeeper.data.Stat;
-
/**
* Zookeeper Info
@@ -45,6 +47,7 @@ import org.apache.zookeeper.data.Stat;
* @since solr 4.0
*/
public final class ZookeeperInfoServlet extends HttpServlet {
+ static final Logger log = LoggerFactory.getLogger(ZookeeperInfoServlet.class);
@Override
public void init() throws ServletException {
@@ -53,27 +56,28 @@ public final class ZookeeperInfoServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
- throws IOException, ServletException {
+ throws IOException, ServletException {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
+ // This attribute is set by the SolrDispatchFilter
CoreContainer cores = (CoreContainer) request.getAttribute("org.apache.solr.CoreContainer");
-
+
String path = request.getParameter("path");
String addr = request.getParameter("addr");
-
- if (addr != null && addr.length() == 0)
- {
+
+ if (addr != null && addr.length() == 0) {
addr = null;
}
-
+
String detailS = request.getParameter("detail");
boolean detail = detailS != null && detailS.equals("true");
PrintWriter out = response.getWriter();
-
+
+
ZKPrinter printer = new ZKPrinter(response, out, cores.getZkController(), addr);
printer.detail = detail;
-
+
try {
printer.print(path);
} finally {
@@ -84,455 +88,350 @@ public final class ZookeeperInfoServlet extends HttpServlet {
@Override
public void doPost(HttpServletRequest request,
HttpServletResponse response)
- throws IOException, ServletException {
- doGet(request,response);
+ throws IOException, ServletException {
+ doGet(request, response);
}
//--------------------------------------------------------------------------------------
- //
+ //
//--------------------------------------------------------------------------------------
-
- static class ZKPrinter
- {
-
+
+ static class ZKPrinter {
static boolean FULLPATH_DEFAULT = false;
-
+
boolean indent = true;
boolean fullpath = FULLPATH_DEFAULT;
boolean detail = false;
-
+
String addr; // the address passed to us
String keeperAddr; // the address we're connected to
-
+
boolean doClose; // close the client after done if we opened it
-
- HttpServletResponse response;
- PrintWriter out;
+
+ final HttpServletResponse response;
+ final PrintWriter out;
SolrZkClient zkClient;
-
+
int level;
int maxData = 95;
-
- public ZKPrinter(HttpServletResponse response, PrintWriter out, ZkController controller, String addr) throws IOException
- {
+
+ public ZKPrinter(HttpServletResponse response, PrintWriter out, ZkController controller, String addr) throws IOException {
this.response = response;
this.out = out;
this.addr = addr;
-
- if (addr == null)
- {
- if (controller != null)
- {
+
+ if (addr == null) {
+ if (controller != null) {
// this core is zk enabled
keeperAddr = controller.getZkServerAddress();
zkClient = controller.getZkClient();
- if (zkClient != null && zkClient.isConnected())
- {
+ if (zkClient != null && zkClient.isConnected()) {
return;
- }
- else
- {
+ } else {
// try a different client with this address
addr = keeperAddr;
}
}
}
-
+
keeperAddr = addr;
- if (addr == null)
- {
- response.setStatus(404);
- out.println
- (
- "{" +
- "\"status\": 404" +
- ", \"error\" : \"Zookeeper is not configured for this Solr Core. Please try connecting to an alternate zookeeper address.\"" +
- "}"
- );
+ if (addr == null) {
+ writeError(404, "Zookeeper is not configured for this Solr Core. Please try connecting to an alternate zookeeper address.");
return;
}
-
- try
- {
+
+ try {
zkClient = new SolrZkClient(addr, 10000);
doClose = true;
- }
- catch (TimeoutException e)
- {
- response.setStatus(503);
- out.println
- (
- "{" +
- "\"status\": 503" +
- ", \"error\" : \"Could not connect to zookeeper at '" + addr + "'\"" +
- "}"
- );
+ } catch (TimeoutException e) {
+ writeError(503, "Could not connect to zookeeper at '" + addr + "'\"");
zkClient = null;
return;
- }
- catch (InterruptedException e)
- {
+ } catch (InterruptedException e) {
// Restore the interrupted status
Thread.currentThread().interrupt();
- response.setStatus(503);
- out.println
- (
- "{" +
- "\"status\": 503" +
- ", \"error\" : \"Could not connect to zookeeper at '" + addr + "'\"" +
- "}"
- );
+ writeError(503, "Could not connect to zookeeper at '" + addr + "'\"");
zkClient = null;
return;
}
-
+
}
- public void close()
- {
+ public void close() {
try {
- if (doClose)
- {
+ if (doClose) {
zkClient.close();
}
} catch (InterruptedException e) {
- // ignore exception on close
+ // ignore exception on close
}
}
-
+
// main entry point
- void print(String path) throws IOException
- {
+ void print(String path) throws IOException {
if (zkClient == null) {
return;
}
-
+
// normalize path
if (path == null) {
path = "/";
- }
- else {
+ } else {
path.trim();
- if (path.length() == 0)
- {
+ if (path.length() == 0) {
path = "/";
}
}
-
- if (path.endsWith("/") && path.length() > 1)
- {
+
+ 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)
- {
+ if (parent.length() == 0) {
parent = "/";
}
-
- out.println("{");
-
- if (detail)
- {
- printZnode(path);
- out.println(", ");
- }
-
- out.println("\"tree\" : [");
- printTree(path);
- out.println("]");
-
- out.println("}");
- }
-
- void exception(Exception e)
- {
- response.setStatus(500);
- out.println
- (
- "{" +
- "\"status\": 500" +
- ", \"error\" : \"" + e.toString() + "\"" +
- "}"
- );
- }
-
- void xmlescape(String s)
- {
- try
- {
- XML.escapeCharData(s, out);
- }
- catch (IOException e)
- {
- throw new RuntimeException(e);
- }
- }
-
- // 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);
+
+ CharArr chars = new CharArr();
+ JSONWriter json = new JSONWriter(chars, 2);
+ json.startObject();
+
+ if (detail) {
+ if (!printZnode(json, path)) {
+ return;
}
-
- if (newline) {
- // sb.append("\\n");
- sb.append(" "); // collapse newline to two spaces
- } else if (whitespace) {
- sb.append(' ');
- }
-
- // TODO: handle non-printable chars
- sb.append(ch);
-
- if (sb.length() >= maxData)
- return sb.toString() + " ...";
+ json.writeValueSeparator();
}
- return sb.toString();
+
+ json.writeString("tree");
+ json.writeNameSeparator();
+ json.startArray();
+ if (!printTree(json, path)) {
+ return; // there was an error
+ }
+ json.endArray();
+ json.endObject();
+ out.println(chars.toString());
}
- void url(String label, String path, boolean detail) throws IOException {
- try {
- out.print("");
- xmlescape(label);
- out.print("");
+ CharArr chars = new CharArr();
+ JSONWriter w = new JSONWriter(chars, 2);
+ w.startObject();
+ w.indent();
+ w.writeString("status");
+ w.writeNameSeparator();
+ w.write(code);
+ w.writeValueSeparator();
+ w.indent();
+ w.writeString("error");
+ w.writeNameSeparator();
+ w.writeString(msg);
+ w.endObject();
- } catch (UnsupportedEncodingException e) {
- exception(e);
- }
+ out.println(chars.toString());
}
- void printTree(String path) throws IOException
- {
+
+ boolean printTree(JSONWriter json, String path) throws IOException {
String label = path;
- if (!fullpath)
- {
+ if (!fullpath) {
int idx = path.lastIndexOf('/');
label = idx > 0 ? path.substring(idx + 1) : path;
}
-
- //url(label, path, true);
- out.println("{");
- out.println("\"data\" : \"" + label + "\"");
-
+ json.startObject();
+ //writeKeyValue(json, "data", label, true );
+ json.writeString("data");
+ json.writeNameSeparator();
+
+ json.startObject();
+ writeKeyValue(json, "title", label, true);
+ json.writeValueSeparator();
+ json.writeString("attr");
+ json.writeNameSeparator();
+ json.startObject();
+ writeKeyValue(json, "href", "zookeeper?detail=true&path=" + URLEncoder.encode(path, "UTF-8"), true);
+ json.endObject();
+ json.endObject();
+
Stat stat = new Stat();
- try
- {
+ try {
byte[] data = zkClient.getData(path, null, stat, true);
-
- if( stat.getEphemeralOwner() != 0 )
- {
- out.println(", \"ephemeral\" : true");
- out.println(", \"version\" : \"" + stat.getVersion() + "\"");
+
+ if (stat.getEphemeralOwner() != 0) {
+ writeKeyValue(json, "ephemeral", true, false);
+ writeKeyValue(json, "version", stat.getVersion(), false);
}
-
+
/*
if (stat.getNumChildren() != 0)
{
+ writeKeyValue(json, "children_count", stat.getNumChildren(), false );
out.println(", \"children_count\" : \"" + stat.getNumChildren() + "\"");
}
*/
-
+
//if (data != null)
- if( stat.getDataLength() != 0 )
- {
+ if (stat.getDataLength() != 0) {
String str;
- try
- {
+ try {
str = new String(data, "UTF-8");
str = str.replaceAll("\\\"", "\\\\\"");
-
- out.print(", \"content\" : \"");
- //xmlescape(compress(str));
- out.print(compress(str));
- out.println("\"");
- }
- catch (UnsupportedEncodingException e)
- {
+
+ //writeKeyValue(json, "content", str, false );
+ } 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++)
- {
+ 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)
- {
+ if (limit != data.length) {
sb.append("...");
}
sb.append(")");
str = sb.toString();
- //out.print(str);
+ //?? writeKeyValue(json, "content", str, false );
}
}
- }
- catch (IllegalArgumentException e)
- {
+ } catch (IllegalArgumentException e) {
// path doesn't exist (must have been removed)
- out.println("(path gone)");
+ writeKeyValue(json, "warning", "(path gone)", false);
+ } catch (KeeperException e) {
+ writeKeyValue(json, "warning", e.toString(), false);
+ log.warn("Keeper Exception", e);
+ } catch (InterruptedException e) {
+ writeKeyValue(json, "warning", e.toString(), false);
+ log.warn("InterruptedException", e);
}
- catch (KeeperException e)
- {
- e.printStackTrace();
- }
- catch (InterruptedException e)
- {
- e.printStackTrace();
- }
-
- if( stat.getNumChildren() > 0 )
- {
- out.print(", \"children\" : [");
-
- List children = null;
- try
- {
- children = zkClient.getChildren(path, null, true);
+
+ if (stat.getNumChildren() > 0) {
+ json.writeValueSeparator();
+ if (indent) {
+ json.indent();
}
- 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)");
- }
-
- Integer i = 0;
- for( String child : children )
- {
- if( 0 != i )
- {
- out.print(", ");
+ json.writeString("children");
+ json.writeNameSeparator();
+ json.startArray();
+
+ try {
+ List children = zkClient.getChildren(path, null, true);
+ java.util.Collections.sort(children);
+
+ boolean first = true;
+ for (String child : children) {
+ if (!first) {
+ json.writeValueSeparator();
+ }
+
+ String childPath = path + (path.endsWith("/") ? "" : "/") + child;
+ if (!printTree(json, childPath)) {
+ return false;
+ }
+ first = false;
}
-
- String childPath = path + (path.endsWith("/") ? "" : "/") + child;
- printTree( childPath );
-
- i++;
+ } catch (KeeperException e) {
+ writeError(500, e.toString());
+ return false;
+ } catch (InterruptedException e) {
+ writeError(500, e.toString());
+ return false;
+ } catch (IllegalArgumentException e) {
+ // path doesn't exist (must have been removed)
+ json.writeString("(children gone)");
}
-
- out.println("]");
+
+ json.endArray();
}
-
- out.println("}");
+
+ json.endObject();
+ return true;
}
String time(long ms) {
return (new Date(ms)).toString() + " (" + ms + ")";
}
-
- void printZnode(String path) throws IOException
- {
- try
- {
+
+ public void writeKeyValue(JSONWriter json, String k, Object v, boolean isFirst) {
+ if (!isFirst) {
+ json.writeValueSeparator();
+ }
+ if (indent) {
+ json.indent();
+ }
+ json.writeString(k);
+ json.writeNameSeparator();
+ json.write(v);
+ }
+
+ boolean printZnode(JSONWriter json, String path) throws IOException {
+ try {
Stat stat = new Stat();
byte[] data = zkClient.getData(path, null, stat, true);
-
- out.println("\"znode\" : {");
-
- out.print("\"path\" : \"");
- xmlescape(path);
- out.println("\"");
-
- out.println(", \"version\" : \"" + stat.getVersion() + "\"");
- out.println(", \"aversion\" : \"" + stat.getAversion() + "\"");
- out.println(", \"cversion\" : \"" + stat.getCversion() + "\"");
- out.println(", \"ctime\" : \"" + time(stat.getCtime()) + "\"");
- out.println(", \"mtime\" : \"" + time(stat.getMtime()) + "\"");
- out.println(", \"czxid\" : \"" + stat.getCzxid() + "\"");
- out.println(", \"mzxid\" : \"" + stat.getMzxid() + "\"");
- out.println(", \"pzxid\" : \"" + stat.getPzxid() + "\"");
- out.println(", \"children_count\" : \"" + stat.getNumChildren() + "\"");
- out.println(", \"ephemeralOwner\" : \"" + stat.getEphemeralOwner() + "\"");
- out.println(", \"dataLength\" : \"" + stat.getDataLength() + "\"");
-
- if( stat.getDataLength() != 0 )
- {
- boolean isBinary = false;
+
+ json.writeString("znode");
+ json.writeNameSeparator();
+ json.startObject();
+
+ writeKeyValue(json, "path", path, true);
+
+ json.writeValueSeparator();
+ json.writeString("prop");
+ json.writeNameSeparator();
+ json.startObject();
+ writeKeyValue(json, "version", stat.getVersion(), true);
+ writeKeyValue(json, "aversion", stat.getAversion(), false);
+ writeKeyValue(json, "children_count", stat.getNumChildren(), false);
+ writeKeyValue(json, "ctime", time(stat.getCtime()), false);
+ writeKeyValue(json, "cversion", stat.getCversion(), false);
+ writeKeyValue(json, "czxid", stat.getCzxid(), false);
+ writeKeyValue(json, "dataLength", stat.getDataLength(), false);
+ writeKeyValue(json, "ephemeralOwner", stat.getEphemeralOwner(), false);
+ writeKeyValue(json, "mtime", time(stat.getMtime()), false);
+ writeKeyValue(json, "mzxid", stat.getMzxid(), false);
+ writeKeyValue(json, "pzxid", stat.getPzxid(), false);
+ json.endObject();
+
+ if (stat.getDataLength() != 0) {
String str;
- try
- {
+ try {
str = new String(data, "UTF-8");
- }
- catch (UnsupportedEncodingException e)
- {
+ } catch (UnsupportedEncodingException e) {
// The results are unspecified
// when the bytes are not properly encoded.
-
+
// not UTF8
StringBuilder sb = new StringBuilder(data.length * 2);
- for (int i = 0; i < data.length; i++)
- {
+ 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)
- {
+ if ((i & 0x3f) == 0x3f) {
sb.append("\n");
}
}
str = sb.toString();
}
str = str.replaceAll("\\\"", "\\\\\"");
-
- out.print(", \"data\" : \"");
- //xmlescape(str);
- out.print(str);
- out.println("\"");
+ writeKeyValue(json, "data", str, false);
}
-
- out.println("}");
-
- }
- catch (KeeperException e)
- {
- exception(e);
- return;
- }
- catch (InterruptedException e)
- {
- exception(e);
+ json.endObject();
+ } catch (KeeperException e) {
+ writeError(500, e.toString());
+ return false;
+ } catch (InterruptedException e) {
+ writeError(500, e.toString());
+ return false;
}
+ return true;
}
}
}
-