diff --git a/solr/core/src/java/org/apache/solr/handler/admin/SolrInfoMBeanHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/SolrInfoMBeanHandler.java index 5b3b5fa52db..138ab097a59 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/SolrInfoMBeanHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/SolrInfoMBeanHandler.java @@ -17,15 +17,22 @@ package org.apache.solr.handler.admin; * limitations under the License. */ +import org.apache.commons.io.IOUtils; import org.apache.solr.handler.RequestHandlerBase; import org.apache.solr.request.SolrQueryRequest; +import org.apache.solr.client.solrj.impl.XMLResponseParser; import org.apache.solr.core.SolrInfoMBean; -import org.apache.solr.core.SolrCore; +import org.apache.solr.common.SolrException; +import org.apache.solr.common.SolrException.ErrorCode; +import org.apache.solr.common.util.ContentStream; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.SimpleOrderedMap; +import org.apache.solr.response.BinaryResponseWriter; import org.apache.solr.response.SolrQueryResponse; +import java.io.StringReader; import java.net.URL; +import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -36,11 +43,12 @@ import java.util.HashSet; * A request handler that provides info about all * registered SolrInfoMBeans. */ +@SuppressWarnings("unchecked") public class SolrInfoMBeanHandler extends RequestHandlerBase { /** * Take an array of any type and generate a Set containing the toString. - * Set is garunteed to never be null (but may be empty) + * Set is guarantee to never be null (but may be empty) */ private Set arrayToSet(Object[] arr) { HashSet r = new HashSet(); @@ -50,14 +58,61 @@ public class SolrInfoMBeanHandler extends RequestHandlerBase { } return r; } - @Override public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { - SolrCore core = req.getCore(); - + NamedList>> cats = getMBeanInfo(req); + if(req.getParams().getBool("diff", false)) { + ContentStream body = null; + try { + body = req.getContentStreams().iterator().next(); + } + catch(Exception ex) { + throw new SolrException(ErrorCode.BAD_REQUEST, "missing content-stream for diff"); + } + String content = IOUtils.toString(body.getReader()); + + NamedList>> ref = fromXML(content); + + + // Normalize the output + SolrQueryResponse wrap = new SolrQueryResponse(); + wrap.add("solr-mbeans", cats); + cats = (NamedList>>) + BinaryResponseWriter.getParsedResponse(req, wrap).get("solr-mbeans"); + + // Get rid of irrelevant things + ref = normalize(ref); + cats = normalize(cats); + + // Only the changes + rsp.add("solr-mbeans", getDiff(ref,cats)); + } + else { + rsp.add("solr-mbeans", cats); + } + rsp.setHttpCaching(false); // never cache, no matter what init config looks like + } + + static NamedList>> fromXML(String content) { + int idx = content.indexOf(""); + if(idx<0) { + throw new SolrException(ErrorCode.BAD_REQUEST, "Body does not appear to be an XML response"); + } + + try { + XMLResponseParser parser = new XMLResponseParser(); + return (NamedList>>) + parser.processResponse(new StringReader(content.substring(idx))).get("solr-mbeans"); + } + catch(Exception ex) { + throw new SolrException(ErrorCode.BAD_REQUEST, "Unable to read original XML", ex); + } + } + + protected NamedList>> getMBeanInfo(SolrQueryRequest req) { + NamedList>> cats = new NamedList>>(); - rsp.add("solr-mbeans", cats); String[] requestedCats = req.getParams().getParams("cat"); if (null == requestedCats || 0 == requestedCats.length) { @@ -72,7 +127,7 @@ public class SolrInfoMBeanHandler extends RequestHandlerBase { Set requestedKeys = arrayToSet(req.getParams().getParams("key")); - Map reg = core.getInfoRegistry(); + Map reg = req.getCore().getInfoRegistry(); for (Map.Entry entry : reg.entrySet()) { String key = entry.getKey(); SolrInfoMBean m = entry.getValue(); @@ -103,16 +158,122 @@ public class SolrInfoMBeanHandler extends RequestHandlerBase { catInfo.add(key, mBeanInfo); } - rsp.setHttpCaching(false); // never cache, no matter what init config looks like + return cats; } + protected NamedList>> getDiff(NamedList>> ref, NamedList>> now) { + NamedList>> changed = new NamedList>>(); + + // Cycle through each category + for(int i=0;i> ref_cat = ref.get(category); + NamedList> now_cat = now.get(category); + if(now_cat != null) { + String ref_txt = ref_cat+""; + String now_txt = now_cat+""; + if(!ref_txt.equals(now_txt)) { + // Something in the category changed + // Now iterate the real beans + + NamedList> cat = new NamedList>(); + for(int j=0;j ref_bean = ref_cat.get(name); + NamedList now_bean = now_cat.get(name); + + ref_txt = ref_bean+""; + now_txt = now_bean+""; + if(!ref_txt.equals(now_txt)) { +// System.out.println( "----" ); +// System.out.println( category +" : " + name ); +// System.out.println( "REF: " + ref_txt ); +// System.out.println( "NOW: " + now_txt ); + + // Calculate the differences + cat.add(name, diffNamedList(ref_bean,now_bean)); + } + } + if(cat.size()>0) { + changed.add(category, cat); + } + } + } + } + return changed; + } + + public NamedList diffNamedList(NamedList ref, NamedList now) { + NamedList out = new NamedList(); + for(int i=0; i streams = new ArrayList(); + streams.add(new ContentStreamBase.StringStream(xml)); + + LocalSolrQueryRequest req = lrf.makeRequest( + CommonParams.QT,"/admin/mbeans", + "stats","true", + CommonParams.WT,"xml", + "diff","true"); + req.setContentStreams(streams); + + xml = h.query(req); + NamedList>> diff = SolrInfoMBeanHandler.fromXML(xml); + + // The stats bean for SolrInfoMBeanHandler + NamedList stats = (NamedList)diff.get("QUERYHANDLER").get("/admin/mbeans").get("stats"); + + //System.out.println("stats:"+stats); + assertEquals("Was: 1, Now: 2, Delta: 1", stats.get("requests")); + } +}