blob: 3224e748082ec49673b05a9482674cc6c6aa9935 [file] [log] [blame]
/*
* 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>
*/
@SuppressWarnings({"rawtypes"})
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();
}
}