You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ho...@apache.org on 2014/09/03 21:18:20 UTC
svn commit: r1622321 - in /lucene/dev/trunk/solr: ./
core/src/java/org/apache/solr/response/ core/src/java/org/apache/solr/rest/
core/src/java/org/apache/solr/servlet/
core/src/test/org/apache/solr/response/
Author: hossman
Date: Wed Sep 3 19:18:20 2014
New Revision: 1622321
URL: http://svn.apache.org/r1622321
Log:
SOLR-4406: Fix RawResponseWriter to respect 'base' writer
Added:
lucene/dev/trunk/solr/core/src/java/org/apache/solr/response/QueryResponseWriterUtil.java (with props)
lucene/dev/trunk/solr/core/src/test/org/apache/solr/response/TestRawResponseWriter.java (with props)
Modified:
lucene/dev/trunk/solr/CHANGES.txt
lucene/dev/trunk/solr/core/src/java/org/apache/solr/response/RawResponseWriter.java
lucene/dev/trunk/solr/core/src/java/org/apache/solr/rest/BaseSolrResource.java
lucene/dev/trunk/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1622321&r1=1622320&r2=1622321&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Wed Sep 3 19:18:20 2014
@@ -158,6 +158,9 @@ Bug Fixes
* SOLR-5966: Admin UI Menu is fixed and doesn't respect smaller viewports.
(Aman Tandon, steffkes via shalin)
+* SOLR-4406: Fix RawResponseWriter to respect 'base' writer
+ (Steve Davids, hossman)
+
Other Changes
---------------------
Added: lucene/dev/trunk/solr/core/src/java/org/apache/solr/response/QueryResponseWriterUtil.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/response/QueryResponseWriterUtil.java?rev=1622321&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/response/QueryResponseWriterUtil.java (added)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/response/QueryResponseWriterUtil.java Wed Sep 3 19:18:20 2014
@@ -0,0 +1,64 @@
+/*
+ * 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.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.solr.common.util.ContentStreamBase;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.util.FastWriter;
+
+/**
+ * Static utility methods relating to {@link QueryResponseWriter}s
+ */
+public final class QueryResponseWriterUtil {
+ private QueryResponseWriterUtil() { /* static helpers only */ }
+
+ /**
+ * Writes the response writer's result to the given output stream.
+ * This method inspects the specified writer to determine if it is a
+ * {@link BinaryQueryResponseWriter} or not to delegate to the approprate method.
+ * @see BinaryQueryResponseWriter#write(OutputStream,SolrQueryRequest,SolrQueryResponse)
+ * @see BinaryQueryResponseWriter#write(Writer,SolrQueryRequest,SolrQueryResponse)
+ */
+ public static void writeQueryResponse(OutputStream outputStream,
+ QueryResponseWriter responseWriter, SolrQueryRequest solrRequest,
+ SolrQueryResponse solrResponse, String contentType) throws IOException {
+
+ if (responseWriter instanceof BinaryQueryResponseWriter) {
+ BinaryQueryResponseWriter binWriter = (BinaryQueryResponseWriter) responseWriter;
+ binWriter.write(outputStream, solrRequest, solrResponse);
+ } else {
+ Writer writer = buildWriter(outputStream, ContentStreamBase.getCharsetFromContentType(contentType));
+ responseWriter.write(writer, solrRequest, solrResponse);
+ writer.flush();
+ }
+ }
+
+ private static Writer buildWriter(OutputStream outputStream, String charset) throws UnsupportedEncodingException {
+ Writer writer = (charset == null) ? new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)
+ : new OutputStreamWriter(outputStream, charset);
+
+ return new FastWriter(writer);
+ }
+}
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/response/RawResponseWriter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/response/RawResponseWriter.java?rev=1622321&r1=1622320&r2=1622321&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/response/RawResponseWriter.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/response/RawResponseWriter.java Wed Sep 3 19:18:20 2014
@@ -18,6 +18,7 @@
package org.apache.solr.response;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
@@ -45,8 +46,7 @@ import org.apache.solr.request.SolrQuery
*
* @since solr 1.3
*/
-public class RawResponseWriter implements BinaryQueryResponseWriter
-{
+public class RawResponseWriter implements BinaryQueryResponseWriter {
/**
* The key that should be used to add a ContentStream to the
* SolrQueryResponse if you intend to use this Writer.
@@ -65,8 +65,7 @@ public class RawResponseWriter implement
}
// Even if this is null, it should be ok
- protected QueryResponseWriter getBaseWriter( SolrQueryRequest request )
- {
+ protected QueryResponseWriter getBaseWriter( SolrQueryRequest request ) {
return request.getCore().getQueryResponseWriter( _baseWriter );
}
@@ -80,42 +79,31 @@ public class RawResponseWriter implement
}
@Override
- public void write(Writer writer, SolrQueryRequest request, SolrQueryResponse response) throws IOException
- {
+ public void write(Writer writer, SolrQueryRequest request, SolrQueryResponse response) throws IOException {
Object obj = response.getValues().get( CONTENT );
if( obj != null && (obj instanceof ContentStream ) ) {
// copy the contents to the writer...
ContentStream content = (ContentStream)obj;
- Reader reader = content.getReader();
- try {
+ try(Reader reader = content.getReader()) {
IOUtils.copy( reader, writer );
- } finally {
- reader.close();
}
- }
- else {
+ } else {
getBaseWriter( request ).write( writer, request, response );
}
}
-@Override
-public void write(OutputStream out, SolrQueryRequest request,
- SolrQueryResponse response) throws IOException {
+ @Override
+ public void write(OutputStream out, SolrQueryRequest request, SolrQueryResponse response) throws IOException {
Object obj = response.getValues().get( CONTENT );
if( obj != null && (obj instanceof ContentStream ) ) {
// copy the contents to the writer...
ContentStream content = (ContentStream)obj;
- java.io.InputStream in = content.getStream();
- try {
+ try(InputStream in = content.getStream()) {
IOUtils.copy( in, out );
- } finally {
- in.close();
}
+ } else {
+ QueryResponseWriterUtil.writeQueryResponse(out,
+ getBaseWriter(request), request, response, getContentType(request, response));
}
- else {
- //getBaseWriter( request ).write( writer, request, response );
- throw new IOException("did not find a CONTENT object");
- }
-
}
}
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/rest/BaseSolrResource.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/rest/BaseSolrResource.java?rev=1622321&r1=1622320&r2=1622321&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/rest/BaseSolrResource.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/rest/BaseSolrResource.java Wed Sep 3 19:18:20 2014
@@ -24,12 +24,11 @@ import org.apache.solr.common.util.Simpl
import org.apache.solr.core.SolrCore;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrRequestInfo;
-import org.apache.solr.response.BinaryQueryResponseWriter;
import org.apache.solr.response.QueryResponseWriter;
+import org.apache.solr.response.QueryResponseWriterUtil;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.servlet.ResponseUtils;
-import org.apache.solr.util.FastWriter;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.data.Status;
@@ -40,19 +39,14 @@ import org.slf4j.Logger;
import java.io.IOException;
import java.io.OutputStream;
-import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
-import java.io.Writer;
import java.net.URLDecoder;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
/**
* Base class of all Solr Restlet server resource classes.
*/
public abstract class BaseSolrResource extends ServerResource {
- protected static final Charset UTF8 = StandardCharsets.UTF_8;
protected static final String SHOW_DEFAULTS = "showDefaults";
private SolrCore solrCore;
@@ -157,18 +151,7 @@ public abstract class BaseSolrResource e
@Override
public void write(OutputStream outputStream) throws IOException {
if (getRequest().getMethod() != Method.HEAD) {
- if (responseWriter instanceof BinaryQueryResponseWriter) {
- BinaryQueryResponseWriter binWriter = (BinaryQueryResponseWriter)responseWriter;
- binWriter.write(outputStream, solrRequest, solrResponse);
- } else {
- String charset = ContentStreamBase.getCharsetFromContentType(contentType);
- Writer out = (charset == null)
- ? new OutputStreamWriter(outputStream, UTF8)
- : new OutputStreamWriter(outputStream, charset);
- out = new FastWriter(out);
- responseWriter.write(out, solrRequest, solrResponse);
- out.flush();
- }
+ QueryResponseWriterUtil.writeQueryResponse(outputStream, responseWriter, solrRequest, solrResponse, contentType);
}
}
}
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java?rev=1622321&r1=1622320&r2=1622321&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java Wed Sep 3 19:18:20 2014
@@ -66,11 +66,11 @@ import org.apache.solr.request.SolrReque
import org.apache.solr.request.SolrRequestInfo;
import org.apache.solr.response.BinaryQueryResponseWriter;
import org.apache.solr.response.QueryResponseWriter;
+import org.apache.solr.response.QueryResponseWriterUtil;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.servlet.cache.HttpCacheHeaderUtil;
import org.apache.solr.servlet.cache.Method;
import org.apache.solr.update.processor.DistributingUpdateProcessorFactory;
-import org.apache.solr.util.FastWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -86,11 +86,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
import java.net.URL;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -120,8 +116,6 @@ public class SolrDispatchFilter extends
protected String abortErrorMessage = null;
protected final HttpClient httpClient = HttpClientUtil.createClient(new ModifiableSolrParams());
- private static final Charset UTF8 = StandardCharsets.UTF_8;
-
public SolrDispatchFilter() {
}
@@ -756,18 +750,7 @@ public class SolrDispatchFilter extends
}
if (Method.HEAD != reqMethod) {
- if (responseWriter instanceof BinaryQueryResponseWriter) {
- BinaryQueryResponseWriter binWriter = (BinaryQueryResponseWriter) responseWriter;
- binWriter.write(response.getOutputStream(), solrReq, solrRsp);
- } else {
- String charset = ContentStreamBase.getCharsetFromContentType(ct);
- Writer out = (charset == null)
- ? new OutputStreamWriter(response.getOutputStream(), UTF8)
- : new OutputStreamWriter(response.getOutputStream(), charset);
- out = new FastWriter(out);
- responseWriter.write(out, solrReq, solrRsp);
- out.flush();
- }
+ QueryResponseWriterUtil.writeQueryResponse(response.getOutputStream(), responseWriter, solrReq, solrRsp, ct);
}
//else http HEAD request, nothing to write out, waited this long just to get ContentType
}
Added: lucene/dev/trunk/solr/core/src/test/org/apache/solr/response/TestRawResponseWriter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/response/TestRawResponseWriter.java?rev=1622321&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/response/TestRawResponseWriter.java (added)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/response/TestRawResponseWriter.java Wed Sep 3 19:18:20 2014
@@ -0,0 +1,200 @@
+/*
+ * 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.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Collections;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.lucene.util.TestUtil;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.solrj.impl.BinaryResponseParser;
+import org.apache.solr.common.util.ContentStreamBase.ByteArrayStream;
+import org.apache.solr.common.util.ContentStreamBase.StringStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.request.SolrQueryRequest;
+
+import org.junit.BeforeClass;
+import org.junit.AfterClass;
+
+/**
+ * Tests the {@link RawResponseWriter} behavior, in particular when dealing with "base" writer
+ */
+public class TestRawResponseWriter extends SolrTestCaseJ4 {
+
+ private static RawResponseWriter writerXmlBase;
+ private static RawResponseWriter writerJsonBase;
+ private static RawResponseWriter writerBinBase;
+ private static RawResponseWriter writerNoBase;
+
+ private static RawResponseWriter[] allWriters;
+
+ @BeforeClass
+ public static void setupCoreAndWriters() throws Exception {
+ // we don't directly use this core or it's config, we use
+ // QueryResponseWriters' constructed programaticly,
+ // but we do use this core for managing the life cycle of the requests
+ // we spin up.
+ initCore("solrconfig.xml","schema.xml");
+
+ writerNoBase = newRawResponseWriter(null); /* defaults to standard writer as base */
+ writerXmlBase = newRawResponseWriter("xml");
+ writerJsonBase = newRawResponseWriter("json");
+ writerBinBase = newRawResponseWriter("javabin");
+
+ allWriters = new RawResponseWriter[] {
+ writerXmlBase, writerJsonBase, writerBinBase, writerNoBase
+ };
+ }
+
+ @AfterClass
+ public static void cleanupWriters() throws Exception {
+ writerXmlBase = null;
+ writerJsonBase = null;
+ writerBinBase = null;
+ writerNoBase = null;
+
+ allWriters = null;
+ }
+
+ /**
+ * Regardless of base writer, the bytes in should be the same as the bytes out
+ * when response is a raw ContentStream written to an OutputStream
+ */
+ public void testRawBinaryContentStream() throws IOException {
+ SolrQueryResponse rsp = new SolrQueryResponse();
+ byte[] data = new byte[TestUtil.nextInt(random(), 10, 2048)];
+ random().nextBytes(data);
+ ByteArrayStream stream = new ByteArrayStream(data, TestUtil.randomUnicodeString(random()));
+
+ stream.setContentType(TestUtil.randomSimpleString(random()));
+ rsp.add(RawResponseWriter.CONTENT, stream);
+
+ for (RawResponseWriter writer : allWriters) {
+ assertEquals(stream.getContentType(), writer.getContentType(req(), rsp));
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ writer.write(out, req(), rsp);
+ assertArrayEquals(data, out.toByteArray());
+ }
+ }
+
+ /**
+ * Regardless of base writer, the String in should be the same as the String out
+ * when response is a raw ContentStream written to a Writer (or OutputStream)
+ */
+ public void testRawStringContentStream() throws IOException {
+ SolrQueryResponse rsp = new SolrQueryResponse();
+ String data = TestUtil.randomUnicodeString(random());
+ StringStream stream = new StringStream(data);
+
+ stream.setContentType(TestUtil.randomSimpleString(random()));
+ rsp.add(RawResponseWriter.CONTENT, stream);
+
+ for (RawResponseWriter writer : allWriters) {
+ assertEquals(stream.getContentType(), writer.getContentType(req(), rsp));
+
+ // we should have the same string if we use a Writer
+ StringWriter sout = new StringWriter();
+ writer.write(sout, req(), rsp);
+ assertEquals(data, sout.toString());
+
+ // we should have UTF-8 Bytes if we use an OutputStream
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ writer.write(bout, req(), rsp);
+ assertEquals(data, bout.toString(StandardCharsets.UTF_8.toString()));
+ }
+ }
+
+ /**
+ * When no real ContentStream is specified, each base writer should be used for formatting
+ */
+ public void testStructuredDataViaBaseWriters() throws IOException {
+ SolrQueryResponse rsp = new SolrQueryResponse();
+ // Don't send a ContentStream back, this will fall back to the configured base writer.
+ // But abuse the CONTENT key to ensure writer is also checking type
+ rsp.add(RawResponseWriter.CONTENT, "test");
+ rsp.add("foo", "bar");
+
+ // check Content-Type against each writer
+ assertEquals("application/xml; charset=UTF-8", writerNoBase.getContentType(req(), rsp));
+ assertEquals("application/xml; charset=UTF-8", writerXmlBase.getContentType(req(), rsp));
+ assertEquals("application/json; charset=UTF-8", writerJsonBase.getContentType(req(), rsp));
+ assertEquals("application/octet-stream", writerBinBase.getContentType(req(), rsp));
+
+ // check response against each writer
+
+ // xml & none (default behavior same as XML)
+ String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<response>\n<str name=\"content\">test</str><str name=\"foo\">bar</str>\n</response>\n";
+ StringWriter xmlSout = new StringWriter();
+ writerXmlBase.write(xmlSout, req(), rsp);
+ assertEquals(xml, xmlSout.toString());
+ ByteArrayOutputStream xmlBout = new ByteArrayOutputStream();
+ writerXmlBase.write(xmlBout, req(), rsp);
+ assertEquals(xml, xmlBout.toString(StandardCharsets.UTF_8.toString()));
+ //
+ StringWriter noneSout = new StringWriter();
+ writerNoBase.write(noneSout, req(), rsp);
+ assertEquals(xml, noneSout.toString());
+ ByteArrayOutputStream noneBout = new ByteArrayOutputStream();
+ writerNoBase.write(noneBout, req(), rsp);
+ assertEquals(xml, noneBout.toString(StandardCharsets.UTF_8.toString()));
+
+ // json
+ String json = "{\"content\":\"test\",\"foo\":\"bar\"}\n";
+ StringWriter jsonSout = new StringWriter();
+ writerJsonBase.write(jsonSout, req(), rsp);
+ assertEquals(json, jsonSout.toString());
+ ByteArrayOutputStream jsonBout = new ByteArrayOutputStream();
+ writerJsonBase.write(jsonBout, req(), rsp);
+ assertEquals(json, jsonBout.toString(StandardCharsets.UTF_8.toString()));
+
+ // javabin
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ writerBinBase.write(bytes, req(), rsp);
+ BinaryResponseParser parser = new BinaryResponseParser();
+ NamedList<Object> out = parser.processResponse
+ (new ByteArrayInputStream(bytes.toByteArray()), /* encoding irelevent */ null);
+ assertEquals(RawResponseWriter.CONTENT, out.getName(0));
+ assertEquals("test", out.getVal(0));
+ assertEquals("foo", out.getName(1));
+ assertEquals("bar", out.getVal(1));
+
+ }
+
+ /**
+ * Generates a new {@link RawResponseWriter} wraping the specified baseWriter name
+ * (which much either be an implicitly definied response writer, or one explicitly
+ * configured in solrconfig.xml)
+ *
+ * @param baseWriter null or the name of a valid base writer
+ */
+ private static RawResponseWriter newRawResponseWriter(String baseWriter) {
+ RawResponseWriter writer = new RawResponseWriter();
+ NamedList initArgs = new NamedList<Object>();
+ if (null != baseWriter) {
+ initArgs.add("base", baseWriter);
+ }
+ writer.init(initArgs);
+ return writer;
+ }
+
+}