All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.solr.handler.admin.SolrInfoMBeanHandler Maven / Gradle / Ivy

There is a newer version: 9.6.1
Show newest version
/*
 * 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.SolrInfoBean;
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.text.NumberFormat;
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 arrayToSet(Object[] arr) {
    HashSet 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>> 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
      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>> 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)).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<>();
    
    String[] requestedCats = req.getParams().getParams("cat");
    if (null == requestedCats || 0 == requestedCats.length) {
      for (SolrInfoBean.Category cat : SolrInfoBean.Category.values()) {
        cats.add(cat.name(), new SimpleOrderedMap>());
      }
    } else {
      for (String catName : requestedCats) {
        cats.add(catName,new SimpleOrderedMap>());
      }
    }
         
    Set requestedKeys = arrayToSet(req.getParams().getParams("key"));
    
    Map reg = req.getCore().getInfoRegistry();
    for (Map.Entry entry : reg.entrySet()) {
      addMBean(req, cats, requestedKeys, entry.getKey(),entry.getValue());
    }

    for (SolrInfoBean infoMBean : req.getCore().getCoreContainer().getResourceLoader().getInfoMBeans()) {
      addMBean(req,cats,requestedKeys,infoMBean.getName(),infoMBean);
    }
    return cats;
  }

  private void addMBean(SolrQueryRequest req, NamedList>> cats, Set requestedKeys, String key, SolrInfoBean m) {
    if ( ! ( requestedKeys.isEmpty() || requestedKeys.contains(key) ) ) return;
    NamedList> catInfo = cats.get(m.getCategory().name());
    if ( null == catInfo ) return;
    NamedList mBeanInfo = new SimpleOrderedMap<>();
    mBeanInfo.add("class", m.getName());
    mBeanInfo.add("description", m.getDescription());

    if (req.getParams().getFieldBool(key, "stats", false))
      mBeanInfo.add("stats", m.getMetricsSnapshot());

    catInfo.add(key, mBeanInfo);
  }

  protected NamedList>> getDiff(
      NamedList>> ref, 
      NamedList>> now,
      boolean includeAll ) {
    
    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 SimpleOrderedMap<>();
          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
              @SuppressWarnings({"rawtypes"})
              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;
  }
  
  @SuppressWarnings({"rawtypes"})
  public NamedList diffNamedList(NamedList ref, NamedList now) {
    NamedList out = new SimpleOrderedMap();
    for(int i=0; i