diff --git a/solr/core/src/java/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java b/solr/core/src/java/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java index c1bb7116d72..e9d0397e12d 100644 --- a/solr/core/src/java/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java +++ b/solr/core/src/java/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java @@ -58,7 +58,6 @@ import org.apache.solr.request.SolrRequestHandler; import org.apache.solr.request.SolrRequestInfo; import org.apache.solr.response.BinaryResponseWriter; -import org.apache.solr.response.QueryResponseWriterUtil; import org.apache.solr.response.ResultContext; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.servlet.SolrRequestParsers; @@ -276,8 +275,7 @@ ByteArrayInputStream toInputStream() { }; if (callback == null) { - QueryResponseWriterUtil.writeQueryResponse( - byteBuffer, req.getResponseWriter(), req, rsp, null); + req.getResponseWriter().write(byteBuffer, req, rsp); } else { // mostly stream results to the callback; rest goes into the byteBuffer if (!(responseParser instanceof BinaryResponseParser)) diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java index 720a751f07a..a1473d0be14 100644 --- a/solr/core/src/java/org/apache/solr/core/SolrCore.java +++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java @@ -3053,7 +3053,8 @@ public PluginBag getResponseWriters() { private static BinaryResponseWriter getFileStreamWriter() { return new BinaryResponseWriter() { @Override - public void write(OutputStream out, SolrQueryRequest req, SolrQueryResponse response) + public void write( + OutputStream out, SolrQueryRequest req, SolrQueryResponse response, String contentType) throws IOException { RawWriter rawWriter = (RawWriter) response.getValues().get(ReplicationAPIBase.FILE_STREAM); if (rawWriter != null) { diff --git a/solr/core/src/java/org/apache/solr/jersey/MessageBodyWriters.java b/solr/core/src/java/org/apache/solr/jersey/MessageBodyWriters.java index d2020f4dc6a..f73146a864a 100644 --- a/solr/core/src/java/org/apache/solr/jersey/MessageBodyWriters.java +++ b/solr/core/src/java/org/apache/solr/jersey/MessageBodyWriters.java @@ -39,7 +39,6 @@ import org.apache.solr.response.BinaryResponseWriter; import org.apache.solr.response.CSVResponseWriter; import org.apache.solr.response.QueryResponseWriter; -import org.apache.solr.response.QueryResponseWriterUtil; import org.apache.solr.response.RawResponseWriter; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.response.XMLResponseWriter; @@ -141,8 +140,7 @@ public void writeTo( (SolrQueryResponse) requestContext.getProperty(SOLR_QUERY_RESPONSE); V2ApiUtils.squashIntoSolrResponseWithHeader(solrQueryResponse, toWrite); - QueryResponseWriterUtil.writeQueryResponse( - entityStream, responseWriter, solrQueryRequest, solrQueryResponse, mediaType.toString()); + responseWriter.write(entityStream, solrQueryRequest, solrQueryResponse, mediaType.toString()); } } } diff --git a/solr/core/src/java/org/apache/solr/response/BinaryQueryResponseWriter.java b/solr/core/src/java/org/apache/solr/response/BinaryQueryResponseWriter.java deleted file mode 100644 index c9ecfb8c55d..00000000000 --- a/solr/core/src/java/org/apache/solr/response/BinaryQueryResponseWriter.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.nio.charset.StandardCharsets; -import org.apache.solr.request.SolrQueryRequest; - -/** - * Implementations of BinaryQueryResponseWriter are used to write response in binary - * format. - * - *

Functionality is exactly same as its parent class QueryResponseWriter But it may - * not implement the - * write(Writer writer, SolrQueryRequest request, SolrQueryResponse response) method - */ -public interface BinaryQueryResponseWriter extends QueryResponseWriter { - - /** Use it to write the response in a binary format */ - void write(OutputStream out, SolrQueryRequest request, SolrQueryResponse response) - throws IOException; - - default String serializeResponse(SolrQueryRequest req, SolrQueryResponse rsp) { - java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(); - try { - write(baos, req, rsp); - return baos.toString(StandardCharsets.UTF_8); - } catch (IOException e) { - // unlikely - throw new RuntimeException(e); - } - } -} diff --git a/solr/core/src/java/org/apache/solr/response/BinaryResponseWriter.java b/solr/core/src/java/org/apache/solr/response/BinaryResponseWriter.java index 317412802d1..fa0f94801c6 100644 --- a/solr/core/src/java/org/apache/solr/response/BinaryResponseWriter.java +++ b/solr/core/src/java/org/apache/solr/response/BinaryResponseWriter.java @@ -23,7 +23,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.Writer; import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.Collection; @@ -45,12 +44,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BinaryResponseWriter implements BinaryQueryResponseWriter { +/** Solr's "javabin" format. TODO rename accordingly. */ +public class BinaryResponseWriter implements QueryResponseWriter { // public static boolean useUtf8CharSeq = true; private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); @Override - public void write(OutputStream out, SolrQueryRequest req, SolrQueryResponse response) + public void write( + OutputStream out, SolrQueryRequest req, SolrQueryResponse response, String contentType) throws IOException { Resolver resolver = new Resolver(req, response.getReturnFields()); if (req.getParams().getBool(CommonParams.OMIT_HEADER, false)) response.removeResponseHeader(); @@ -59,12 +60,6 @@ public void write(OutputStream out, SolrQueryRequest req, SolrQueryResponse resp } } - @Override - public void write(Writer writer, SolrQueryRequest request, SolrQueryResponse response) - throws IOException { - throw new RuntimeException("This is a binary writer , Cannot write to a characterstream"); - } - @Override public String getContentType(SolrQueryRequest request, SolrQueryResponse response) { return BinaryResponseParser.BINARY_CONTENT_TYPE; diff --git a/solr/core/src/java/org/apache/solr/response/CSVResponseWriter.java b/solr/core/src/java/org/apache/solr/response/CSVResponseWriter.java index 8cb30080fd7..b630b697d75 100644 --- a/solr/core/src/java/org/apache/solr/response/CSVResponseWriter.java +++ b/solr/core/src/java/org/apache/solr/response/CSVResponseWriter.java @@ -37,8 +37,8 @@ import org.apache.solr.schema.StrField; import org.apache.solr.search.ReturnFields; -/** Response writer for csv data */ -public class CSVResponseWriter implements QueryResponseWriter { +/** Response writer for CSV data */ +public class CSVResponseWriter implements TextQueryResponseWriter { @Override public void write(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp) throws IOException { diff --git a/solr/core/src/java/org/apache/solr/response/CborResponseWriter.java b/solr/core/src/java/org/apache/solr/response/CborResponseWriter.java index 294cba59851..f0f3f2a2e46 100644 --- a/solr/core/src/java/org/apache/solr/response/CborResponseWriter.java +++ b/solr/core/src/java/org/apache/solr/response/CborResponseWriter.java @@ -30,7 +30,7 @@ * A response writer impl that can write results in CBOR (cbor.io) format when wt=cbor. It uses the * jackson library to write the stream out */ -public class CborResponseWriter extends BinaryResponseWriter { +public class CborResponseWriter implements QueryResponseWriter { final CBORFactory cborFactory; final CBORFactory cborFactoryCompact; @@ -40,7 +40,8 @@ public CborResponseWriter() { } @Override - public void write(OutputStream out, SolrQueryRequest req, SolrQueryResponse response) + public void write( + OutputStream out, SolrQueryRequest req, SolrQueryResponse response, String contentType) throws IOException { boolean useStringRef = req.getParams().getBool("string_ref", true); WriterImpl writer = diff --git a/solr/core/src/java/org/apache/solr/response/GraphMLResponseWriter.java b/solr/core/src/java/org/apache/solr/response/GraphMLResponseWriter.java index 11a04d10240..f05113bb452 100644 --- a/solr/core/src/java/org/apache/solr/response/GraphMLResponseWriter.java +++ b/solr/core/src/java/org/apache/solr/response/GraphMLResponseWriter.java @@ -28,7 +28,12 @@ import org.apache.solr.handler.GraphHandler; import org.apache.solr.request.SolrQueryRequest; -public class GraphMLResponseWriter implements QueryResponseWriter { +/** + * Used with streaming expressions to export graphs to be visualized. + * + * @see GraphML + */ +public class GraphMLResponseWriter implements TextQueryResponseWriter { @Override public String getContentType(SolrQueryRequest req, SolrQueryResponse res) { diff --git a/solr/core/src/java/org/apache/solr/response/JSONResponseWriter.java b/solr/core/src/java/org/apache/solr/response/JSONResponseWriter.java index f972ca5e362..c4439c20d7e 100644 --- a/solr/core/src/java/org/apache/solr/response/JSONResponseWriter.java +++ b/solr/core/src/java/org/apache/solr/response/JSONResponseWriter.java @@ -29,8 +29,8 @@ import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.search.ReturnFields; -/** */ -public class JSONResponseWriter implements QueryResponseWriter { +/** JSON {@link QueryResponseWriter}. */ +public class JSONResponseWriter implements TextQueryResponseWriter { public static String CONTENT_TYPE_JSON_UTF8 = "application/json; charset=UTF-8"; private String contentType = CONTENT_TYPE_JSON_UTF8; diff --git a/solr/core/src/java/org/apache/solr/response/JacksonJsonWriter.java b/solr/core/src/java/org/apache/solr/response/JacksonJsonWriter.java index 3ab9121c37d..f254f625a52 100644 --- a/solr/core/src/java/org/apache/solr/response/JacksonJsonWriter.java +++ b/solr/core/src/java/org/apache/solr/response/JacksonJsonWriter.java @@ -23,13 +23,17 @@ import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; import java.io.IOException; import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.io.Writer; import java.math.BigDecimal; import java.math.BigInteger; +import java.util.Arrays; import org.apache.solr.common.PushWriter; +import org.apache.solr.common.util.ContentStreamBase; import org.apache.solr.request.SolrQueryRequest; /** A JSON ResponseWriter that uses jackson. */ -public class JacksonJsonWriter extends BinaryResponseWriter { +public class JacksonJsonWriter implements TextQueryResponseWriter { protected final JsonFactory jsonfactory; protected static final DefaultPrettyPrinter pretty = @@ -43,17 +47,42 @@ public JacksonJsonWriter() { jsonfactory = new JsonFactory(); } + // let's also implement the binary version since Jackson supports that (probably faster) @Override - public void write(OutputStream out, SolrQueryRequest request, SolrQueryResponse response) + public void write( + OutputStream out, SolrQueryRequest request, SolrQueryResponse response, String contentType) throws IOException { - WriterImpl sw = new WriterImpl(jsonfactory, out, request, response); + out = new NonFlushingStream(out); + // resolve the encoding + final String charSet = ContentStreamBase.getCharsetFromContentType(contentType); + JsonEncoding jsonEncoding; + if (charSet != null) { + assert JsonEncoding.values().length < 10; // fast to iterate + jsonEncoding = + Arrays.stream(JsonEncoding.values()) + .filter(e -> e.getJavaName().equalsIgnoreCase(charSet)) + .findAny() + .orElseThrow(() -> new UnsupportedEncodingException(charSet)); + } else { + jsonEncoding = JsonEncoding.UTF8; + } + + var sw = new WriterImpl(request, response, jsonfactory.createGenerator(out, jsonEncoding)); + sw.writeResponse(); + sw.close(); + } + + @Override + public void write(Writer writer, SolrQueryRequest request, SolrQueryResponse response) + throws IOException { + var sw = new WriterImpl(request, response, jsonfactory.createGenerator(writer)); sw.writeResponse(); sw.close(); } public PushWriter getWriter( - OutputStream out, SolrQueryRequest request, SolrQueryResponse response) { - return new WriterImpl(jsonfactory, out, request, response); + OutputStream out, SolrQueryRequest request, SolrQueryResponse response) throws IOException { + return new WriterImpl(request, response, jsonfactory.createGenerator(out, JsonEncoding.UTF8)); } @Override @@ -67,16 +96,11 @@ public static class WriterImpl extends JSONWriter { protected JsonGenerator gen; - public WriterImpl( - JsonFactory j, OutputStream out, SolrQueryRequest req, SolrQueryResponse rsp) { + public WriterImpl(SolrQueryRequest req, SolrQueryResponse rsp, JsonGenerator generator) { super(null, req, rsp); - try { - gen = j.createGenerator(out, JsonEncoding.UTF8); - if (doIndent) { - gen.setPrettyPrinter(pretty.createInstance()); - } - } catch (IOException e) { - throw new RuntimeException(e); + gen = generator; + if (doIndent) { + gen.setPrettyPrinter(pretty.createInstance()); } } diff --git a/solr/core/src/java/org/apache/solr/response/PrometheusResponseWriter.java b/solr/core/src/java/org/apache/solr/response/PrometheusResponseWriter.java index 8689751a514..5919a0ec858 100644 --- a/solr/core/src/java/org/apache/solr/response/PrometheusResponseWriter.java +++ b/solr/core/src/java/org/apache/solr/response/PrometheusResponseWriter.java @@ -47,12 +47,15 @@ * org.apache.solr.handler.admin.MetricsHandler} */ @SuppressWarnings(value = "unchecked") -public class PrometheusResponseWriter extends RawResponseWriter { +public class PrometheusResponseWriter implements QueryResponseWriter { + // not TextQueryResponseWriter because Prometheus libs work with an OutputStream + private static final String CONTENT_TYPE_PROMETHEUS = "text/plain; version=0.0.4"; private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); @Override - public void write(OutputStream out, SolrQueryRequest request, SolrQueryResponse response) + public void write( + OutputStream out, SolrQueryRequest request, SolrQueryResponse response, String contentType) throws IOException { NamedList prometheusRegistries = (NamedList) response.getValues().get("metrics"); diff --git a/solr/core/src/java/org/apache/solr/response/QueryResponseWriter.java b/solr/core/src/java/org/apache/solr/response/QueryResponseWriter.java index 932df711bd2..673543b8e6a 100644 --- a/solr/core/src/java/org/apache/solr/response/QueryResponseWriter.java +++ b/solr/core/src/java/org/apache/solr/response/QueryResponseWriter.java @@ -16,14 +16,16 @@ */ package org.apache.solr.response; +import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.Writer; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import net.jcip.annotations.ThreadSafe; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.util.plugin.NamedListInitializedPlugin; /** - * Implementations of QueryResponseWriter are used to format responses to query - * requests. + * Used to format responses to the client (not necessarily a "query"). * *

Different QueryResponseWriters are registered with the SolrCore. One * way to register a QueryResponseWriter with the core is through the solrconfig.xml @@ -39,23 +41,26 @@ *

A single instance of any registered QueryResponseWriter is created via the default constructor * and is reused for all relevant queries. */ +@ThreadSafe public interface QueryResponseWriter extends NamedListInitializedPlugin { public static String CONTENT_TYPE_XML_UTF8 = "application/xml; charset=UTF-8"; public static String CONTENT_TYPE_TEXT_UTF8 = "text/plain; charset=UTF-8"; public static String CONTENT_TYPE_TEXT_ASCII = "text/plain; charset=US-ASCII"; /** - * Write a SolrQueryResponse, this method must be thread save. - * - *

Information about the request (in particular: formatting options) may be obtained from - * req but the dominant source of information should be rsp. - * - *

There are no mandatory actions that write must perform. An empty write implementation would - * fulfill all interface obligations. + * Writes the response to the {@link OutputStream}. {@code contentType} is from {@link + * #getContentType(SolrQueryRequest, SolrQueryResponse)}, and it's often ignored. */ - public void write(Writer writer, SolrQueryRequest request, SolrQueryResponse response) + void write( + OutputStream out, SolrQueryRequest request, SolrQueryResponse response, String contentType) throws IOException; + // should be "final" if interfaces allowed that + default void write(OutputStream out, SolrQueryRequest request, SolrQueryResponse response) + throws IOException { + write(out, request, response, getContentType(request, response)); + } + /** * Return the applicable Content Type for a request, this method must be thread safe. * @@ -64,5 +69,13 @@ public void write(Writer writer, SolrQueryRequest request, SolrQueryResponse res * * @return a Content-Type string, which may not be null. */ - public String getContentType(SolrQueryRequest request, SolrQueryResponse response); + String getContentType(SolrQueryRequest request, SolrQueryResponse response); + + /** Writes a String for debugging / testing purposes. */ + default String writeToString(SolrQueryRequest request, SolrQueryResponse response) + throws IOException { + var buffer = new ByteArrayOutputStream(32000); + write(buffer, request, response); + return buffer.toString(StandardCharsets.UTF_8); + } } diff --git a/solr/core/src/java/org/apache/solr/response/RawResponseWriter.java b/solr/core/src/java/org/apache/solr/response/RawResponseWriter.java index d20128ae4e0..922b4932952 100644 --- a/solr/core/src/java/org/apache/solr/response/RawResponseWriter.java +++ b/solr/core/src/java/org/apache/solr/response/RawResponseWriter.java @@ -20,8 +20,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.Reader; -import java.io.Writer; import org.apache.solr.common.util.ContentStream; import org.apache.solr.common.util.NamedList; import org.apache.solr.core.SolrCore; @@ -39,7 +37,7 @@ * * @since solr 1.3 */ -public class RawResponseWriter implements BinaryQueryResponseWriter { +public class RawResponseWriter implements QueryResponseWriter { public static final String CONTENT_TYPE = "application/vnd.apache.solr.raw"; @@ -75,8 +73,7 @@ protected QueryResponseWriter getBaseWriter(SolrQueryRequest request) { } // Requests to a specific core already have writers, but we still need a 'default writer' for - // non-core - // (i.e. container-level) APIs + // non-core (i.e. container-level) APIs synchronized (this) { if (defaultWriter == null) { defaultWriter = new JSONResponseWriter(); @@ -88,41 +85,27 @@ protected QueryResponseWriter getBaseWriter(SolrQueryRequest request) { @Override public String getContentType(SolrQueryRequest request, SolrQueryResponse response) { Object obj = response.getValues().get(CONTENT); - if (obj != null && (obj instanceof ContentStream)) { - return ((ContentStream) obj).getContentType(); + if (obj instanceof ContentStream content) { + return content.getContentType(); } return getBaseWriter(request).getContentType(request, response); } @Override - public void write(Writer writer, SolrQueryRequest request, SolrQueryResponse response) + public void write( + OutputStream out, SolrQueryRequest request, SolrQueryResponse response, String contentType) throws IOException { Object obj = response.getValues().get(CONTENT); - if (obj != null && (obj instanceof ContentStream content)) { - // copy the contents to the writer... - try (Reader reader = content.getReader()) { - reader.transferTo(writer); - } - } else { - getBaseWriter(request).write(writer, request, response); - } - } - - @Override - public void write(OutputStream out, SolrQueryRequest request, SolrQueryResponse response) - throws IOException { - Object obj = response.getValues().get(CONTENT); - if (obj != null && (obj instanceof ContentStream content)) { + if (obj instanceof ContentStream content) { // copy the contents to the writer... try (InputStream in = content.getStream()) { in.transferTo(out); } - } else if (obj != null && (obj instanceof SolrCore.RawWriter rawWriter)) { + } else if (obj instanceof SolrCore.RawWriter rawWriter) { rawWriter.write(out); - if (rawWriter instanceof Closeable) ((Closeable) rawWriter).close(); + if (rawWriter instanceof Closeable closeable) closeable.close(); } else { - QueryResponseWriterUtil.writeQueryResponse( - out, getBaseWriter(request), request, response, getContentType(request, response)); + getBaseWriter(request).write(out, request, response, contentType); } } } diff --git a/solr/core/src/java/org/apache/solr/response/SchemaXmlResponseWriter.java b/solr/core/src/java/org/apache/solr/response/SchemaXmlResponseWriter.java index 340cd91def7..1480004d03b 100644 --- a/solr/core/src/java/org/apache/solr/response/SchemaXmlResponseWriter.java +++ b/solr/core/src/java/org/apache/solr/response/SchemaXmlResponseWriter.java @@ -22,7 +22,7 @@ import org.apache.solr.request.SolrQueryRequest; /** */ -public class SchemaXmlResponseWriter implements QueryResponseWriter { +public class SchemaXmlResponseWriter implements TextQueryResponseWriter { @Override public void write(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp) throws IOException { SchemaXmlWriter w = new SchemaXmlWriter(writer, req, rsp); diff --git a/solr/core/src/java/org/apache/solr/response/SmileResponseWriter.java b/solr/core/src/java/org/apache/solr/response/SmileResponseWriter.java index 00f986200a4..d4b283ec06e 100644 --- a/solr/core/src/java/org/apache/solr/response/SmileResponseWriter.java +++ b/solr/core/src/java/org/apache/solr/response/SmileResponseWriter.java @@ -24,16 +24,27 @@ import java.math.BigInteger; import org.apache.solr.request.SolrQueryRequest; -public class SmileResponseWriter extends BinaryResponseWriter { +/** + * A Smile formatting {@link QueryResponseWriter}. + * + * @see Smile + */ +public class SmileResponseWriter implements QueryResponseWriter { @Override - public void write(OutputStream out, SolrQueryRequest request, SolrQueryResponse response) + public void write( + OutputStream out, SolrQueryRequest request, SolrQueryResponse response, String contentType) throws IOException { try (SmileWriter sw = new SmileWriter(out, request, response)) { sw.writeResponse(); } } + @Override + public String getContentType(SolrQueryRequest request, SolrQueryResponse response) { + return "application/x-jackson-smile"; + } + // smile format is an equivalent of JSON format . So we extend JSONWriter and override the // relevant methods diff --git a/solr/core/src/java/org/apache/solr/response/QueryResponseWriterUtil.java b/solr/core/src/java/org/apache/solr/response/TextQueryResponseWriter.java similarity index 62% rename from solr/core/src/java/org/apache/solr/response/QueryResponseWriterUtil.java rename to solr/core/src/java/org/apache/solr/response/TextQueryResponseWriter.java index 1ea0642738d..f4df38f830d 100644 --- a/solr/core/src/java/org/apache/solr/response/QueryResponseWriterUtil.java +++ b/solr/core/src/java/org/apache/solr/response/TextQueryResponseWriter.java @@ -14,12 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.apache.solr.response; -import java.io.BufferedOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; +import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.nio.charset.StandardCharsets; @@ -27,50 +28,51 @@ import org.apache.solr.common.util.FastWriter; import org.apache.solr.request.SolrQueryRequest; -/** Static utility methods relating to {@link QueryResponseWriter}s */ -public final class QueryResponseWriterUtil { - private QueryResponseWriterUtil() { - /* static helpers only */ - } +/** A writer supporting character streams ({@link Writer} based). */ +public interface TextQueryResponseWriter extends QueryResponseWriter { /** - * 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 appropriate method. + * Write a SolrQueryResponse in a textual manner. + * + *

Information about the request (in particular: formatting options) may be obtained from + * req but the dominant source of information should be rsp. * - * @see BinaryQueryResponseWriter#write(OutputStream,SolrQueryRequest,SolrQueryResponse) - * @see BinaryQueryResponseWriter#write(Writer,SolrQueryRequest,SolrQueryResponse) + *

There are no mandatory actions that write must perform. An empty write implementation would + * fulfill all interface obligations. */ - public static void writeQueryResponse( + void write(Writer writer, SolrQueryRequest request, SolrQueryResponse response) + throws IOException; + + @Override + default String writeToString(SolrQueryRequest request, SolrQueryResponse response) + throws IOException { + StringWriter sw = new StringWriter(32000); + write(sw, request, response); + return sw.toString(); + } + + @Override + default void write( OutputStream outputStream, - QueryResponseWriter responseWriter, - SolrQueryRequest solrRequest, - SolrQueryResponse solrResponse, + SolrQueryRequest request, + SolrQueryResponse response, String contentType) throws IOException { - - if (responseWriter instanceof JacksonJsonWriter binWriter) { - BufferedOutputStream bos = new BufferedOutputStream(new NonFlushingStream(outputStream)); - binWriter.write(bos, solrRequest, solrResponse); - bos.flush(); - } else if (responseWriter instanceof BinaryQueryResponseWriter binWriter) { - binWriter.write(outputStream, solrRequest, solrResponse); - } else { - OutputStream out = new NonFlushingStream(outputStream); - Writer writer = buildWriter(out, ContentStreamBase.getCharsetFromContentType(contentType)); - responseWriter.write(writer, solrRequest, solrResponse); - writer.flush(); - } + OutputStream out = new NonFlushingStream(outputStream); + Writer writer = buildWriter(out, ContentStreamBase.getCharsetFromContentType(contentType)); + write(writer, request, response); + writer.flush(); } private static Writer buildWriter(OutputStream outputStream, String charset) throws UnsupportedEncodingException { + // note: OutputStreamWriter has an internal buffer; flush is needed Writer writer = (charset == null) ? new OutputStreamWriter(outputStream, StandardCharsets.UTF_8) : new OutputStreamWriter(outputStream, charset); - return new FastWriter(writer); + return new FastWriter(writer); // note: buffered; therefore we need to call flush() } /** @@ -81,7 +83,8 @@ private static Writer buildWriter(OutputStream outputStream, String charset) * *

See SOLR-8669. */ - private static class NonFlushingStream extends OutputStream { + // TODO instead do in ServletUtils.closeShield(HttpServletResponse) + class NonFlushingStream extends OutputStream { private final OutputStream outputStream; public NonFlushingStream(OutputStream outputStream) { diff --git a/solr/core/src/java/org/apache/solr/response/XMLResponseWriter.java b/solr/core/src/java/org/apache/solr/response/XMLResponseWriter.java index f0f3672520a..6dbfdddd873 100644 --- a/solr/core/src/java/org/apache/solr/response/XMLResponseWriter.java +++ b/solr/core/src/java/org/apache/solr/response/XMLResponseWriter.java @@ -21,8 +21,8 @@ import org.apache.solr.client.solrj.impl.XMLResponseParser; import org.apache.solr.request.SolrQueryRequest; -/** */ -public class XMLResponseWriter implements QueryResponseWriter { +/** An XML {@link QueryResponseWriter}. */ +public class XMLResponseWriter implements TextQueryResponseWriter { @Override public void write(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp) throws IOException { XMLWriter w = new XMLWriter(writer, req, rsp); diff --git a/solr/core/src/java/org/apache/solr/servlet/DirectSolrConnection.java b/solr/core/src/java/org/apache/solr/servlet/DirectSolrConnection.java index 9b54f9319df..2d6acb19d73 100644 --- a/solr/core/src/java/org/apache/solr/servlet/DirectSolrConnection.java +++ b/solr/core/src/java/org/apache/solr/servlet/DirectSolrConnection.java @@ -16,7 +16,6 @@ */ package org.apache.solr.servlet; -import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import org.apache.solr.common.SolrException; @@ -28,8 +27,6 @@ import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrRequestHandler; import org.apache.solr.request.SolrRequestInfo; -import org.apache.solr.response.BinaryResponseWriter; -import org.apache.solr.response.QueryResponseWriter; import org.apache.solr.response.SolrQueryResponse; /** @@ -114,14 +111,7 @@ public String request(SolrRequestHandler handler, SolrParams params, String body } // Now write it out - QueryResponseWriter responseWriter = core.getQueryResponseWriter(req); - if (responseWriter instanceof BinaryResponseWriter) { - return ((BinaryResponseWriter) responseWriter).serializeResponse(req, rsp); - } else { - StringWriter out = new StringWriter(); - responseWriter.write(out, req, rsp); - return out.toString(); - } + return req.getResponseWriter().writeToString(req, rsp); } finally { if (req != null) { req.close(); diff --git a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java index 904f3216b35..97a0290fa49 100644 --- a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java +++ b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java @@ -110,7 +110,6 @@ import org.apache.solr.request.SolrRequestHandler; import org.apache.solr.request.SolrRequestInfo; import org.apache.solr.response.QueryResponseWriter; -import org.apache.solr.response.QueryResponseWriterUtil; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.security.AuditEvent; import org.apache.solr.security.AuditEvent.EventType; @@ -1000,8 +999,7 @@ protected void writeResponse( } if (Method.HEAD != reqMethod) { - OutputStream out = response.getOutputStream(); - QueryResponseWriterUtil.writeQueryResponse(out, responseWriter, solrReq, solrRsp, ct); + responseWriter.write(response.getOutputStream(), solrReq, solrRsp, ct); } // else http HEAD request, nothing to write out, waited this long just to get ContentType } catch (EOFException e) { diff --git a/solr/core/src/test/org/apache/solr/OutputWriterTest.java b/solr/core/src/test/org/apache/solr/OutputWriterTest.java index 13eb69d9014..f230733383c 100644 --- a/solr/core/src/test/org/apache/solr/OutputWriterTest.java +++ b/solr/core/src/test/org/apache/solr/OutputWriterTest.java @@ -23,6 +23,7 @@ import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.QueryResponseWriter; import org.apache.solr.response.SolrQueryResponse; +import org.apache.solr.response.TextQueryResponseWriter; import org.junit.BeforeClass; import org.junit.Test; @@ -77,7 +78,7 @@ public void testLazy() { //////////////////////////////////////////////////////////////////////////// /** An output writer that doesn't do anything useful. */ - public static class UselessOutputWriter implements QueryResponseWriter { + public static class UselessOutputWriter implements TextQueryResponseWriter { public UselessOutputWriter() {} diff --git a/solr/core/src/test/org/apache/solr/TestCrossCoreJoin.java b/solr/core/src/test/org/apache/solr/TestCrossCoreJoin.java index 83f91365294..8cc81184c40 100644 --- a/solr/core/src/test/org/apache/solr/TestCrossCoreJoin.java +++ b/solr/core/src/test/org/apache/solr/TestCrossCoreJoin.java @@ -16,7 +16,6 @@ */ package org.apache.solr; -import java.io.StringWriter; import java.util.Collections; import java.util.Map; import org.apache.solr.common.SolrException.ErrorCode; @@ -27,7 +26,6 @@ import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrRequestHandler; import org.apache.solr.request.SolrRequestInfo; -import org.apache.solr.response.QueryResponseWriter; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.search.join.TestScoreJoinQPNoScore; import org.apache.solr.servlet.DirectSolrConnection; @@ -213,11 +211,12 @@ void doTestJoin(String joinPrefix) throws Exception { @Test public void testCoresAreDifferent() throws Exception { assertQEx("schema12.xml" + " has no \"cat\" field", req("cat:*"), ErrorCode.BAD_REQUEST); - final LocalSolrQueryRequest req = - new LocalSolrQueryRequest(fromCore, "cat:*", "/select", 0, 100, Collections.emptyMap()); - final String resp = query(fromCore, req); - assertTrue(resp, resp.contains("numFound=\"1\"")); - assertTrue(resp, resp.contains("10")); + try (var req = + new LocalSolrQueryRequest(fromCore, "cat:*", "/select", 0, 100, Collections.emptyMap())) { + final String resp = query(fromCore, req); + assertTrue(resp, resp.contains("numFound=\"1\"")); + assertTrue(resp, resp.contains("10")); + } } public String query(SolrCore core, SolrQueryRequest req) throws Exception { @@ -232,16 +231,15 @@ public String query(SolrCore core, SolrQueryRequest req) throws Exception { } SolrQueryResponse rsp = new SolrQueryResponse(); SolrRequestInfo.setRequestInfo(new SolrRequestInfo(req, rsp)); - core.execute(core.getRequestHandler(handler), req, rsp); - if (rsp.getException() != null) { - throw rsp.getException(); + try { + core.execute(core.getRequestHandler(handler), req, rsp); + if (rsp.getException() != null) { + throw rsp.getException(); + } + return req.getResponseWriter().writeToString(req, rsp); + } finally { + SolrRequestInfo.clearRequestInfo(); } - StringWriter sw = new StringWriter(32000); - QueryResponseWriter responseWriter = core.getQueryResponseWriter(req); - responseWriter.write(sw, req, rsp); - req.close(); - SolrRequestInfo.clearRequestInfo(); - return sw.toString(); } @AfterClass diff --git a/solr/core/src/test/org/apache/solr/TestTolerantSearch.java b/solr/core/src/test/org/apache/solr/TestTolerantSearch.java index 4995ed378c2..c0571affd6c 100644 --- a/solr/core/src/test/org/apache/solr/TestTolerantSearch.java +++ b/solr/core/src/test/org/apache/solr/TestTolerantSearch.java @@ -258,7 +258,8 @@ public BadResponseWriter() { } @Override - public void write(OutputStream out, SolrQueryRequest req, SolrQueryResponse response) + public void write( + OutputStream out, SolrQueryRequest req, SolrQueryResponse response, String contentType) throws IOException { // I want to fail on the shard request, not the original user request, and only on the @@ -281,7 +282,7 @@ public void write(OutputStream out, SolrQueryRequest req, SolrQueryResponse resp throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "Dummy exception in BadResponseWriter"); } - super.write(out, req, response); + super.write(out, req, response, contentType); } } } diff --git a/solr/core/src/test/org/apache/solr/logging/TestLogWatcher.java b/solr/core/src/test/org/apache/solr/logging/TestLogWatcher.java index 34cd05e8cbd..c688956a08c 100644 --- a/solr/core/src/test/org/apache/solr/logging/TestLogWatcher.java +++ b/solr/core/src/test/org/apache/solr/logging/TestLogWatcher.java @@ -16,11 +16,8 @@ */ package org.apache.solr.logging; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.StringWriter; import java.lang.invoke.MethodHandles; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; @@ -32,7 +29,6 @@ import org.apache.solr.common.util.TimeSource; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrQueryRequestBase; -import org.apache.solr.response.BinaryQueryResponseWriter; import org.apache.solr.response.JSONResponseWriter; import org.apache.solr.response.JacksonJsonWriter; import org.apache.solr.response.QueryResponseWriter; @@ -133,18 +129,7 @@ private static void validateWrite( SolrQueryRequest req = new SolrQueryRequestBase(null, new ModifiableSolrParams()) {}; SolrQueryResponse rsp = new SolrQueryResponse(); rsp.addResponse(docs); - String output; - if (responseWriter instanceof BinaryQueryResponseWriter) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ((BinaryQueryResponseWriter) responseWriter).write(baos, req, rsp); - baos.close(); - output = baos.toString(StandardCharsets.UTF_8); - } else { - StringWriter writer = new StringWriter(); - responseWriter.write(writer, req, rsp); - writer.close(); - output = writer.toString(); - } + String output = responseWriter.writeToString(req, rsp); assertTrue("found: " + output, output.contains(expectMsg)); validateWrite(docs, expectMsg); } diff --git a/solr/core/src/test/org/apache/solr/request/TestWriterPerf.java b/solr/core/src/test/org/apache/solr/request/TestWriterPerf.java index 4ba2c17bedf..676f5622eee 100644 --- a/solr/core/src/test/org/apache/solr/request/TestWriterPerf.java +++ b/solr/core/src/test/org/apache/solr/request/TestWriterPerf.java @@ -18,16 +18,12 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; import java.lang.invoke.MethodHandles; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.solrj.ResponseParser; import org.apache.solr.client.solrj.impl.BinaryResponseParser; import org.apache.solr.client.solrj.impl.XMLResponseParser; -import org.apache.solr.response.BinaryQueryResponseWriter; import org.apache.solr.response.QueryResponseWriter; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.util.RTimer; @@ -179,18 +175,9 @@ void doPerf(String writerName, SolrQueryRequest req, int encIter, int decIter) t System.gc(); RTimer timer = new RTimer(); for (int i = 0; i < encIter; i++) { - if (w instanceof BinaryQueryResponseWriter binWriter) { - out = new ByteArrayOutputStream(); - binWriter.write(out, req, rsp); - out.close(); - } else { - out = new ByteArrayOutputStream(); - // to be fair, from my previous tests, much of the performance will be sucked up - // by java's UTF-8 encoding/decoding, not the actual writing - Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8); - w.write(writer, req, rsp); - writer.close(); - } + out = new ByteArrayOutputStream(32_000); + w.write(out, req, rsp); + out.close(); } double encodeTime = timer.getTime(); diff --git a/solr/core/src/test/org/apache/solr/response/JSONWriterTest.java b/solr/core/src/test/org/apache/solr/response/JSONWriterTest.java index 5ccf19cdecf..7cb358f6904 100644 --- a/solr/core/src/test/org/apache/solr/response/JSONWriterTest.java +++ b/solr/core/src/test/org/apache/solr/response/JSONWriterTest.java @@ -54,9 +54,9 @@ private void jsonEq(String expected, String received) { @Test public void testSimpleJson() throws IOException { - SolrQueryRequest req = req("q", "dummy", "indent", "off"); - SolrQueryResponse rsp = new SolrQueryResponse(); - QueryResponseWriter w = new JSONResponseWriter(); + var req = req("q", "dummy", "indent", "off"); + var rsp = new SolrQueryResponse(); + var w = new JSONResponseWriter(); StringWriter buf = new StringWriter(); diff --git a/solr/core/src/test/org/apache/solr/response/TestBinaryResponseWriter.java b/solr/core/src/test/org/apache/solr/response/TestBinaryResponseWriter.java index 80dfe9db363..4331c58e1c8 100644 --- a/solr/core/src/test/org/apache/solr/response/TestBinaryResponseWriter.java +++ b/solr/core/src/test/org/apache/solr/response/TestBinaryResponseWriter.java @@ -73,10 +73,8 @@ public void testUUID() throws Exception { assertU(commit()); LocalSolrQueryRequest req = lrf.makeRequest("q", "*:*"); SolrQueryResponse rsp = h.queryAndResponse(req.getParams().get(CommonParams.QT), req); - BinaryQueryResponseWriter writer = - (BinaryQueryResponseWriter) h.getCore().getQueryResponseWriter("javabin"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - writer.write(baos, req, rsp); + h.getCore().getQueryResponseWriter("javabin").write(baos, req, rsp); NamedList res; try (JavaBinCodec jbc = new JavaBinCodec()) { res = (NamedList) jbc.unmarshal(new ByteArrayInputStream(baos.toByteArray())); diff --git a/solr/core/src/test/org/apache/solr/response/TestCSVResponseWriter.java b/solr/core/src/test/org/apache/solr/response/TestCSVResponseWriter.java index 282db9c917b..3c5afeb2085 100644 --- a/solr/core/src/test/org/apache/solr/response/TestCSVResponseWriter.java +++ b/solr/core/src/test/org/apache/solr/response/TestCSVResponseWriter.java @@ -25,7 +25,6 @@ import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocumentList; -import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.search.SolrReturnFields; import org.junit.BeforeClass; import org.junit.Test; @@ -285,10 +284,10 @@ public void testCSVOutput() throws Exception { sdl.add(d1); sdl.add(d2); - SolrQueryRequest req = req("q", "*:*"); - SolrQueryResponse rsp = new SolrQueryResponse(); + var req = req("q", "*:*"); + var rsp = new SolrQueryResponse(); rsp.addResponse(sdl); - QueryResponseWriter w = new CSVResponseWriter(); + var w = new CSVResponseWriter(); rsp.setReturnFields(new SolrReturnFields("id,foo_s", req)); StringWriter buf = new StringWriter(); diff --git a/solr/core/src/test/org/apache/solr/response/TestRawResponseWriter.java b/solr/core/src/test/org/apache/solr/response/TestRawResponseWriter.java index adf15bdb706..d84a91cf1f8 100644 --- a/solr/core/src/test/org/apache/solr/response/TestRawResponseWriter.java +++ b/solr/core/src/test/org/apache/solr/response/TestRawResponseWriter.java @@ -19,7 +19,6 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.StringWriter; import java.nio.charset.StandardCharsets; import org.apache.lucene.tests.util.TestUtil; import org.apache.solr.SolrTestCaseJ4; @@ -104,9 +103,7 @@ public void testRawStringContentStream() throws IOException { 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()); + assertEquals(data, writer.writeToString(req(), rsp)); // we should have UTF-8 Bytes if we use an OutputStream ByteArrayOutputStream bout = new ByteArrayOutputStream(); @@ -139,23 +136,20 @@ public void testStructuredDataViaBaseWriters() throws IOException { + "test\n" + "bar\n" + "\n"; - StringWriter xmlSout = new StringWriter(); - writerXmlBase.write(xmlSout, req(), rsp); - assertEquals(xml, xmlSout.toString()); + assertEquals(xml, writerXmlBase.writeToString(req(), rsp)); 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()); + assertEquals(xml, writerNoBase.writeToString(req(), rsp)); ByteArrayOutputStream noneBout = new ByteArrayOutputStream(); writerNoBase.write(noneBout, req(), rsp); assertEquals(xml, noneBout.toString(StandardCharsets.UTF_8.toString())); // json String json = "{\n" + " \"content\":\"test\",\n" + " \"foo\":\"bar\"}\n"; - assertJSONEquals(json, writerJsonBase.serializeResponse(req(), rsp)); + assertJSONEquals(json, writerJsonBase.writeToString(req(), rsp)); // javabin ByteArrayOutputStream bytes = new ByteArrayOutputStream(); diff --git a/solr/core/src/test/org/apache/solr/response/TestRetrieveFieldsOptimizer.java b/solr/core/src/test/org/apache/solr/response/TestRetrieveFieldsOptimizer.java index e5cbeaf44d1..9550528f810 100644 --- a/solr/core/src/test/org/apache/solr/response/TestRetrieveFieldsOptimizer.java +++ b/solr/core/src/test/org/apache/solr/response/TestRetrieveFieldsOptimizer.java @@ -314,10 +314,8 @@ private void check(String flIn, SolrReturnFields.FIELD_SOURCES source) throws Ex SolrQueryRequest req = lrf.makeRequest("q", "*:*", CommonParams.FL, fl); SolrQueryResponse rsp = h.queryAndResponse("", req); - BinaryQueryResponseWriter writer = - (BinaryQueryResponseWriter) core.getQueryResponseWriter("javabin"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - writer.write(baos, req, rsp); + core.getQueryResponseWriter("javabin").write(baos, req, rsp); // This is really the main point! assertEquals( diff --git a/solr/core/src/test/org/apache/solr/response/transform/TestSubQueryTransformer.java b/solr/core/src/test/org/apache/solr/response/transform/TestSubQueryTransformer.java index 461fa4c9560..072ac509853 100644 --- a/solr/core/src/test/org/apache/solr/response/transform/TestSubQueryTransformer.java +++ b/solr/core/src/test/org/apache/solr/response/transform/TestSubQueryTransformer.java @@ -36,7 +36,6 @@ 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.SolrQueryResponse; import org.junit.BeforeClass; import org.junit.Test; @@ -630,10 +629,8 @@ public void testJustJohnJavabin() throws Exception { SolrQueryResponse response = h.queryAndResponse(johnTwoFL.getParams().get(CommonParams.QT), johnTwoFL); - BinaryQueryResponseWriter responseWriter = - (BinaryQueryResponseWriter) core.getQueryResponseWriter(johnTwoFL); ByteArrayOutputStream bytes = new ByteArrayOutputStream(); - responseWriter.write(bytes, johnTwoFL, response); + johnTwoFL.getResponseWriter().write(bytes, johnTwoFL, response); try (JavaBinCodec jbc = new JavaBinCodec()) { unmarshalled = diff --git a/solr/core/src/test/org/apache/solr/search/TestSmileRequest.java b/solr/core/src/test/org/apache/solr/search/TestSmileRequest.java index a5f59890854..5d31ee02121 100644 --- a/solr/core/src/test/org/apache/solr/search/TestSmileRequest.java +++ b/solr/core/src/test/org/apache/solr/search/TestSmileRequest.java @@ -18,12 +18,15 @@ import java.io.IOException; import java.io.InputStream; +import java.io.Reader; +import java.util.Collection; import java.util.Map; +import java.util.Set; import org.apache.solr.JSONTestUtil; import org.apache.solr.SolrTestCaseHS; import org.apache.solr.SolrTestCaseJ4; +import org.apache.solr.client.solrj.ResponseParser; import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.impl.BinaryResponseParser; import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.NamedList; @@ -90,7 +93,7 @@ public void assertJQ(SolrClient client, SolrParams args, String... tests) // adding this to core adds the dependency on a few extra jars to our distribution. // So this is not added there - public static class SmileResponseParser extends BinaryResponseParser { + public static class SmileResponseParser extends ResponseParser { @Override public String getWriterType() { @@ -107,5 +110,15 @@ public NamedList processResponse(InputStream body, String encoding) { throw new RuntimeException(e); } } + + @Override + public NamedList processResponse(Reader reader) { + throw new UnsupportedOperationException(); + } + + @Override + public Collection getContentTypes() { + return Set.of("application/x-jackson-smile", "application/octet-stream"); + } } } diff --git a/solr/modules/extraction/src/java/org/apache/solr/handler/extraction/XLSXResponseWriter.java b/solr/modules/extraction/src/java/org/apache/solr/handler/extraction/XLSXResponseWriter.java index 60a995b4d5d..c2f9f836761 100644 --- a/solr/modules/extraction/src/java/org/apache/solr/handler/extraction/XLSXResponseWriter.java +++ b/solr/modules/extraction/src/java/org/apache/solr/handler/extraction/XLSXResponseWriter.java @@ -40,7 +40,7 @@ import org.apache.poi.xssf.usermodel.XSSFCellStyle; import org.apache.solr.common.SolrDocument; import org.apache.solr.request.SolrQueryRequest; -import org.apache.solr.response.RawResponseWriter; +import org.apache.solr.response.QueryResponseWriter; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.response.TabularResponseWriter; import org.apache.solr.schema.FieldType; @@ -48,10 +48,12 @@ import org.apache.solr.schema.StrField; import org.apache.solr.search.ReturnFields; -public class XLSXResponseWriter extends RawResponseWriter { +/** A .XLSX spreadsheet format {@link org.apache.solr.response.QueryResponseWriter}. */ +public class XLSXResponseWriter implements QueryResponseWriter { @Override - public void write(OutputStream out, SolrQueryRequest req, SolrQueryResponse rsp) + public void write( + OutputStream out, SolrQueryRequest req, SolrQueryResponse rsp, String contentType) throws IOException { // throw away arraywriter just to satisfy super requirements; we're grabbing // all writes before they go to it anyway diff --git a/solr/modules/scripting/src/java/org/apache/solr/scripting/xslt/XSLTResponseWriter.java b/solr/modules/scripting/src/java/org/apache/solr/scripting/xslt/XSLTResponseWriter.java index 2b807a2c019..15b648510dc 100644 --- a/solr/modules/scripting/src/java/org/apache/solr/scripting/xslt/XSLTResponseWriter.java +++ b/solr/modules/scripting/src/java/org/apache/solr/scripting/xslt/XSLTResponseWriter.java @@ -33,8 +33,8 @@ import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.NamedList; import org.apache.solr.request.SolrQueryRequest; -import org.apache.solr.response.QueryResponseWriter; import org.apache.solr.response.SolrQueryResponse; +import org.apache.solr.response.TextQueryResponseWriter; import org.apache.solr.response.XMLWriter; /** @@ -44,7 +44,7 @@ *

QueryResponseWriter captures the output of the XMLWriter (in memory for now, not optimal * performance-wise), and applies an XSLT transform to it. */ -public class XSLTResponseWriter implements QueryResponseWriter { +public class XSLTResponseWriter implements TextQueryResponseWriter { public static final String DEFAULT_CONTENT_TYPE = "application/xml"; private Integer xsltCacheLifetimeSeconds = null; diff --git a/solr/modules/scripting/src/test/org/apache/solr/scripting/xslt/XSLTUpdateRequestHandlerTest.java b/solr/modules/scripting/src/test/org/apache/solr/scripting/xslt/XSLTUpdateRequestHandlerTest.java index af61f99e860..5397780e2e6 100644 --- a/solr/modules/scripting/src/test/org/apache/solr/scripting/xslt/XSLTUpdateRequestHandlerTest.java +++ b/solr/modules/scripting/src/test/org/apache/solr/scripting/xslt/XSLTUpdateRequestHandlerTest.java @@ -16,7 +16,6 @@ */ package org.apache.solr.scripting.xslt; -import java.io.StringWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -29,7 +28,6 @@ import org.apache.solr.handler.loader.ContentStreamLoader; import org.apache.solr.request.LocalSolrQueryRequest; import org.apache.solr.request.SolrQueryRequest; -import org.apache.solr.response.QueryResponseWriter; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.update.AddUpdateCommand; import org.apache.solr.update.processor.BufferingRequestProcessor; @@ -80,11 +78,8 @@ public void testUpdate() throws Exception { handler.init(new NamedList<>()); handler.handleRequestBody(req, rsp); } - StringWriter sw = new StringWriter(32000); - QueryResponseWriter responseWriter = core.getQueryResponseWriter(req); - responseWriter.write(sw, req, rsp); + String response = req.getResponseWriter().writeToString(req, rsp); req.close(); - String response = sw.toString(); assertU(response); assertU(commit()); diff --git a/solr/solrj/src/java/org/apache/solr/common/util/TextWriter.java b/solr/solrj/src/java/org/apache/solr/common/util/TextWriter.java index 5edf9c2c99c..5e04815c322 100644 --- a/solr/solrj/src/java/org/apache/solr/common/util/TextWriter.java +++ b/solr/solrj/src/java/org/apache/solr/common/util/TextWriter.java @@ -41,7 +41,7 @@ import org.apache.solr.common.MapWriter; import org.apache.solr.common.PushWriter; -// Base interface for all text based writers +/** Base interface for all text based writers */ public interface TextWriter extends PushWriter { default void writeVal(String name, Object val) throws IOException { diff --git a/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java b/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java index 12e8ac4805f..87d53af970a 100644 --- a/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java +++ b/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java @@ -16,10 +16,7 @@ */ package org.apache.solr.util; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; @@ -49,8 +46,6 @@ import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrRequestHandler; import org.apache.solr.request.SolrRequestInfo; -import org.apache.solr.response.BinaryQueryResponseWriter; -import org.apache.solr.response.QueryResponseWriter; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.schema.IndexSchema; import org.apache.solr.schema.IndexSchemaFactory; @@ -354,17 +349,7 @@ public String query(String handler, SolrQueryRequest req) throws Exception { if (rsp.getException() != null) { throw rsp.getException(); } - QueryResponseWriter responseWriter = core.getQueryResponseWriter(req); - if (responseWriter instanceof BinaryQueryResponseWriter writer) { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(32000); - writer.write(byteArrayOutputStream, req, rsp); - return new String(byteArrayOutputStream.toByteArray(), StandardCharsets.UTF_8); - } else { - StringWriter sw = new StringWriter(32000); - responseWriter.write(sw, req, rsp); - return sw.toString(); - } - + return req.getResponseWriter().writeToString(req, rsp); } finally { req.close(); SolrRequestInfo.clearRequestInfo();