SOLR-5291: Solrj does not propagate the root cause to the user for many errors.

SOLR-3530: Better error messages / Content-Type validation in SolrJ.

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1527547 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Mark Robert Miller 2013-09-30 13:20:27 +00:00
parent d3d61d7192
commit 4f8f10dcb0
10 changed files with 71 additions and 12 deletions

View File

@ -304,6 +304,9 @@ Bug Fixes
* SOLR-5279: Implicit properties don't seem to exist on core RELOAD * SOLR-5279: Implicit properties don't seem to exist on core RELOAD
(elyograg, hossman, Steve Rowe) (elyograg, hossman, Steve Rowe)
* SOLR-5291: Solrj does not propagate the root cause to the user for many errors.
(Mark Miller)
Optimizations Optimizations
---------------------- ----------------------
@ -318,6 +321,8 @@ Optimizations
* SOLR-4816: CloudSolrServer now uses multiple threads to send updates by default. * SOLR-4816: CloudSolrServer now uses multiple threads to send updates by default.
(Joel Bernstein via Mark Miller) (Joel Bernstein via Mark Miller)
* SOLR-3530: Better error messages / Content-Type validation in SolrJ. (Mark Miller, hossman)
Other Changes Other Changes
---------------------- ----------------------

View File

@ -49,7 +49,10 @@ import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.apache.lucene.store.IOContext; import org.apache.lucene.store.IOContext;
import org.apache.lucene.store.IndexInput; import org.apache.lucene.store.IndexInput;
import static org.apache.lucene.util.IOUtils.CHARSET_UTF_8; import static org.apache.lucene.util.IOUtils.CHARSET_UTF_8;
import org.apache.solr.client.solrj.impl.BinaryResponseParser;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode; import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.CommonParams;
@ -1002,7 +1005,7 @@ public class ReplicationHandler extends RequestHandlerBase implements SolrCoreAw
@Override @Override
public String getContentType(SolrQueryRequest request, SolrQueryResponse response) { public String getContentType(SolrQueryRequest request, SolrQueryResponse response) {
return "application/octet-stream"; return BinaryResponseParser.BINARY_CONTENT_TYPE;
} }
@Override @Override

View File

@ -19,11 +19,10 @@ package org.apache.solr.response;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.StorableField; import org.apache.lucene.index.StorableField;
import org.apache.lucene.index.StoredDocument; import org.apache.lucene.index.StoredDocument;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.apache.solr.client.solrj.impl.BinaryResponseParser;
import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.JavaBinCodec; import org.apache.solr.common.util.JavaBinCodec;
@ -59,7 +58,7 @@ public class BinaryResponseWriter implements BinaryQueryResponseWriter {
@Override @Override
public String getContentType(SolrQueryRequest request, SolrQueryResponse response) { public String getContentType(SolrQueryRequest request, SolrQueryResponse response) {
return "application/octet-stream"; return BinaryResponseParser.BINARY_CONTENT_TYPE;
} }
@Override @Override

View File

@ -20,6 +20,7 @@ package org.apache.solr.response;
import java.io.Writer; import java.io.Writer;
import java.io.IOException; import java.io.IOException;
import org.apache.solr.client.solrj.impl.XMLResponseParser;
import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrQueryRequest;
@ -44,6 +45,6 @@ public class SchemaXmlResponseWriter implements QueryResponseWriter {
@Override @Override
public String getContentType(SolrQueryRequest request, SolrQueryResponse response) { public String getContentType(SolrQueryRequest request, SolrQueryResponse response) {
return CONTENT_TYPE_XML_UTF8; return XMLResponseParser.XML_CONTENT_TYPE;
} }
} }

View File

@ -20,6 +20,7 @@ package org.apache.solr.response;
import java.io.Writer; import java.io.Writer;
import java.io.IOException; import java.io.IOException;
import org.apache.solr.client.solrj.impl.XMLResponseParser;
import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrQueryRequest;
@ -44,6 +45,6 @@ public class XMLResponseWriter implements QueryResponseWriter {
@Override @Override
public String getContentType(SolrQueryRequest request, SolrQueryResponse response) { public String getContentType(SolrQueryRequest request, SolrQueryResponse response) {
return CONTENT_TYPE_XML_UTF8; return XMLResponseParser.XML_CONTENT_TYPE;
} }
} }

View File

