/* * 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.response; import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import javax.servlet.http.HttpServletResponse; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.search.ReturnFields; import org.apache.solr.search.SolrReturnFields; /** * <code>SolrQueryResponse</code> is used by a query handler to return * the response to a query request. * * <p> * <a name="returnable_data"></a><b>Note On Returnable Data...</b><br> * A <code>SolrQueryResponse</code> may contain the following types of * Objects generated by the <code>SolrRequestHandler</code> that processed * the request. * </p> * <ul> * <li>{@link String}</li> * <li>{@link Integer}</li> * <li>{@link Long}</li> * <li>{@link Float}</li> * <li>{@link Double}</li> * <li>{@link Boolean}</li> * <li>{@link Date}</li> * <li>{@link org.apache.solr.search.DocList}</li> * <li>{@link org.apache.solr.common.SolrDocument} (since 1.3)</li> * <li>{@link org.apache.solr.common.SolrDocumentList} (since 1.3)</li> * <li>{@link Map} containing any of the items in this list</li> * <li>{@link NamedList} containing any of the items in this list</li> * <li>{@link Collection} containing any of the items in this list</li> * <li>Array containing any of the items in this list</li> * <li>null</li> * </ul> * <p> * Other data types may be added to the SolrQueryResponse, but there is no guarantee * that QueryResponseWriters will be able to deal with unexpected types. * </p> * * * @since solr 0.9 */ public class SolrQueryResponse { public static final String NAME = "response"; public static final String RESPONSE_HEADER_PARTIAL_RESULTS_KEY = "partialResults"; public static final String RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY = "segmentTerminatedEarly"; private static final String RESPONSE_HEADER_KEY = "responseHeader"; private static final String RESPONSE_KEY = "response"; /** * Container for user defined values * @see #getValues * @see #add * @see #setAllValues * @see <a href="#returnable_data">Note on Returnable Data</a> */ protected NamedList<Object> values = new SimpleOrderedMap<>(); /** * Container for storing information that should be logged by Solr before returning. */ protected NamedList<Object> toLog = new SimpleOrderedMap<>(); protected ReturnFields returnFields; /** * Container for storing HTTP headers. Internal Solr components can add headers to * this SolrQueryResponse through the methods: {@link #addHttpHeader(String, String)} * and {@link #setHttpHeader(String, String)}, or remove existing ones through * {@link #removeHttpHeader(String)} and {@link #removeHttpHeaders(String)}. * All these headers are going to be added to the HTTP response. */ private final NamedList<String> headers = new SimpleOrderedMap<>(); // error if this is set... protected Exception err; /** * Should this response be tagged with HTTP caching headers? */ protected boolean httpCaching=true; /*** // another way of returning an error int errCode; String errMsg; ***/ public SolrQueryResponse() { } /** * Gets data to be returned in this response * @see <a href="#returnable_data">Note on Returnable Data</a> */ public NamedList getValues() { return values; } /** * Sets data to be returned in this response * @see <a href="#returnable_data">Note on Returnable Data</a> */ public void setAllValues(NamedList<Object> nameValuePairs) { values=nameValuePairs; } /** * Sets the document field names of fields to return by default when * returning DocLists */ public void setReturnFields(ReturnFields fields) { returnFields=fields; } /** * Gets the document field names of fields to return by default when * returning DocLists */ public ReturnFields getReturnFields() { if( returnFields == null ) { returnFields = new SolrReturnFields(); // by default return everything } return returnFields; } /** * Appends a named value to the list of named values to be returned. * @param name the name of the value - may be null if unnamed * @param val the value to add - also may be null since null is a legal value * @see <a href="#returnable_data">Note on Returnable Data</a> */ public void add(String name, Object val) { values.add(name,val); } /** * Causes an error to be returned instead of the results. * * In general, new calls to this method should not be added. In most cases * you should simply throw an exception and let it bubble out to * RequestHandlerBase, which will set the exception thrown. */ public void setException(Exception e) { err=e; } /** * Returns an Exception if there was a fatal error in processing the request. * Returns null if the request succeeded. */ public Exception getException() { return err; } /** Set response header */ public void addResponseHeader(NamedList<Object> header) { values.add(RESPONSE_HEADER_KEY, header); } /** Clear response header */ public void removeResponseHeader() { values.remove(RESPONSE_HEADER_KEY); } /** Response header to be logged */ public NamedList<Object> getResponseHeader() { @SuppressWarnings("unchecked") SimpleOrderedMap<Object> header = (SimpleOrderedMap<Object>) values.get(RESPONSE_HEADER_KEY); return header; } /** Set response */ public void addResponse(Object response) { values.add(RESPONSE_KEY, response); } /** Return response */ public Object getResponse() { return values.get(RESPONSE_KEY); } /** Add a value to be logged. * * @param name name of the thing to log * @param val value of the thing to log */ public void addToLog(String name, Object val) { toLog.add(name, val); } /** Get loggable items. * * @return things to log */ public NamedList<Object> getToLog() { return toLog; } /** Returns a string of the form "logid name1=value1 name2=value2 ..." */ public String getToLogAsString(String logid) { StringBuilder sb = new StringBuilder(logid); for (int i=0; i<toLog.size(); i++) { if (sb.length() > 0) { sb.append(' '); } String name = toLog.getName(i); Object val = toLog.getVal(i); if (name != null) { sb.append(name).append('='); } sb.append(val); } return sb.toString(); } /** * Enables or disables the emission of HTTP caching headers for this response. * @param httpCaching true=emit caching headers, false otherwise */ public void setHttpCaching(boolean httpCaching) { this.httpCaching=httpCaching; } /** * Should this response emit HTTP caching headers? * @return true=yes emit headers, false otherwise */ public boolean isHttpCaching() { return this.httpCaching; } /** * * Sets a response header with the given name and value. This header * will be included in the HTTP response * If the header had already been set, the new value overwrites the * previous ones (all of them if there are multiple for the same name). * * @param name the name of the header * @param value the header value If it contains octet string, * it should be encoded according to RFC 2047 * (http://www.ietf.org/rfc/rfc2047.txt) * * @see #addHttpHeader * @see HttpServletResponse#setHeader */ public void setHttpHeader(String name, String value) { headers.removeAll(name); headers.add(name, value); } /** * Adds a response header with the given name and value. This header * will be included in the HTTP response * This method allows response headers to have multiple values. * * @param name the name of the header * @param value the additional header value If it contains * octet string, it should be encoded * according to RFC 2047 * (http://www.ietf.org/rfc/rfc2047.txt) * * @see #setHttpHeader * @see HttpServletResponse#addHeader */ public void addHttpHeader(String name, String value) { headers.add(name, value); } /** * Gets the value of the response header with the given name. * * <p>If a response header with the given name exists and contains * multiple values, the value that was added first will be returned.</p> * * <p>NOTE: this runs in linear time (it scans starting at the * beginning of the list until it finds the first pair with * the specified name).</p> * * @param name the name of the response header whose value to return * @return the value of the response header with the given name, * or <tt>null</tt> if no header with the given name has been set * on this response */ public String getHttpHeader(String name) { return headers.get(name); } /** * Gets the values of the response header with the given name. * * @param name the name of the response header whose values to return * * @return a (possibly empty) <code>Collection</code> of the values * of the response header with the given name * */ public Collection<String> getHttpHeaders(String name) { return headers.getAll(name); } /** * Removes a previously added header with the given name (only * the first one if multiple are present for the same name) * * <p>NOTE: this runs in linear time (it scans starting at the * beginning of the list until it finds the first pair with * the specified name).</p> * * @param name the name of the response header to remove * @return the value of the removed entry or <tt>null</tt> if no * value is found for the given header name */ public String removeHttpHeader(String name) { return headers.remove(name); } /** * Removes all previously added headers with the given name. * * @param name the name of the response headers to remove * @return a <code>Collection</code> with all the values * of the removed entries. It returns <code>null</code> if no * entries are found for the given name */ public Collection<String> removeHttpHeaders(String name) { return headers.removeAll(name); } /** * Returns a new iterator of response headers * @return a new Iterator instance for the response headers */ public Iterator<Entry<String, String>> httpHeaders() { return headers.iterator(); } }