You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by ho...@apache.org on 2025/12/01 21:28:07 UTC
(solr) branch main updated: SOLR-17998: Improve error response, and RemoteSolrException (#1657)
This is an automated email from the ASF dual-hosted git repository.
houston pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/main by this push:
new 70c586f96d1 SOLR-17998: Improve error response, and RemoteSolrException (#1657)
70c586f96d1 is described below
commit 70c586f96d14cc724696172f6adb9057d4e77a6e
Author: Houston Putman <ho...@apache.org>
AuthorDate: Mon Dec 1 13:28:01 2025 -0800
SOLR-17998: Improve error response, and RemoteSolrException (#1657)
This is true for the v1 and v2 API. Various SolrException classes have been refactored to be more streamlined.
JSON lists are (once again) indented if they are larger than 1 element.
---
.../unreleased/SOLR-17998-better-error-info.yml | 12 ++
.../apache/solr/client/api/model/ErrorInfo.java | 35 ++++-
.../src/java/org/apache/solr/api/AnnotatedApi.java | 7 +-
solr/core/src/java/org/apache/solr/api/ApiBag.java | 21 +--
.../api/collections/CollectionHandlingUtils.java | 6 +-
.../org/apache/solr/handler/SchemaHandler.java | 6 +-
.../org/apache/solr/handler/SolrConfigHandler.java | 6 +-
.../apache/solr/response/JSONResponseWriter.java | 6 +
.../apache/solr/response/JacksonJsonWriter.java | 20 ++-
.../solr/response/RawShimTextResponseWriter.java | 5 +
.../org/apache/solr/response/SchemaXmlWriter.java | 5 +
.../solr/response/TabularResponseWriter.java | 3 +
.../java/org/apache/solr/response/XMLWriter.java | 5 +
.../org/apache/solr/servlet/ResponseUtils.java | 130 ++++++++++++------
.../org/apache/solr/TestDistributedSearch.java | 5 +-
.../api/NodeConfigClusterPluginsSourceTest.java | 4 +-
.../embedded/TestEmbeddedSolrServerSchemaAPI.java | 5 +-
.../solr/cloud/CreateCollectionCleanupTest.java | 4 +-
.../solr/cloud/DistribJoinFromCollectionTest.java | 7 +-
.../apache/solr/cloud/LeaderTragicEventTest.java | 2 +-
.../org/apache/solr/cloud/MigrateRouteKeyTest.java | 5 +-
.../apache/solr/cloud/MultiThreadedOCPTest.java | 3 +-
.../org/apache/solr/cloud/OverseerStatusTest.java | 6 +-
.../test/org/apache/solr/cloud/SplitShardTest.java | 5 +-
.../solr/cloud/TestAuthenticationFramework.java | 7 +-
.../org/apache/solr/cloud/TestConfigSetsAPI.java | 3 +-
.../solr/cloud/TestConfigSetsAPIZkFailure.java | 5 +-
.../CollectionsAPIAsyncDistributedZkTest.java | 3 +-
.../solr/cloud/api/collections/ShardSplitTest.java | 11 +-
.../cloud/api/collections/TestCollectionAPI.java | 20 +--
.../TestRequestStatusCollectionAPI.java | 5 +-
.../solr/filestore/TestDistribFileStore.java | 4 +-
.../apache/solr/handler/TestContainerPlugin.java | 20 +--
.../apache/solr/handler/V2ApiIntegrationTest.java | 6 +-
.../solr/handler/admin/CoreAdminHandlerTest.java | 5 +-
.../solr/handler/admin/HealthCheckHandlerTest.java | 9 +-
.../solr/handler/admin/TestCollectionAPIs.java | 6 +-
.../handler/component/ShardsAllowListTest.java | 3 +-
.../src/test/org/apache/solr/pkg/TestPackages.java | 11 +-
.../solr/response/TestErrorResponseStackTrace.java | 139 +++++++++++++++++++
.../apache/solr/response/TestRawTransformer.java | 20 ++-
.../apache/solr/schema/SchemaApiFailureTest.java | 4 +-
.../solr/security/BasicAuthIntegrationTest.java | 17 +--
.../solr/servlet/TestRequestRateLimiter.java | 6 +-
.../processor/TextToVectorUpdateProcessorTest.java | 4 +-
.../client/solrj/io/stream/JSONTupleStream.java | 7 +-
.../solr/client/solrj/RemoteSolrException.java | 148 +++++++++++++++++++++
.../org/apache/solr/client/solrj/SolrClient.java | 17 ---
.../solrj/impl/BaseHttpClusterStateProvider.java | 3 +-
.../solrj/impl/ConcurrentUpdateBaseSolrClient.java | 24 +---
.../solr/client/solrj/impl/HttpSolrClientBase.java | 71 +++-------
.../solr/client/solrj/impl/LBAsyncSolrClient.java | 6 +-
.../solr/client/solrj/impl/LBSolrClient.java | 6 +-
.../solrj/impl/RemoteExecutionException.java | 59 --------
.../solr/common/SolrErrorWrappingException.java | 56 ++++++++
.../java/org/apache/solr/common/SolrException.java | 17 ++-
.../apache/solr/common/util/JsonTextWriter.java | 7 +-
.../org/apache/solr/common/util/TextWriter.java | 5 +
.../apache/solr/client/solrj/SolrExampleTests.java | 46 +++----
.../solr/client/solrj/TestSolrJErrorHandling.java | 2 +-
.../solrj/impl/CloudHttp2SolrClientTest.java | 5 +-
.../client/solrj/impl/HttpJdkSolrClientTest.java | 8 +-
.../client/solrj/impl/HttpSolrClientTestBase.java | 22 +--
.../HttpJettySolrClientCompatibilityTest.java | 8 +-
.../solrj/jetty/HttpJettySolrClientTest.java | 13 +-
.../solr/client/solrj/request/SchemaTest.java | 3 +-
.../solrj/apache/ConcurrentUpdateSolrClient.java | 21 +--
.../solr/client/solrj/apache/HttpSolrClient.java | 61 ++-------
...bstractCollectionsAPIDistributedZkTestBase.java | 3 +-
.../api/collections/AbstractInstallShardTest.java | 7 +-
.../solrj/apache/BasicHttpSolrClientTest.java | 46 +++----
.../client/solrj/apache/CloudSolrClientTest.java | 5 +-
72 files changed, 818 insertions(+), 479 deletions(-)
diff --git a/changelog/unreleased/SOLR-17998-better-error-info.yml b/changelog/unreleased/SOLR-17998-better-error-info.yml
new file mode 100644
index 00000000000..d88319a4290
--- /dev/null
+++ b/changelog/unreleased/SOLR-17998-better-error-info.yml
@@ -0,0 +1,12 @@
+# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc
+title: Return structured error information in responses, parse correctly in SolrJ to give useful SolrExceptions
+type: changed # added, changed, fixed, deprecated, removed, dependency_update, security, other
+authors:
+ - name: Houston Putman
+ nick: HoustonPutman
+ url: https://home.apache.org/phonebook.html?uid=houston
+links:
+ - name: SOLR-17998
+ url: https://issues.apache.org/jira/browse/SOLR-17998
+ - name: PR#1382
+ url: https://github.com/apache/solr/pull/1382
diff --git a/solr/api/src/java/org/apache/solr/client/api/model/ErrorInfo.java b/solr/api/src/java/org/apache/solr/client/api/model/ErrorInfo.java
index 1a6ca071642..0d2d5fa9922 100644
--- a/solr/api/src/java/org/apache/solr/client/api/model/ErrorInfo.java
+++ b/solr/api/src/java/org/apache/solr/client/api/model/ErrorInfo.java
@@ -35,17 +35,20 @@ public class ErrorInfo implements ReflectWritable {
@JsonProperty("metadata")
public ErrorMetadata metadata;
- @JsonProperty("details")
- public List<Map<String, Object>> details;
+ @JsonProperty("code")
+ public Integer code;
+
+ @JsonProperty("errorClass")
+ public String errorClass;
@JsonProperty("msg")
public String msg;
@JsonProperty("trace")
- public String trace;
+ public ErrorStackTrace trace;
- @JsonProperty("code")
- public Integer code;
+ @JsonProperty("details")
+ public List<Map<String, Object>> details;
public static class ErrorMetadata implements ReflectWritable {
@JsonProperty(ERROR_CLASS)
@@ -54,4 +57,26 @@ public class ErrorInfo implements ReflectWritable {
@JsonProperty(ROOT_ERROR_CLASS)
public String rootErrorClass;
}
+
+ public static class ErrorStackTrace implements ReflectWritable {
+ @JsonProperty("stackTrace")
+ public List<String> stackTrace;
+
+ @JsonProperty("causedBy")
+ public ErrorCausedBy causedBy;
+ }
+
+ public static class ErrorCausedBy implements ReflectWritable {
+ @JsonProperty("errorClass")
+ public String errorClass;
+
+ @JsonProperty("msg")
+ public String msg;
+
+ @JsonProperty("trace")
+ public ErrorStackTrace trace;
+
+ @JsonProperty("details")
+ public List<Map<String, Object>> details;
+ }
}
diff --git a/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java b/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java
index d4c6e454520..76df23de362 100644
--- a/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java
+++ b/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java
@@ -36,6 +36,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.common.SolrErrorWrappingException;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SpecProvider;
import org.apache.solr.common.util.CommandOperation;
@@ -207,7 +208,7 @@ public class AnnotatedApi extends Api implements PermissionNameProvider, Closeab
fallback.call(req, rsp);
return;
} else {
- throw new ApiBag.ExceptionWithErrObject(
+ throw new SolrErrorWrappingException(
SolrException.ErrorCode.BAD_REQUEST,
"Error processing commands",
CommandOperation.captureErrors(cmds));
@@ -222,7 +223,7 @@ public class AnnotatedApi extends Api implements PermissionNameProvider, Closeab
List<Map<String, Object>> errs = CommandOperation.captureErrors(cmds);
if (!errs.isEmpty()) {
log.error("{}{}", ERR, Utils.toJSONString(errs));
- throw new ApiBag.ExceptionWithErrObject(SolrException.ErrorCode.BAD_REQUEST, ERR, errs);
+ throw new SolrErrorWrappingException(SolrException.ErrorCode.BAD_REQUEST, ERR, errs);
}
}
@@ -355,7 +356,7 @@ public class AnnotatedApi extends Api implements PermissionNameProvider, Closeab
private void checkForErrorInPayload(CommandOperation cmd) {
if (cmd.hasError()) {
- throw new ApiBag.ExceptionWithErrObject(
+ throw new SolrErrorWrappingException(
SolrException.ErrorCode.BAD_REQUEST,
"Error executing command",
CommandOperation.captureErrors(Collections.singletonList(cmd)));
diff --git a/solr/core/src/java/org/apache/solr/api/ApiBag.java b/solr/core/src/java/org/apache/solr/api/ApiBag.java
index 70a1964263a..26688037c21 100644
--- a/solr/core/src/java/org/apache/solr/api/ApiBag.java
+++ b/solr/core/src/java/org/apache/solr/api/ApiBag.java
@@ -37,6 +37,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.common.SolrErrorWrappingException;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SpecProvider;
import org.apache.solr.common.util.CommandOperation;
@@ -448,30 +449,12 @@ public class ApiBag {
}
List<Map<String, Object>> errs = CommandOperation.captureErrors(commandsCopy);
if (!errs.isEmpty()) {
- throw new ExceptionWithErrObject(
+ throw new SolrErrorWrappingException(
SolrException.ErrorCode.BAD_REQUEST, "Error in command payload", errs);
}
return commandsCopy;
}
- public static class ExceptionWithErrObject extends SolrException {
- private final List<Map<String, Object>> errs;
-
- public ExceptionWithErrObject(ErrorCode code, String msg, List<Map<String, Object>> errs) {
- super(code, msg);
- this.errs = errs;
- }
-
- public List<Map<String, Object>> getErrs() {
- return errs;
- }
-
- @Override
- public String getMessage() {
- return super.getMessage() + ", errors: " + getErrs() + ", ";
- }
- }
-
public static class LazyLoadedApi extends Api {
private final PluginBag.PluginHolder<SolrRequestHandler> holder;
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/CollectionHandlingUtils.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/CollectionHandlingUtils.java
index 85440f4b650..c44a52e2e7d 100644
--- a/solr/core/src/java/org/apache/solr/cloud/api/collections/CollectionHandlingUtils.java
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/CollectionHandlingUtils.java
@@ -36,7 +36,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
-import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrResponse;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.jetty.HttpJettySolrClient;
@@ -441,8 +441,8 @@ public class CollectionHandlingUtils {
String shard,
Set<String> okayExceptions) {
String rootThrowable = null;
- if (e instanceof SolrClient.RemoteSolrException) {
- rootThrowable = ((SolrClient.RemoteSolrException) e).getRootThrowable();
+ if (e instanceof RemoteSolrException remoteSolrException) {
+ rootThrowable = remoteSolrException.getRootThrowable();
}
if (e != null && (rootThrowable == null || !okayExceptions.contains(rootThrowable))) {
diff --git a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
index b4362858daa..967054208b1 100644
--- a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
@@ -34,8 +34,8 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.solr.api.Api;
-import org.apache.solr.api.ApiBag;
import org.apache.solr.api.JerseyResource;
+import org.apache.solr.common.SolrErrorWrappingException;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.SolrParams;
@@ -92,7 +92,7 @@ public class SchemaHandler extends RequestHandlerBase
List<CommandOperation> ops = req.getCommands(false);
List<Map<String, Object>> errs = CommandOperation.captureErrors(ops);
if (!errs.isEmpty()) {
- throw new ApiBag.ExceptionWithErrObject(
+ throw new SolrErrorWrappingException(
SolrException.ErrorCode.BAD_REQUEST, "error processing commands", errs);
}
@@ -102,7 +102,7 @@ public class SchemaHandler extends RequestHandlerBase
.collect(Collectors.toList());
errs = new SchemaManager(req).performOperations(operationList);
if (!errs.isEmpty()) {
- throw new ApiBag.ExceptionWithErrObject(
+ throw new SolrErrorWrappingException(
SolrException.ErrorCode.BAD_REQUEST, "error processing commands", errs);
}
} catch (IOException e) {
diff --git a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
index bbaf39b1931..652649e3669 100644
--- a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
@@ -53,7 +53,6 @@ import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.solr.api.AnnotatedApi;
import org.apache.solr.api.Api;
-import org.apache.solr.api.ApiBag;
import org.apache.solr.client.solrj.SolrResponse;
import org.apache.solr.client.solrj.io.stream.expr.Expressible;
import org.apache.solr.client.solrj.jetty.HttpJettySolrClient;
@@ -62,6 +61,7 @@ import org.apache.solr.client.solrj.response.SimpleSolrResponse;
import org.apache.solr.cloud.ZkController;
import org.apache.solr.cloud.ZkSolrResourceLoader;
import org.apache.solr.common.MapSerializable;
+import org.apache.solr.common.SolrErrorWrappingException;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.cloud.ClusterState;
import org.apache.solr.common.cloud.DocCollection;
@@ -495,7 +495,7 @@ public class SolrConfigHandler extends RequestHandlerBase
@SuppressWarnings({"rawtypes"})
List errs = CommandOperation.captureErrors(ops);
if (!errs.isEmpty()) {
- throw new ApiBag.ExceptionWithErrObject(
+ throw new SolrErrorWrappingException(
SolrException.ErrorCode.BAD_REQUEST, "error processing params", errs);
}
@@ -577,7 +577,7 @@ public class SolrConfigHandler extends RequestHandlerBase
List errs = CommandOperation.captureErrors(ops);
if (!errs.isEmpty()) {
log.error("ERROR:{}", Utils.toJSONString(errs));
- throw new ApiBag.ExceptionWithErrObject(
+ throw new SolrErrorWrappingException(
SolrException.ErrorCode.BAD_REQUEST, "error processing commands", errs);
}
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 c4439c20d7e..de59421827d 100644
--- a/solr/core/src/java/org/apache/solr/response/JSONResponseWriter.java
+++ b/solr/core/src/java/org/apache/solr/response/JSONResponseWriter.java
@@ -251,6 +251,12 @@ public class JSONResponseWriter implements TextQueryResponseWriter {
super.writeArray(name, val, raw);
}
+ @Override
+ public void writeArray(String name, Iterator<?> val, int size, boolean raw) throws IOException {
+ ifNeededWriteTypeAndValueKey("array");
+ super.writeArray(name, val, size, raw);
+ }
+
@Override
public void writeNull(String name) throws IOException {
ifNeededWriteTypeAndValueKey("null");
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 f254f625a52..f5d66865723 100644
--- a/solr/core/src/java/org/apache/solr/response/JacksonJsonWriter.java
+++ b/solr/core/src/java/org/apache/solr/response/JacksonJsonWriter.java
@@ -35,11 +35,16 @@ import org.apache.solr.request.SolrQueryRequest;
/** A JSON ResponseWriter that uses jackson. */
public class JacksonJsonWriter implements TextQueryResponseWriter {
+ protected static final DefaultPrettyPrinter.Indenter SMALL_ARRAY_IDENTIFIER =
+ DefaultPrettyPrinter.NopIndenter.instance;
+ protected static final DefaultPrettyPrinter.Indenter LARGE_ARRAY_IDENTIFIER =
+ new DefaultIndenter().withLinefeed("\n");
+
protected final JsonFactory jsonfactory;
protected static final DefaultPrettyPrinter pretty =
new DefaultPrettyPrinter()
.withoutSpacesInObjectEntries()
- .withArrayIndenter(DefaultPrettyPrinter.NopIndenter.instance)
+ .withArrayIndenter(SMALL_ARRAY_IDENTIFIER)
.withObjectIndenter(new DefaultIndenter().withLinefeed("\n"));
public JacksonJsonWriter() {
@@ -95,12 +100,16 @@ public class JacksonJsonWriter implements TextQueryResponseWriter {
public static class WriterImpl extends JSONWriter {
protected JsonGenerator gen;
+ private final DefaultPrettyPrinter prettyPrinter;
public WriterImpl(SolrQueryRequest req, SolrQueryResponse rsp, JsonGenerator generator) {
super(null, req, rsp);
gen = generator;
if (doIndent) {
- gen.setPrettyPrinter(pretty.createInstance());
+ prettyPrinter = pretty.createInstance();
+ gen.setPrettyPrinter(prettyPrinter);
+ } else {
+ prettyPrinter = null;
}
}
@@ -187,6 +196,13 @@ public class JacksonJsonWriter implements TextQueryResponseWriter {
@Override
public void writeArrayOpener(int size) throws IOException, IllegalArgumentException {
+ if (prettyPrinter != null) {
+ if (size == 1 || size == 0) {
+ prettyPrinter.indentArraysWith(SMALL_ARRAY_IDENTIFIER);
+ } else {
+ prettyPrinter.indentArraysWith(LARGE_ARRAY_IDENTIFIER);
+ }
+ }
gen.writeStartArray();
}
diff --git a/solr/core/src/java/org/apache/solr/response/RawShimTextResponseWriter.java b/solr/core/src/java/org/apache/solr/response/RawShimTextResponseWriter.java
index fff644020f4..81099abba01 100644
--- a/solr/core/src/java/org/apache/solr/response/RawShimTextResponseWriter.java
+++ b/solr/core/src/java/org/apache/solr/response/RawShimTextResponseWriter.java
@@ -48,6 +48,11 @@ class RawShimTextResponseWriter extends TextResponseWriter {
backing.writeArray(name, val, true);
}
+ @Override
+ public void writeArray(String name, Iterator<?> val, int size, boolean raw) throws IOException {
+ backing.writeArray(name, val, size, true);
+ }
+
// Other stuff; just no-op delegation
@Override
public void writeStartDocumentList(
diff --git a/solr/core/src/java/org/apache/solr/response/SchemaXmlWriter.java b/solr/core/src/java/org/apache/solr/response/SchemaXmlWriter.java
index 7ea7509564b..e6f96174fc2 100644
--- a/solr/core/src/java/org/apache/solr/response/SchemaXmlWriter.java
+++ b/solr/core/src/java/org/apache/solr/response/SchemaXmlWriter.java
@@ -402,6 +402,11 @@ public class SchemaXmlWriter extends TextResponseWriter {
}
}
+ @Override
+ public void writeArray(String name, Iterator<?> iter, int size, boolean raw) throws IOException {
+ writeArray(name, iter, raw);
+ }
+
//
// Primitive types
//
diff --git a/solr/core/src/java/org/apache/solr/response/TabularResponseWriter.java b/solr/core/src/java/org/apache/solr/response/TabularResponseWriter.java
index c05f6cef833..133b53405f3 100644
--- a/solr/core/src/java/org/apache/solr/response/TabularResponseWriter.java
+++ b/solr/core/src/java/org/apache/solr/response/TabularResponseWriter.java
@@ -138,6 +138,9 @@ public abstract class TabularResponseWriter extends TextResponseWriter {
@Override
public void writeArray(String name, Iterator<?> val, boolean raw) throws IOException {}
+ @Override
+ public void writeArray(String name, Iterator<?> val, int size, boolean raw) throws IOException {}
+
@Override
public void writeDate(String name, Date val) throws IOException {
writeDate(name, val.toInstant().toString());
diff --git a/solr/core/src/java/org/apache/solr/response/XMLWriter.java b/solr/core/src/java/org/apache/solr/response/XMLWriter.java
index e8748e2ae78..708bc83e5d8 100644
--- a/solr/core/src/java/org/apache/solr/response/XMLWriter.java
+++ b/solr/core/src/java/org/apache/solr/response/XMLWriter.java
@@ -300,6 +300,11 @@ public class XMLWriter extends TextResponseWriter {
}
}
+ @Override
+ public void writeArray(String name, Iterator<?> iter, int size, boolean raw) throws IOException {
+ writeArray(name, iter, raw);
+ }
+
@Override
public void writeIterator(String name, IteratorWriter val, boolean raw) throws IOException {
// As the size is not known. So, always both startTag and endTag is written
diff --git a/solr/core/src/java/org/apache/solr/servlet/ResponseUtils.java b/solr/core/src/java/org/apache/solr/servlet/ResponseUtils.java
index f28b1c2cfea..dd4011a4dc0 100644
--- a/solr/core/src/java/org/apache/solr/servlet/ResponseUtils.java
+++ b/solr/core/src/java/org/apache/solr/servlet/ResponseUtils.java
@@ -16,12 +16,12 @@
*/
package org.apache.solr.servlet;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import org.apache.solr.api.ApiBag;
+import java.util.Arrays;
+import java.util.stream.Collectors;
import org.apache.solr.client.api.model.ErrorInfo;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.NamedList;
+import org.apache.solr.common.util.SimpleOrderedMap;
import org.slf4j.Logger;
/** Response helper methods. */
@@ -72,33 +72,50 @@ public class ResponseUtils {
code = solrExc.code();
NamedList<String> errorMetadata = solrExc.getMetadata();
if (errorMetadata == null) {
- errorMetadata = new NamedList<>();
+ errorMetadata = new SimpleOrderedMap<>();
}
errorMetadata.add(ErrorInfo.ERROR_CLASS, ex.getClass().getName());
errorMetadata.add(
ErrorInfo.ROOT_ERROR_CLASS, SolrException.getRootCause(ex).getClass().getName());
info.add("metadata", errorMetadata);
- if (ex instanceof ApiBag.ExceptionWithErrObject exception) {
- info.add("details", exception.getErrs());
- }
}
- for (Throwable th = ex; th != null; th = th.getCause()) {
- String msg = th.getMessage();
- if (msg != null) {
- info.add("msg", msg);
- break;
+ // For any regular code, don't include the stack trace
+ boolean printStackTrace = (code == 500 || code < 100) && !hideStackTrace(hideTrace);
+ boolean stackTracePrinted = false;
+ NamedList<Object> lastTrace = null;
+ Throwable causedBy = ex;
+ NamedList<Object> errorInfo = info;
+ while (causedBy != null) {
+ if (lastTrace != null) {
+ lastTrace.add("causedBy", errorInfo);
+ }
+ errorInfo.add("errorClass", causedBy.getClass().getName());
+ if (causedBy instanceof SolrException solrException) {
+ errorInfo.add("msg", solrException.getResponseMessage());
+ if (solrException.getDetails() != null) {
+ errorInfo.add("details", solrException.getDetails());
+ }
+ } else {
+ errorInfo.add("msg", causedBy.getMessage());
+ }
+ if (printStackTrace) {
+ stackTracePrinted = true;
+ lastTrace = new SimpleOrderedMap<>();
+ errorInfo.add("trace", lastTrace);
+ lastTrace.add(
+ "stackTrace",
+ Arrays.stream(causedBy.getStackTrace())
+ .map(StackTraceElement::toString)
+ .collect(Collectors.toList()));
+ causedBy = causedBy.getCause();
+ errorInfo = new SimpleOrderedMap<>();
+ } else {
+ causedBy = null;
}
}
- // For any regular code, don't include the stack trace
if (code == 500 || code < 100) {
- // hide all stack traces, as configured
- if (!hideStackTrace(hideTrace)) {
- StringWriter sw = new StringWriter();
- ex.printStackTrace(new PrintWriter(sw));
- info.add("trace", sw.toString());
- }
log.error("500 Exception", ex);
// non standard codes have undefined results with various servers
@@ -107,6 +124,16 @@ public class ResponseUtils {
code = 500;
}
}
+ if (!stackTracePrinted && ex != null && ex.getMessage() == null) {
+ // Find the first non-null message if we aren't printing the stacktrace
+ for (Throwable th = ex; th != null; th = th.getCause()) {
+ String msg = th.getMessage();
+ if (msg != null) {
+ info.add("msg", msg);
+ break;
+ }
+ }
+ }
info.add("code", code);
return code;
@@ -145,35 +172,60 @@ public class ResponseUtils {
errorInfo.metadata = new ErrorInfo.ErrorMetadata();
errorInfo.metadata.errorClass = ex.getClass().getName();
errorInfo.metadata.rootErrorClass = SolrException.getRootCause(ex).getClass().getName();
- if (ex instanceof ApiBag.ExceptionWithErrObject exception) {
- errorInfo.details = exception.getErrs();
- }
+ errorInfo.details = solrExc.getDetails();
+ errorInfo.msg = solrExc.getResponseMessage();
}
- for (Throwable th = ex; th != null; th = th.getCause()) {
- String msg = th.getMessage();
- if (msg != null) {
- errorInfo.msg = msg;
- break;
- }
+ for (Throwable th = ex; errorInfo.msg == null && th != null; th = th.getCause()) {
+ errorInfo.msg = th.getMessage();
}
// For any regular code, don't include the stack trace
- if (code == 500 || code < 100) {
- if (!hideStackTrace(hideTrace)) {
- StringWriter sw = new StringWriter();
- ex.printStackTrace(new PrintWriter(sw));
- errorInfo.trace = sw.toString();
- }
- log.error("500 Exception", ex);
+ boolean printStackTrace = (code == 500 || code < 100) && !hideStackTrace(hideTrace);
+ errorInfo.errorClass = ex.getClass().getName();
+ if (errorInfo.msg == null) {
+ errorInfo.msg = ex.getMessage();
+ }
- // non standard codes have undefined results with various servers
- if (code < 100) {
- log.warn("invalid return code: {}", code);
- code = 500;
+ if (printStackTrace) {
+ errorInfo.trace = new ErrorInfo.ErrorStackTrace();
+ errorInfo.trace.stackTrace =
+ Arrays.stream(ex.getStackTrace())
+ .map(StackTraceElement::toString)
+ .collect(Collectors.toList());
+
+ ErrorInfo.ErrorStackTrace lastTrace = errorInfo.trace;
+ Throwable causedBy = ex.getCause();
+
+ while (causedBy != null) {
+ ErrorInfo.ErrorCausedBy errorCausedBy = new ErrorInfo.ErrorCausedBy();
+ lastTrace.causedBy = errorCausedBy;
+ errorCausedBy.errorClass = causedBy.getClass().getName();
+ if (ex instanceof SolrException solrExc) {
+ errorCausedBy.msg = solrExc.getResponseMessage();
+ errorInfo.details = solrExc.getDetails();
+ } else {
+ errorCausedBy.msg = causedBy.getMessage();
+ }
+ errorCausedBy.trace = new ErrorInfo.ErrorStackTrace();
+ errorCausedBy.trace.stackTrace =
+ Arrays.stream(causedBy.getStackTrace())
+ .map(StackTraceElement::toString)
+ .collect(Collectors.toList());
+ lastTrace = errorCausedBy.trace;
+ causedBy = causedBy.getCause();
}
}
+ // non standard codes have undefined results with various servers
+ if (code < 100) {
+ log.warn("invalid return code: {}", code);
+ code = 500;
+ }
+ if (code == 500) {
+ log.error("500 Exception", ex);
+ }
+
errorInfo.code = code;
return errorInfo;
}
diff --git a/solr/core/src/test/org/apache/solr/TestDistributedSearch.java b/solr/core/src/test/org/apache/solr/TestDistributedSearch.java
index 4b76ed51b17..3c823f6601e 100644
--- a/solr/core/src/test/org/apache/solr/TestDistributedSearch.java
+++ b/solr/core/src/test/org/apache/solr/TestDistributedSearch.java
@@ -32,6 +32,7 @@ import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Future;
import org.apache.solr.SolrTestCaseJ4.SuppressSSL;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.SolrQuery;
@@ -1716,8 +1717,8 @@ public class TestDistributedSearch extends BaseDistributedSearchTestCase {
tdate_b,
"stats.calcdistinct",
"true");
- } catch (SolrClient.RemoteSolrException e) {
- if (e.getMessage().startsWith("java.lang.NullPointerException")) {
+ } catch (RemoteSolrException e) {
+ if (e.getMessage().contains("java.lang.NullPointerException")) {
fail("NullPointerException with stats request on empty index");
} else {
throw e;
diff --git a/solr/core/src/test/org/apache/solr/api/NodeConfigClusterPluginsSourceTest.java b/solr/core/src/test/org/apache/solr/api/NodeConfigClusterPluginsSourceTest.java
index ad640ebb495..a50979b3418 100644
--- a/solr/core/src/test/org/apache/solr/api/NodeConfigClusterPluginsSourceTest.java
+++ b/solr/core/src/test/org/apache/solr/api/NodeConfigClusterPluginsSourceTest.java
@@ -20,7 +20,7 @@ package org.apache.solr.api;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
-import org.apache.solr.client.solrj.impl.RemoteExecutionException;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.request.V2Request;
import org.apache.solr.client.solrj.request.beans.PluginMeta;
import org.apache.solr.client.solrj.response.V2Response;
@@ -125,7 +125,7 @@ public class NodeConfigClusterPluginsSourceTest extends SolrCloudTestCase {
try {
req.process(cluster.getSolrClient());
fail("Expected a 404 response code because the Edit Apis are not registered");
- } catch (RemoteExecutionException e) {
+ } catch (RemoteSolrException e) {
assertEquals(
"Expected a HTTP 404 response code because the /cluster/plugin API should not be registered",
404,
diff --git a/solr/core/src/test/org/apache/solr/client/solrj/embedded/TestEmbeddedSolrServerSchemaAPI.java b/solr/core/src/test/org/apache/solr/client/solrj/embedded/TestEmbeddedSolrServerSchemaAPI.java
index e7e22a065a4..c0a4a3aaecc 100644
--- a/solr/core/src/test/org/apache/solr/client/solrj/embedded/TestEmbeddedSolrServerSchemaAPI.java
+++ b/solr/core/src/test/org/apache/solr/client/solrj/embedded/TestEmbeddedSolrServerSchemaAPI.java
@@ -22,7 +22,6 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.solr.SolrTestCaseJ4;
-import org.apache.solr.api.ApiBag;
import org.apache.solr.client.solrj.request.schema.SchemaRequest;
import org.apache.solr.client.solrj.response.schema.SchemaResponse;
import org.apache.solr.common.SolrException;
@@ -107,8 +106,8 @@ public class TestEmbeddedSolrServerSchemaAPI extends SolrTestCaseJ4 {
private static void assertFailedSchemaResponse(
ThrowingRunnable runnable, String expectedErrorMessage) {
- ApiBag.ExceptionWithErrObject e = expectThrows(ApiBag.ExceptionWithErrObject.class, runnable);
- String msg = e.getErrs().get(0).get("errorMessages").toString();
+ SolrException e = expectThrows(SolrException.class, runnable);
+ String msg = e.getDetails().get(0).get("errorMessages").toString();
assertTrue(msg.contains(expectedErrorMessage));
}
}
diff --git a/solr/core/src/test/org/apache/solr/cloud/CreateCollectionCleanupTest.java b/solr/core/src/test/org/apache/solr/cloud/CreateCollectionCleanupTest.java
index 92b61ce1217..d5c342e3629 100644
--- a/solr/core/src/test/org/apache/solr/cloud/CreateCollectionCleanupTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/CreateCollectionCleanupTest.java
@@ -24,7 +24,7 @@ import static org.hamcrest.CoreMatchers.not;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Properties;
-import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.response.RequestStatusState;
@@ -84,7 +84,7 @@ public class CreateCollectionCleanupTest extends SolrCloudTestCase {
properties.put(CoreAdminParams.DATA_DIR, tmpDir.toString());
create.setProperties(properties);
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
create.process(cloudClient);
});
diff --git a/solr/core/src/test/org/apache/solr/cloud/DistribJoinFromCollectionTest.java b/solr/core/src/test/org/apache/solr/cloud/DistribJoinFromCollectionTest.java
index 0d2d7bef066..8a14d00ace8 100644
--- a/solr/core/src/test/org/apache/solr/cloud/DistribJoinFromCollectionTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/DistribJoinFromCollectionTest.java
@@ -25,7 +25,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
@@ -224,9 +224,8 @@ public class DistribJoinFromCollectionTest extends SolrCloudTestCase {
+ " to=join_s}match_s:c";
final QueryRequest qr =
new QueryRequest(params("collection", toColl, "q", joinQ, "fl", "id,get_s,score"));
- SolrClient.RemoteSolrException ex =
- assertThrows(
- SolrClient.RemoteSolrException.class, () -> cluster.getSolrClient().request(qr));
+ RemoteSolrException ex =
+ assertThrows(RemoteSolrException.class, () -> cluster.getSolrClient().request(qr));
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
assertTrue(ex.getMessage().contains(wrongName));
}
diff --git a/solr/core/src/test/org/apache/solr/cloud/LeaderTragicEventTest.java b/solr/core/src/test/org/apache/solr/cloud/LeaderTragicEventTest.java
index 40653362c5d..c1520025fe8 100644
--- a/solr/core/src/test/org/apache/solr/cloud/LeaderTragicEventTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/LeaderTragicEventTest.java
@@ -23,8 +23,8 @@ import static org.hamcrest.CoreMatchers.is;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import org.apache.lucene.store.AlreadyClosedException;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
-import org.apache.solr.client.solrj.SolrClient.RemoteSolrException;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.apache.HttpSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
diff --git a/solr/core/src/test/org/apache/solr/cloud/MigrateRouteKeyTest.java b/solr/core/src/test/org/apache/solr/cloud/MigrateRouteKeyTest.java
index 4c64bb8d624..c990f43423a 100644
--- a/solr/core/src/test/org/apache/solr/cloud/MigrateRouteKeyTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/MigrateRouteKeyTest.java
@@ -20,6 +20,7 @@ import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.Map;
import java.util.concurrent.TimeUnit;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
@@ -87,9 +88,9 @@ public class MigrateRouteKeyTest extends SolrCloudTestCase {
CollectionAdminRequest.createCollection(targetCollection, "conf", 1, 1)
.process(cluster.getSolrClient());
- SolrClient.RemoteSolrException remoteSolrException =
+ RemoteSolrException remoteSolrException =
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
"Expected an exception in case split.key is not specified",
() -> {
CollectionAdminRequest.migrateData(sourceCollection, targetCollection, "")
diff --git a/solr/core/src/test/org/apache/solr/cloud/MultiThreadedOCPTest.java b/solr/core/src/test/org/apache/solr/cloud/MultiThreadedOCPTest.java
index 833f28a1a63..6a8e56cbb51 100644
--- a/solr/core/src/test/org/apache/solr/cloud/MultiThreadedOCPTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/MultiThreadedOCPTest.java
@@ -21,6 +21,7 @@ import static org.apache.solr.cloud.OverseerTaskProcessor.MAX_PARALLEL_TASKS;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.Random;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
@@ -259,7 +260,7 @@ public class MultiThreadedOCPTest extends AbstractFullDistribZkTestBase {
// Now submit another task with the same id. At this time, hopefully the previous 3002 should
// still be in the queue.
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
CollectionAdminRequest.splitShard("ocptest_shardsplit2")
.setShardName(SHARD1)
diff --git a/solr/core/src/test/org/apache/solr/cloud/OverseerStatusTest.java b/solr/core/src/test/org/apache/solr/cloud/OverseerStatusTest.java
index 8e99d751854..f8883662e74 100644
--- a/solr/core/src/test/org/apache/solr/cloud/OverseerStatusTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/OverseerStatusTest.java
@@ -16,7 +16,7 @@
*/
package org.apache.solr.cloud;
-import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.common.params.CollectionParams;
import org.apache.solr.common.util.NamedList;
@@ -89,9 +89,9 @@ public class OverseerStatusTest extends SolrCloudTestCase {
collection_operations.get(CollectionParams.CollectionAction.RELOAD.toLower());
assertEquals("No stats for reload in OverseerCollectionProcessor", 1, reload.get("requests"));
- SolrClient.RemoteSolrException e =
+ RemoteSolrException e =
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
"Split shard for non existent collection should have failed",
() ->
CollectionAdminRequest.splitShard("non_existent_collection")
diff --git a/solr/core/src/test/org/apache/solr/cloud/SplitShardTest.java b/solr/core/src/test/org/apache/solr/cloud/SplitShardTest.java
index 1fc7baa77d8..9018a32e294 100644
--- a/solr/core/src/test/org/apache/solr/cloud/SplitShardTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/SplitShardTest.java
@@ -31,6 +31,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
@@ -101,7 +102,7 @@ public class SplitShardTest extends SolrCloudTestCase {
.setNumSubShards(10);
splitShard.process(cluster.getSolrClient());
fail("SplitShard should throw an exception when numSubShards > 8");
- } catch (SolrClient.RemoteSolrException ex) {
+ } catch (RemoteSolrException ex) {
assertTrue(
ex.getMessage()
.contains("A shard can only be split into 2 to 8 subshards in one split request."));
@@ -114,7 +115,7 @@ public class SplitShardTest extends SolrCloudTestCase {
.setNumSubShards(1);
splitShard.process(cluster.getSolrClient());
fail("SplitShard should throw an exception when numSubShards < 2");
- } catch (SolrClient.RemoteSolrException ex) {
+ } catch (RemoteSolrException ex) {
assertTrue(
ex.getMessage()
.contains(
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestAuthenticationFramework.java b/solr/core/src/test/org/apache/solr/cloud/TestAuthenticationFramework.java
index 88c80d73f33..70fb6eb9812 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestAuthenticationFramework.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestAuthenticationFramework.java
@@ -22,7 +22,7 @@ import jakarta.servlet.http.HttpServletResponse;
import java.lang.invoke.MethodHandles;
import java.util.Map;
import org.apache.http.HttpRequestInterceptor;
-import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.apache.HttpClientUtil;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
@@ -72,9 +72,8 @@ public class TestAuthenticationFramework extends SolrCloudTestCase {
// Should fail with 401
try {
- SolrClient.RemoteSolrException e =
- expectThrows(
- SolrClient.RemoteSolrException.class, this::collectionCreateSearchDeleteTwice);
+ RemoteSolrException e =
+ expectThrows(RemoteSolrException.class, this::collectionCreateSearchDeleteTwice);
assertTrue("Should've returned a 401 error", e.getMessage().contains("Error 401"));
} finally {
MockAuthenticationPlugin.expectedUsername = null;
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java b/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java
index e318ee02821..2909539433f 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java
@@ -66,6 +66,7 @@ import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.api.AnnotatedApi;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest.METHOD;
import org.apache.solr.client.solrj.SolrRequest.SolrRequestType;
@@ -1078,7 +1079,7 @@ public class TestConfigSetsAPI extends SolrCloudTestCase {
ignoreException("uploaded without any authentication in place");
Throwable thrown =
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
createCollection(
"newcollection2",
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPIZkFailure.java b/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPIZkFailure.java
index f271850fd62..0b8ccf57b7a 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPIZkFailure.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPIZkFailure.java
@@ -35,6 +35,7 @@ import org.apache.jute.InputArchive;
import org.apache.jute.OutputArchive;
import org.apache.jute.Record;
import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.request.ConfigSetAdminRequest.Create;
import org.apache.solr.common.SolrException;
@@ -127,8 +128,8 @@ public class TestConfigSetsAPIZkFailure extends SolrTestCaseJ4 {
Create create = new Create();
create.setBaseConfigSetName(BASE_CONFIGSET_NAME).setConfigSetName(CONFIGSET_NAME);
- SolrClient.RemoteSolrException se =
- expectThrows(SolrClient.RemoteSolrException.class, () -> create.process(solrClient));
+ RemoteSolrException se =
+ expectThrows(RemoteSolrException.class, () -> create.process(solrClient));
// partial creation should have been cleaned up
assertFalse(configSetService.checkConfigExists(CONFIGSET_NAME));
assertEquals(SolrException.ErrorCode.SERVER_ERROR.code, se.code());
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIAsyncDistributedZkTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIAsyncDistributedZkTest.java
index bdc47a6a82e..6eae89d164f 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIAsyncDistributedZkTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIAsyncDistributedZkTest.java
@@ -27,6 +27,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.lucene.tests.util.TestUtil;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.apache.HttpSolrClient;
@@ -273,7 +274,7 @@ public class CollectionsAPIAsyncDistributedZkTest extends SolrCloudTestCase {
reloadCollectionRequest.processAsync(
"repeatedId", clients[random().nextInt(clients.length)]);
numSuccess.incrementAndGet();
- } catch (SolrServerException | SolrClient.RemoteSolrException e) {
+ } catch (SolrServerException | RemoteSolrException e) {
if (log.isInfoEnabled()) {
log.info("Exception during collection reloading, we were waiting for one: ", e);
}
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/ShardSplitTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/ShardSplitTest.java
index eb7c37fec5c..5092a8aca24 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/ShardSplitTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/ShardSplitTest.java
@@ -38,6 +38,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.lucene.tests.util.LuceneTestCase;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.apache.CloudLegacySolrClient;
@@ -801,7 +802,7 @@ public class ShardSplitTest extends BasicDistributedZkTest {
try {
splitShard(AbstractFullDistribZkTestBase.DEFAULT_COLLECTION, SHARD1, subRanges, null, false);
fail("Shard splitting with just one custom hash range should not succeed");
- } catch (SolrClient.RemoteSolrException e) {
+ } catch (RemoteSolrException e) {
log.info("Expected exception:", e);
}
subRanges.clear();
@@ -812,7 +813,7 @@ public class ShardSplitTest extends BasicDistributedZkTest {
try {
splitShard(AbstractFullDistribZkTestBase.DEFAULT_COLLECTION, SHARD1, subRanges, null, false);
fail("Shard splitting with missing hashes in between given ranges should not succeed");
- } catch (SolrClient.RemoteSolrException e) {
+ } catch (RemoteSolrException e) {
log.info("Expected exception:", e);
}
subRanges.clear();
@@ -825,7 +826,7 @@ public class ShardSplitTest extends BasicDistributedZkTest {
try {
splitShard(AbstractFullDistribZkTestBase.DEFAULT_COLLECTION, SHARD1, subRanges, null, false);
fail("Shard splitting with overlapping ranges should not succeed");
- } catch (SolrClient.RemoteSolrException e) {
+ } catch (RemoteSolrException e) {
log.info("Expected exception:", e);
}
subRanges.clear();
@@ -920,7 +921,7 @@ public class ShardSplitTest extends BasicDistributedZkTest {
log.info("Layout after split: \n");
printLayout();
break;
- } catch (SolrClient.RemoteSolrException e) {
+ } catch (RemoteSolrException e) {
if (e.code() != 500) {
throw e;
}
@@ -1139,7 +1140,7 @@ public class ShardSplitTest extends BasicDistributedZkTest {
try {
splitShard(collectionName, shardId, null, splitKey, false);
break;
- } catch (SolrClient.RemoteSolrException e) {
+ } catch (RemoteSolrException e) {
if (e.code() != 500) {
throw e;
}
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionAPI.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionAPI.java
index 0623a459acf..9d8f1c60469 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionAPI.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionAPI.java
@@ -26,7 +26,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.LongAdder;
-import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrRequest.METHOD;
import org.apache.solr.client.solrj.SolrRequest.SolrRequestType;
import org.apache.solr.client.solrj.SolrServerException;
@@ -171,9 +171,9 @@ public class TestCollectionAPI extends ReplicaPropertiesBase {
try {
client.request(request);
fail("Trying to unset an unknown property should have failed");
- } catch (SolrClient.RemoteSolrException e) {
+ } catch (RemoteSolrException e) {
// expected
- assertTrue(e.getMessage().contains("no supported values provided"));
+ assertTrue(e.toString().contains("no supported values provided"));
}
}
}
@@ -193,7 +193,7 @@ public class TestCollectionAPI extends ReplicaPropertiesBase {
try {
client.request(request);
fail();
- } catch (SolrClient.RemoteSolrException e) {
+ } catch (RemoteSolrException e) {
final String errorMessage = e.getMessage();
assertTrue(
errorMessage.contains(
@@ -1149,7 +1149,7 @@ public class TestCollectionAPI extends ReplicaPropertiesBase {
try {
client.request(request);
fail();
- } catch (SolrClient.RemoteSolrException e) {
+ } catch (RemoteSolrException e) {
final String errorMessage = e.getMessage();
assertTrue(errorMessage.contains("Invalid collection"));
assertTrue(errorMessage.contains("invalid@name#with$weird%characters"));
@@ -1172,7 +1172,7 @@ public class TestCollectionAPI extends ReplicaPropertiesBase {
try {
client.request(request);
fail();
- } catch (SolrClient.RemoteSolrException e) {
+ } catch (RemoteSolrException e) {
final String errorMessage = e.getMessage();
assertTrue(errorMessage.contains("Invalid shard"));
assertTrue(errorMessage.contains("invalid@name#with$weird%characters"));
@@ -1193,7 +1193,7 @@ public class TestCollectionAPI extends ReplicaPropertiesBase {
try {
client.request(request);
fail();
- } catch (SolrClient.RemoteSolrException e) {
+ } catch (RemoteSolrException e) {
final String errorMessage = e.getMessage();
assertTrue(errorMessage.contains("Invalid alias"));
assertTrue(errorMessage.contains("invalid@name#with$weird%characters"));
@@ -1226,7 +1226,7 @@ public class TestCollectionAPI extends ReplicaPropertiesBase {
try {
client.request(request);
fail();
- } catch (SolrClient.RemoteSolrException e) {
+ } catch (RemoteSolrException e) {
final String errorMessage = e.getMessage();
assertTrue(errorMessage.contains("Invalid shard"));
assertTrue(errorMessage.contains("invalid@name#with$weird%characters"));
@@ -1298,9 +1298,9 @@ public class TestCollectionAPI extends ReplicaPropertiesBase {
try (CloudSolrClient client = createCloudClient(null)) {
// first, try creating a collection with badconf
- SolrClient.RemoteSolrException rse =
+ RemoteSolrException rse =
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
CollectionAdminRequest.createCollection("testcollection", "badconf", 1, 2)
.process(client);
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/TestRequestStatusCollectionAPI.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/TestRequestStatusCollectionAPI.java
index 1e6e0681808..b48ae59b668 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/TestRequestStatusCollectionAPI.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/TestRequestStatusCollectionAPI.java
@@ -24,6 +24,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.apache.HttpSolrClient;
@@ -171,9 +172,9 @@ public class TestRequestStatusCollectionAPI extends BasicDistributedZkTest {
duplicateRequestIdParams.set("collection.configName", "conf1");
duplicateRequestIdParams.set(CommonAdminParams.ASYNC, "1002");
- final SolrClient.RemoteSolrException thrown =
+ final RemoteSolrException thrown =
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
sendRequest(duplicateRequestIdParams);
});
diff --git a/solr/core/src/test/org/apache/solr/filestore/TestDistribFileStore.java b/solr/core/src/test/org/apache/solr/filestore/TestDistribFileStore.java
index 0efdb3ca25d..a4de2935534 100644
--- a/solr/core/src/test/org/apache/solr/filestore/TestDistribFileStore.java
+++ b/solr/core/src/test/org/apache/solr/filestore/TestDistribFileStore.java
@@ -34,12 +34,12 @@ import java.util.concurrent.Callable;
import java.util.function.Predicate;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.client.methods.HttpDelete;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.apache.HttpClientUtil;
import org.apache.solr.client.solrj.apache.HttpSolrClient;
-import org.apache.solr.client.solrj.impl.RemoteExecutionException;
import org.apache.solr.client.solrj.request.FileStoreApi;
import org.apache.solr.client.solrj.request.V2Request;
import org.apache.solr.client.solrj.response.SimpleSolrResponse;
@@ -94,7 +94,7 @@ public class TestDistribFileStore extends SolrCloudTestCase {
"/package/mypkg/v1.0/runtimelibs.jar",
"j+Rflxi64tXdqosIhbusqi6GTwZq8znunC/dzwcWW0/dHlFGKDurOaE1Nz9FSPJuXbHkVLj638yZ0Lp1ssnoYA==");
fail("should have failed because of wrong signature ");
- } catch (RemoteExecutionException e) {
+ } catch (RemoteSolrException e) {
assertThat(e.getMessage(), containsString("Signature does not match"));
}
diff --git a/solr/core/src/test/org/apache/solr/handler/TestContainerPlugin.java b/solr/core/src/test/org/apache/solr/handler/TestContainerPlugin.java
index 7f913a513f8..f7f0560b6f3 100644
--- a/solr/core/src/test/org/apache/solr/handler/TestContainerPlugin.java
+++ b/solr/core/src/test/org/apache/solr/handler/TestContainerPlugin.java
@@ -39,8 +39,8 @@ import org.apache.solr.api.Command;
import org.apache.solr.api.ConfigurablePlugin;
import org.apache.solr.api.ContainerPluginsRegistry;
import org.apache.solr.api.EndPoint;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
-import org.apache.solr.client.solrj.impl.RemoteExecutionException;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.request.V2Request;
import org.apache.solr.client.solrj.request.beans.PackagePayload;
@@ -51,6 +51,7 @@ import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.annotation.JsonProperty;
import org.apache.solr.common.util.ReflectMapWriter;
+import org.apache.solr.common.util.Utils;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.embedded.JettySolrRunner;
@@ -212,12 +213,11 @@ public class TestContainerPlugin extends SolrCloudTestCase {
version = phaser.awaitAdvanceInterruptibly(version, 10, TimeUnit.SECONDS);
- RemoteExecutionException e =
+ RemoteSolrException e =
assertThrows(
- RemoteExecutionException.class,
- () -> getPlugin("/my-random-prefix/their/plugin").call());
+ RemoteSolrException.class, () -> getPlugin("/my-random-prefix/their/plugin").call());
assertEquals(404, e.code());
- final String msg = (String) ((Map<String, Object>) (e.getMetaData().get("error"))).get("msg");
+ final String msg = Utils.getObjectByPath(e.getRemoteErrorObject(), false, "msg").toString();
assertThat(msg, containsString("Cannot find API for the path"));
// test ClusterSingleton plugin
@@ -580,15 +580,17 @@ public class TestContainerPlugin extends SolrCloudTestCase {
}
private void expectError(V2Request req, String expectErrorMsg) {
- String errPath = "/error/details[0]/errorMessages[0]";
+ String errPath = "details[0]/errorMessages[0]";
expectError(req, cluster.getSolrClient(), errPath, expectErrorMsg);
}
private static void expectError(
V2Request req, SolrClient client, String errPath, String expectErrorMsg) {
- RemoteExecutionException e =
- expectThrows(RemoteExecutionException.class, () -> req.process(client));
- String msg = Objects.requireNonNullElse(e.getMetaData()._getStr(errPath), "");
+ RemoteSolrException e = expectThrows(RemoteSolrException.class, () -> req.process(client));
+ String msg =
+ Objects.requireNonNullElse(
+ Utils.getObjectByPath(e.getRemoteErrorObject(), false, errPath), "")
+ .toString();
assertTrue(expectErrorMsg, msg.contains(expectErrorMsg));
}
}
diff --git a/solr/core/src/test/org/apache/solr/handler/V2ApiIntegrationTest.java b/solr/core/src/test/org/apache/solr/handler/V2ApiIntegrationTest.java
index e00a0bd2e9b..3b7a85eb096 100644
--- a/solr/core/src/test/org/apache/solr/handler/V2ApiIntegrationTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/V2ApiIntegrationTest.java
@@ -26,7 +26,7 @@ import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
-import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.apache.CloudLegacySolrClient;
@@ -79,9 +79,9 @@ public class V2ApiIntegrationTest extends SolrCloudTestCase {
.withPayload(payload)
.build();
v2Request.setResponseParser(responseParser);
- SolrClient.RemoteSolrException ex =
+ RemoteSolrException ex =
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
v2Request.process(cluster.getSolrClient());
});
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/CoreAdminHandlerTest.java b/solr/core/src/test/org/apache/solr/handler/admin/CoreAdminHandlerTest.java
index 6feae5d21f5..33f3d9c4da5 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/CoreAdminHandlerTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/CoreAdminHandlerTest.java
@@ -33,6 +33,7 @@ import org.apache.commons.io.file.PathUtils;
import org.apache.lucene.util.Constants;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.api.model.CoreStatusResponse;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.apache.HttpSolrClient;
import org.apache.solr.client.solrj.request.CoreAdminRequest;
@@ -421,9 +422,9 @@ public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
req.process(client);
}
- SolrClient.RemoteSolrException rse =
+ RemoteSolrException rse =
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
try (SolrClient client =
new HttpSolrClient.Builder(runner.getBaseUrl().toString())
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/HealthCheckHandlerTest.java b/solr/core/src/test/org/apache/solr/handler/admin/HealthCheckHandlerTest.java
index ced47e30c78..43838707d05 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/HealthCheckHandlerTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/HealthCheckHandlerTest.java
@@ -23,6 +23,7 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Properties;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
@@ -102,9 +103,9 @@ public class HealthCheckHandlerTest extends SolrCloudTestCase {
newJetty.getCoreContainer().getZkController().getZkClient().close();
// negative check of our (new) "broken" node that we deliberately put into an unhealthy state
- SolrClient.RemoteSolrException e =
+ RemoteSolrException e =
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
runHealthcheckWithClient(solrClient);
});
@@ -157,9 +158,9 @@ public class HealthCheckHandlerTest extends SolrCloudTestCase {
newJetty.getCoreContainer().getZkController().getZkClient().close();
// negative check of our (new) "broken" node that we deliberately put into an unhealthy state
- SolrClient.RemoteSolrException e =
+ RemoteSolrException e =
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
new V2Request.Builder("/node/health").build().process(solrClient);
});
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java b/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java
index a8dde0459f5..7e6529ac269 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java
@@ -169,11 +169,7 @@ public class TestCollectionAPIs extends SolrTestCaseJ4 {
return method.toString();
}
};
- try {
- api.call(req, rsp);
- } catch (ApiBag.ExceptionWithErrObject e) {
- throw new RuntimeException(e.getMessage() + Utils.toJSONString(e.getErrs()), e);
- }
+ api.call(req, rsp);
return new Pair<>(req, rsp);
}
diff --git a/solr/core/src/test/org/apache/solr/handler/component/ShardsAllowListTest.java b/solr/core/src/test/org/apache/solr/handler/component/ShardsAllowListTest.java
index d6b19fad4f1..57ff3e91958 100644
--- a/solr/core/src/test/org/apache/solr/handler/component/ShardsAllowListTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/component/ShardsAllowListTest.java
@@ -27,6 +27,7 @@ import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.SolrQuery;
import org.apache.solr.cloud.MiniSolrCloudCluster;
@@ -270,7 +271,7 @@ public class ShardsAllowListTest extends MultiSolrCloudTestCase {
numDocs(query, shards, cluster);
fail("Expecting failure for shards parameter: '" + shards + "'");
} catch (SolrServerException e) {
- assertThat(e.getCause(), instanceOf(SolrException.class));
+ assertThat(e.getCause(), instanceOf(RemoteSolrException.class));
assertThat(((SolrException) e.getCause()).code(), is(SolrException.ErrorCode.FORBIDDEN.code));
assertThat(e.getCause().getMessage(), containsString(expectedExceptionMessage));
} finally {
diff --git a/solr/core/src/test/org/apache/solr/pkg/TestPackages.java b/solr/core/src/test/org/apache/solr/pkg/TestPackages.java
index 9a7c084f6b6..88113d83cf8 100644
--- a/solr/core/src/test/org/apache/solr/pkg/TestPackages.java
+++ b/solr/core/src/test/org/apache/solr/pkg/TestPackages.java
@@ -42,12 +42,12 @@ import org.apache.lucene.analysis.core.WhitespaceTokenizerFactory;
import org.apache.lucene.analysis.pattern.PatternReplaceCharFilterFactory;
import org.apache.lucene.util.ResourceLoader;
import org.apache.lucene.util.ResourceLoaderAware;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.apache.HttpClientUtil;
import org.apache.solr.client.solrj.apache.HttpSolrClient;
-import org.apache.solr.client.solrj.impl.RemoteExecutionException;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.request.GenericSolrRequest;
import org.apache.solr.client.solrj.request.RequestWriter;
@@ -579,7 +579,7 @@ public class TestPackages extends SolrCloudTestCase {
@Test
@SuppressWarnings("unchecked")
public void testAPI() throws Exception {
- String errPath = "/error/details[0]/errorMessages[0]";
+ String errPath = "/details[0]/errorMessages[0]";
String FILE1 = "/mypkg/v.0.12/jar_a.jar";
String FILE2 = "/mypkg/v.0.12/jar_b.jar";
String FILE3 = "/mypkg/v.0.13/jar_a.jar";
@@ -877,8 +877,11 @@ public class TestPackages extends SolrCloudTestCase {
try {
req.process(client);
fail("should have failed with message : " + expectErrorMsg);
- } catch (RemoteExecutionException e) {
- String msg = Objects.requireNonNullElse(e.getMetaData()._getStr(errPath), "");
+ } catch (RemoteSolrException e) {
+ String msg =
+ Objects.requireNonNullElse(
+ Utils.getObjectByPath(e.getRemoteErrorObject(), false, errPath), "")
+ .toString();
assertTrue(
"should have failed with message: " + expectErrorMsg + "actual message : " + msg,
msg.contains(expectErrorMsg));
diff --git a/solr/core/src/test/org/apache/solr/response/TestErrorResponseStackTrace.java b/solr/core/src/test/org/apache/solr/response/TestErrorResponseStackTrace.java
new file mode 100644
index 00000000000..ce10d4e2d48
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/response/TestErrorResponseStackTrace.java
@@ -0,0 +1,139 @@
+/*
+ * 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.nio.file.Files;
+import java.nio.file.Path;
+import org.apache.commons.codec.CharEncoding;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.lucene.tests.util.LuceneTestCase;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.SolrTestCaseJ4.SuppressSSL;
+import org.apache.solr.client.solrj.RemoteSolrException;
+import org.apache.solr.client.solrj.apache.HttpClientUtil;
+import org.apache.solr.client.solrj.request.QueryRequest;
+import org.apache.solr.client.solrj.response.json.JsonMapResponseParser;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.handler.component.ResponseBuilder;
+import org.apache.solr.handler.component.SearchComponent;
+import org.apache.solr.util.SolrJettyTestRule;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+@SuppressSSL
+public class TestErrorResponseStackTrace extends SolrTestCaseJ4 {
+
+ @ClassRule public static final SolrJettyTestRule solrRule = new SolrJettyTestRule();
+
+ @BeforeClass
+ public static void setupSolrHome() throws Exception {
+ Path configSet = createTempDir("configSet");
+ copyMinConf(configSet);
+ // insert a special filterCache configuration
+ Path solrConfig = configSet.resolve("conf/solrconfig.xml");
+ Files.writeString(
+ solrConfig,
+ Files.readString(solrConfig)
+ .replace(
+ "</config>",
+ " <searchComponent name=\"errorComponent\" class=\"org.apache.solr.response.TestErrorResponseStackTrace$ErrorComponent\"/>\n"
+ + " <requestHandler name=\"/withError\" class=\"solr.SearchHandler\">\n"
+ + " <arr name=\"first-components\">\n"
+ + " <str>errorComponent</str>\n"
+ + " </arr>\n"
+ + " </requestHandler>\n"
+ + "</config>"));
+
+ solrRule.startSolr(LuceneTestCase.createTempDir());
+ solrRule.newCollection().withConfigSet(configSet.toString()).create();
+ }
+
+ @Test
+ public void testFullStackTrace() throws Exception {
+ final String url = solrRule.getBaseUrl().toString() + "/collection1/withError?q=*:*&wt=json";
+ final HttpGet get = new HttpGet(url);
+ var client = HttpClientUtil.createClient(null);
+ try (CloseableHttpResponse responseRaw = client.execute(get)) {
+
+ assertEquals(500, responseRaw.getStatusLine().getStatusCode());
+ NamedList<Object> response =
+ new JsonMapResponseParser()
+ .processResponse(responseRaw.getEntity().getContent(), CharEncoding.UTF_8);
+
+ assertEquals(500L, response._get("error/code"));
+ assertEquals("java.lang.RuntimeException", response._get("error/errorClass"));
+ assertEquals("Stacktrace should be populated.", response._get("error/msg"));
+ assertTrue(
+ ((String) response._get("error/trace/stackTrace[0]"))
+ .contains("org.apache.solr.response.TestErrorResponseStackTrace$ErrorComponent"));
+ assertEquals("java.io.IOException", response._get("error/trace/causedBy/errorClass"));
+ assertEquals("This is the cause", response._get("error/trace/causedBy/msg"));
+ assertTrue(
+ ((String) response._get("error/trace/causedBy/trace/stackTrace[0]"))
+ .contains("org.apache.solr.response.TestErrorResponseStackTrace$ErrorComponent"));
+ } finally {
+ HttpClientUtil.close(client);
+ }
+ }
+
+ @Test
+ @SuppressWarnings({"unchecked"})
+ public void testRemoteSolrException() {
+ var client = solrRule.getSolrClient("collection1");
+ QueryRequest queryRequest =
+ new QueryRequest(new ModifiableSolrParams().set("q", "*:*").set("wt", "json"));
+ queryRequest.setPath("/withError");
+ RemoteSolrException exception =
+ expectThrows(RemoteSolrException.class, () -> queryRequest.process(client, "collection1"));
+ assertTrue(exception.getRemoteErrorObject() instanceof NamedList);
+ var remoteError = (NamedList<Object>) exception.getRemoteErrorObject();
+ assertEquals(500, remoteError._get("code"));
+ assertEquals("java.lang.RuntimeException", remoteError._get("errorClass"));
+ assertEquals("Stacktrace should be populated.", remoteError._get("msg"));
+ assertTrue(
+ ((String) remoteError._get("trace/stackTrace[0]"))
+ .contains("org.apache.solr.response.TestErrorResponseStackTrace$ErrorComponent"));
+ assertEquals("java.io.IOException", remoteError._get("trace/causedBy/errorClass"));
+ assertEquals("This is the cause", remoteError._get("trace/causedBy/msg"));
+ assertTrue(
+ ((String) remoteError._get("trace/causedBy/trace/stackTrace[0]"))
+ .contains("org.apache.solr.response.TestErrorResponseStackTrace$ErrorComponent"));
+ }
+
+ public static class ErrorComponent extends SearchComponent {
+
+ @Override
+ public void prepare(ResponseBuilder rb) throws IOException {
+ // prepared
+ }
+
+ @Override
+ public void process(ResponseBuilder rb) throws IOException {
+ throw new RuntimeException(
+ "Stacktrace should be populated.", new IOException("This is the cause"));
+ }
+
+ @Override
+ public String getDescription() {
+ return null;
+ }
+ }
+}
diff --git a/solr/core/src/test/org/apache/solr/response/TestRawTransformer.java b/solr/core/src/test/org/apache/solr/response/TestRawTransformer.java
index 469558a4599..f806032b7b4 100644
--- a/solr/core/src/test/org/apache/solr/response/TestRawTransformer.java
+++ b/solr/core/src/test/org/apache/solr/response/TestRawTransformer.java
@@ -184,7 +184,9 @@ public class TestRawTransformer extends SolrCloudTestCase {
"fl",
new String[] {"author:[xml],content_type:[xml]"},
"wt",
- new String[] {"xml"})));
+ new String[] {"xml"},
+ "indent",
+ new String[] {"false"})));
req.setResponseParser(XML_STREAM_RESPONSE_PARSER);
NamedList<Object> rsp = CLIENT.request(req, "collection1");
String strResponse = InputStreamResponseParser.consumeResponseToString(rsp);
@@ -209,7 +211,9 @@ public class TestRawTransformer extends SolrCloudTestCase {
"fl",
new String[] {"author,content_type"},
"wt",
- new String[] {"xml"})));
+ new String[] {"xml"},
+ "indent",
+ new String[] {"false"})));
req.setResponseParser(XML_STREAM_RESPONSE_PARSER);
rsp = CLIENT.request(req, "collection1");
strResponse = InputStreamResponseParser.consumeResponseToString(rsp);
@@ -232,7 +236,9 @@ public class TestRawTransformer extends SolrCloudTestCase {
"fl",
new String[] {"author:[xml],content_type:[xml]"},
"wt",
- new String[] {"json"})));
+ new String[] {"json"},
+ "indent",
+ new String[] {"false"})));
req.setResponseParser(JSON_STREAM_RESPONSE_PARSER);
rsp = CLIENT.request(req, "collection1");
strResponse = InputStreamResponseParser.consumeResponseToString(rsp);
@@ -257,7 +263,9 @@ public class TestRawTransformer extends SolrCloudTestCase {
"fl",
new String[] {"subject:[json],links:[json]"},
"wt",
- new String[] {"json"})));
+ new String[] {"json"},
+ "indent",
+ new String[] {"false"})));
req.setResponseParser(JSON_STREAM_RESPONSE_PARSER);
NamedList<Object> rsp = CLIENT.request(req, "collection1");
String strResponse = InputStreamResponseParser.consumeResponseToString(rsp);
@@ -280,7 +288,9 @@ public class TestRawTransformer extends SolrCloudTestCase {
"fl",
new String[] {"id", "subject,links"},
"wt",
- new String[] {"json"})));
+ new String[] {"json"},
+ "indent",
+ new String[] {"false"})));
req.setResponseParser(JSON_STREAM_RESPONSE_PARSER);
rsp = CLIENT.request(req, "collection1");
strResponse = InputStreamResponseParser.consumeResponseToString(rsp);
diff --git a/solr/core/src/test/org/apache/solr/schema/SchemaApiFailureTest.java b/solr/core/src/test/org/apache/solr/schema/SchemaApiFailureTest.java
index f9267d27db2..3837d21bc7a 100644
--- a/solr/core/src/test/org/apache/solr/schema/SchemaApiFailureTest.java
+++ b/solr/core/src/test/org/apache/solr/schema/SchemaApiFailureTest.java
@@ -21,7 +21,7 @@ import static org.hamcrest.Matchers.containsStringIgnoringCase;
import java.util.Map;
import java.util.concurrent.TimeUnit;
-import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.request.schema.SchemaRequest;
@@ -57,7 +57,7 @@ public class SchemaApiFailureTest extends SolrCloudTestCase {
final var thrown =
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
fieldAddition.process(client, COLLECTION);
});
diff --git a/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java b/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java
index 1bd45efc256..453d96401e6 100644
--- a/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java
+++ b/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java
@@ -34,6 +34,7 @@ import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.solr.cli.CLITestHelper;
import org.apache.solr.cli.StatusTool;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
@@ -153,9 +154,9 @@ public class BasicAuthIntegrationTest extends SolrCloudAuthTestCase {
httpClient.getConnectionManager().closeExpiredConnections();
httpClient.getConnectionManager().closeIdleConnections(1, TimeUnit.MILLISECONDS);
- SolrClient.RemoteSolrException exp =
+ RemoteSolrException exp =
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
cluster.getSolrClient().request(genericReq);
});
@@ -222,9 +223,9 @@ public class BasicAuthIntegrationTest extends SolrCloudAuthTestCase {
CollectionAdminRequest.Reload reload = CollectionAdminRequest.reloadCollection(COLLECTION);
try (SolrClient solrClient = getHttpSolrClient(baseUrl)) {
- expectThrows(SolrClient.RemoteSolrException.class, () -> solrClient.request(reload));
+ expectThrows(RemoteSolrException.class, () -> solrClient.request(reload));
reload.setMethod(SolrRequest.METHOD.POST);
- expectThrows(SolrClient.RemoteSolrException.class, () -> solrClient.request(reload));
+ expectThrows(RemoteSolrException.class, () -> solrClient.request(reload));
}
cluster
.getSolrClient()
@@ -233,7 +234,7 @@ public class BasicAuthIntegrationTest extends SolrCloudAuthTestCase {
.setBasicAuthCredentials("harry", "HarryIsUberCool"));
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
cluster
.getSolrClient()
@@ -264,9 +265,9 @@ public class BasicAuthIntegrationTest extends SolrCloudAuthTestCase {
delQuery.setBasicAuthCredentials("harry", "HarryIsUberCool");
delQuery.process(aNewClient, COLLECTION); // this should succeed
try {
- SolrClient.RemoteSolrException e =
+ RemoteSolrException e =
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
new UpdateRequest().deleteByQuery("*:*").process(aNewClient, COLLECTION);
});
@@ -305,7 +306,7 @@ public class BasicAuthIntegrationTest extends SolrCloudAuthTestCase {
// Query that fails due to missing credentials
exp =
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
cluster.getSolrClient().query(COLLECTION, params);
});
diff --git a/solr/core/src/test/org/apache/solr/servlet/TestRequestRateLimiter.java b/solr/core/src/test/org/apache/solr/servlet/TestRequestRateLimiter.java
index c9caca31b2f..fd29c164b02 100644
--- a/solr/core/src/test/org/apache/solr/servlet/TestRequestRateLimiter.java
+++ b/solr/core/src/test/org/apache/solr/servlet/TestRequestRateLimiter.java
@@ -39,6 +39,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;
import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
@@ -376,9 +377,8 @@ public class TestRequestRateLimiter extends SolrCloudTestCase {
try {
assertNotNull(future.get());
} catch (ExecutionException e) {
- assertThat(e.getCause().getCause(), instanceOf(SolrClient.RemoteSolrException.class));
- SolrClient.RemoteSolrException rse =
- (SolrClient.RemoteSolrException) e.getCause().getCause();
+ assertThat(e.getCause().getCause(), instanceOf(RemoteSolrException.class));
+ RemoteSolrException rse = (RemoteSolrException) e.getCause().getCause();
assertEquals(SolrException.ErrorCode.TOO_MANY_REQUESTS.code, rse.code());
assertThat(
rse.getMessage(), containsString("non ok status: 429, message:Too Many Requests"));
diff --git a/solr/modules/llm/src/test/org/apache/solr/llm/textvectorisation/update/processor/TextToVectorUpdateProcessorTest.java b/solr/modules/llm/src/test/org/apache/solr/llm/textvectorisation/update/processor/TextToVectorUpdateProcessorTest.java
index 602659b276c..c82d2312977 100644
--- a/solr/modules/llm/src/test/org/apache/solr/llm/textvectorisation/update/processor/TextToVectorUpdateProcessorTest.java
+++ b/solr/modules/llm/src/test/org/apache/solr/llm/textvectorisation/update/processor/TextToVectorUpdateProcessorTest.java
@@ -17,7 +17,7 @@
package org.apache.solr.llm.textvectorisation.update.processor;
import java.io.IOException;
-import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.SolrQuery;
import org.apache.solr.client.solrj.request.UpdateRequest;
@@ -87,7 +87,7 @@ public class TextToVectorUpdateProcessorTest extends TestLlmBase {
RuntimeException thrown =
assertThrows(
"model not found should throw an exception",
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
addWithChain(
sdoc("id", "99", "_text_", "Vegeta is the saiyan prince."), "textToVector");
diff --git a/solr/solrj-streaming/src/java/org/apache/solr/client/solrj/io/stream/JSONTupleStream.java b/solr/solrj-streaming/src/java/org/apache/solr/client/solrj/io/stream/JSONTupleStream.java
index e81f4e3709f..ae7b895498f 100644
--- a/solr/solrj-streaming/src/java/org/apache/solr/client/solrj/io/stream/JSONTupleStream.java
+++ b/solr/solrj-streaming/src/java/org/apache/solr/client/solrj/io/stream/JSONTupleStream.java
@@ -141,6 +141,7 @@ public class JSONTupleStream implements TupleStreamParser {
}
private void handleError() throws IOException {
+ int objectLevel = 0;
for (; ; ) {
int event = parser.nextEvent();
if (event == JSONParser.STRING) {
@@ -154,8 +155,12 @@ public class JSONTupleStream implements TupleStreamParser {
}
}
}
+ } else if (event == JSONParser.OBJECT_START) {
+ objectLevel++;
} else if (event == JSONParser.OBJECT_END) {
- throw new IOException("");
+ if (--objectLevel == 0) {
+ throw new IOException("");
+ }
}
}
}
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/RemoteSolrException.java b/solr/solrj/src/java/org/apache/solr/client/solrj/RemoteSolrException.java
new file mode 100644
index 00000000000..94bbca5ebb8
--- /dev/null
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/RemoteSolrException.java
@@ -0,0 +1,148 @@
+/*
+ * 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.client.solrj;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import org.apache.solr.common.SolrErrorWrappingException;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.common.util.Utils;
+
+/**
+ * Subclass of SolrException that allows us to capture an arbitrary HTTP status code and error
+ * details that may have been returned by the remote server or a proxy along the way.
+ */
+public final class RemoteSolrException extends SolrException {
+
+ private String remoteErrorMessageSuffix = "";
+ private final boolean skipRetry;
+
+ /**
+ * @param remoteHost the host the error was received from
+ * @param code Arbitrary HTTP status code
+ * @param msg Exception Message
+ * @param th Throwable to wrap with this Exception
+ */
+ public RemoteSolrException(String remoteHost, int code, String msg, Throwable th) {
+ super(code, "Error from server at " + remoteHost + ": " + msg, th);
+ skipRetry = false;
+ }
+
+ /**
+ * @param remoteHost the host the error was received from
+ * @param code Arbitrary HTTP status code
+ * @param remoteError Error response sent back from remoteHost
+ */
+ @SuppressWarnings("unchecked")
+ public RemoteSolrException(String remoteHost, int code, Object remoteError) {
+ this(remoteHost, code, remoteError, false);
+ }
+
+ /**
+ * @param remoteHost the host the error was received from
+ * @param code Arbitrary HTTP status code
+ * @param remoteError Error response sent back from remoteHost
+ * @param skipRetry Skip retry if the client is set to retry on failure
+ */
+ @SuppressWarnings("unchecked")
+ public RemoteSolrException(String remoteHost, int code, Object remoteError, boolean skipRetry) {
+ super(ErrorCode.getErrorCode(code), "Error from server at " + remoteHost);
+ this.skipRetry = skipRetry;
+ setDetails(List.of(Map.of("remoteHost", remoteHost, "remoteError", remoteError)));
+ if (remoteError != null) {
+ String remoteErrorMessageSuffix = getRemoteErrorMessageSuffix(remoteError, "");
+ if (remoteErrorMessageSuffix.length() > 2) {
+ this.remoteErrorMessageSuffix = remoteErrorMessageSuffix;
+ }
+
+ Object metadataObj =
+ Utils.getObjectByPath(remoteError, false, Collections.singletonList("metadata"));
+ if (metadataObj instanceof NamedList) {
+ setMetadata((NamedList<String>) metadataObj);
+ } else if (metadataObj instanceof List) {
+ // NamedList parsed as List convert to NamedList again
+ List<Object> list = (List<Object>) metadataObj;
+ setMetadata(new NamedList<>(list.size() / 2));
+ for (int i = 0; i < list.size(); i += 2) {
+ setMetadata((String) list.get(i), (String) list.get(i + 1));
+ }
+ } else if (metadataObj instanceof Map) {
+ setMetadata(new NamedList<>((Map<String, String>) metadataObj));
+ }
+ }
+ }
+
+ private String getRemoteErrorMessageSuffix(Object remoteError, String startingJsonPath) {
+ Object remoteErrorClass =
+ Utils.getObjectByPath(remoteError, false, startingJsonPath + "/errorClass");
+ Object remoteErrorMsg = Utils.getObjectByPath(remoteError, false, startingJsonPath + "/msg");
+ String remoteErrorMessageSuffix = "";
+
+ // Special cases for what the message should look like
+ if (SolrErrorWrappingException.class.getName().equals(remoteErrorClass)) {
+ remoteErrorMessageSuffix =
+ SolrErrorWrappingException.constructMessage(
+ remoteErrorMsg != null ? remoteErrorMsg.toString() : null,
+ Utils.getObjectByPath(remoteError, false, "details"));
+ }
+ if (RemoteSolrException.class.getName().equals(remoteErrorClass)) {
+ remoteErrorMessageSuffix += remoteErrorClass + ": " + remoteErrorMsg;
+ // Drill down into the next remote error to get info from that
+ String nextRemoteErrorMessage =
+ getRemoteErrorMessageSuffix(remoteError, startingJsonPath + "/details[0]/remoteError");
+ if (!nextRemoteErrorMessage.isEmpty()) {
+ remoteErrorMessageSuffix += ": " + nextRemoteErrorMessage;
+ }
+ } else {
+ if (remoteErrorClass != null) {
+ remoteErrorMessageSuffix = remoteErrorMessageSuffix + remoteErrorClass + ": ";
+ }
+ if (remoteErrorMsg != null) {
+ remoteErrorMessageSuffix = remoteErrorMessageSuffix + remoteErrorMsg;
+ }
+ }
+ if (remoteErrorMessageSuffix.isEmpty()) {
+ return "";
+ } else {
+ return ": " + remoteErrorMessageSuffix;
+ }
+ }
+
+ @Override
+ public String getResponseMessage() {
+ return super.getMessage();
+ }
+
+ @Override
+ public String getMessage() {
+ return super.getMessage() + remoteErrorMessageSuffix;
+ }
+
+ public Object getRemoteErrorObject() {
+ if (details != null && !details.isEmpty()) {
+ return details.get(0).get("remoteError");
+ } else {
+ return null;
+ }
+ }
+
+ public boolean shouldSkipRetry() {
+ return skipRetry;
+ }
+}
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/SolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/SolrClient.java
index 76f9888a712..5b21d582d45 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/SolrClient.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/SolrClient.java
@@ -38,7 +38,6 @@ import org.apache.solr.client.solrj.response.StreamingResponseCallback;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
-import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.ModifiableSolrParams;
@@ -1214,22 +1213,6 @@ public abstract class SolrClient implements Serializable, Closeable {
return defaultCollection;
}
- /**
- * Subclass of SolrException that allows us to capture an arbitrary HTTP status code that may have
- * been returned by the remote server or a proxy along the way.
- */
- public static class RemoteSolrException extends SolrException {
- /**
- * @param remoteHost the host the error was received from
- * @param code Arbitrary HTTP status code
- * @param msg Exception Message
- * @param th Throwable to wrap with this Exception
- */
- public RemoteSolrException(String remoteHost, int code, String msg, Throwable th) {
- super(code, "Error from server at " + remoteHost + ": " + msg, th);
- }
- }
-
/** A lambda intended for invoking SolrClient operations */
@FunctionalInterface
public interface SolrClientFunction<C extends SolrClient, R> {
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BaseHttpClusterStateProvider.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BaseHttpClusterStateProvider.java
index 23ce0c99b37..c477c55aca4 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BaseHttpClusterStateProvider.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BaseHttpClusterStateProvider.java
@@ -17,8 +17,6 @@
package org.apache.solr.client.solrj.impl;
-import static org.apache.solr.client.solrj.SolrClient.RemoteSolrException;
-
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.net.MalformedURLException;
@@ -34,6 +32,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest.METHOD;
import org.apache.solr.client.solrj.SolrServerException;
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ConcurrentUpdateBaseSolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ConcurrentUpdateBaseSolrClient.java
index 38a82b1791e..16bac664891 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ConcurrentUpdateBaseSolrClient.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ConcurrentUpdateBaseSolrClient.java
@@ -29,6 +29,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
@@ -231,7 +232,6 @@ public abstract class ConcurrentUpdateBaseSolrClient extends SolrClient {
// Pull from the queue multiple times and streams over a single connection.
// Exits on exception, interruption, or an empty queue to pull from.
//
- @SuppressWarnings({"unchecked"})
void sendUpdateStream() throws Exception {
try {
@@ -255,34 +255,18 @@ public abstract class ConcurrentUpdateBaseSolrClient extends SolrClient {
int statusCode = response.getStatus();
if (statusCode != HttpStatus.OK_200) {
- StringBuilder msg = new StringBuilder();
- msg.append(response.getReason());
- msg.append("\n\n\n\n");
- msg.append("request: ").append(basePath);
-
SolrException solrExc;
- NamedList<String> metadata = null;
+ Object remoteError = null;
// parse out the metadata from the SolrException
try {
String encoding = "UTF-8"; // default
NamedList<Object> resp = client.getParser().processResponse(rspBody, encoding);
- NamedList<Object> error = (NamedList<Object>) resp.get("error");
- if (error != null) {
- metadata = (NamedList<String>) error.get("metadata");
- String remoteMsg = (String) error.get("msg");
- if (remoteMsg != null) {
- msg.append("\nRemote error message: ");
- msg.append(remoteMsg);
- }
- }
+ remoteError = resp.get("error");
} catch (Exception exc) {
// don't want to fail to report error if parsing the response fails
log.warn("Failed to parse error response from {} due to: ", basePath, exc);
} finally {
- solrExc = new RemoteSolrException(basePath, statusCode, msg.toString(), null);
- if (metadata != null) {
- solrExc.setMetadata(metadata);
- }
+ solrExc = new RemoteSolrException(basePath, statusCode, remoteError);
}
handleError(solrExc);
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClientBase.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClientBase.java
index e6130255a1f..84e329f25a4 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClientBase.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClientBase.java
@@ -17,8 +17,6 @@
package org.apache.solr.client.solrj.impl;
-import static org.apache.solr.common.util.Utils.getObjectByPath;
-
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -28,13 +26,12 @@ import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import java.util.function.Function;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
@@ -49,7 +46,6 @@ import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.util.ContentStream;
import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.Utils;
/**
* Utility/base functionality for direct HTTP client implementations.
@@ -203,7 +199,7 @@ public abstract class HttpSolrClientBase extends SolrClient {
break;
default:
if (processor == null || mimeType == null) {
- throw new SolrClient.RemoteSolrException(
+ throw new RemoteSolrException(
urlExceptionMessage,
httpStatus,
"non ok status: " + httpStatus + ", message:" + responseReason,
@@ -224,57 +220,26 @@ public abstract class HttpSolrClientBase extends SolrClient {
try {
rsp = processor.processResponse(is, encoding);
} catch (Exception e) {
- throw new SolrClient.RemoteSolrException(
- urlExceptionMessage, httpStatus, e.getMessage(), e);
+ throw new RemoteSolrException(urlExceptionMessage, httpStatus, e.getMessage(), e);
}
Object error = rsp == null ? null : rsp.get("error");
-
- if (error != null
- && (String.valueOf(getObjectByPath(error, true, errPath))
- .endsWith("ExceptionWithErrObject"))) {
- throw RemoteExecutionException.create(urlExceptionMessage, rsp);
+ if (error != null && isV2Api) {
+ throw new RemoteSolrException(urlExceptionMessage, httpStatus, error, true);
}
if (httpStatus != 200 && !isV2Api) {
- NamedList<String> metadata = null;
- String reason = null;
- try {
- if (error != null) {
- reason = (String) Utils.getObjectByPath(error, false, Collections.singletonList("msg"));
- if (reason == null) {
- reason =
- (String) Utils.getObjectByPath(error, false, Collections.singletonList("trace"));
- }
- Object metadataObj =
- Utils.getObjectByPath(error, false, Collections.singletonList("metadata"));
- if (metadataObj instanceof NamedList) {
- metadata = (NamedList<String>) metadataObj;
- } else if (metadataObj instanceof List) {
- // NamedList parsed as List convert to NamedList again
- List<Object> list = (List<Object>) metadataObj;
- metadata = new NamedList<>(list.size() / 2);
- for (int i = 0; i < list.size(); i += 2) {
- metadata.add((String) list.get(i), (String) list.get(i + 1));
- }
- } else if (metadataObj instanceof Map) {
- metadata = new NamedList((Map) metadataObj);
- }
- }
- } catch (Exception ex) {
- /* Ignored */
- }
- if (reason == null) {
- StringBuilder msg = new StringBuilder();
- msg.append(responseReason).append("\n").append("request: ").append(responseMethod);
- if (error != null) {
- msg.append("\n\nError returned:\n").append(error);
- }
- reason = java.net.URLDecoder.decode(msg.toString(), FALLBACK_CHARSET);
+ if (error == null) {
+ StringBuilder msg =
+ new StringBuilder()
+ .append(responseReason)
+ .append("\n")
+ .append("request: ")
+ .append(responseMethod);
+ String reason = java.net.URLDecoder.decode(msg.toString(), FALLBACK_CHARSET);
+ throw new RemoteSolrException(urlExceptionMessage, httpStatus, reason, null);
+ } else {
+ throw new RemoteSolrException(urlExceptionMessage, httpStatus, error);
}
- SolrClient.RemoteSolrException rss =
- new SolrClient.RemoteSolrException(urlExceptionMessage, httpStatus, reason, null);
- if (metadata != null) rss.setMetadata(metadata);
- throw rss;
}
return rsp;
} finally {
@@ -328,10 +293,10 @@ public abstract class HttpSolrClientBase extends SolrClient {
try {
ByteArrayOutputStream body = new ByteArrayOutputStream();
is.transferTo(body);
- throw new SolrClient.RemoteSolrException(
+ throw new RemoteSolrException(
urlExceptionMessage, httpStatus, prefix + body.toString(exceptionEncoding), null);
} catch (IOException e) {
- throw new SolrClient.RemoteSolrException(
+ throw new RemoteSolrException(
urlExceptionMessage,
httpStatus,
"Could not parse response with encoding " + exceptionEncoding,
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBAsyncSolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBAsyncSolrClient.java
index 41225ffaf25..c02197c2d4d 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBAsyncSolrClient.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBAsyncSolrClient.java
@@ -22,6 +22,7 @@ import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrRequest.SolrRequestType;
@@ -180,9 +181,10 @@ public abstract class LBAsyncSolrClient extends LBSolrClient {
RetryListener listener) {
try {
throw (Exception) oe;
- } catch (RemoteExecutionException e) {
- listener.onFailure(e, false);
} catch (SolrException e) {
+ if (!isNonRetryable && e instanceof RemoteSolrException rse) {
+ isNonRetryable = rse.shouldSkipRetry();
+ }
// we retry on 404 or 403 or 503 or 500
// unless it's an update - then we only retry on connect exception
if (!isNonRetryable && RETRY_CODES.contains(e.code())) {
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBSolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBSolrClient.java
index 48198b1400c..fc0d06c7f29 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBSolrClient.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBSolrClient.java
@@ -40,6 +40,7 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrRequest.SolrRequestType;
@@ -635,9 +636,10 @@ public abstract class LBSolrClient extends SolrClient {
if (isZombie) {
reviveZombieServer(baseUrl);
}
- } catch (RemoteExecutionException e) {
- throw e;
} catch (SolrException e) {
+ if (!isNonRetryable && e instanceof RemoteSolrException rse) {
+ isNonRetryable = rse.shouldSkipRetry();
+ }
// we retry on 404 or 403 or 503 or 500
// unless it's an update - then we only retry on connect exception
if (!isNonRetryable && RETRY_CODES.contains(e.code())) {
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/RemoteExecutionException.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/RemoteExecutionException.java
deleted file mode 100644
index 18baf4f6756..00000000000
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/RemoteExecutionException.java
+++ /dev/null
@@ -1,59 +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.client.solrj.impl;
-
-import static org.apache.solr.common.util.Utils.getObjectByPath;
-
-import java.util.Collections;
-import org.apache.solr.client.solrj.SolrClient;
-import org.apache.solr.common.util.NamedList;
-
-/**
- * This should be thrown when a server has an error in executing the request, and it sends a proper
- * payload back to the client
- *
- * <p>THIS IS INTERNAL AND MAY DISAPPEAR
- */
-public class RemoteExecutionException extends SolrClient.RemoteSolrException {
- private NamedList<?> meta;
-
- public RemoteExecutionException(String remoteHost, int code, String msg, NamedList<?> meta) {
- super(remoteHost, code, msg + (meta != null ? ": " + meta : ""), null);
- this.meta = meta;
- }
-
- public static RemoteExecutionException create(String host, NamedList<?> errResponse) {
- Object errObj = errResponse.get("error");
- if (errObj != null) {
- Number code = (Number) getObjectByPath(errObj, true, Collections.singletonList("code"));
- String msg = (String) getObjectByPath(errObj, true, Collections.singletonList("msg"));
- return new RemoteExecutionException(
- host,
- code == null ? ErrorCode.UNKNOWN.code : code.intValue(),
- msg == null ? "Unknown Error" : msg,
- errResponse);
-
- } else {
- throw new RuntimeException("No error");
- }
- }
-
- public NamedList<?> getMetaData() {
- return meta;
- }
-}
diff --git a/solr/solrj/src/java/org/apache/solr/common/SolrErrorWrappingException.java b/solr/solrj/src/java/org/apache/solr/common/SolrErrorWrappingException.java
new file mode 100644
index 00000000000..ac7be9227ad
--- /dev/null
+++ b/solr/solrj/src/java/org/apache/solr/common/SolrErrorWrappingException.java
@@ -0,0 +1,56 @@
+/*
+ * 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.common;
+
+import java.util.List;
+import java.util.Map;
+import org.apache.solr.common.util.Utils;
+
+/**
+ * Subclass of SolrException that allows us to wrap arbitrary error objects, and pass them in the
+ * errorMessage while preserving the error object structure when returning a response to the user.
+ */
+public final class SolrErrorWrappingException extends SolrException {
+
+ public SolrErrorWrappingException(ErrorCode code, String msg, List<Map<String, Object>> errs) {
+ super(code, msg);
+ setDetails(errs);
+ }
+
+ @Override
+ public String getResponseMessage() {
+ return super.getMessage();
+ }
+
+ @Override
+ public String getMessage() {
+ return constructMessage(super.getMessage(), getDetails());
+ }
+
+ public static String constructMessage(String message, Object details) {
+ String builtMessage = "";
+ if (message != null) {
+ builtMessage = message;
+ } else {
+ builtMessage = SolrErrorWrappingException.class.getName();
+ }
+ if (details != null) {
+ builtMessage += ", errors: " + Utils.toJSONString(details);
+ }
+ return builtMessage;
+ }
+}
diff --git a/solr/solrj/src/java/org/apache/solr/common/SolrException.java b/solr/solrj/src/java/org/apache/solr/common/SolrException.java
index 983c75bcafd..66a5a4b4fb2 100644
--- a/solr/solrj/src/java/org/apache/solr/common/SolrException.java
+++ b/solr/solrj/src/java/org/apache/solr/common/SolrException.java
@@ -19,8 +19,10 @@ package org.apache.solr.common;
import static org.apache.solr.client.api.model.ErrorInfo.ERROR_CLASS;
import static org.apache.solr.client.api.model.ErrorInfo.ROOT_ERROR_CLASS;
+import java.util.List;
import java.util.Map;
import org.apache.solr.common.util.NamedList;
+import org.apache.solr.common.util.SimpleOrderedMap;
import org.slf4j.Logger;
import org.slf4j.MDC;
@@ -93,6 +95,7 @@ public class SolrException extends RuntimeException {
int code = 0;
protected NamedList<String> metadata;
+ protected List<Map<String, Object>> details;
/**
* The HTTP Status code associated with this Exception. For SolrExceptions thrown by Solr "Server
@@ -122,10 +125,22 @@ public class SolrException extends RuntimeException {
if (key == null || value == null)
throw new IllegalArgumentException("Exception metadata cannot be null!");
- if (metadata == null) metadata = new NamedList<>();
+ if (metadata == null) metadata = new SimpleOrderedMap<>();
metadata.add(key, value);
}
+ public void setDetails(List<Map<String, Object>> details) {
+ this.details = details;
+ }
+
+ public List<Map<String, Object>> getDetails() {
+ return details;
+ }
+
+ public String getResponseMessage() {
+ return getMessage();
+ }
+
public String getThrowable() {
return getMetadata(ERROR_CLASS);
}
diff --git a/solr/solrj/src/java/org/apache/solr/common/util/JsonTextWriter.java b/solr/solrj/src/java/org/apache/solr/common/util/JsonTextWriter.java
index 9cb39b09320..f637d884103 100644
--- a/solr/solrj/src/java/org/apache/solr/common/util/JsonTextWriter.java
+++ b/solr/solrj/src/java/org/apache/solr/common/util/JsonTextWriter.java
@@ -291,7 +291,12 @@ public interface JsonTextWriter extends TextWriter {
@Override
default void writeArray(String name, Iterator<?> val, boolean raw) throws IOException {
- writeArrayOpener(-1); // no trivial way to determine array size
+ writeArray(name, val, -1, raw);
+ }
+
+ @Override
+ default void writeArray(String name, Iterator<?> val, int size, boolean raw) throws IOException {
+ writeArrayOpener(size); // no trivial way to determine array size
writeJsonIter(val, raw);
writeArrayCloser();
}
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 5e04815c322..6901b2db5ed 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
@@ -24,6 +24,7 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Base64;
+import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -93,6 +94,8 @@ public interface TextWriter extends PushWriter {
writeMap(name, ((MapSerializable) val).toMap(new LinkedHashMap<>()), false, true);
} else if (val instanceof Map) {
writeMap(name, (Map) val, false, true);
+ } else if (val instanceof Collection<?> cval) { // very generic; keep towards the end
+ writeArray(name, cval.iterator(), cval.size(), raw);
} else if (val instanceof Iterator) { // very generic; keep towards the end
writeArray(name, (Iterator) val, raw);
} else if (val instanceof Iterable) { // very generic; keep towards the end
@@ -129,6 +132,8 @@ public interface TextWriter extends PushWriter {
void writeArray(String name, Iterator<?> val, boolean raw) throws IOException;
+ void writeArray(String name, Iterator<?> val, int size, boolean raw) throws IOException;
+
void writeNull(String name) throws IOException;
/** if this form of the method is called, val is the Java string form of an int */
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java b/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java
index b1b659cb993..8935d0301a5 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java
@@ -752,14 +752,15 @@ public abstract class SolrExampleTests extends SolrExampleTestsBase {
assertNotNull("Should throw exception!", concurrentClient.lastError);
assertEquals(
"Unexpected exception type",
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
concurrentClient.lastError.getClass());
assertTrue(
"Unexpected exception message: " + concurrentClient.lastError.getMessage(),
concurrentClient
.lastError
.getMessage()
- .contains("Remote error message: Document contains multiple values for uniqueKey"));
+ .contains(
+ "org.apache.solr.common.SolrException: Document contains multiple values for uniqueKey"));
} else {
if (log.isInfoEnabled()) {
log.info("Ignoring update test for client: {}", client.getClass().getName());
@@ -913,31 +914,26 @@ public abstract class SolrExampleTests extends SolrExampleTestsBase {
@Test
public void testUpdateRequestWithParameters() throws Exception {
- SolrClient client = createNewSolrClient();
-
- client.deleteByQuery("*:*");
- client.commit();
+ try (SolrClient client = createNewSolrClient()) {
+ client.deleteByQuery("*:*");
+ client.commit();
- SolrInputDocument doc = new SolrInputDocument();
- doc.addField("id", "id1");
+ SolrInputDocument doc = new SolrInputDocument();
+ doc.addField("id", "id1");
- UpdateRequest req = new UpdateRequest();
- req.setParam("overwrite", "false");
- req.add(doc);
- client.request(req);
- client.request(req);
- client.commit();
+ UpdateRequest req = new UpdateRequest();
+ req.setParam("overwrite", "false");
+ req.add(doc);
+ client.request(req);
+ client.request(req);
+ client.commit();
- SolrQuery query = new SolrQuery();
- query.setQuery("*:*");
- QueryResponse rsp = client.query(query);
+ SolrQuery query = new SolrQuery();
+ query.setQuery("*:*");
+ QueryResponse rsp = client.query(query);
- SolrDocumentList out = rsp.getResults();
- assertEquals(2, out.getNumFound());
- if (!(client instanceof EmbeddedSolrServer)) {
- /* Do not close in case of using EmbeddedSolrServer,
- * as that would close the CoreContainer */
- client.close();
+ SolrDocumentList out = rsp.getResults();
+ assertEquals(2, out.getNumFound());
}
}
@@ -2442,7 +2438,7 @@ public abstract class SolrExampleTests extends SolrExampleTestsBase {
"ConcurrentUpdateSolrClient did not report an error", concurrentClient.lastError);
assertTrue(
"ConcurrentUpdateSolrClient did not report an error",
- concurrentClient.lastError.getMessage().contains("Conflict"));
+ concurrentClient.lastError.getMessage().contains("version conflict"));
} else if (client
instanceof
SolrExampleStreamingHttp2Test.ErrorTrackingConcurrentUpdateSolrClient
@@ -2452,7 +2448,7 @@ public abstract class SolrExampleTests extends SolrExampleTestsBase {
"ConcurrentUpdateSolrClient did not report an error", concurrentClient.lastError);
assertTrue(
"ConcurrentUpdateSolrClient did not report an error",
- concurrentClient.lastError.getMessage().contains("conflict"));
+ concurrentClient.lastError.getMessage().contains("version conflict"));
}
} catch (SolrException se) {
assertTrue(
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/TestSolrJErrorHandling.java b/solr/solrj/src/test/org/apache/solr/client/solrj/TestSolrJErrorHandling.java
index 8c2d5752807..ea3602b5f7d 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/TestSolrJErrorHandling.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/TestSolrJErrorHandling.java
@@ -215,7 +215,7 @@ public class TestSolrJErrorHandling extends SolrJettyTestBase {
void doSingle(SolrClient client, int threadNum) {
try {
client.add(manyDocs(threadNum * 1000000, 1000));
- } catch (SolrClient.RemoteSolrException e) {
+ } catch (RemoteSolrException e) {
String msg = e.getMessage();
assertTrue(msg, msg.contains("field_does_not_exist"));
} catch (Throwable e) {
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudHttp2SolrClientTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudHttp2SolrClientTest.java
index c6481018de1..95ac8ef41a5 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudHttp2SolrClientTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudHttp2SolrClientTest.java
@@ -38,6 +38,7 @@ import java.util.Set;
import java.util.concurrent.TimeoutException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.lucene.tests.util.TestUtil;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
@@ -822,7 +823,7 @@ public class CloudHttp2SolrClientTest extends SolrCloudTestCase {
Replica r = coll.getSlices().iterator().next().getReplicas().iterator().next();
SolrQuery q = new SolrQuery().setQuery("*:*");
- SolrClient.RemoteSolrException sse = null;
+ RemoteSolrException sse = null;
try (SolrClient solrClient = getHttpSolrClient(r.getBaseUrl(), COLLECTION)) {
@@ -876,7 +877,7 @@ public class CloudHttp2SolrClientTest extends SolrCloudTestCase {
try {
QueryResponse rsp = solrClient.query(q);
log.info("error was expected");
- } catch (SolrClient.RemoteSolrException e) {
+ } catch (RemoteSolrException e) {
sse = e;
}
assertNotNull(sse);
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpJdkSolrClientTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpJdkSolrClientTest.java
index 7f5ef6d63fe..4e2bf500e65 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpJdkSolrClientTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpJdkSolrClientTest.java
@@ -32,7 +32,7 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.apache.lucene.util.NamedThreadFactory;
import org.apache.solr.client.api.util.SolrVersion;
-import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.JavaBinRequestWriter;
@@ -110,7 +110,7 @@ public class HttpJdkSolrClientTest extends HttpSolrClientTestBase {
try (HttpJdkSolrClient client = builder(url).build()) {
try {
client.deleteById("id");
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
assertEquals("javabin", DebugServlet.parameters.get(CommonParams.WT)[0]);
validateDelete();
@@ -125,7 +125,7 @@ public class HttpJdkSolrClientTest extends HttpSolrClientTestBase {
builder(url).withResponseParser(new XMLResponseParser()).build()) {
try {
client.deleteByQuery("*:*");
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
assertEquals("xml", DebugServlet.parameters.get(CommonParams.WT)[0]);
validateDelete();
@@ -225,7 +225,7 @@ public class HttpJdkSolrClientTest extends HttpSolrClientTestBase {
builder(getBaseUrl() + DEBUG_SERVLET_PATH, DEFAULT_CONNECTION_TIMEOUT, 0).build()) {
try {
client.query(q, SolrRequest.METHOD.GET);
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
}
}
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientTestBase.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientTestBase.java
index 632406e3278..c77df8c803f 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientTestBase.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientTestBase.java
@@ -36,7 +36,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.apache.solr.SolrJettyTestBase;
-import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.jetty.HttpJettySolrClient;
@@ -231,22 +231,22 @@ public abstract class HttpSolrClientTestBase extends SolrJettyTestBase {
Collection<String> ids = Collections.singletonList("a");
try {
client.getById("a");
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
try {
client.getById(ids, null);
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
try {
client.getById("foo", "a");
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
try {
client.getById("foo", ids, null);
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
}
@@ -293,7 +293,7 @@ public abstract class HttpSolrClientTestBase extends SolrJettyTestBase {
try {
client.request(req);
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
assertEquals("post", DebugServlet.lastMethod);
@@ -390,7 +390,7 @@ public abstract class HttpSolrClientTestBase extends SolrJettyTestBase {
try {
client.request(req);
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
verifyServletState(client, req);
@@ -406,7 +406,7 @@ public abstract class HttpSolrClientTestBase extends SolrJettyTestBase {
setReqParamsOf(req, "requestOnly", "notRequest");
try {
client.request(req);
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
verifyServletState(client, req);
@@ -422,7 +422,7 @@ public abstract class HttpSolrClientTestBase extends SolrJettyTestBase {
setReqParamsOf(req, "serverOnly", "requestOnly", "both", "neither");
try {
client.request(req);
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
verifyServletState(client, req);
}
@@ -439,7 +439,7 @@ public abstract class HttpSolrClientTestBase extends SolrJettyTestBase {
setReqParamsOf(req, "serverOnly", "requestOnly", "both", "neither");
try {
client.request(req);
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
// NOTE: single stream requests send all the params
// as part of the query string. So add "neither" to the request,
@@ -651,7 +651,7 @@ public abstract class HttpSolrClientTestBase extends SolrJettyTestBase {
ee = ee1;
}
assertTrue(future.isCompletedExceptionally());
- assertTrue(ee.getCause() instanceof SolrClient.RemoteSolrException);
+ assertTrue(ee.getCause() instanceof RemoteSolrException);
assertTrue(ee.getMessage(), ee.getMessage().contains("mime type"));
}
}
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/jetty/HttpJettySolrClientCompatibilityTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/jetty/HttpJettySolrClientCompatibilityTest.java
index 6ce0f910aa9..c213b3d3130 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/jetty/HttpJettySolrClientCompatibilityTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/jetty/HttpJettySolrClientCompatibilityTest.java
@@ -19,7 +19,7 @@ package org.apache.solr.client.solrj.jetty;
import org.apache.solr.SolrJettyTestBase;
import org.apache.solr.SolrTestCaseJ4;
-import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.SolrQuery;
@@ -59,7 +59,7 @@ public class HttpJettySolrClientCompatibilityTest extends SolrJettyTestBase {
assertTrue(client.getHttpClient().getTransport() instanceof HttpClientTransportOverHTTP);
try {
client.query(new SolrQuery("*:*"), SolrRequest.METHOD.GET);
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
} finally {
solrClientTestRule.reset();
@@ -80,7 +80,7 @@ public class HttpJettySolrClientCompatibilityTest extends SolrJettyTestBase {
assertTrue(client.getHttpClient().getTransport() instanceof HttpClientTransportOverHTTP);
try {
client.query(new SolrQuery("*:*"), SolrRequest.METHOD.GET);
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
} finally {
solrClientTestRule.reset();
@@ -105,7 +105,7 @@ public class HttpJettySolrClientCompatibilityTest extends SolrJettyTestBase {
try {
client.query(new SolrQuery("*:*"), SolrRequest.METHOD.GET);
fail("Jetty client with HTTP2 transport should not be able to connect to HTTP1 only nodes");
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
fail("Jetty client with HTTP2 transport should not be able to connect to HTTP1 only nodes");
} catch (SolrServerException e) {
// expected
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/jetty/HttpJettySolrClientTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/jetty/HttpJettySolrClientTest.java
index 81c9f75bae4..4e927ac7e91 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/jetty/HttpJettySolrClientTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/jetty/HttpJettySolrClientTest.java
@@ -30,6 +30,7 @@ import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.apache.lucene.tests.util.LuceneTestCase;
import org.apache.solr.client.api.util.SolrVersion;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
@@ -100,7 +101,7 @@ public class HttpJettySolrClientTest extends HttpSolrClientTestBase {
.build()) {
try {
client.query(q, SolrRequest.METHOD.GET);
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
}
}
@@ -174,7 +175,7 @@ public class HttpJettySolrClientTest extends HttpSolrClientTestBase {
client.query(q, method);
assertEquals(
client.getParser().getWriterType(), DebugServlet.parameters.get(CommonParams.WT)[0]);
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
}
@@ -228,7 +229,7 @@ public class HttpJettySolrClientTest extends HttpSolrClientTestBase {
new HttpJettySolrClient.Builder(defaultUrl).withDefaultCollection(DEFAULT_CORE).build()) {
try {
client.requestWithBaseUrl(urlToUse, (c) -> c.query(queryParams));
- } catch (SolrClient.RemoteSolrException rse) {
+ } catch (RemoteSolrException rse) {
}
assertEquals(urlToUse + "/select", DebugServlet.url);
@@ -239,7 +240,7 @@ public class HttpJettySolrClientTest extends HttpSolrClientTestBase {
new HttpJettySolrClient.Builder(defaultUrl).withDefaultCollection(DEFAULT_CORE).build()) {
try {
client.requestWithBaseUrl(urlToUse, new QueryRequest(queryParams), null);
- } catch (SolrClient.RemoteSolrException rse) {
+ } catch (RemoteSolrException rse) {
}
assertEquals(urlToUse + "/select", DebugServlet.url);
@@ -254,7 +255,7 @@ public class HttpJettySolrClientTest extends HttpSolrClientTestBase {
new HttpJettySolrClient.Builder(url).withDefaultCollection(DEFAULT_CORE).build()) {
try {
client.deleteById("id");
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
assertEquals("javabin", DebugServlet.parameters.get(CommonParams.WT)[0]);
validateDelete();
@@ -272,7 +273,7 @@ public class HttpJettySolrClientTest extends HttpSolrClientTestBase {
.build()) {
try {
client.deleteByQuery("*:*");
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
assertEquals("xml", DebugServlet.parameters.get(CommonParams.WT)[0]);
validateDelete();
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/request/SchemaTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/request/SchemaTest.java
index d029c54605c..22ea7401ef5 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/request/SchemaTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/request/SchemaTest.java
@@ -32,6 +32,7 @@ import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.commons.io.file.PathUtils;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.request.schema.AnalyzerDefinition;
import org.apache.solr.client.solrj.request.schema.FieldTypeDefinition;
@@ -62,7 +63,7 @@ public class SchemaTest extends RestTestBase {
private static void assertFailedSchemaResponse(
ThrowingRunnable runnable, String expectedErrorMessage) {
- final var e = expectThrows(SolrClient.RemoteSolrException.class, runnable);
+ final var e = expectThrows(RemoteSolrException.class, runnable);
assertThat(e.getMessage(), containsString(expectedErrorMessage));
}
diff --git a/solr/test-framework/src/java/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClient.java b/solr/test-framework/src/java/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClient.java
index 09cdc17b51c..1882dcbcc2f 100644
--- a/solr/test-framework/src/java/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClient.java
+++ b/solr/test-framework/src/java/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClient.java
@@ -38,6 +38,7 @@ import org.apache.http.NameValuePair;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentProducer;
import org.apache.http.entity.EntityTemplate;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
@@ -219,7 +220,6 @@ public class ConcurrentUpdateSolrClient extends SolrClient {
// Pull from the queue multiple times and streams over a single connection.
// Exits on exception, interruption, or an empty queue to pull from.
//
- @SuppressWarnings({"unchecked"})
void sendUpdateStream() throws Exception {
while (!queue.isEmpty()) {
@@ -362,7 +362,7 @@ public class ConcurrentUpdateSolrClient extends SolrClient {
msg.append("request: ").append(method.getURI());
SolrException solrExc;
- NamedList<String> metadata = null;
+ Object remoteError = null;
// parse out the metadata from the SolrException
try {
String encoding = "UTF-8"; // default
@@ -378,25 +378,12 @@ public class ConcurrentUpdateSolrClient extends SolrClient {
}
}
NamedList<Object> resp = client.parser.processResponse(rspBody, encoding);
- NamedList<Object> error = (NamedList<Object>) resp.get("error");
- if (error != null) {
- metadata = (NamedList<String>) error.get("metadata");
- String remoteMsg = (String) error.get("msg");
- if (remoteMsg != null) {
- msg.append("\nRemote error message: ");
- msg.append(remoteMsg);
- }
- }
+ remoteError = resp.get("error");
} catch (Exception exc) {
// don't want to fail to report error if parsing the response fails
log.warn("Failed to parse error response from {} due to: ", client.getBaseURL(), exc);
} finally {
- solrExc =
- new SolrClient.RemoteSolrException(
- client.getBaseURL(), statusCode, msg.toString(), null);
- if (metadata != null) {
- solrExc.setMetadata(metadata);
- }
+ solrExc = new RemoteSolrException(client.getBaseURL(), statusCode, remoteError);
}
handleError(solrExc);
diff --git a/solr/test-framework/src/java/org/apache/solr/client/solrj/apache/HttpSolrClient.java b/solr/test-framework/src/java/org/apache/solr/client/solrj/apache/HttpSolrClient.java
index 3d11423f440..7f11c01e774 100644
--- a/solr/test-framework/src/java/org/apache/solr/client/solrj/apache/HttpSolrClient.java
+++ b/solr/test-framework/src/java/org/apache/solr/client/solrj/apache/HttpSolrClient.java
@@ -16,8 +16,6 @@
*/
package org.apache.solr.client.solrj.apache;
-import static org.apache.solr.common.util.Utils.getObjectByPath;
-
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -72,11 +70,11 @@ import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.solr.client.api.util.SolrVersion;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpJdkSolrClient;
-import org.apache.solr.client.solrj.impl.RemoteExecutionException;
import org.apache.solr.client.solrj.jetty.HttpJettySolrClient;
import org.apache.solr.client.solrj.request.JavaBinRequestWriter;
import org.apache.solr.client.solrj.request.RequestWriter;
@@ -92,7 +90,6 @@ import org.apache.solr.common.util.ContentStream;
import org.apache.solr.common.util.ExecutorUtil;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SolrNamedThreadFactory;
-import org.apache.solr.common.util.Utils;
import org.slf4j.MDC;
/**
@@ -603,7 +600,7 @@ public class HttpSolrClient extends SolrClient {
break;
default:
if (processor == null || contentType == null) {
- throw new SolrClient.RemoteSolrException(
+ throw new RemoteSolrException(
baseUrl,
httpStatus,
"non ok status: "
@@ -635,7 +632,7 @@ public class HttpSolrClient extends SolrClient {
.collect(Collectors.toSet());
if (!processorMimeTypes.contains(mimeType)) {
if (isUnmatchedErrorCode(mimeType, httpStatus)) {
- throw new SolrClient.RemoteSolrException(
+ throw new RemoteSolrException(
baseUrl,
httpStatus,
"non ok status: "
@@ -653,10 +650,10 @@ public class HttpSolrClient extends SolrClient {
try {
ByteArrayOutputStream body = new ByteArrayOutputStream();
respBody.transferTo(body);
- throw new SolrClient.RemoteSolrException(
+ throw new RemoteSolrException(
baseUrl, httpStatus, prefix + body.toString(exceptionCharset), null);
} catch (IOException e) {
- throw new SolrClient.RemoteSolrException(
+ throw new RemoteSolrException(
baseUrl,
httpStatus,
"Could not parse response with encoding " + exceptionCharset,
@@ -669,54 +666,24 @@ public class HttpSolrClient extends SolrClient {
try {
rsp = processor.processResponse(respBody, charsetName);
} catch (Exception e) {
- throw new SolrClient.RemoteSolrException(baseUrl, httpStatus, e.getMessage(), e);
+ throw new RemoteSolrException(baseUrl, httpStatus, e.getMessage(), e);
}
Object error = rsp == null ? null : rsp.get("error");
- if (error != null
- && (isV2Api
- || String.valueOf(getObjectByPath(error, true, errPath))
- .endsWith("ExceptionWithErrObject"))) {
- throw RemoteExecutionException.create(baseUrl, rsp);
+ if (error != null && isV2Api) {
+ throw new RemoteSolrException(baseUrl, httpStatus, error, true);
}
- if (httpStatus != HttpStatus.SC_OK && !isV2Api) {
- NamedList<String> metadata = null;
- String reason = null;
- try {
- if (error != null) {
- reason = (String) Utils.getObjectByPath(error, false, Collections.singletonList("msg"));
- if (reason == null) {
- reason =
- (String) Utils.getObjectByPath(error, false, Collections.singletonList("trace"));
- }
- Object metadataObj =
- Utils.getObjectByPath(error, false, Collections.singletonList("metadata"));
- if (metadataObj instanceof NamedList) {
- metadata = (NamedList<String>) metadataObj;
- } else if (metadataObj instanceof List) {
- // NamedList parsed as List convert to NamedList again
- List<Object> list = (List<Object>) metadataObj;
- metadata = new NamedList<>(list.size() / 2);
- for (int i = 0; i < list.size(); i += 2) {
- metadata.add((String) list.get(i), (String) list.get(i + 1));
- }
- } else if (metadataObj instanceof Map) {
- metadata = new NamedList((Map) metadataObj);
- }
- }
- } catch (Exception ex) {
- }
- if (reason == null) {
+ if (httpStatus != 200 && !isV2Api) {
+ if (error == null) {
StringBuilder msg = new StringBuilder();
msg.append(response.getStatusLine().getReasonPhrase())
.append("\n\n")
.append("request: ")
.append(method.getURI());
- reason = java.net.URLDecoder.decode(msg.toString(), FALLBACK_CHARSET);
+ String reason = java.net.URLDecoder.decode(msg.toString(), FALLBACK_CHARSET);
+ throw new RemoteSolrException(baseUrl, httpStatus, reason, null);
+ } else {
+ throw new RemoteSolrException(baseUrl, httpStatus, error);
}
- SolrClient.RemoteSolrException rss =
- new SolrClient.RemoteSolrException(baseUrl, httpStatus, reason, null);
- if (metadata != null) rss.setMetadata(metadata);
- throw rss;
}
return rsp;
} catch (ConnectException e) {
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCollectionsAPIDistributedZkTestBase.java b/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCollectionsAPIDistributedZkTestBase.java
index e773a941e7d..1fe728e757a 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCollectionsAPIDistributedZkTestBase.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCollectionsAPIDistributedZkTestBase.java
@@ -36,6 +36,7 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.lucene.tests.util.TestUtil;
import org.apache.solr.client.api.model.CoreStatusResponse;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest.METHOD;
import org.apache.solr.client.solrj.SolrRequest.SolrRequestType;
@@ -283,7 +284,7 @@ public abstract class AbstractCollectionsAPIDistributedZkTestBase extends SolrCl
.isSuccess());
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
CollectionAdminRequest.createCollection("halfcollection", "conf", 1, 1)
.setCreateNodeSet(nn1 + "," + nn2)
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractInstallShardTest.java b/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractInstallShardTest.java
index a1aa541959f..eae246c0486 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractInstallShardTest.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractInstallShardTest.java
@@ -35,6 +35,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.apache.lucene.store.Directory;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
@@ -149,9 +150,9 @@ public abstract class AbstractInstallShardTest extends SolrCloudTestCase {
deleteAfterTest(collectionName);
final String singleShardLocation = singleShard1Uri.toString();
- final SolrClient.RemoteSolrException rse =
+ final RemoteSolrException rse =
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
CollectionAdminRequest.installDataToShard(
collectionName, "shard1", singleShardLocation, BACKUP_REPO_NAME)
@@ -188,7 +189,7 @@ public abstract class AbstractInstallShardTest extends SolrCloudTestCase {
{ // Test synchronous request error reporting
final var expectedException =
expectThrows(
- SolrClient.RemoteSolrException.class,
+ RemoteSolrException.class,
() -> {
CollectionAdminRequest.installDataToShard(
collectionName, "shard1", nonExistentLocation, BACKUP_REPO_NAME)
diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/BasicHttpSolrClientTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/BasicHttpSolrClientTest.java
index e5c987df4cc..c56d452d272 100644
--- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/BasicHttpSolrClientTest.java
+++ b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/BasicHttpSolrClientTest.java
@@ -47,6 +47,7 @@ import org.apache.http.protocol.HttpContext;
import org.apache.solr.SolrJettyTestBase;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.api.util.SolrVersion;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrRequest.METHOD;
@@ -143,7 +144,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
queryRequest.setPath(debugPath);
try (HttpSolrClient client = getHttpSolrClient(getBaseUrl())) {
- expectThrows(SolrClient.RemoteSolrException.class, () -> queryRequest.process(client));
+ expectThrows(RemoteSolrException.class, () -> queryRequest.process(client));
// default method
assertEquals("get", DebugServlet.lastMethod);
@@ -169,7 +170,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
// POST
DebugServlet.clear();
queryRequest.setMethod(METHOD.POST);
- expectThrows(SolrClient.RemoteSolrException.class, () -> queryRequest.process(client));
+ expectThrows(RemoteSolrException.class, () -> queryRequest.process(client));
assertEquals("post", DebugServlet.lastMethod);
assertEquals(
@@ -190,7 +191,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
// PUT
DebugServlet.clear();
queryRequest.setMethod(METHOD.PUT);
- expectThrows(SolrClient.RemoteSolrException.class, () -> queryRequest.process(client));
+ expectThrows(RemoteSolrException.class, () -> queryRequest.process(client));
assertEquals("put", DebugServlet.lastMethod);
assertEquals(
@@ -217,7 +218,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
// XML/GET
DebugServlet.clear();
queryRequest.setMethod(METHOD.GET); // Reset to the default here after using 'PUT' above
- expectThrows(SolrClient.RemoteSolrException.class, () -> queryRequest.process(client));
+ expectThrows(RemoteSolrException.class, () -> queryRequest.process(client));
assertEquals("get", DebugServlet.lastMethod);
assertEquals(
@@ -235,7 +236,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
// XML/POST
DebugServlet.clear();
queryRequest.setMethod(METHOD.POST);
- expectThrows(SolrClient.RemoteSolrException.class, () -> queryRequest.process(client));
+ expectThrows(RemoteSolrException.class, () -> queryRequest.process(client));
assertEquals("post", DebugServlet.lastMethod);
assertEquals(
@@ -255,7 +256,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
DebugServlet.clear();
queryRequest.setMethod(METHOD.PUT);
- expectThrows(SolrClient.RemoteSolrException.class, () -> queryRequest.process(client));
+ expectThrows(RemoteSolrException.class, () -> queryRequest.process(client));
assertEquals("put", DebugServlet.lastMethod);
assertEquals(
@@ -284,7 +285,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
final UpdateRequest deleteById = new UpdateRequest();
deleteById.deleteById("id");
deleteById.setPath(debugPath + deleteById.getPath());
- expectThrows(SolrClient.RemoteSolrException.class, () -> deleteById.process(client));
+ expectThrows(RemoteSolrException.class, () -> deleteById.process(client));
// default method
assertEquals("post", DebugServlet.lastMethod);
@@ -312,8 +313,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
deleteByQueryRequest.setPath(debugPath + deleteByQueryRequest.getPath());
deleteByQueryRequest.deleteByQuery("*:*");
deleteByQueryRequest.setCommitWithin(-1);
- expectThrows(
- SolrClient.RemoteSolrException.class, () -> deleteByQueryRequest.process(client));
+ expectThrows(RemoteSolrException.class, () -> deleteByQueryRequest.process(client));
assertEquals("post", DebugServlet.lastMethod);
assertEquals(
@@ -333,10 +333,10 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
DebugServlet.clear();
try (SolrClient client = getHttpSolrClient(getBaseUrl() + "/debug/foo")) {
Collection<String> ids = Collections.singletonList("a");
- expectThrows(SolrClient.RemoteSolrException.class, () -> client.getById("a"));
- expectThrows(SolrClient.RemoteSolrException.class, () -> client.getById(ids, null));
- expectThrows(SolrClient.RemoteSolrException.class, () -> client.getById("foo", "a"));
- expectThrows(SolrClient.RemoteSolrException.class, () -> client.getById("foo", ids, null));
+ expectThrows(RemoteSolrException.class, () -> client.getById("a"));
+ expectThrows(RemoteSolrException.class, () -> client.getById(ids, null));
+ expectThrows(RemoteSolrException.class, () -> client.getById("foo", "a"));
+ expectThrows(RemoteSolrException.class, () -> client.getById("foo", ids, null));
}
}
@@ -350,7 +350,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
req.add(new SolrInputDocument());
req.setPath(debugPath + req.getPath());
req.setParam("a", "\u1234");
- expectThrows(SolrClient.RemoteSolrException.class, () -> req.process(client));
+ expectThrows(RemoteSolrException.class, () -> req.process(client));
// default method
assertEquals("post", DebugServlet.lastMethod);
@@ -379,7 +379,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
req.setPath(debugPath + req.getPath());
req.setParam("a", "\u1234");
- expectThrows(SolrClient.RemoteSolrException.class, () -> client.request(req));
+ expectThrows(RemoteSolrException.class, () -> client.request(req));
assertEquals("post", DebugServlet.lastMethod);
assertEquals(
@@ -403,7 +403,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
req.setPath(debugPath + req.getPath());
req.setParam("a", "\u1234");
- expectThrows(SolrClient.RemoteSolrException.class, () -> client.request(req));
+ expectThrows(RemoteSolrException.class, () -> client.request(req));
assertEquals("post", DebugServlet.lastMethod);
assertEquals(
@@ -456,7 +456,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
try (SolrClient client = getHttpSolrClient(getBaseUrl())) {
// verify request header gets set
DebugServlet.clear();
- expectThrows(SolrClient.RemoteSolrException.class, () -> queryRequest.process(client));
+ expectThrows(RemoteSolrException.class, () -> queryRequest.process(client));
assertNull(DebugServlet.headers.toString(), DebugServlet.headers.get("accept-encoding"));
}
@@ -464,7 +464,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
new HttpSolrClient.Builder(getBaseUrl()).allowCompression(true).build()) {
try {
queryRequest.process(client);
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
assertNotNull(DebugServlet.headers.get("accept-encoding"));
}
@@ -473,7 +473,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
new HttpSolrClient.Builder(getBaseUrl()).allowCompression(false).build()) {
try {
queryRequest.process(client);
- } catch (SolrClient.RemoteSolrException ignored) {
+ } catch (RemoteSolrException ignored) {
}
}
assertNull(DebugServlet.headers.get("accept-encoding"));
@@ -683,7 +683,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
UpdateRequest req = new UpdateRequest();
req.setPath(debugPath + req.getPath());
setReqParamsOf(req, "serverOnly", "notServer");
- expectThrows(SolrClient.RemoteSolrException.class, () -> client.request(req));
+ expectThrows(RemoteSolrException.class, () -> client.request(req));
verifyServletState(client, req);
}
try (HttpSolrClient client = builder.withTheseParamNamesInTheUrl(Set.of()).build()) {
@@ -693,7 +693,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
req2.setPath(debugPath + req2.getPath());
req2.setQueryParams(Set.of("requestOnly"));
setReqParamsOf(req2, "requestOnly", "notRequest");
- expectThrows(SolrClient.RemoteSolrException.class, () -> client.request(req2));
+ expectThrows(RemoteSolrException.class, () -> client.request(req2));
verifyServletState(client, req2);
}
try (HttpSolrClient client =
@@ -704,7 +704,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
req3.setPath(debugPath + req3.getPath());
req3.setQueryParams(Set.of("requestOnly", "both"));
setReqParamsOf(req3, "serverOnly", "requestOnly", "both", "neither");
- expectThrows(SolrClient.RemoteSolrException.class, () -> client.request(req3));
+ expectThrows(RemoteSolrException.class, () -> client.request(req3));
verifyServletState(client, req3);
}
try (HttpSolrClient client =
@@ -716,7 +716,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
req4.add(new SolrInputDocument());
req4.setQueryParams(Set.of("requestOnly", "both"));
setReqParamsOf(req4, "serverOnly", "requestOnly", "both", "neither");
- expectThrows(SolrClient.RemoteSolrException.class, () -> client.request(req4));
+ expectThrows(RemoteSolrException.class, () -> client.request(req4));
// NOTE: single stream requests send all the params
// as part of the query string. So add "neither" to the request,
// so it passes the verification step.
diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientTest.java
index 8802719304c..89d050dc431 100644
--- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientTest.java
+++ b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientTest.java
@@ -36,6 +36,7 @@ import java.util.Set;
import java.util.concurrent.TimeoutException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.lucene.tests.util.TestUtil;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest.METHOD;
import org.apache.solr.client.solrj.SolrRequest.SolrRequestType;
@@ -711,7 +712,7 @@ public class CloudSolrClientTest extends SolrCloudTestCase {
Replica r = coll.getSlices().iterator().next().getReplicas().iterator().next();
SolrQuery q = new SolrQuery().setQuery("*:*");
- SolrClient.RemoteSolrException sse = null;
+ RemoteSolrException sse = null;
try (SolrClient solrClient = getHttpSolrClient(r.getBaseUrl(), COLLECTION)) {
@@ -765,7 +766,7 @@ public class CloudSolrClientTest extends SolrCloudTestCase {
try {
QueryResponse rsp = solrClient.query(q);
log.info("error was expected");
- } catch (SolrClient.RemoteSolrException e) {
+ } catch (RemoteSolrException e) {
sse = e;
}
assertNotNull(sse);