Java tutorial
/* * 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.solr.handler.admin; 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.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.Locale; import java.util.Set; import java.util.Map; 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 guarantee to never be null (but may be empty) */ private Set<String> arrayToSet(Object[] arr) { HashSet<String> r = new HashSet<>(); if (null == arr) return r; for (Object o : arr) { if (null != o) r.add(o.toString()); } return r; } @Override public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { NamedList<NamedList<NamedList<Object>>> 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<NamedList<NamedList<Object>>> ref = fromXML(content); // Normalize the output SolrQueryResponse wrap = new SolrQueryResponse(); wrap.add("solr-mbeans", cats); cats = (NamedList<NamedList<NamedList<Object>>>) BinaryResponseWriter.getParsedResponse(req, wrap) .get("solr-mbeans"); // Get rid of irrelevant things ref = normalize(ref); cats = normalize(cats); // Only the changes boolean showAll = req.getParams().getBool("all", false); rsp.add("solr-mbeans", getDiff(ref, cats, showAll)); } else { rsp.add("solr-mbeans", cats); } rsp.setHttpCaching(false); // never cache, no matter what init config looks like } static NamedList<NamedList<NamedList<Object>>> fromXML(String content) { int idx = content.indexOf("<response>"); 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<NamedList<NamedList<Object>>>) parser.processResponse(new StringReader(content)) .get("solr-mbeans"); } catch (Exception ex) { throw new SolrException(ErrorCode.BAD_REQUEST, "Unable to read original XML", ex); } } protected NamedList<NamedList<NamedList<Object>>> getMBeanInfo(SolrQueryRequest req) { NamedList<NamedList<NamedList<Object>>> cats = new NamedList<>(); String[] requestedCats = req.getParams().getParams("cat"); if (null == requestedCats || 0 == requestedCats.length) { for (SolrInfoMBean.Category cat : SolrInfoMBean.Category.values()) { cats.add(cat.name(), new SimpleOrderedMap<NamedList<Object>>()); } } else { for (String catName : requestedCats) { cats.add(catName, new SimpleOrderedMap<NamedList<Object>>()); } } Set<String> requestedKeys = arrayToSet(req.getParams().getParams("key")); Map<String, SolrInfoMBean> reg = req.getCore().getInfoRegistry(); for (Map.Entry<String, SolrInfoMBean> entry : reg.entrySet()) { addMBean(req, cats, requestedKeys, entry.getKey(), entry.getValue()); } for (SolrInfoMBean infoMBean : req.getCore().getCoreDescriptor().getCoreContainer().getResourceLoader() .getInfoMBeans()) { addMBean(req, cats, requestedKeys, infoMBean.getName(), infoMBean); } return cats; } private void addMBean(SolrQueryRequest req, NamedList<NamedList<NamedList<Object>>> cats, Set<String> requestedKeys, String key, SolrInfoMBean m) { if (!(requestedKeys.isEmpty() || requestedKeys.contains(key))) return; NamedList<NamedList<Object>> catInfo = cats.get(m.getCategory().name()); if (null == catInfo) return; NamedList<Object> mBeanInfo = new SimpleOrderedMap<>(); mBeanInfo.add("class", m.getName()); mBeanInfo.add("version", m.getVersion()); mBeanInfo.add("description", m.getDescription()); mBeanInfo.add("src", m.getSource()); // Use an external form URL[] urls = m.getDocs(); if (urls != null) { List<String> docs = new ArrayList<>(urls.length); for (URL url : urls) { docs.add(url.toExternalForm()); } mBeanInfo.add("docs", docs); } if (req.getParams().getFieldBool(key, "stats", false)) mBeanInfo.add("stats", m.getStatistics()); catInfo.add(key, mBeanInfo); } protected NamedList<NamedList<NamedList<Object>>> getDiff(NamedList<NamedList<NamedList<Object>>> ref, NamedList<NamedList<NamedList<Object>>> now, boolean includeAll) { NamedList<NamedList<NamedList<Object>>> changed = new NamedList<>(); // Cycle through each category for (int i = 0; i < ref.size(); i++) { String category = ref.getName(i); NamedList<NamedList<Object>> ref_cat = ref.get(category); NamedList<NamedList<Object>> 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<NamedList<Object>> cat = new SimpleOrderedMap<>(); for (int j = 0; j < ref_cat.size(); j++) { String name = ref_cat.getName(j); NamedList<Object> ref_bean = ref_cat.get(name); NamedList<Object> 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 NamedList diff = diffNamedList(ref_bean, now_bean); diff.add("_changed_", true); // flag the changed thing cat.add(name, diff); } else if (includeAll) { cat.add(name, ref_bean); } } if (cat.size() > 0) { changed.add(category, cat); } } else if (includeAll) { changed.add(category, ref_cat); } } } return changed; } public NamedList diffNamedList(NamedList ref, NamedList now) { NamedList out = new SimpleOrderedMap(); for (int i = 0; i < ref.size(); i++) { String name = ref.getName(i); Object r = ref.getVal(i); Object n = now.remove(name); if (n == null) { if (r != null) { out.add("REMOVE " + name, r); } } else { out.add(name, diffObject(r, n)); } } for (int i = 0; i < now.size(); i++) { String name = now.getName(i); Object v = now.getVal(i); if (v != null) { out.add("ADD " + name, v); } } return out; } public Object diffObject(Object ref, Object now) { if (ref instanceof NamedList) { return diffNamedList((NamedList) ref, (NamedList) now); } if (ref.equals(now)) { return ref; } StringBuilder str = new StringBuilder(); str.append("Was: ").append(ref).append(", Now: ").append(now); if (ref instanceof Number) { NumberFormat nf = NumberFormat.getIntegerInstance(Locale.ROOT); if ((ref instanceof Double) || (ref instanceof Float)) { nf = NumberFormat.getInstance(Locale.ROOT); } double dref = ((Number) ref).doubleValue(); double dnow = ((Number) now).doubleValue(); double diff = Double.NaN; if (Double.isNaN(dref)) { diff = dnow; } else if (Double.isNaN(dnow)) { diff = dref; } else { diff = dnow - dref; } str.append(", Delta: ").append(nf.format(diff)); } return str.toString(); } /** * The 'avgRequestsPerSecond' field will make everything look like it changed */ public NamedList normalize(NamedList input) { input.remove("avgRequestsPerSecond"); for (int i = 0; i < input.size(); i++) { Object v = input.getVal(i); if (v instanceof NamedList) { input.setVal(i, normalize((NamedList) v)); } } return input; } @Override public String getDescription() { return "Get Info (and statistics) for registered SolrInfoMBeans"; } @Override public Category getCategory() { return Category.ADMIN; } }