@ -120,7 +120,7 @@ public class TestCloudManagedSchema extends AbstractFullDistribZkTestBase {
protected final void assertFileNotInZooKeeper(String fileName) throws Exception { protected final void assertFileNotInZooKeeper(String fileName) throws Exception {
// Stolen from AbstractBadConfigTestBase // Stolen from AbstractBadConfigTestBase
String errString = "returned non ok status:404, message:Not Found"; String errString = "Not Found";
ignoreException(Pattern.quote(errString)); ignoreException(Pattern.quote(errString));
String rawContent = null; String rawContent = null;
try { try {

View File

@ -34,6 +34,15 @@ public abstract class ResponseParser
public abstract NamedList<Object> processResponse(Reader reader); public abstract NamedList<Object> processResponse(Reader reader);
/**
* A well behaved ResponseParser will return it's content-type.
*
* @return the content-type this parser expects to parse
*/
public String getContentType() {
return null;
}
/** /**
* @return the version param passed to solr * @return the version param passed to solr
*/ */

View File

@ -30,6 +30,8 @@ import java.io.Reader;
* @since solr 1.3 * @since solr 1.3
*/ */
public class BinaryResponseParser extends ResponseParser { public class BinaryResponseParser extends ResponseParser {
public static final String BINARY_CONTENT_TYPE = "application/octet-stream";
@Override @Override
public String getWriterType() { public String getWriterType() {
return "javabin"; return "javabin";
@ -45,6 +47,10 @@ public class BinaryResponseParser extends ResponseParser {
} }
} }
@Override
public String getContentType() {
return BINARY_CONTENT_TYPE;
}
@Override @Override
public String getVersion() { public String getVersion() {

View File

@ -26,6 +26,7 @@ import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header; import org.apache.http.Header;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
@ -265,7 +266,7 @@ public class HttpSolrServer extends SolrServer {
for (ContentStream content : streams) { for (ContentStream content : streams) {
String contentType = content.getContentType(); String contentType = content.getContentType();
if(contentType==null) { if(contentType==null) {
contentType = "application/octet-stream"; // default contentType = BinaryResponseParser.BINARY_CONTENT_TYPE; // default
} }
String name = content.getName(); String name = content.getName();
if(name==null) { if(name==null) {
@ -367,6 +368,13 @@ public class HttpSolrServer extends SolrServer {
// Read the contents // Read the contents
respBody = response.getEntity().getContent(); respBody = response.getEntity().getContent();
Header ctHeader = response.getLastHeader("content-type");
String contentType;
if (ctHeader != null) {
contentType = ctHeader.getValue();
} else {
contentType = "";
}
// handle some http level checks before trying to parse the response // handle some http level checks before trying to parse the response
switch (httpStatus) { switch (httpStatus) {
@ -382,11 +390,15 @@ public class HttpSolrServer extends SolrServer {
} }
break; break;
default: default:
throw new RemoteSolrException(httpStatus, "Server at " + getBaseURL() if (processor == null) {
+ " returned non ok status:" + httpStatus + ", message:" throw new RemoteSolrException(httpStatus, "Server at "
+ response.getStatusLine().getReasonPhrase(), null); + getBaseURL() + " returned non ok status:" + httpStatus
+ ", message:" + response.getStatusLine().getReasonPhrase(),
null);
}
} }
if (processor == null) { if (processor == null) {
// no processor specified, return raw stream // no processor specified, return raw stream
NamedList<Object> rsp = new NamedList<Object>(); NamedList<Object> rsp = new NamedList<Object>();
rsp.add("stream", respBody); rsp.add("stream", respBody);
@ -395,6 +407,17 @@ public class HttpSolrServer extends SolrServer {
return rsp; return rsp;
} }
String procCt = processor.getContentType();
if (procCt != null) {
if (!contentType.equals(procCt)) {
// unexpected content type
String msg = "Expected content type " + procCt + " but got " + contentType + ".";
RemoteSolrException e = new RemoteSolrException(httpStatus, msg + " " +
IOUtils.toString(respBody), null);
throw e;
}
}
// if(true) { // if(true) {
// ByteArrayOutputStream copy = new ByteArrayOutputStream(); // ByteArrayOutputStream copy = new ByteArrayOutputStream();
// IOUtils.copy(respBody, copy); // IOUtils.copy(respBody, copy);
@ -403,8 +426,13 @@ public class HttpSolrServer extends SolrServer {
// respBody = new ByteArrayInputStream(copy.toByteArray()); // respBody = new ByteArrayInputStream(copy.toByteArray());
// } // }
NamedList<Object> rsp = null;
String charset = EntityUtils.getContentCharSet(response.getEntity()); String charset = EntityUtils.getContentCharSet(response.getEntity());
NamedList<Object> rsp = processor.processResponse(respBody, charset); try {
rsp = processor.processResponse(respBody, charset);
} catch (Exception e) {
throw new RemoteSolrException(httpStatus, e.getMessage(), e);
}
if (httpStatus != HttpStatus.SC_OK) { if (httpStatus != HttpStatus.SC_OK) {
String reason = null; String reason = null;
try { try {

View File

@ -32,6 +32,7 @@ import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamReader;
import java.io.InputStream; import java.io.InputStream;
import java.io.Reader; import java.io.Reader;
import java.util.ArrayList; import java.util.ArrayList;
@ -46,6 +47,7 @@ import java.util.Locale;
*/ */
public class XMLResponseParser extends ResponseParser public class XMLResponseParser extends ResponseParser
{ {
public static final String XML_CONTENT_TYPE = "application/xml; charset=UTF-8";
public static Logger log = LoggerFactory.getLogger(XMLResponseParser.class); public static Logger log = LoggerFactory.getLogger(XMLResponseParser.class);
private static final XMLErrorLogger xmllog = new XMLErrorLogger(log); private static final XMLErrorLogger xmllog = new XMLErrorLogger(log);
@ -79,6 +81,11 @@ public class XMLResponseParser extends ResponseParser
return "xml"; return "xml";
} }
@Override
public String getContentType() {
return XML_CONTENT_TYPE;
}
@Override @Override
public NamedList<Object> processResponse(Reader in) { public NamedList<Object> processResponse(Reader in) {
XMLStreamReader parser = null; XMLStreamReader parser = null;