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

org.apache.solr.rest.BaseSolrResource Maven / Gradle / Ivy

There is a newer version: 9.7.0
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.rest;

import static org.apache.solr.common.params.CommonParams.JSON;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.core.SolrCore;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.QueryResponseWriter;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.servlet.ResponseUtils;
import org.slf4j.Logger;

/**
 * Base class for delegating REST-oriented requests to ManagedResources. ManagedResources are
 * heavy-weight and should not be created for every request, so this class serves as a gateway
 * between a REST call and the resource.
 */
public abstract class BaseSolrResource {
  protected static final String SHOW_DEFAULTS = "showDefaults";
  public static final String UPDATE_TIMEOUT_SECS = "updateTimeoutSecs";

  private SolrCore solrCore;
  private IndexSchema schema;
  private SolrQueryRequest solrRequest;
  private SolrQueryResponse solrResponse;
  private QueryResponseWriter responseWriter;
  private String contentType;
  private int updateTimeoutSecs = -1;
  private int statusCode = -1;

  public SolrCore getSolrCore() {
    return solrCore;
  }

  public IndexSchema getSchema() {
    return schema;
  }

  public SolrQueryRequest getSolrRequest() {
    return solrRequest;
  }

  public SolrQueryResponse getSolrResponse() {
    return solrResponse;
  }

  public String getContentType() {
    return contentType;
  }

  protected int getUpdateTimeoutSecs() {
    return updateTimeoutSecs;
  }

  protected BaseSolrResource() {
    super();
  }

  /**
   * Pulls the SolrQueryRequest constructed in SolrDispatchFilter from the SolrRequestInfo thread
   * local, then gets the SolrCore and IndexSchema and sets up the response. writer.
   */
  public void doInit(SolrQueryRequest solrRequest, SolrQueryResponse solrResponse) {
    try {
      this.solrRequest = solrRequest;
      this.solrResponse = solrResponse;
      solrCore = solrRequest.getCore();
      schema = solrRequest.getSchema();
      String responseWriterName = solrRequest.getParams().get(CommonParams.WT, JSON);
      responseWriter = solrCore.getQueryResponseWriter(responseWriterName);
      contentType = responseWriter.getContentType(solrRequest, solrResponse);
      final String path = solrRequest.getPath();
      if (!RestManager.SCHEMA_BASE_PATH.equals(path)) {
        // don't set webapp property on the request when context and core/collection are excluded
        final int cutoffPoint = path.indexOf('/', 1);
        final String firstPathElement = -1 == cutoffPoint ? path : path.substring(0, cutoffPoint);
        solrRequest.getContext().put("webapp", firstPathElement); // Context path
      }

      // client application can set a timeout for update requests
      String updateTimeoutSecsParam = solrRequest.getParams().get(UPDATE_TIMEOUT_SECS);
      if (updateTimeoutSecsParam != null)
        updateTimeoutSecs = Integer.parseInt(updateTimeoutSecsParam);
    } catch (Throwable t) {
      if (t instanceof OutOfMemoryError) {
        throw (OutOfMemoryError) t;
      }
      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, t);
    }
  }

  /**
   * Deal with an exception on the SolrResponse, fill in response header info, and log the
   * accumulated messages on the SolrResponse.
   */
  protected void handlePostExecution(Logger log) {

    handleException(log);

    addDeprecatedWarning();

    if (log.isInfoEnabled() && solrResponse.getToLog().size() > 0) {
      log.info(solrResponse.getToLogAsString());
    }
  }

  protected void addDeprecatedWarning() {
    solrResponse.add("warn", "This API is deprecated");
  }

  /**
   * If there is an exception on the SolrResponse:
   *
   * 
    *
  • error info is added to the SolrResponse; *
  • the response status code is set to the error code from the exception; and *
  • the exception message is added to the list of things to be logged. *
*/ protected void handleException(Logger log) { Exception exception = getSolrResponse().getException(); if (null != exception) { NamedList info = new SimpleOrderedMap<>(); this.statusCode = ResponseUtils.getErrorInfo( exception, info, log, solrCore != null && solrCore.getCoreContainer().hideStackTrace()); getSolrResponse().add("error", info); String message = (String) info.get("msg"); if (null != message && !message.trim().isEmpty()) { getSolrResponse().getToLog().add("msg", "{" + message.trim() + "}"); } } } /** Decode URL-encoded strings as UTF-8, and avoid converting "+" to space */ protected static String urlDecode(String str) throws UnsupportedEncodingException { return URLDecoder.decode(str.replace("+", "%2B"), StandardCharsets.UTF_8); } }