/*
* 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;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrInfoMBean;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrRequestHandler;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.search.SyntaxError;
import org.apache.solr.util.SolrPluginUtils;
import org.apache.solr.util.stats.Snapshot;
import org.apache.solr.util.stats.Timer;
import org.apache.solr.util.stats.TimerContext;
import java.net.URL;
import java.util.concurrent.atomic.AtomicLong;
/**
*
*/
public abstract class RequestHandlerBase implements SolrRequestHandler, SolrInfoMBean {
protected NamedList initArgs = null;
protected SolrParams defaults;
protected SolrParams appends;
protected SolrParams invariants;
protected boolean httpCaching = true;
// Statistics
private final AtomicLong numRequests = new AtomicLong();
private final AtomicLong numErrors = new AtomicLong();
private final AtomicLong numTimeouts = new AtomicLong();
private final Timer requestTimes = new Timer();
private final long handlerStart = System.currentTimeMillis();
/**
* Initializes the {@link org.apache.solr.request.SolrRequestHandler} by creating three {@link org.apache.solr.common.params.SolrParams} named.
* <table border="1">
* <tr><th>Name</th><th>Description</th></tr>
* <tr><td>defaults</td><td>Contains all of the named arguments contained within the list element named "defaults".</td></tr>
* <tr><td>appends</td><td>Contains all of the named arguments contained within the list element named "appends".</td></tr>
* <tr><td>invariants</td><td>Contains all of the named arguments contained within the list element named "invariants".</td></tr>
* </table>
*
* Example:
* <pre>
* <lst name="defaults">
* <str name="echoParams">explicit</str>
* <str name="qf">text^0.5 features^1.0 name^1.2 sku^1.5 id^10.0</str>
* <str name="mm">2<-1 5<-2 6<90%</str>
* <str name="bq">incubationdate_dt:[* TO NOW/DAY-1MONTH]^2.2</str>
* </lst>
* <lst name="appends">
* <str name="fq">inStock:true</str>
* </lst>
*
* <lst name="invariants">
* <str name="facet.field">cat</str>
* <str name="facet.field">manu_exact</str>
* <str name="facet.query">price:[* TO 500]</str>
* <str name="facet.query">price:[500 TO *]</str>
* </lst>
* </pre>
*
*
* @param args The {@link org.apache.solr.common.util.NamedList} to initialize from
*
* @see #handleRequest(org.apache.solr.request.SolrQueryRequest, org.apache.solr.response.SolrQueryResponse)
* @see #handleRequestBody(org.apache.solr.request.SolrQueryRequest, org.apache.solr.response.SolrQueryResponse)
* @see org.apache.solr.util.SolrPluginUtils#setDefaults(org.apache.solr.request.SolrQueryRequest, org.apache.solr.common.params.SolrParams, org.apache.solr.common.params.SolrParams, org.apache.solr.common.params.SolrParams)
* @see SolrParams#toSolrParams(org.apache.solr.common.util.NamedList)
*
* See also the example solrconfig.xml located in the Solr codebase (example/solr/conf).
*/
@Override
public void init(NamedList args) {
initArgs = args;
// Copied from StandardRequestHandler
if( args != null ) {
Object o = args.get("defaults");
if (o != null && o instanceof NamedList) {
defaults = SolrParams.toSolrParams((NamedList)o);
}
o = args.get("appends");
if (o != null && o instanceof NamedList) {
appends = SolrParams.toSolrParams((NamedList)o);
}
o = args.get("invariants");
if (o != null && o instanceof NamedList) {
invariants = SolrParams.toSolrParams((NamedList)o);
}
}
if (initArgs != null) {
Object caching = initArgs.get("httpCaching");
httpCaching = caching != null ? Boolean.parseBoolean(caching.toString()) : true;
}
}
public NamedList getInitArgs() {
return initArgs;
}
public abstract void handleRequestBody( SolrQueryRequest req, SolrQueryResponse rsp ) throws Exception;
@Override
public void handleRequest(SolrQueryRequest req, SolrQueryResponse rsp) {
numRequests.incrementAndGet();
TimerContext timer = requestTimes.time();
try {
SolrPluginUtils.setDefaults(req,defaults,appends,invariants);
rsp.setHttpCaching(httpCaching);
handleRequestBody( req, rsp );
// count timeouts
NamedList header = rsp.getResponseHeader();
if(header != null) {
Object partialResults = header.get("partialResults");
boolean timedOut = partialResults == null ? false : (Boolean)partialResults;
if( timedOut ) {
numTimeouts.incrementAndGet();
rsp.setHttpCaching(false);
}
}
} catch (Exception e) {
if (e instanceof SolrException) {
SolrException se = (SolrException)e;
if (se.code() == SolrException.ErrorCode.CONFLICT.code) {
// TODO: should we allow this to be counted as an error (numErrors++)?
} else {
SolrException.log(SolrCore.log,e);
}
} else {
SolrException.log(SolrCore.log,e);
if (e instanceof SyntaxError) {
e = new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
}
}
rsp.setException(e);
numErrors.incrementAndGet();
}
finally {
timer.stop();
}
}
//////////////////////// SolrInfoMBeans methods //////////////////////
@Override
public String getName() {
return this.getClass().getName();
}
@Override
public abstract String getDescription();
@Override
public abstract String getSource();
@Override
public String getVersion() {
return getClass().getPackage().getSpecificationVersion();
}
@Override
public Category getCategory() {
return Category.QUERYHANDLER;
}
@Override
public URL[] getDocs() {
return null; // this can be overridden, but not required
}
@Override
public NamedList<Object> getStatistics() {
NamedList<Object> lst = new SimpleOrderedMap<>();
Snapshot snapshot = requestTimes.getSnapshot();
lst.add("handlerStart",handlerStart);
lst.add("requests", numRequests.longValue());
lst.add("errors", numErrors.longValue());
lst.add("timeouts", numTimeouts.longValue());
lst.add("totalTime", requestTimes.getSum());
lst.add("avgRequestsPerSecond", requestTimes.getMeanRate());
lst.add("5minRateReqsPerSecond", requestTimes.getFiveMinuteRate());
lst.add("15minRateReqsPerSecond", requestTimes.getFifteenMinuteRate());
lst.add("avgTimePerRequest", requestTimes.getMean());
lst.add("medianRequestTime", snapshot.getMedian());
lst.add("75thPcRequestTime", snapshot.get75thPercentile());
lst.add("95thPcRequestTime", snapshot.get95thPercentile());
lst.add("99thPcRequestTime", snapshot.get99thPercentile());
lst.add("999thPcRequestTime", snapshot.get999thPercentile());
return lst;
}
}