Skip to content

Commit

Permalink
Fixes SOLR-11841, SOLR-13331, SOLR-13347; add additional unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas Wöckinger committed May 13, 2019
1 parent e542b44 commit c6b6377
Show file tree
Hide file tree
Showing 13 changed files with 1,329 additions and 677 deletions.
Expand Up @@ -16,6 +16,8 @@
*/
package org.apache.solr.client.solrj.embedded;

import static org.apache.solr.common.params.CommonParams.PATH;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
Expand All @@ -24,8 +26,8 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Supplier;

import com.google.common.base.Strings;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
Expand All @@ -34,7 +36,9 @@
import org.apache.solr.client.solrj.impl.BinaryRequestWriter;
import org.apache.solr.client.solrj.impl.BinaryRequestWriter.BAOS;
import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
import org.apache.solr.client.solrj.request.QueryRequest;
import org.apache.solr.client.solrj.request.RequestWriter;
import org.apache.solr.client.solrj.util.ClientUtils;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrException;
Expand All @@ -57,7 +61,7 @@
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.servlet.SolrRequestParsers;

import static org.apache.solr.common.params.CommonParams.PATH;
import com.google.common.base.Strings;

/**
* SolrClient that connects directly to a CoreContainer.
Expand All @@ -69,49 +73,86 @@ public class EmbeddedSolrServer extends SolrClient {
protected final CoreContainer coreContainer;
protected final String coreName;
private final SolrRequestParsers _parser;
private final RequestWriterSupplier supplier;

public enum RequestWriterSupplier {
JavaBin(() -> new BinaryRequestWriter()), XML(() -> new RequestWriter());

private Supplier<RequestWriter> supplier;

private RequestWriterSupplier(final Supplier<RequestWriter> supplier) {
this.supplier = supplier;
}

public RequestWriter newRequestWriter() {
return supplier.get();
}
}

/**
* Create an EmbeddedSolrServer using a given solr home directory
*
* @param solrHome the solr home directory
* @param defaultCoreName the core to route requests to by default
* @param solrHome
* the solr home directory
* @param defaultCoreName
* the core to route requests to by default
*/
public EmbeddedSolrServer(Path solrHome, String defaultCoreName) {
public EmbeddedSolrServer(final Path solrHome, final String defaultCoreName) {
this(load(new CoreContainer(SolrXmlConfig.fromSolrHome(solrHome))), defaultCoreName);
}

/**
* Create an EmbeddedSolrServer using a NodeConfig
*
* @param nodeConfig the configuration
* @param defaultCoreName the core to route requests to by default
* @param nodeConfig
* the configuration
* @param defaultCoreName
* the core to route requests to by default
*/
public EmbeddedSolrServer(NodeConfig nodeConfig, String defaultCoreName) {
public EmbeddedSolrServer(final NodeConfig nodeConfig, final String defaultCoreName) {
this(load(new CoreContainer(nodeConfig)), defaultCoreName);
}

private static CoreContainer load(CoreContainer cc) {
private static CoreContainer load(final CoreContainer cc) {
cc.load();
return cc;
}

/**
* Create an EmbeddedSolrServer wrapping a particular SolrCore
*/
public EmbeddedSolrServer(SolrCore core) {
public EmbeddedSolrServer(final SolrCore core) {
this(core.getCoreContainer(), core.getName());
}

/**
* Create an EmbeddedSolrServer wrapping a CoreContainer.
* <p>
* Note that EmbeddedSolrServer will shutdown the wrapped CoreContainer when
* {@link #close()} is called.
* Note that EmbeddedSolrServer will shutdown the wrapped CoreContainer when {@link #close()} is called.
*
* @param coreContainer
* the core container
* @param coreName
* the core to route requests to by default
*/
public EmbeddedSolrServer(final CoreContainer coreContainer, final String coreName) {
this(coreContainer, coreName, RequestWriterSupplier.JavaBin);
}

/**
* Create an EmbeddedSolrServer wrapping a CoreContainer.
* <p>
* Note that EmbeddedSolrServer will shutdown the wrapped CoreContainer when {@link #close()} is called.
*
* @param coreContainer the core container
* @param coreName the core to route requests to by default
* @param coreContainer
* the core container
* @param coreName
* the core to route requests to by default
* @param supplier
* the supplier used to create a {@link RequestWriter}
*/
public EmbeddedSolrServer(CoreContainer coreContainer, String coreName) {
public EmbeddedSolrServer(final CoreContainer coreContainer, final String coreName,
final RequestWriterSupplier supplier) {
if (coreContainer == null) {
throw new NullPointerException("CoreContainer instance required");
}
Expand All @@ -120,13 +161,14 @@ public EmbeddedSolrServer(CoreContainer coreContainer, String coreName) {
this.coreContainer = coreContainer;
this.coreName = coreName;
_parser = new SolrRequestParsers(null);
this.supplier = supplier;
}

// TODO-- this implementation sends the response to XML and then parses it.
// It *should* be able to convert the response directly into a named list.

@Override
public NamedList<Object> request(SolrRequest request, String coreName) throws SolrServerException, IOException {
public NamedList<Object> request(final SolrRequest request, String coreName) throws SolrServerException, IOException {

String path = request.getPath();
if (path == null || !path.startsWith("/")) {
Expand All @@ -136,16 +178,16 @@ public NamedList<Object> request(SolrRequest request, String coreName) throws So
SolrRequestHandler handler = coreContainer.getRequestHandler(path);
if (handler != null) {
try {
SolrQueryRequest req = _parser.buildRequestFrom(null, request.getParams(), getContentStreams(request));
final SolrQueryRequest req = _parser.buildRequestFrom(null, request.getParams(), getContentStreams(request));
req.getContext().put("httpMethod", request.getMethod().name());
req.getContext().put(PATH, path);
SolrQueryResponse resp = new SolrQueryResponse();
final SolrQueryResponse resp = new SolrQueryResponse();
handler.handleRequest(req, resp);
checkForExceptions(resp);
return BinaryResponseWriter.getParsedResponse(req, resp);
} catch (IOException | SolrException iox) {
throw iox;
} catch (Exception ex) {
} catch (final Exception ex) {
throw new SolrServerException(ex);
}
}
Expand All @@ -170,7 +212,7 @@ public NamedList<Object> request(SolrRequest request, String coreName) throws So
handler = core.getRequestHandler(path);
if (handler == null) {
if ("/select".equals(path) || "/select/".equalsIgnoreCase(path)) {
String qt = params.get(CommonParams.QT);
final String qt = params.get(CommonParams.QT);
handler = core.getRequestHandler(qt);
if (handler == null) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "unknown handler: " + qt);
Expand All @@ -185,7 +227,7 @@ public NamedList<Object> request(SolrRequest request, String coreName) throws So
req = _parser.buildRequestFrom(core, params, getContentStreams(request));
req.getContext().put(PATH, path);
req.getContext().put("httpMethod", request.getMethod().name());
SolrQueryResponse rsp = new SolrQueryResponse();
final SolrQueryResponse rsp = new SolrQueryResponse();
SolrRequestInfo.setRequestInfo(new SolrRequestInfo(req, rsp));

core.execute(handler, req, rsp);
Expand All @@ -195,22 +237,20 @@ public NamedList<Object> request(SolrRequest request, String coreName) throws So
if (request.getStreamingResponseCallback() != null) {
try {
final StreamingResponseCallback callback = request.getStreamingResponseCallback();
BinaryResponseWriter.Resolver resolver =
new BinaryResponseWriter.Resolver(req, rsp.getReturnFields()) {
@Override
public void writeResults(ResultContext ctx, JavaBinCodec codec) throws IOException {
// write an empty list...
SolrDocumentList docs = new SolrDocumentList();
docs.setNumFound(ctx.getDocList().matches());
docs.setStart(ctx.getDocList().offset());
docs.setMaxScore(ctx.getDocList().maxScore());
codec.writeSolrDocumentList(docs);

// This will transform
writeResultsBody(ctx, codec);
}
};

final BinaryResponseWriter.Resolver resolver = new BinaryResponseWriter.Resolver(req, rsp.getReturnFields()) {
@Override
public void writeResults(final ResultContext ctx, final JavaBinCodec codec) throws IOException {
// write an empty list...
final SolrDocumentList docs = new SolrDocumentList();
docs.setNumFound(ctx.getDocList().matches());
docs.setStart(ctx.getDocList().offset());
docs.setMaxScore(ctx.getDocList().maxScore());
codec.writeSolrDocumentList(docs);

// This will transform
writeResultsBody(ctx, codec);
}
};

try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
createJavaBinCodec(callback, resolver).setWritableDocFields(resolver).marshal(rsp.getValues(), out);
Expand All @@ -219,68 +259,79 @@ public void writeResults(ResultContext ctx, JavaBinCodec codec) throws IOExcepti
return (NamedList<Object>) new JavaBinCodec(resolver).unmarshal(in);
}
}
} catch (Exception ex) {
} catch (final Exception ex) {
throw new RuntimeException(ex);
}
}

// Now write it out
NamedList<Object> normalized = BinaryResponseWriter.getParsedResponse(req, rsp);
final NamedList<Object> normalized = BinaryResponseWriter.getParsedResponse(req, rsp);
return normalized;
} catch (IOException | SolrException iox) {
throw iox;
} catch (Exception ex) {
} catch (final Exception ex) {
throw new SolrServerException(ex);
} finally {
if (req != null) req.close();
SolrRequestInfo.clearRequestInfo();
}
}

private Set<ContentStream> getContentStreams(SolrRequest request) throws IOException {
if (request.getMethod() == SolrRequest.METHOD.GET) return null;
private Set<ContentStream> getContentStreams(final SolrRequest<?> request) throws IOException {
if (request.getMethod() == SolrRequest.METHOD.GET || request instanceof QueryRequest) return null;
if (request instanceof ContentStreamUpdateRequest) {
ContentStreamUpdateRequest csur = (ContentStreamUpdateRequest) request;
Collection<ContentStream> cs = csur.getContentStreams();
final ContentStreamUpdateRequest csur = (ContentStreamUpdateRequest) request;
final Collection<ContentStream> cs = csur.getContentStreams();
if (cs != null) return new HashSet<>(cs);
}
RequestWriter.ContentWriter contentWriter = request.getContentWriter(CommonParams.JAVABIN_MIME);
final String cType = contentWriter == null ? CommonParams.JAVABIN_MIME : contentWriter.getContentType();
final String preferedContentType = ClientUtils.TEXT_XML;// CommonParams.JAVABIN_MIME

final RequestWriter.ContentWriter contentWriter = request.getContentWriter(preferedContentType);

String cType;
final BAOS baos = new BAOS();
if (contentWriter != null) {
contentWriter.write(baos);
cType = contentWriter.getContentType();
} else {
final RequestWriter rw = supplier.newRequestWriter();
cType = rw.getUpdateContentType();
rw.write(request, baos);
}

return Collections.singleton(new ContentStreamBase() {
final byte[] buf = baos.toByteArray();
if (buf.length > 0) {
return Collections.singleton(new ContentStreamBase() {

@Override
public InputStream getStream() throws IOException {
BAOS baos = new BAOS();
if (contentWriter != null) {
contentWriter.write(baos);
} else {
new BinaryRequestWriter().write(request, baos);
@Override
public InputStream getStream() throws IOException {
return new ByteArrayInputStream(buf);
}
return new ByteArrayInputStream(baos.toByteArray());
}

@Override
public String getContentType() {
return cType;
@Override
public String getContentType() {
return cType;
}
});
}

}
});
return null;
}

private JavaBinCodec createJavaBinCodec(final StreamingResponseCallback callback, final BinaryResponseWriter.Resolver resolver) {
private JavaBinCodec createJavaBinCodec(final StreamingResponseCallback callback,
final BinaryResponseWriter.Resolver resolver) {
return new JavaBinCodec(resolver) {

@Override
public void writeSolrDocument(SolrDocument doc) {
public void writeSolrDocument(final SolrDocument doc) {
callback.streamSolrDocument(doc);
//super.writeSolrDocument( doc, fields );
// super.writeSolrDocument( doc, fields );
}

@Override
public void writeSolrDocumentList(SolrDocumentList docs) throws IOException {
if (docs.size() > 0) {
SolrDocumentList tmp = new SolrDocumentList();
final SolrDocumentList tmp = new SolrDocumentList();
tmp.setMaxScore(docs.getMaxScore());
tmp.setNumFound(docs.getNumFound());
tmp.setStart(docs.getStart());
Expand All @@ -293,7 +344,7 @@ public void writeSolrDocumentList(SolrDocumentList docs) throws IOException {
};
}

private static void checkForExceptions(SolrQueryResponse rsp) throws Exception {
private static void checkForExceptions(final SolrQueryResponse rsp) throws Exception {
if (rsp.getException() != null) {
if (rsp.getException() instanceof SolrException) {
throw rsp.getException();
Expand Down

0 comments on commit c6b6377

Please sign in to comment.