From 35f1a2b1b3745f218daa2f14581b989543b53205 Mon Sep 17 00:00:00 2001 From: Nick Knize Date: Mon, 19 Jun 2023 15:25:39 -0500 Subject: [PATCH] [Refactor] StreamIO and OpenSearchException foundation to core library (#8035) This commit refactors the Stream IO classes from the server to core library to support cloud native and serverless extensions. The following classes are refactored: * StreamInput * StreamOutput * Writeable * NamedWriteable * NamedWriteableRegistry * Index * ShardId * BytesReference * ByteArray * BigArray * SecureString * Text * ParsingException * RestStatus The namespace is left unchanged but will be refactored in a follow up commit to avoid split package in order to support jigsaw modularity. Signed-off-by: Nicholas Walter Knize --- CHANGELOG.md | 1 + .../org/opensearch/BaseExceptionsHelper.java | 283 ----- .../opensearch/BaseOpenSearchException.java | 535 ---------- .../java/org/opensearch/ExceptionsHelper.java | 83 +- .../org/opensearch/OpenSearchException.java | 980 ++++++++++++++++++ .../action/ShardOperationFailedException.java | 0 .../org/opensearch/action/package-info.java | 10 + .../DefaultShardOperationFailedException.java | 6 +- .../action/support/package-info.java | 10 + .../opensearch/common/ParsingException.java | 0 .../common/bytes/AbstractBytesReference.java | 0 .../opensearch/common/bytes/BytesArray.java | 0 .../common/bytes/BytesReference.java | 0 .../common/bytes/CompositeBytesReference.java | 0 .../common/bytes/PagedBytesReference.java | 7 +- .../opensearch/common/bytes/package-info.java | 10 + .../common/compress/NotXContentException.java | 0 .../common/compress/package-info.java | 10 + .../opensearch/common/io/package-info.java | 10 + .../common/io/stream/BytesStream.java | 0 .../io/stream/InputStreamStreamInput.java | 4 +- .../common/io/stream/NamedWriteable.java | 0 .../io/stream/NamedWriteableRegistry.java | 1 + .../NotSerializableExceptionWrapper.java | 7 +- .../common/io/stream/StreamInput.java | 323 +++++- .../common/io/stream/StreamOutput.java | 191 +++- .../common/io/stream/Writeable.java | 175 ++++ .../common/io/stream/package-info.java | 3 +- .../org/opensearch/common/package-info.java | 10 + .../common/settings/SecureString.java | 0 .../common/settings/package-info.java | 10 + .../java/org/opensearch/common/text/Text.java | 0 .../opensearch/common/text/package-info.java | 10 + .../org/opensearch/common/util/BigArray.java | 0 .../org/opensearch/common/util/ByteArray.java | 0 .../opensearch/common/util/package-info.java | 10 + .../common/xcontent/XContentParserUtils.java | 0 .../common/xcontent/package-info.java | 10 + .../core/common/io/package-info.java | 10 + .../common/io/stream/BaseStreamInput.java | 341 ------ .../common/io/stream/BaseStreamOutput.java | 150 --- .../core/common/io/stream/BaseWriteable.java | 130 --- .../main/java/org/opensearch/index/Index.java | 0 .../org/opensearch/index/package-info.java | 10 + .../org/opensearch/index/shard/ShardId.java | 4 +- .../opensearch/index/shard/package-info.java | 10 + .../IndexShardSnapshotException.java | 0 .../IndexShardSnapshotFailedException.java | 0 .../index/snapshots/package-info.java | 10 + .../java/org/opensearch/rest/RestStatus.java | 0 .../org/opensearch/rest/package-info.java | 10 + .../geogrid/GeoTileGridParserTests.java | 4 +- .../mustache/MultiSearchTemplateResponse.java | 4 +- .../index/rankeval/RankEvalRequestIT.java | 4 +- .../index/rankeval/RankEvalResponse.java | 3 +- .../reindex/remote/RemoteResponseParsers.java | 2 +- .../reindex/AsyncBulkByScrollActionTests.java | 3 +- .../http/DetailedErrorsEnabledIT.java | 2 +- .../opensearch/action/RejectionActionIT.java | 4 +- .../action/search/TransportSearchIT.java | 8 +- .../org/opensearch/blocks/SimpleBlocksIT.java | 6 +- .../breaker/CircuitBreakerServiceIT.java | 4 +- .../indices/state/CloseIndexIT.java | 4 +- .../AggregationsIntegrationIT.java | 4 +- .../aggregations/bucket/DateHistogramIT.java | 6 +- .../aggregations/bucket/HistogramIT.java | 6 +- .../bucket/terms/StringTermsIT.java | 5 +- .../aggregations/pipeline/DerivativeIT.java | 4 +- .../pipeline/ExtendedStatsBucketIT.java | 4 +- .../pipeline/PercentilesBucketIT.java | 6 +- .../SharedClusterSnapshotRestoreIT.java | 4 +- ...on.java => OpenSearchServerException.java} | 478 +-------- .../action/TaskOperationFailure.java | 5 +- .../NodesReloadSecureSettingsResponse.java | 4 +- .../indices/close/CloseIndexResponse.java | 4 +- .../readonly/AddIndexBlockResponse.java | 4 +- .../shards/IndicesShardStoresResponse.java | 4 +- .../action/bulk/BulkItemResponse.java | 5 +- .../action/bulk/TransportBulkAction.java | 4 +- .../action/bulk/TransportShardBulkAction.java | 4 +- .../action/get/MultiGetResponse.java | 3 +- .../ingest/SimulateDocumentBaseResult.java | 3 +- .../ingest/SimulateProcessorResult.java | 5 +- .../search/AbstractSearchAsyncAction.java | 6 +- .../action/search/MultiSearchResponse.java | 4 +- .../search/SearchPhaseExecutionException.java | 18 +- .../action/search/ShardSearchFailure.java | 9 +- .../action/support/TransportActions.java | 4 +- .../replication/ReplicationOperation.java | 7 +- .../replication/ReplicationResponse.java | 6 +- .../termvectors/MultiTermVectorsResponse.java | 4 +- .../action/shard/ShardStateAction.java | 3 +- .../cluster/routing/UnassignedInfo.java | 4 +- .../routing/allocation/FailedShard.java | 4 +- .../allocation/NodeAllocationResult.java | 4 +- .../java/org/opensearch/common/Strings.java | 4 +- .../org/opensearch/common/geo/GeoPoint.java | 14 - .../org/opensearch/common/io/Streams.java | 31 +- .../common/io/stream/Streamables.java | 88 ++ .../common/io/stream/Writeable.java | 88 -- .../common/lucene/search/Queries.java | 4 +- .../common/util/PageCacheRecycler.java | 3 +- .../opensearch/gateway/AsyncShardFetch.java | 4 +- .../index/engine/InternalEngine.java | 6 +- .../index/mapper/MappedFieldType.java | 5 +- .../index/query/MoreLikeThisQueryBuilder.java | 3 +- .../index/reindex/BulkByScrollTask.java | 3 +- .../index/reindex/ReindexRequest.java | 2 +- .../index/reindex/ScrollableHitSource.java | 4 +- .../opensearch/index/shard/StoreRecovery.java | 4 +- .../org/opensearch/index/store/Store.java | 3 +- .../recovery/PeerRecoveryTargetService.java | 6 +- .../recovery/RetryableTransportClient.java | 6 +- .../SegmentReplicationTargetService.java | 4 +- .../replication/common/ReplicationTarget.java | 4 +- .../opensearch/rest/BytesRestResponse.java | 17 +- .../script/JodaCompatibleZonedDateTime.java | 26 - .../java/org/opensearch/script/Script.java | 2 +- .../BaseMultiValuesSourceFieldConfig.java | 2 +- .../ValuesSourceAggregationBuilder.java | 2 +- .../DirectCandidateGeneratorBuilder.java | 4 +- .../tasks/TaskCancellationService.java | 6 +- .../org/opensearch/tasks/TaskManager.java | 5 +- .../java/org/opensearch/tasks/TaskResult.java | 4 +- .../opensearch/tasks/TaskResultsService.java | 4 +- .../transport/TransportService.java | 23 +- .../ExceptionSerializationTests.java | 8 +- .../org/opensearch/ExceptionsHelperTests.java | 6 +- .../opensearch/OpenSearchExceptionTests.java | 54 +- .../action/bulk/BulkItemResponseTests.java | 2 +- .../action/bulk/BulkResponseTests.java | 2 +- .../search/MultiSearchRequestTests.java | 2 +- .../client/AbstractClientHeadersTestCase.java | 4 +- .../common/io/stream/BytesStreamsTests.java | 8 +- .../rest/BytesRestResponseTests.java | 6 +- .../pipeline/DerivativeAggregatorTests.java | 4 +- .../transport/TransportActionProxyTests.java | 4 +- .../test/OpenSearchIntegTestCase.java | 4 +- .../AbstractSimpleTransportTestCase.java | 11 +- 139 files changed, 2195 insertions(+), 2358 deletions(-) delete mode 100644 libs/core/src/main/java/org/opensearch/BaseExceptionsHelper.java delete mode 100644 libs/core/src/main/java/org/opensearch/BaseOpenSearchException.java rename {server => libs/core}/src/main/java/org/opensearch/ExceptionsHelper.java (81%) create mode 100644 libs/core/src/main/java/org/opensearch/OpenSearchException.java rename {server => libs/core}/src/main/java/org/opensearch/action/ShardOperationFailedException.java (100%) create mode 100644 libs/core/src/main/java/org/opensearch/action/package-info.java rename {server => libs/core}/src/main/java/org/opensearch/action/support/DefaultShardOperationFailedException.java (97%) create mode 100644 libs/core/src/main/java/org/opensearch/action/support/package-info.java rename {server => libs/core}/src/main/java/org/opensearch/common/ParsingException.java (100%) rename {server => libs/core}/src/main/java/org/opensearch/common/bytes/AbstractBytesReference.java (100%) rename {server => libs/core}/src/main/java/org/opensearch/common/bytes/BytesArray.java (100%) rename {server => libs/core}/src/main/java/org/opensearch/common/bytes/BytesReference.java (100%) rename {server => libs/core}/src/main/java/org/opensearch/common/bytes/CompositeBytesReference.java (100%) rename {server => libs/core}/src/main/java/org/opensearch/common/bytes/PagedBytesReference.java (94%) create mode 100644 libs/core/src/main/java/org/opensearch/common/bytes/package-info.java rename {server => libs/core}/src/main/java/org/opensearch/common/compress/NotXContentException.java (100%) create mode 100644 libs/core/src/main/java/org/opensearch/common/compress/package-info.java create mode 100644 libs/core/src/main/java/org/opensearch/common/io/package-info.java rename {server => libs/core}/src/main/java/org/opensearch/common/io/stream/BytesStream.java (100%) rename {server => libs/core}/src/main/java/org/opensearch/common/io/stream/InputStreamStreamInput.java (97%) rename {server => libs/core}/src/main/java/org/opensearch/common/io/stream/NamedWriteable.java (100%) rename {server => libs/core}/src/main/java/org/opensearch/common/io/stream/NamedWriteableRegistry.java (99%) rename {server => libs/core}/src/main/java/org/opensearch/common/io/stream/NotSerializableExceptionWrapper.java (93%) rename {server => libs/core}/src/main/java/org/opensearch/common/io/stream/StreamInput.java (74%) rename {server => libs/core}/src/main/java/org/opensearch/common/io/stream/StreamOutput.java (89%) create mode 100644 libs/core/src/main/java/org/opensearch/common/io/stream/Writeable.java rename libs/core/src/main/java/org/opensearch/{core => }/common/io/stream/package-info.java (83%) create mode 100644 libs/core/src/main/java/org/opensearch/common/package-info.java rename {server => libs/core}/src/main/java/org/opensearch/common/settings/SecureString.java (100%) create mode 100644 libs/core/src/main/java/org/opensearch/common/settings/package-info.java rename {server => libs/core}/src/main/java/org/opensearch/common/text/Text.java (100%) create mode 100644 libs/core/src/main/java/org/opensearch/common/text/package-info.java rename {server => libs/core}/src/main/java/org/opensearch/common/util/BigArray.java (100%) rename {server => libs/core}/src/main/java/org/opensearch/common/util/ByteArray.java (100%) create mode 100644 libs/core/src/main/java/org/opensearch/common/util/package-info.java rename {server => libs/core}/src/main/java/org/opensearch/common/xcontent/XContentParserUtils.java (100%) create mode 100644 libs/core/src/main/java/org/opensearch/common/xcontent/package-info.java create mode 100644 libs/core/src/main/java/org/opensearch/core/common/io/package-info.java delete mode 100644 libs/core/src/main/java/org/opensearch/core/common/io/stream/BaseStreamInput.java delete mode 100644 libs/core/src/main/java/org/opensearch/core/common/io/stream/BaseStreamOutput.java delete mode 100644 libs/core/src/main/java/org/opensearch/core/common/io/stream/BaseWriteable.java rename {server => libs/core}/src/main/java/org/opensearch/index/Index.java (100%) create mode 100644 libs/core/src/main/java/org/opensearch/index/package-info.java rename {server => libs/core}/src/main/java/org/opensearch/index/shard/ShardId.java (96%) create mode 100644 libs/core/src/main/java/org/opensearch/index/shard/package-info.java rename {server => libs/core}/src/main/java/org/opensearch/index/snapshots/IndexShardSnapshotException.java (100%) rename {server => libs/core}/src/main/java/org/opensearch/index/snapshots/IndexShardSnapshotFailedException.java (100%) create mode 100644 libs/core/src/main/java/org/opensearch/index/snapshots/package-info.java rename {server => libs/core}/src/main/java/org/opensearch/rest/RestStatus.java (100%) create mode 100644 libs/core/src/main/java/org/opensearch/rest/package-info.java rename server/src/main/java/org/opensearch/{OpenSearchException.java => OpenSearchServerException.java} (69%) create mode 100644 server/src/main/java/org/opensearch/common/io/stream/Streamables.java delete mode 100644 server/src/main/java/org/opensearch/common/io/stream/Writeable.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 63660429b4f9e..8af6fe7fd44eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -97,6 +97,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Move span actions to Scope ([#8411](https://github.com/opensearch-project/OpenSearch/pull/8411)) - [Refactor] OpenSearchException streamables to a registry ([#7646](https://github.com/opensearch-project/OpenSearch/pull/7646)) - [Refactor] Serverless common classes to libraries ([#8065](https://github.com/opensearch-project/OpenSearch/pull/8065)) +- [Refactor] StreamIO and OpenSearchException foundation to core library ([#8035](https://github.com/opensearch-project/OpenSearch/pull/8035)) ### Deprecated diff --git a/libs/core/src/main/java/org/opensearch/BaseExceptionsHelper.java b/libs/core/src/main/java/org/opensearch/BaseExceptionsHelper.java deleted file mode 100644 index 2b282d1fc48c3..0000000000000 --- a/libs/core/src/main/java/org/opensearch/BaseExceptionsHelper.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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. - */ - -/* - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ -package org.opensearch; - -import com.fasterxml.jackson.core.JsonParseException; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.opensearch.core.ParseField; -import org.opensearch.core.concurrency.OpenSearchRejectedExecutionException; -import org.opensearch.core.xcontent.ToXContent; -import org.opensearch.core.xcontent.XContentBuilder; - -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.List; -import java.util.Map; - -import static java.util.Collections.emptyMap; - -/** - * Base helper class for OpenSearch Exceptions - * - * @opensearch.internal - */ -public abstract class BaseExceptionsHelper { - /** - * Passed in the {@link ToXContent.Params} of {@link #generateThrowableXContent(XContentBuilder, ToXContent.Params, Throwable)} - * to control if the {@code stack_trace} element should render. Unlike most parameters to {@code toXContent} methods this parameter is - * internal only and not available as a URL parameter. Use the {@code error_trace} parameter instead. - */ - public static final String REST_EXCEPTION_SKIP_STACK_TRACE = "rest.exception.stacktrace.skip"; - public static final boolean REST_EXCEPTION_SKIP_STACK_TRACE_DEFAULT = true; - public static final String STACK_TRACE = "stack_trace"; - protected static final Logger logger = LogManager.getLogger(BaseExceptionsHelper.class); - protected static final String OPENSEARCH_PREFIX_KEY = "opensearch."; - /** - * Passed in the {@link ToXContent.Params} of {@link #generateThrowableXContent(XContentBuilder, ToXContent.Params, Throwable)} - * to control if the {@code caused_by} element should render. Unlike most parameters to {@code toXContent} methods this parameter is - * internal only and not available as a URL parameter. - */ - protected static final String REST_EXCEPTION_SKIP_CAUSE = "rest.exception.cause.skip"; - protected static final String TYPE = "type"; - protected static final String REASON = "reason"; - protected static final String CAUSED_BY = "caused_by"; - protected static final ParseField SUPPRESSED = new ParseField("suppressed"); - protected static final String HEADER = "header"; - private static final boolean REST_EXCEPTION_SKIP_CAUSE_DEFAULT = false; - - public static Throwable unwrapCause(Throwable t) { - int counter = 0; - Throwable result = t; - while (result instanceof OpenSearchWrapperException) { - if (result.getCause() == null) { - return result; - } - if (result.getCause() == result) { - return result; - } - if (counter++ > 10) { - // dear god, if we got more than 10 levels down, WTF? just bail - logger.warn("Exception cause unwrapping ran for 10 levels...", t); - return result; - } - result = result.getCause(); - } - return result; - } - - /** - * @deprecated Don't swallow exceptions, allow them to propagate. - */ - @Deprecated - public static String detailedMessage(Throwable t) { - if (t == null) { - return "Unknown"; - } - if (t.getCause() != null) { - StringBuilder sb = new StringBuilder(); - while (t != null) { - sb.append(t.getClass().getSimpleName()); - if (t.getMessage() != null) { - sb.append("["); - sb.append(t.getMessage()); - sb.append("]"); - } - sb.append("; "); - t = t.getCause(); - if (t != null) { - sb.append("nested: "); - } - } - return sb.toString(); - } else { - return t.getClass().getSimpleName() + "[" + t.getMessage() + "]"; - } - } - - public static String stackTrace(Throwable e) { - StringWriter stackTraceStringWriter = new StringWriter(); - PrintWriter printWriter = new PrintWriter(stackTraceStringWriter); - e.printStackTrace(printWriter); - return stackTraceStringWriter.toString(); - } - - public static String summaryMessage(Throwable t) { - if (t != null) { - if (t instanceof BaseOpenSearchException) { - return t.getClass().getSimpleName() + "[" + t.getMessage() + "]"; - } else if (t instanceof IllegalArgumentException) { - return "Invalid argument"; - } else if (t instanceof JsonParseException) { - return "Failed to parse JSON"; - } else if (t instanceof OpenSearchRejectedExecutionException) { - return "Too many requests"; - } - } - return "Internal failure"; - } - - public static void innerToXContent( - XContentBuilder builder, - ToXContent.Params params, - Throwable throwable, - String type, - String message, - Map> headers, - Map> metadata, - Throwable cause - ) throws IOException { - builder.field(TYPE, type); - builder.field(REASON, message); - - for (Map.Entry> entry : metadata.entrySet()) { - headerToXContent(builder, entry.getKey().substring(OPENSEARCH_PREFIX_KEY.length()), entry.getValue()); - } - - if (throwable instanceof BaseOpenSearchException) { - BaseOpenSearchException exception = (BaseOpenSearchException) throwable; - exception.metadataToXContent(builder, params); - } - - if (params.paramAsBoolean(REST_EXCEPTION_SKIP_CAUSE, REST_EXCEPTION_SKIP_CAUSE_DEFAULT) == false) { - if (cause != null) { - builder.field(CAUSED_BY); - builder.startObject(); - generateThrowableXContent(builder, params, cause); - builder.endObject(); - } - } - - if (headers.isEmpty() == false) { - builder.startObject(HEADER); - for (Map.Entry> entry : headers.entrySet()) { - headerToXContent(builder, entry.getKey(), entry.getValue()); - } - builder.endObject(); - } - - if (params.paramAsBoolean(REST_EXCEPTION_SKIP_STACK_TRACE, REST_EXCEPTION_SKIP_STACK_TRACE_DEFAULT) == false) { - builder.field(STACK_TRACE, stackTrace(throwable)); - } - - Throwable[] allSuppressed = throwable.getSuppressed(); - if (allSuppressed.length > 0) { - builder.startArray(SUPPRESSED.getPreferredName()); - for (Throwable suppressed : allSuppressed) { - builder.startObject(); - generateThrowableXContent(builder, params, suppressed); - builder.endObject(); - } - builder.endArray(); - } - } - - /** - * Static toXContent helper method that renders {@link BaseOpenSearchException} or {@link Throwable} instances - * as XContent, delegating the rendering to {@link BaseOpenSearchException#toXContent(XContentBuilder, ToXContent.Params)} - * or {@link #innerToXContent(XContentBuilder, ToXContent.Params, Throwable, String, String, Map, Map, Throwable)}. - * - * This method is usually used when the {@link Throwable} is rendered as a part of another XContent object, and its result can - * be parsed back using the {@code OpenSearchException.fromXContent(XContentParser)} method. - */ - public static void generateThrowableXContent(XContentBuilder builder, ToXContent.Params params, Throwable t) throws IOException { - t = unwrapCause(t); - - if (t instanceof BaseOpenSearchException) { - ((BaseOpenSearchException) t).toXContent(builder, params); - } else { - innerToXContent(builder, params, t, getExceptionName(t), t.getMessage(), emptyMap(), emptyMap(), t.getCause()); - } - } - - /** - * Returns an underscore case name for the given exception. This method strips {@code OpenSearch} prefixes from exception names. - */ - public static String getExceptionName(Throwable ex) { - String simpleName = ex.getClass().getSimpleName(); - if (simpleName.startsWith("OpenSearch")) { - simpleName = simpleName.substring("OpenSearch".length()); - } - // TODO: do we really need to make the exception name in underscore casing? - return toUnderscoreCase(simpleName); - } - - // lower cases and adds underscores to transitions in a name - private static String toUnderscoreCase(String value) { - StringBuilder sb = new StringBuilder(); - boolean changed = false; - for (int i = 0; i < value.length(); i++) { - char c = value.charAt(i); - if (Character.isUpperCase(c)) { - if (!changed) { - // copy it over here - for (int j = 0; j < i; j++) { - sb.append(value.charAt(j)); - } - changed = true; - if (i == 0) { - sb.append(Character.toLowerCase(c)); - } else { - sb.append('_'); - sb.append(Character.toLowerCase(c)); - } - } else { - sb.append('_'); - sb.append(Character.toLowerCase(c)); - } - } else { - if (changed) { - sb.append(c); - } - } - } - if (!changed) { - return value; - } - return sb.toString(); - } - - protected static void headerToXContent(XContentBuilder builder, String key, List values) throws IOException { - if (values != null && values.isEmpty() == false) { - if (values.size() == 1) { - builder.field(key, values.get(0)); - } else { - builder.startArray(key); - for (String value : values) { - builder.value(value); - } - builder.endArray(); - } - } - } -} diff --git a/libs/core/src/main/java/org/opensearch/BaseOpenSearchException.java b/libs/core/src/main/java/org/opensearch/BaseOpenSearchException.java deleted file mode 100644 index 248673d11797a..0000000000000 --- a/libs/core/src/main/java/org/opensearch/BaseOpenSearchException.java +++ /dev/null @@ -1,535 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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. - */ - -/* - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ -package org.opensearch; - -import org.opensearch.common.CheckedFunction; -import org.opensearch.common.Nullable; -import org.opensearch.core.common.Strings; -import org.opensearch.core.common.io.stream.BaseStreamInput; -import org.opensearch.core.common.logging.LoggerMessageFormat; -import org.opensearch.core.xcontent.ToXContent; -import org.opensearch.core.xcontent.ToXContentFragment; -import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.core.xcontent.XContentParseException; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import static java.util.Collections.singletonMap; - -/** - * A core library base class for all opensearch exceptions. - * - * @opensearch.internal - */ -public abstract class BaseOpenSearchException extends RuntimeException implements ToXContentFragment { - - protected static final String ERROR = "error"; - protected static final String ROOT_CAUSE = "root_cause"; - protected static final String RESOURCE_METADATA_TYPE_KEY = "opensearch.resource.type"; - protected static final String RESOURCE_METADATA_ID_KEY = "opensearch.resource.id"; - protected static final Version UNKNOWN_VERSION_ADDED = Version.fromId(0); - protected static final String INDEX_METADATA_KEY = "opensearch.index"; - protected static final String SHARD_METADATA_KEY = "opensearch.shard"; - protected static final String INDEX_METADATA_KEY_UUID = "opensearch.index_uuid"; - protected final Map> metadata = new HashMap<>(); - protected final Map> headers = new HashMap<>(); - - /** - * Construct a BaseOpenSearchException with the specified cause exception. - */ - public BaseOpenSearchException(Throwable cause) { - super(cause); - } - - /** - * Construct a OpenSearchException with the specified detail message. - * - * The message can be parameterized using {} as placeholders for the given - * arguments - * - * @param msg the detail message - * @param args the arguments for the message - */ - public BaseOpenSearchException(String msg, Object... args) { - super(LoggerMessageFormat.format(msg, args)); - } - - /** - * Construct a OpenSearchException with the specified detail message - * and nested exception. - * - * The message can be parameterized using {} as placeholders for the given - * arguments - * - * @param msg the detail message - * @param cause the nested exception - * @param args the arguments for the message - */ - public BaseOpenSearchException(String msg, Throwable cause, Object... args) { - super(LoggerMessageFormat.format(msg, args), cause); - } - - /** - * Render any exception as a xcontent, encapsulated within a field or object named "error". The level of details that are rendered - * depends on the value of the "detailed" parameter: when it's false only a simple message based on the type and message of the - * exception is rendered. When it's true all detail are provided including guesses root causes, cause and potentially stack - * trace. - * - * This method is usually used when the {@link Exception} is rendered as a full XContent object, and its output can be parsed - * by the {@code #OpenSearchException.failureFromXContent(XContentParser)} method. - */ - public static void generateFailureXContent(XContentBuilder builder, ToXContent.Params params, @Nullable Exception e, boolean detailed) - throws IOException { - // No exception to render as an error - if (e == null) { - builder.field(ERROR, "unknown"); - return; - } - - // Render the exception with a simple message - if (detailed == false) { - Throwable t = e; - for (int counter = 0; counter < 10 && t != null; counter++) { - if (t instanceof BaseOpenSearchException) { - break; - } - t = t.getCause(); - } - builder.field(ERROR, BaseExceptionsHelper.summaryMessage(t != null ? t : e)); - return; - } - - // Render the exception with all details - final BaseOpenSearchException[] rootCauses = BaseOpenSearchException.guessRootCauses(e); - builder.startObject(ERROR); - { - builder.startArray(ROOT_CAUSE); - for (BaseOpenSearchException rootCause : rootCauses) { - builder.startObject(); - rootCause.toXContent( - builder, - new ToXContent.DelegatingMapParams(singletonMap(BaseExceptionsHelper.REST_EXCEPTION_SKIP_CAUSE, "true"), params) - ); - builder.endObject(); - } - builder.endArray(); - } - BaseExceptionsHelper.generateThrowableXContent(builder, params, e); - builder.endObject(); - } - - /** - * Returns the root cause of this exception or multiple if different shards caused different exceptions. - * If the given exception is not an instance of {@link BaseOpenSearchException} an empty array - * is returned. - */ - public static BaseOpenSearchException[] guessRootCauses(Throwable t) { - Throwable ex = BaseExceptionsHelper.unwrapCause(t); - if (ex instanceof BaseOpenSearchException) { - // OpenSearchException knows how to guess its own root cause - return ((BaseOpenSearchException) ex).guessRootCauses(); - } - if (ex instanceof XContentParseException) { - /* - * We'd like to unwrap parsing exceptions to the inner-most - * parsing exception because that is generally the most interesting - * exception to return to the user. If that exception is caused by - * an OpenSearchException we'd like to keep unwrapping because - * OpenSearchException instances tend to contain useful information - * for the user. - */ - Throwable cause = ex.getCause(); - if (cause != null) { - if (cause instanceof XContentParseException || cause instanceof BaseOpenSearchException) { - return BaseOpenSearchException.guessRootCauses(ex.getCause()); - } - } - } - return new BaseOpenSearchException[] { new BaseOpenSearchException(ex.getMessage(), ex) { - @Override - protected String getExceptionName() { - return BaseExceptionsHelper.getExceptionName(getCause()); - } - } }; - } - - static String buildMessage(String type, String reason, String stack) { - StringBuilder message = new StringBuilder("OpenSearch exception ["); - message.append(BaseExceptionsHelper.TYPE).append('=').append(type).append(", "); - message.append(BaseExceptionsHelper.REASON).append('=').append(reason); - if (stack != null) { - message.append(", ").append(BaseExceptionsHelper.STACK_TRACE).append('=').append(stack); - } - message.append(']'); - return message.toString(); - } - - /** - * Adds a new piece of metadata with the given key. - * If the provided key is already present, the corresponding metadata will be replaced - */ - public void addMetadata(String key, String... values) { - addMetadata(key, Arrays.asList(values)); - } - - /** - * Adds a new piece of metadata with the given key. - * If the provided key is already present, the corresponding metadata will be replaced - */ - public void addMetadata(String key, List values) { - // we need to enforce this otherwise bw comp doesn't work properly, as "opensearch." - // was the previous criteria to split headers in two sets - if (key.startsWith(BaseExceptionsHelper.OPENSEARCH_PREFIX_KEY) == false) { - throw new IllegalArgumentException("exception metadata must start with [opensearch.], found [" + key + "] instead"); - } - this.metadata.put(key, values); - } - - /** - * Returns a set of all metadata keys on this exception - */ - public Set getMetadataKeys() { - return metadata.keySet(); - } - - /** - * Returns the list of metadata values for the given key or {@code null} if no metadata for the - * given key exists. - */ - public List getMetadata(String key) { - return metadata.get(key); - } - - protected Map> getMetadata() { - return metadata; - } - - /** - * Adds a new header with the given key. - * This method will replace existing header if a header with the same key already exists - */ - public void addHeader(String key, List value) { - // we need to enforce this otherwise bw comp doesn't work properly, as "opensearch." - // was the previous criteria to split headers in two sets - if (key.startsWith(BaseExceptionsHelper.OPENSEARCH_PREFIX_KEY)) { - throw new IllegalArgumentException("exception headers must not start with [opensearch.], found [" + key + "] instead"); - } - this.headers.put(key, value); - } - - /** - * Adds a new header with the given key. - * This method will replace existing header if a header with the same key already exists - */ - public void addHeader(String key, String... value) { - addHeader(key, Arrays.asList(value)); - } - - /** - * Returns a set of all header keys on this exception - */ - public Set getHeaderKeys() { - return headers.keySet(); - } - - /** - * Returns the list of header values for the given key or {@code null} if no header for the - * given key exists. - */ - public List getHeader(String key) { - return headers.get(key); - } - - protected Map> getHeaders() { - return headers; - } - - /** - * Unwraps the actual cause from the exception for cases when the exception is a - * {@link OpenSearchWrapperException}. - * - * @see BaseExceptionsHelper#unwrapCause(Throwable) - */ - public Throwable unwrapCause() { - return BaseExceptionsHelper.unwrapCause(this); - } - - /** - * Return the detail message, including the message from the nested exception - * if there is one. - */ - public String getDetailedMessage() { - if (getCause() != null) { - StringBuilder sb = new StringBuilder(); - sb.append(toString()).append("; "); - if (getCause() instanceof BaseOpenSearchException) { - sb.append(((BaseOpenSearchException) getCause()).getDetailedMessage()); - } else { - sb.append(getCause()); - } - return sb.toString(); - } else { - return toString(); - } - } - - /** - * Retrieve the innermost cause of this exception, if none, returns the current exception. - */ - public Throwable getRootCause() { - Throwable rootCause = this; - Throwable cause = getCause(); - while (cause != null && cause != rootCause) { - rootCause = cause; - cause = cause.getCause(); - } - return rootCause; - } - - /** - * Renders additional per exception information into the XContent - */ - protected void metadataToXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {} - - public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException { - Throwable ex = BaseExceptionsHelper.unwrapCause(this); - if (ex != this) { - BaseExceptionsHelper.generateThrowableXContent(builder, params, this); - } else { - BaseExceptionsHelper.innerToXContent(builder, params, this, getExceptionName(), getMessage(), headers, metadata, getCause()); - } - return builder; - } - - protected String getExceptionName() { - return BaseExceptionsHelper.getExceptionName(this); - } - - /** - * Returns the root cause of this exception or multiple if different shards caused different exceptions - */ - public BaseOpenSearchException[] guessRootCauses() { - final Throwable cause = getCause(); - if (cause != null && cause instanceof BaseOpenSearchException) { - return ((BaseOpenSearchException) cause).guessRootCauses(); - } - return new BaseOpenSearchException[] { this }; - } - - public void setResources(String type, String... id) { - assert type != null; - addMetadata(RESOURCE_METADATA_ID_KEY, id); - addMetadata(RESOURCE_METADATA_TYPE_KEY, type); - } - - public List getResourceId() { - return getMetadata(RESOURCE_METADATA_ID_KEY); - } - - public String getResourceType() { - List header = getMetadata(RESOURCE_METADATA_TYPE_KEY); - if (header != null && header.isEmpty() == false) { - assert header.size() == 1; - return header.get(0); - } - return null; - } - - public String getIndexName() { - List index = getMetadata(INDEX_METADATA_KEY); - if (index != null && index.isEmpty() == false) { - return index.get(0); - } - return null; - } - - /** - * Get index uuid as a string - * - * @deprecated remove in favor of Index#toString once Index class is moved to core library - */ - @Deprecated - private String getIndexUUID() { - List index_uuid = getMetadata(INDEX_METADATA_KEY_UUID); - if (index_uuid != null && index_uuid.isEmpty() == false) { - return index_uuid.get(0); - } - return null; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - if (metadata.containsKey(INDEX_METADATA_KEY)) { - builder.append(getIndexString()); - if (metadata.containsKey(SHARD_METADATA_KEY)) { - builder.append('[').append(getShardIdString()).append(']'); - } - builder.append(' '); - } - return builder.append(BaseExceptionsHelper.detailedMessage(this).trim()).toString(); - } - - /** - * Get index string - * - * @deprecated remove in favor of Index#toString once Index class is moved to core library - */ - @Deprecated - private String getIndexString() { - String uuid = getIndexUUID(); - if (uuid != null) { - String name = getIndexName(); - if (Strings.UNKNOWN_UUID_VALUE.equals(uuid)) { - return "[" + name + "]"; - } - return "[" + name + "/" + uuid + "]"; - } - return null; - } - - /** - * Get shard id string - * - * @deprecated remove in favor of ShardId#toString once ShardId class is moved to core library - */ - @Deprecated - private String getShardIdString() { - String indexName = getIndexName(); - List shard = getMetadata(SHARD_METADATA_KEY); - if (indexName != null && shard != null && shard.isEmpty() == false) { - return "[" + indexName + "][" + Integer.parseInt(shard.get(0)) + "]"; - } - return null; - } - - /** - * An ExceptionHandle for registering Exceptions that can be serialized over the transport wire - * - * @opensearch.internal - */ - protected static abstract class BaseOpenSearchExceptionHandle { - final Class exceptionClass; - final CheckedFunction constructor; - final int id; - final Version versionAdded; - - BaseOpenSearchExceptionHandle( - Class exceptionClass, - CheckedFunction constructor, - int id, - Version versionAdded - ) { - // We need the exceptionClass because you can't dig it out of the constructor reliably. - this.exceptionClass = exceptionClass; - this.constructor = constructor; - this.versionAdded = versionAdded; - this.id = id; - } - } - - @SuppressWarnings("unchecked") - public static BaseOpenSearchException readException(T input, int id) throws IOException { - CheckedFunction opensearchException = (CheckedFunction< - T, - ? extends BaseOpenSearchException, - IOException>) OpenSearchExceptionHandleRegistry.getSupplier(id); - if (opensearchException == null) { - throw new IllegalStateException("unknown exception for id: " + id); - } - return opensearchException.apply(input); - } - - /** - * Registry of ExceptionHandlers - * - * @opensearch.internal - */ - public static class OpenSearchExceptionHandleRegistry { - /** Registry mapping from unique Ordinal to the Exception Constructor */ - private static final Map< - Integer, - CheckedFunction> ID_TO_SUPPLIER_REGISTRY = - new ConcurrentHashMap<>(); - /** Registry mapping from Exception class to the Exception Handler */ - private static final Map< - Class, - BaseOpenSearchExceptionHandle> CLASS_TO_OPENSEARCH_EXCEPTION_HANDLE_REGISTRY = new ConcurrentHashMap<>(); - - /** returns the Exception constructor function from a given ordinal */ - public static CheckedFunction getSupplier(final int id) { - return ID_TO_SUPPLIER_REGISTRY.get(id); - } - - /** registers the Exception handler */ - public static void registerExceptionHandle(final BaseOpenSearchExceptionHandle handle) { - ID_TO_SUPPLIER_REGISTRY.put(handle.id, handle.constructor); - CLASS_TO_OPENSEARCH_EXCEPTION_HANDLE_REGISTRY.put(handle.exceptionClass, handle); - } - - /** Gets the unique ordinal id of the Exception from the given class */ - public static int getId(final Class exception) { - return CLASS_TO_OPENSEARCH_EXCEPTION_HANDLE_REGISTRY.get(exception).id; - } - - /** returns a set of ids */ - public static Set ids() { - return ID_TO_SUPPLIER_REGISTRY.keySet(); - } - - /** returns a collection of handles */ - public static Collection handles() { - return CLASS_TO_OPENSEARCH_EXCEPTION_HANDLE_REGISTRY.values(); - } - - /** checks that the exception class is registered */ - public static boolean isRegistered(final Class exception, final Version version) { - BaseOpenSearchExceptionHandle openSearchExceptionHandle = CLASS_TO_OPENSEARCH_EXCEPTION_HANDLE_REGISTRY.get(exception); - if (openSearchExceptionHandle != null) { - return version.onOrAfter(openSearchExceptionHandle.versionAdded); - } - return false; - } - - /** returns a set of registered exception classes */ - public static Set> getRegisteredKeys() { // for testing - return CLASS_TO_OPENSEARCH_EXCEPTION_HANDLE_REGISTRY.keySet(); - } - } -} diff --git a/server/src/main/java/org/opensearch/ExceptionsHelper.java b/libs/core/src/main/java/org/opensearch/ExceptionsHelper.java similarity index 81% rename from server/src/main/java/org/opensearch/ExceptionsHelper.java rename to libs/core/src/main/java/org/opensearch/ExceptionsHelper.java index 3d82070d351dc..239ebba28828f 100644 --- a/server/src/main/java/org/opensearch/ExceptionsHelper.java +++ b/libs/core/src/main/java/org/opensearch/ExceptionsHelper.java @@ -33,6 +33,8 @@ package org.opensearch; import com.fasterxml.jackson.core.JsonParseException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.IndexFormatTooNewException; import org.apache.lucene.index.IndexFormatTooOldException; @@ -45,6 +47,8 @@ import org.opensearch.rest.RestStatus; import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -59,12 +63,18 @@ import java.util.function.Predicate; import java.util.stream.Collectors; +import static org.opensearch.OpenSearchException.getExceptionSimpleClassName; + /** * Helper class for OpenSearch Exceptions * * @opensearch.internal */ -public final class ExceptionsHelper extends BaseExceptionsHelper { +public final class ExceptionsHelper { + private static final Logger logger = LogManager.getLogger(ExceptionsHelper.class); + + // utility class: no ctor + private ExceptionsHelper() {} public static RuntimeException convertToRuntime(Exception e) { if (e instanceof RuntimeException) { @@ -95,6 +105,77 @@ public static RestStatus status(Throwable t) { return RestStatus.INTERNAL_SERVER_ERROR; } + public static String summaryMessage(Throwable t) { + if (t != null) { + if (t instanceof OpenSearchException) { + return getExceptionSimpleClassName(t) + "[" + t.getMessage() + "]"; + } else if (t instanceof IllegalArgumentException) { + return "Invalid argument"; + } else if (t instanceof JsonParseException) { + return "Failed to parse JSON"; + } else if (t instanceof OpenSearchRejectedExecutionException) { + return "Too many requests"; + } + } + return "Internal failure"; + } + + public static Throwable unwrapCause(Throwable t) { + int counter = 0; + Throwable result = t; + while (result instanceof OpenSearchWrapperException) { + if (result.getCause() == null) { + return result; + } + if (result.getCause() == result) { + return result; + } + if (counter++ > 10) { + // dear god, if we got more than 10 levels down, WTF? just bail + logger.warn("Exception cause unwrapping ran for 10 levels...", t); + return result; + } + result = result.getCause(); + } + return result; + } + + /** + * @deprecated Don't swallow exceptions, allow them to propagate. + */ + @Deprecated + public static String detailedMessage(Throwable t) { + if (t == null) { + return "Unknown"; + } + if (t.getCause() != null) { + StringBuilder sb = new StringBuilder(); + while (t != null) { + sb.append(getExceptionSimpleClassName(t)); + if (t.getMessage() != null) { + sb.append("["); + sb.append(t.getMessage()); + sb.append("]"); + } + sb.append("; "); + t = t.getCause(); + if (t != null) { + sb.append("nested: "); + } + } + return sb.toString(); + } else { + return getExceptionSimpleClassName(t) + "[" + t.getMessage() + "]"; + } + } + + public static String stackTrace(Throwable e) { + StringWriter stackTraceStringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stackTraceStringWriter); + e.printStackTrace(printWriter); + return stackTraceStringWriter.toString(); + } + public static String formatStackTrace(final StackTraceElement[] stackTrace) { return Arrays.stream(stackTrace).skip(1).map(e -> "\tat " + e).collect(Collectors.joining("\n")); } diff --git a/libs/core/src/main/java/org/opensearch/OpenSearchException.java b/libs/core/src/main/java/org/opensearch/OpenSearchException.java new file mode 100644 index 0000000000000..707b53dfa58f9 --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/OpenSearchException.java @@ -0,0 +1,980 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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. + */ + +/* + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ +package org.opensearch; + +import org.opensearch.common.CheckedFunction; +import org.opensearch.common.Nullable; +import org.opensearch.common.collect.Tuple; +import org.opensearch.common.io.stream.StreamInput; +import org.opensearch.common.io.stream.StreamOutput; +import org.opensearch.common.io.stream.Writeable; +import org.opensearch.core.ParseField; +import org.opensearch.core.common.Strings; +import org.opensearch.core.common.logging.LoggerMessageFormat; +import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.core.xcontent.ToXContentFragment; +import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.core.xcontent.XContentParseException; +import org.opensearch.core.xcontent.XContentParser; +import org.opensearch.index.Index; +import org.opensearch.index.shard.ShardId; +import org.opensearch.rest.RestStatus; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import static java.util.Collections.emptyMap; +import static org.opensearch.OpenSearchException.OpenSearchExceptionHandleRegistry.registerExceptionHandle; +import static org.opensearch.common.xcontent.XContentParserUtils.ensureExpectedToken; +import static org.opensearch.common.xcontent.XContentParserUtils.ensureFieldName; + +import static java.util.Collections.singletonMap; + +/** + * A core library base class for all opensearch exceptions. + * + * @opensearch.internal + */ +public class OpenSearchException extends RuntimeException implements Writeable, ToXContentFragment { + + protected static final Version UNKNOWN_VERSION_ADDED = Version.fromId(0); + + /** + * Passed in the {@link ToXContent.Params} of {@link #generateThrowableXContent(XContentBuilder, ToXContent.Params, Throwable)} + * to control if the {@code caused_by} element should render. Unlike most parameters to {@code toXContent} methods this parameter is + * internal only and not available as a URL parameter. + */ + private static final String REST_EXCEPTION_SKIP_CAUSE = "rest.exception.cause.skip"; + /** + * Passed in the {@link ToXContent.Params} of {@link #generateThrowableXContent(XContentBuilder, ToXContent.Params, Throwable)} + * to control if the {@code stack_trace} element should render. Unlike most parameters to {@code toXContent} methods this parameter is + * internal only and not available as a URL parameter. Use the {@code error_trace} parameter instead. + */ + public static final String REST_EXCEPTION_SKIP_STACK_TRACE = "rest.exception.stacktrace.skip"; + public static final boolean REST_EXCEPTION_SKIP_STACK_TRACE_DEFAULT = true; + private static final boolean REST_EXCEPTION_SKIP_CAUSE_DEFAULT = false; + private static final String RESOURCE_METADATA_TYPE_KEY = "opensearch.resource.type"; + private static final String RESOURCE_METADATA_ID_KEY = "opensearch.resource.id"; + private static final String INDEX_METADATA_KEY = "opensearch.index"; + private static final String INDEX_METADATA_KEY_UUID = "opensearch.index_uuid"; + private static final String SHARD_METADATA_KEY = "opensearch.shard"; + private static final String OPENSEARCH_PREFIX_KEY = "opensearch."; + + private static final String TYPE = "type"; + private static final String REASON = "reason"; + private static final String CAUSED_BY = "caused_by"; + private static final ParseField SUPPRESSED = new ParseField("suppressed"); + public static final String STACK_TRACE = "stack_trace"; + private static final String HEADER = "header"; + private static final String ERROR = "error"; + private static final String ROOT_CAUSE = "root_cause"; + + protected final Map> metadata = new HashMap<>(); + protected final Map> headers = new HashMap<>(); + + static { + registerExceptionHandle( + new OpenSearchExceptionHandle( + org.opensearch.index.snapshots.IndexShardSnapshotFailedException.class, + org.opensearch.index.snapshots.IndexShardSnapshotFailedException::new, + 0, + UNKNOWN_VERSION_ADDED + ) + ); + registerExceptionHandle( + new OpenSearchExceptionHandle( + org.opensearch.common.ParsingException.class, + org.opensearch.common.ParsingException::new, + 40, + UNKNOWN_VERSION_ADDED + ) + ); + registerExceptionHandle( + new OpenSearchExceptionHandle( + org.opensearch.common.io.stream.NotSerializableExceptionWrapper.class, + org.opensearch.common.io.stream.NotSerializableExceptionWrapper::new, + 62, + UNKNOWN_VERSION_ADDED + ) + ); + } + + /** + * Construct a OpenSearchException with the specified cause exception. + */ + public OpenSearchException(Throwable cause) { + super(cause); + } + + /** + * Construct a OpenSearchException with the specified detail message. + * + * The message can be parameterized using {} as placeholders for the given + * arguments + * + * @param msg the detail message + * @param args the arguments for the message + */ + public OpenSearchException(String msg, Object... args) { + super(LoggerMessageFormat.format(msg, args)); + } + + /** + * Construct a OpenSearchException with the specified detail message + * and nested exception. + * + * The message can be parameterized using {} as placeholders for the given + * arguments + * + * @param msg the detail message + * @param cause the nested exception + * @param args the arguments for the message + */ + public OpenSearchException(String msg, Throwable cause, Object... args) { + super(LoggerMessageFormat.format(msg, args), cause); + } + + public OpenSearchException(StreamInput in) throws IOException { + this(in.readOptionalString(), in.readException()); + readStackTrace(this, in); + headers.putAll(in.readMapOfLists(StreamInput::readString, StreamInput::readString)); + metadata.putAll(in.readMapOfLists(StreamInput::readString, StreamInput::readString)); + } + + @Override + public void writeTo(final StreamOutput out) throws IOException { + out.writeOptionalString(this.getMessage()); + out.writeException(this.getCause()); + writeStackTraces(this, out, StreamOutput::writeException); + out.writeMapOfLists(headers, StreamOutput::writeString, StreamOutput::writeString); + out.writeMapOfLists(metadata, StreamOutput::writeString, StreamOutput::writeString); + } + + /** + * Adds a new piece of metadata with the given key. + * If the provided key is already present, the corresponding metadata will be replaced + */ + public void addMetadata(String key, String... values) { + addMetadata(key, Arrays.asList(values)); + } + + /** + * Adds a new piece of metadata with the given key. + * If the provided key is already present, the corresponding metadata will be replaced + */ + public void addMetadata(String key, List values) { + // we need to enforce this otherwise bw comp doesn't work properly, as "opensearch." + // was the previous criteria to split headers in two sets + if (key.startsWith(OPENSEARCH_PREFIX_KEY) == false) { + throw new IllegalArgumentException("exception metadata must start with [opensearch.], found [" + key + "] instead"); + } + this.metadata.put(key, values); + } + + /** + * Returns a set of all metadata keys on this exception + */ + public Set getMetadataKeys() { + return metadata.keySet(); + } + + /** + * Returns the list of metadata values for the given key or {@code null} if no metadata for the + * given key exists. + */ + public List getMetadata(String key) { + return metadata.get(key); + } + + protected Map> getMetadata() { + return metadata; + } + + /** + * Adds a new header with the given key. + * This method will replace existing header if a header with the same key already exists + */ + public void addHeader(String key, List value) { + // we need to enforce this otherwise bw comp doesn't work properly, as "opensearch." + // was the previous criteria to split headers in two sets + if (key.startsWith(OPENSEARCH_PREFIX_KEY)) { + throw new IllegalArgumentException("exception headers must not start with [opensearch.], found [" + key + "] instead"); + } + this.headers.put(key, value); + } + + /** + * Adds a new header with the given key. + * This method will replace existing header if a header with the same key already exists + */ + public void addHeader(String key, String... value) { + addHeader(key, Arrays.asList(value)); + } + + /** + * Returns a set of all header keys on this exception + */ + public Set getHeaderKeys() { + return headers.keySet(); + } + + /** + * Returns the list of header values for the given key or {@code null} if no header for the + * given key exists. + */ + public List getHeader(String key) { + return headers.get(key); + } + + protected Map> getHeaders() { + return headers; + } + + /** + * Returns the rest status code associated with this exception. + */ + public RestStatus status() { + Throwable cause = unwrapCause(); + if (cause == this) { + return RestStatus.INTERNAL_SERVER_ERROR; + } else { + return ExceptionsHelper.status(cause); + } + } + + /** + * Unwraps the actual cause from the exception for cases when the exception is a + * {@link OpenSearchWrapperException}. + * + * @see ExceptionsHelper#unwrapCause(Throwable) + */ + public Throwable unwrapCause() { + return ExceptionsHelper.unwrapCause(this); + } + + /** + * Return the detail message, including the message from the nested exception + * if there is one. + */ + public String getDetailedMessage() { + if (getCause() != null) { + StringBuilder sb = new StringBuilder(); + sb.append(toString()).append("; "); + if (getCause() instanceof OpenSearchException) { + sb.append(((OpenSearchException) getCause()).getDetailedMessage()); + } else { + sb.append(getCause()); + } + return sb.toString(); + } else { + return toString(); + } + } + + /** + * Retrieve the innermost cause of this exception, if none, returns the current exception. + */ + public Throwable getRootCause() { + Throwable rootCause = this; + Throwable cause = getCause(); + while (cause != null && cause != rootCause) { + rootCause = cause; + cause = cause.getCause(); + } + return rootCause; + } + + @SuppressWarnings("unchecked") + public static OpenSearchException readException(T input, int id) throws IOException { + CheckedFunction opensearchException = (CheckedFunction< + T, + ? extends OpenSearchException, + IOException>) OpenSearchExceptionHandleRegistry.getSupplier(id); + if (opensearchException == null) { + throw new IllegalStateException("unknown exception for id: " + id); + } + return opensearchException.apply(input); + } + + /** + * Returns true iff the given class is a registered for an exception to be read. + */ + public static boolean isRegistered(final Class exception, Version version) { + return OpenSearchExceptionHandleRegistry.isRegistered(exception, version); + } + + static Set> getRegisteredKeys() { // for testing + return OpenSearchExceptionHandleRegistry.getRegisteredKeys(); + } + + /** + * Returns the serialization id the given exception. + */ + public static int getId(final Class exception) { + return OpenSearchExceptionHandleRegistry.getId(exception); + } + + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + Throwable ex = ExceptionsHelper.unwrapCause(this); + if (ex != this) { + generateThrowableXContent(builder, params, this); + } else { + innerToXContent(builder, params, this, getExceptionName(), getMessage(), headers, metadata, getCause()); + } + return builder; + } + + protected static void innerToXContent( + XContentBuilder builder, + ToXContent.Params params, + Throwable throwable, + String type, + String message, + Map> headers, + Map> metadata, + Throwable cause + ) throws IOException { + builder.field(TYPE, type); + builder.field(REASON, message); + + for (Map.Entry> entry : metadata.entrySet()) { + headerToXContent(builder, entry.getKey().substring(OPENSEARCH_PREFIX_KEY.length()), entry.getValue()); + } + + if (throwable instanceof OpenSearchException) { + OpenSearchException exception = (OpenSearchException) throwable; + exception.metadataToXContent(builder, params); + } + + if (params.paramAsBoolean(REST_EXCEPTION_SKIP_CAUSE, REST_EXCEPTION_SKIP_CAUSE_DEFAULT) == false) { + if (cause != null) { + builder.field(CAUSED_BY); + builder.startObject(); + generateThrowableXContent(builder, params, cause); + builder.endObject(); + } + } + + if (headers.isEmpty() == false) { + builder.startObject(HEADER); + for (Map.Entry> entry : headers.entrySet()) { + headerToXContent(builder, entry.getKey(), entry.getValue()); + } + builder.endObject(); + } + + if (params.paramAsBoolean(REST_EXCEPTION_SKIP_STACK_TRACE, REST_EXCEPTION_SKIP_STACK_TRACE_DEFAULT) == false) { + builder.field(STACK_TRACE, ExceptionsHelper.stackTrace(throwable)); + } + + Throwable[] allSuppressed = throwable.getSuppressed(); + if (allSuppressed.length > 0) { + builder.startArray(SUPPRESSED.getPreferredName()); + for (Throwable suppressed : allSuppressed) { + builder.startObject(); + generateThrowableXContent(builder, params, suppressed); + builder.endObject(); + } + builder.endArray(); + } + } + + protected static void headerToXContent(XContentBuilder builder, String key, List values) throws IOException { + if (values != null && values.isEmpty() == false) { + if (values.size() == 1) { + builder.field(key, values.get(0)); + } else { + builder.startArray(key); + for (String value : values) { + builder.value(value); + } + builder.endArray(); + } + } + } + + /** + * Renders additional per exception information into the XContent + */ + protected void metadataToXContent(XContentBuilder builder, Params params) throws IOException {} + + /** + * Generate a {@link OpenSearchException} from a {@link XContentParser}. This does not + * return the original exception type (ie NodeClosedException for example) but just wraps + * the type, the reason and the cause of the exception. It also recursively parses the + * tree structure of the cause, returning it as a tree structure of {@link OpenSearchException} + * instances. + */ + public static OpenSearchException fromXContent(XContentParser parser) throws IOException { + XContentParser.Token token = parser.nextToken(); + ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser); + return innerFromXContent(parser, false); + } + + public static OpenSearchException innerFromXContent(XContentParser parser, boolean parseRootCauses) throws IOException { + XContentParser.Token token = parser.currentToken(); + ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser); + + String type = null, reason = null, stack = null; + OpenSearchException cause = null; + Map> metadata = new HashMap<>(); + Map> headers = new HashMap<>(); + List rootCauses = new ArrayList<>(); + List suppressed = new ArrayList<>(); + + for (; token == XContentParser.Token.FIELD_NAME; token = parser.nextToken()) { + String currentFieldName = parser.currentName(); + token = parser.nextToken(); + + if (token.isValue()) { + if (TYPE.equals(currentFieldName)) { + type = parser.text(); + } else if (REASON.equals(currentFieldName)) { + reason = parser.text(); + } else if (STACK_TRACE.equals(currentFieldName)) { + stack = parser.text(); + } else if (token == XContentParser.Token.VALUE_STRING) { + metadata.put(currentFieldName, Collections.singletonList(parser.text())); + } + } else if (token == XContentParser.Token.START_OBJECT) { + if (CAUSED_BY.equals(currentFieldName)) { + cause = fromXContent(parser); + } else if (HEADER.equals(currentFieldName)) { + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + if (token == XContentParser.Token.FIELD_NAME) { + currentFieldName = parser.currentName(); + } else { + List values = headers.getOrDefault(currentFieldName, new ArrayList<>()); + if (token == XContentParser.Token.VALUE_STRING) { + values.add(parser.text()); + } else if (token == XContentParser.Token.START_ARRAY) { + while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { + if (token == XContentParser.Token.VALUE_STRING) { + values.add(parser.text()); + } else { + parser.skipChildren(); + } + } + } else if (token == XContentParser.Token.START_OBJECT) { + parser.skipChildren(); + } + headers.put(currentFieldName, values); + } + } + } else { + // Any additional metadata object added by the metadataToXContent method is ignored + // and skipped, so that the parser does not fail on unknown fields. The parser only + // support metadata key-pairs and metadata arrays of values. + parser.skipChildren(); + } + } else if (token == XContentParser.Token.START_ARRAY) { + if (parseRootCauses && ROOT_CAUSE.equals(currentFieldName)) { + while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { + rootCauses.add(fromXContent(parser)); + } + } else if (SUPPRESSED.match(currentFieldName, parser.getDeprecationHandler())) { + while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { + suppressed.add(fromXContent(parser)); + } + } else { + // Parse the array and add each item to the corresponding list of metadata. + // Arrays of objects are not supported yet and just ignored and skipped. + List values = new ArrayList<>(); + while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { + if (token == XContentParser.Token.VALUE_STRING) { + values.add(parser.text()); + } else { + parser.skipChildren(); + } + } + if (values.size() > 0) { + if (metadata.containsKey(currentFieldName)) { + values.addAll(metadata.get(currentFieldName)); + } + metadata.put(currentFieldName, values); + } + } + } + } + + OpenSearchException e = new OpenSearchException(buildMessage(type, reason, stack), cause) { + }; + for (Map.Entry> entry : metadata.entrySet()) { + // subclasses can print out additional metadata through the metadataToXContent method. Simple key-value pairs will be + // parsed back and become part of this metadata set, while objects and arrays are not supported when parsing back. + // Those key-value pairs become part of the metadata set and inherit the "opensearch." prefix as that is currently required + // by addMetadata. The prefix will get stripped out when printing metadata out so it will be effectively invisible. + // TODO move subclasses that print out simple metadata to using addMetadata directly and support also numbers and booleans. + // TODO rename metadataToXContent and have only SearchPhaseExecutionException use it, which prints out complex objects + e.addMetadata(OPENSEARCH_PREFIX_KEY + entry.getKey(), entry.getValue()); + } + for (Map.Entry> header : headers.entrySet()) { + e.addHeader(header.getKey(), header.getValue()); + } + + // Adds root causes as suppressed exception. This way they are not lost + // after parsing and can be retrieved using getSuppressed() method. + for (OpenSearchException rootCause : rootCauses) { + e.addSuppressed(rootCause); + } + for (OpenSearchException s : suppressed) { + e.addSuppressed(s); + } + return e; + } + + /** + * Static toXContent helper method that renders {@link OpenSearchException} or {@link Throwable} instances + * as XContent, delegating the rendering to {@link OpenSearchException#toXContent(XContentBuilder, ToXContent.Params)} + * or {@link #innerToXContent(XContentBuilder, ToXContent.Params, Throwable, String, String, Map, Map, Throwable)}. + * + * This method is usually used when the {@link Throwable} is rendered as a part of another XContent object, and its result can + * be parsed back using the {@code OpenSearchException.fromXContent(XContentParser)} method. + */ + public static void generateThrowableXContent(XContentBuilder builder, ToXContent.Params params, Throwable t) throws IOException { + t = ExceptionsHelper.unwrapCause(t); + + if (t instanceof OpenSearchException) { + ((OpenSearchException) t).toXContent(builder, params); + } else { + innerToXContent(builder, params, t, getExceptionName(t), t.getMessage(), emptyMap(), emptyMap(), t.getCause()); + } + } + + /** + * Render any exception as a xcontent, encapsulated within a field or object named "error". The level of details that are rendered + * depends on the value of the "detailed" parameter: when it's false only a simple message based on the type and message of the + * exception is rendered. When it's true all detail are provided including guesses root causes, cause and potentially stack + * trace. + * + * This method is usually used when the {@link Exception} is rendered as a full XContent object, and its output can be parsed + * by the {@code #OpenSearchException.failureFromXContent(XContentParser)} method. + */ + public static void generateFailureXContent(XContentBuilder builder, ToXContent.Params params, @Nullable Exception e, boolean detailed) + throws IOException { + // No exception to render as an error + if (e == null) { + builder.field(ERROR, "unknown"); + return; + } + + // Render the exception with a simple message + if (detailed == false) { + Throwable t = e; + for (int counter = 0; counter < 10 && t != null; counter++) { + if (t instanceof OpenSearchException) { + break; + } + t = t.getCause(); + } + builder.field(ERROR, ExceptionsHelper.summaryMessage(t != null ? t : e)); + return; + } + + // Render the exception with all details + final OpenSearchException[] rootCauses = OpenSearchException.guessRootCauses(e); + builder.startObject(ERROR); + { + builder.startArray(ROOT_CAUSE); + for (OpenSearchException rootCause : rootCauses) { + builder.startObject(); + rootCause.toXContent(builder, new ToXContent.DelegatingMapParams(singletonMap(REST_EXCEPTION_SKIP_CAUSE, "true"), params)); + builder.endObject(); + } + builder.endArray(); + } + generateThrowableXContent(builder, params, e); + builder.endObject(); + } + + /** + * Parses the output of {@link #generateFailureXContent(XContentBuilder, Params, Exception, boolean)} + */ + public static OpenSearchException failureFromXContent(XContentParser parser) throws IOException { + XContentParser.Token token = parser.currentToken(); + ensureFieldName(parser, token, ERROR); + + token = parser.nextToken(); + if (token.isValue()) { + return new OpenSearchException(buildMessage("exception", parser.text(), null)) { + }; + } + + ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser); + token = parser.nextToken(); + + // Root causes are parsed in the innerFromXContent() and are added as suppressed exceptions. + return innerFromXContent(parser, true); + } + + /** + * Returns the root cause of this exception or multiple if different shards caused different exceptions + */ + public OpenSearchException[] guessRootCauses() { + final Throwable cause = getCause(); + if (cause != null && cause instanceof OpenSearchException) { + return ((OpenSearchException) cause).guessRootCauses(); + } + return new OpenSearchException[] { this }; + } + + /** + * Returns the root cause of this exception or multiple if different shards caused different exceptions. + * If the given exception is not an instance of {@link OpenSearchException} an empty array + * is returned. + */ + public static OpenSearchException[] guessRootCauses(Throwable t) { + Throwable ex = ExceptionsHelper.unwrapCause(t); + if (ex instanceof OpenSearchException) { + // OpenSearchException knows how to guess its own root cause + return ((OpenSearchException) ex).guessRootCauses(); + } + if (ex instanceof XContentParseException) { + /* + * We'd like to unwrap parsing exceptions to the inner-most + * parsing exception because that is generally the most interesting + * exception to return to the user. If that exception is caused by + * an OpenSearchException we'd like to keep unwrapping because + * OpenSearchException instances tend to contain useful information + * for the user. + */ + Throwable cause = ex.getCause(); + if (cause != null) { + if (cause instanceof XContentParseException || cause instanceof OpenSearchException) { + return OpenSearchException.guessRootCauses(ex.getCause()); + } + } + } + return new OpenSearchException[] { new OpenSearchException(ex.getMessage(), ex) { + @Override + protected String getExceptionName() { + return getExceptionName(getCause()); + } + } }; + } + + protected String getExceptionName() { + return getExceptionName(this); + } + + /** + * Returns an underscore case name for the given exception. This method strips {@code OpenSearch} prefixes from exception names. + */ + public static String getExceptionName(Throwable ex) { + String simpleName = getExceptionSimpleClassName(ex); + if (simpleName.startsWith("OpenSearch")) { + simpleName = simpleName.substring("OpenSearch".length()); + } + // TODO: do we really need to make the exception name in underscore casing? + return toUnderscoreCase(simpleName); + } + + public static String getExceptionSimpleClassName(final Throwable ex) { + String simpleName = ex.getClass().getSimpleName(); + if (Strings.isEmpty(simpleName)) { + simpleName = "OpenSearchException"; + } + return simpleName; + } + + static String buildMessage(String type, String reason, String stack) { + StringBuilder message = new StringBuilder("OpenSearch exception ["); + message.append(TYPE).append('=').append(type).append(", "); + message.append(REASON).append('=').append(reason); + if (stack != null) { + message.append(", ").append(STACK_TRACE).append('=').append(stack); + } + message.append(']'); + return message.toString(); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + if (metadata.containsKey(INDEX_METADATA_KEY)) { + builder.append(getIndex()); + if (metadata.containsKey(SHARD_METADATA_KEY)) { + builder.append('[').append(getShardId()).append(']'); + } + builder.append(' '); + } + return builder.append(ExceptionsHelper.detailedMessage(this).trim()).toString(); + } + + /** + * Deserializes stacktrace elements as well as suppressed exceptions from the given output stream and + * adds it to the given exception. + */ + public static T readStackTrace(T throwable, StreamInput in) throws IOException { + throwable.setStackTrace(in.readArray(i -> { + final String declaringClasss = i.readString(); + final String fileName = i.readOptionalString(); + final String methodName = i.readString(); + final int lineNumber = i.readVInt(); + return new StackTraceElement(declaringClasss, methodName, fileName, lineNumber); + }, StackTraceElement[]::new)); + + int numSuppressed = in.readVInt(); + for (int i = 0; i < numSuppressed; i++) { + throwable.addSuppressed(in.readException()); + } + return throwable; + } + + /** + * Serializes the given exceptions stacktrace elements as well as it's suppressed exceptions to the given output stream. + */ + public static T writeStackTraces( + T throwable, + StreamOutput out, + Writer exceptionWriter + ) throws IOException { + out.writeArray((o, v) -> { + o.writeString(v.getClassName()); + o.writeOptionalString(v.getFileName()); + o.writeString(v.getMethodName()); + o.writeVInt(v.getLineNumber()); + }, throwable.getStackTrace()); + out.writeArray(exceptionWriter, throwable.getSuppressed()); + return throwable; + } + + public void setResources(String type, String... id) { + assert type != null; + addMetadata(RESOURCE_METADATA_ID_KEY, id); + addMetadata(RESOURCE_METADATA_TYPE_KEY, type); + } + + public List getResourceId() { + return getMetadata(RESOURCE_METADATA_ID_KEY); + } + + public String getResourceType() { + List header = getMetadata(RESOURCE_METADATA_TYPE_KEY); + if (header != null && header.isEmpty() == false) { + assert header.size() == 1; + return header.get(0); + } + return null; + } + + // lower cases and adds underscores to transitions in a name + private static String toUnderscoreCase(String value) { + StringBuilder sb = new StringBuilder(); + boolean changed = false; + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + if (Character.isUpperCase(c)) { + if (!changed) { + // copy it over here + for (int j = 0; j < i; j++) { + sb.append(value.charAt(j)); + } + changed = true; + if (i == 0) { + sb.append(Character.toLowerCase(c)); + } else { + sb.append('_'); + sb.append(Character.toLowerCase(c)); + } + } else { + sb.append('_'); + sb.append(Character.toLowerCase(c)); + } + } else { + if (changed) { + sb.append(c); + } + } + } + if (!changed) { + return value; + } + return sb.toString(); + } + + /** + * Returns an array of all registered handle IDs. These are the IDs for every registered + * exception. + * + * @return an array of all registered handle IDs + */ + static int[] ids() { + return OpenSearchExceptionHandleRegistry.ids().stream().mapToInt(i -> i).toArray(); + } + + /** + * Returns an array of all registered pairs of handle IDs and exception classes. These pairs are + * provided for every registered exception. + * + * @return an array of all registered pairs of handle IDs and exception classes + */ + @SuppressWarnings("unchecked") + static Tuple>[] classes() { + final Tuple>[] ts = OpenSearchExceptionHandleRegistry.handles() + .stream() + .map(h -> Tuple.tuple(h.id, h.exceptionClass)) + .toArray(Tuple[]::new); + return ts; + } + + public Index getIndex() { + List index = getMetadata(INDEX_METADATA_KEY); + if (index != null && index.isEmpty() == false) { + List index_uuid = getMetadata(INDEX_METADATA_KEY_UUID); + return new Index(index.get(0), index_uuid.get(0)); + } + + return null; + } + + public void setIndex(Index index) { + if (index != null) { + addMetadata(INDEX_METADATA_KEY, index.getName()); + addMetadata(INDEX_METADATA_KEY_UUID, index.getUUID()); + } + } + + public void setIndex(String index) { + if (index != null) { + setIndex(new Index(index, Strings.UNKNOWN_UUID_VALUE)); + } + } + + public ShardId getShardId() { + List shard = getMetadata(SHARD_METADATA_KEY); + if (shard != null && shard.isEmpty() == false) { + return new ShardId(getIndex(), Integer.parseInt(shard.get(0))); + } + return null; + } + + public void setShard(ShardId shardId) { + if (shardId != null) { + setIndex(shardId.getIndex()); + addMetadata(SHARD_METADATA_KEY, Integer.toString(shardId.id())); + } + } + + /** + * This is the list of Exceptions OpenSearch can throw over the wire or save into a corruption marker. Each value in the enum is a + * single exception tying the Class to an id for use of the encode side and the id back to a constructor for use on the decode side. As + * such its ok if the exceptions to change names so long as their constructor can still read the exception. Each exception is listed + * in id order. If you want to remove an exception leave a tombstone comment and mark the id as null in + * ExceptionSerializationTests.testIds.ids. + * + * @opensearch.internal + */ + protected static class OpenSearchExceptionHandle { + final Class exceptionClass; + final CheckedFunction constructor; + final int id; + final Version versionAdded; + + OpenSearchExceptionHandle( + Class exceptionClass, + CheckedFunction constructor, + int id, + Version versionAdded + ) { + // We need the exceptionClass because you can't dig it out of the constructor reliably. + this.exceptionClass = exceptionClass; + this.constructor = constructor; + this.versionAdded = versionAdded; + this.id = id; + } + } + + /** + * Registry of ExceptionHandlers + * + * @opensearch.internal + */ + public static class OpenSearchExceptionHandleRegistry { + /** Registry mapping from unique Ordinal to the Exception Constructor */ + private static final Map< + Integer, + CheckedFunction> ID_TO_SUPPLIER_REGISTRY = new ConcurrentHashMap<>(); + /** Registry mapping from Exception class to the Exception Handler */ + private static final Map< + Class, + OpenSearchExceptionHandle> CLASS_TO_OPENSEARCH_EXCEPTION_HANDLE_REGISTRY = new ConcurrentHashMap<>(); + + /** returns the Exception constructor function from a given ordinal */ + public static CheckedFunction getSupplier(final int id) { + return ID_TO_SUPPLIER_REGISTRY.get(id); + } + + /** registers the Exception handler */ + public static void registerExceptionHandle(final OpenSearchExceptionHandle handle) { + ID_TO_SUPPLIER_REGISTRY.put(handle.id, handle.constructor); + CLASS_TO_OPENSEARCH_EXCEPTION_HANDLE_REGISTRY.put(handle.exceptionClass, handle); + } + + /** Gets the unique ordinal id of the Exception from the given class */ + public static int getId(final Class exception) { + return CLASS_TO_OPENSEARCH_EXCEPTION_HANDLE_REGISTRY.get(exception).id; + } + + /** returns a set of ids */ + public static Set ids() { + return ID_TO_SUPPLIER_REGISTRY.keySet(); + } + + /** returns a collection of handles */ + public static Collection handles() { + return CLASS_TO_OPENSEARCH_EXCEPTION_HANDLE_REGISTRY.values(); + } + + /** checks that the exception class is registered */ + public static boolean isRegistered(final Class exception, final Version version) { + OpenSearchExceptionHandle openSearchExceptionHandle = CLASS_TO_OPENSEARCH_EXCEPTION_HANDLE_REGISTRY.get(exception); + if (openSearchExceptionHandle != null) { + return version.onOrAfter(openSearchExceptionHandle.versionAdded); + } + return false; + } + + /** returns a set of registered exception classes */ + public static Set> getRegisteredKeys() { // for testing + return CLASS_TO_OPENSEARCH_EXCEPTION_HANDLE_REGISTRY.keySet(); + } + } +} diff --git a/server/src/main/java/org/opensearch/action/ShardOperationFailedException.java b/libs/core/src/main/java/org/opensearch/action/ShardOperationFailedException.java similarity index 100% rename from server/src/main/java/org/opensearch/action/ShardOperationFailedException.java rename to libs/core/src/main/java/org/opensearch/action/ShardOperationFailedException.java diff --git a/libs/core/src/main/java/org/opensearch/action/package-info.java b/libs/core/src/main/java/org/opensearch/action/package-info.java new file mode 100644 index 0000000000000..a7b89f63a6217 --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/action/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Core action module */ +package org.opensearch.action; diff --git a/server/src/main/java/org/opensearch/action/support/DefaultShardOperationFailedException.java b/libs/core/src/main/java/org/opensearch/action/support/DefaultShardOperationFailedException.java similarity index 97% rename from server/src/main/java/org/opensearch/action/support/DefaultShardOperationFailedException.java rename to libs/core/src/main/java/org/opensearch/action/support/DefaultShardOperationFailedException.java index 35334cbbad801..5a7e48a5efef7 100644 --- a/server/src/main/java/org/opensearch/action/support/DefaultShardOperationFailedException.java +++ b/libs/core/src/main/java/org/opensearch/action/support/DefaultShardOperationFailedException.java @@ -32,9 +32,8 @@ package org.opensearch.action.support; -import org.opensearch.BaseExceptionsHelper; -import org.opensearch.OpenSearchException; import org.opensearch.ExceptionsHelper; +import org.opensearch.OpenSearchException; import org.opensearch.action.ShardOperationFailedException; import org.opensearch.core.ParseField; import org.opensearch.common.io.stream.StreamInput; @@ -48,6 +47,7 @@ import java.io.IOException; import static org.opensearch.ExceptionsHelper.detailedMessage; +import static org.opensearch.OpenSearchException.generateThrowableXContent; import static org.opensearch.core.xcontent.ConstructingObjectParser.constructorArg; /** @@ -136,7 +136,7 @@ protected XContentBuilder innerToXContent(XContentBuilder builder, Params params builder.field("status", status.name()); if (reason != null) { builder.startObject("reason"); - BaseExceptionsHelper.generateThrowableXContent(builder, params, cause); + generateThrowableXContent(builder, params, cause); builder.endObject(); } return builder; diff --git a/libs/core/src/main/java/org/opensearch/action/support/package-info.java b/libs/core/src/main/java/org/opensearch/action/support/package-info.java new file mode 100644 index 0000000000000..6665904e2b318 --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/action/support/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Support classes for core action module */ +package org.opensearch.action.support; diff --git a/server/src/main/java/org/opensearch/common/ParsingException.java b/libs/core/src/main/java/org/opensearch/common/ParsingException.java similarity index 100% rename from server/src/main/java/org/opensearch/common/ParsingException.java rename to libs/core/src/main/java/org/opensearch/common/ParsingException.java diff --git a/server/src/main/java/org/opensearch/common/bytes/AbstractBytesReference.java b/libs/core/src/main/java/org/opensearch/common/bytes/AbstractBytesReference.java similarity index 100% rename from server/src/main/java/org/opensearch/common/bytes/AbstractBytesReference.java rename to libs/core/src/main/java/org/opensearch/common/bytes/AbstractBytesReference.java diff --git a/server/src/main/java/org/opensearch/common/bytes/BytesArray.java b/libs/core/src/main/java/org/opensearch/common/bytes/BytesArray.java similarity index 100% rename from server/src/main/java/org/opensearch/common/bytes/BytesArray.java rename to libs/core/src/main/java/org/opensearch/common/bytes/BytesArray.java diff --git a/server/src/main/java/org/opensearch/common/bytes/BytesReference.java b/libs/core/src/main/java/org/opensearch/common/bytes/BytesReference.java similarity index 100% rename from server/src/main/java/org/opensearch/common/bytes/BytesReference.java rename to libs/core/src/main/java/org/opensearch/common/bytes/BytesReference.java diff --git a/server/src/main/java/org/opensearch/common/bytes/CompositeBytesReference.java b/libs/core/src/main/java/org/opensearch/common/bytes/CompositeBytesReference.java similarity index 100% rename from server/src/main/java/org/opensearch/common/bytes/CompositeBytesReference.java rename to libs/core/src/main/java/org/opensearch/common/bytes/CompositeBytesReference.java diff --git a/server/src/main/java/org/opensearch/common/bytes/PagedBytesReference.java b/libs/core/src/main/java/org/opensearch/common/bytes/PagedBytesReference.java similarity index 94% rename from server/src/main/java/org/opensearch/common/bytes/PagedBytesReference.java rename to libs/core/src/main/java/org/opensearch/common/bytes/PagedBytesReference.java index b7439853f11ba..9d432bc6fdd8c 100644 --- a/server/src/main/java/org/opensearch/common/bytes/PagedBytesReference.java +++ b/libs/core/src/main/java/org/opensearch/common/bytes/PagedBytesReference.java @@ -35,7 +35,6 @@ import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRefIterator; import org.opensearch.common.util.ByteArray; -import org.opensearch.common.util.PageCacheRecycler; import java.io.IOException; @@ -47,7 +46,7 @@ */ public class PagedBytesReference extends AbstractBytesReference { - private static final int PAGE_SIZE = PageCacheRecycler.BYTE_PAGE_SIZE; + public static final int PAGE_SIZE_IN_BYTES = 1 << 14; private final ByteArray byteArray; private final int offset; @@ -95,7 +94,7 @@ public final BytesRefIterator iterator() { // we calculate the initial fragment size here to ensure that if this reference is a slice we are still page aligned // across the entire iteration. The first page is smaller if our offset != 0 then we start in the middle of the page // otherwise we iterate full pages until we reach the last chunk which also might end within a page. - final int initialFragmentSize = offset != 0 ? PAGE_SIZE - (offset % PAGE_SIZE) : PAGE_SIZE; + final int initialFragmentSize = offset != 0 ? PAGE_SIZE_IN_BYTES - (offset % PAGE_SIZE_IN_BYTES) : PAGE_SIZE_IN_BYTES; return new BytesRefIterator() { int position = 0; int nextFragmentSize = Math.min(length, initialFragmentSize); @@ -109,7 +108,7 @@ public BytesRef next() throws IOException { assert materialized == false : "iteration should be page aligned but array got materialized"; position += nextFragmentSize; final int remaining = length - position; - nextFragmentSize = Math.min(remaining, PAGE_SIZE); + nextFragmentSize = Math.min(remaining, PAGE_SIZE_IN_BYTES); return slice; } else { assert nextFragmentSize == 0 : "fragmentSize expected [0] but was: [" + nextFragmentSize + "]"; diff --git a/libs/core/src/main/java/org/opensearch/common/bytes/package-info.java b/libs/core/src/main/java/org/opensearch/common/bytes/package-info.java new file mode 100644 index 0000000000000..0644188656496 --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/common/bytes/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Classes for core Bytes module */ +package org.opensearch.common.bytes; diff --git a/server/src/main/java/org/opensearch/common/compress/NotXContentException.java b/libs/core/src/main/java/org/opensearch/common/compress/NotXContentException.java similarity index 100% rename from server/src/main/java/org/opensearch/common/compress/NotXContentException.java rename to libs/core/src/main/java/org/opensearch/common/compress/NotXContentException.java diff --git a/libs/core/src/main/java/org/opensearch/common/compress/package-info.java b/libs/core/src/main/java/org/opensearch/common/compress/package-info.java new file mode 100644 index 0000000000000..b3b2f2a2ec7ed --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/common/compress/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Classes for core compress module */ +package org.opensearch.common.compress; diff --git a/libs/core/src/main/java/org/opensearch/common/io/package-info.java b/libs/core/src/main/java/org/opensearch/common/io/package-info.java new file mode 100644 index 0000000000000..0d57efe860d09 --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/common/io/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Classes for core io module */ +package org.opensearch.common.io; diff --git a/server/src/main/java/org/opensearch/common/io/stream/BytesStream.java b/libs/core/src/main/java/org/opensearch/common/io/stream/BytesStream.java similarity index 100% rename from server/src/main/java/org/opensearch/common/io/stream/BytesStream.java rename to libs/core/src/main/java/org/opensearch/common/io/stream/BytesStream.java diff --git a/server/src/main/java/org/opensearch/common/io/stream/InputStreamStreamInput.java b/libs/core/src/main/java/org/opensearch/common/io/stream/InputStreamStreamInput.java similarity index 97% rename from server/src/main/java/org/opensearch/common/io/stream/InputStreamStreamInput.java rename to libs/core/src/main/java/org/opensearch/common/io/stream/InputStreamStreamInput.java index 991fd0fc09a9d..06e10c67cf972 100644 --- a/server/src/main/java/org/opensearch/common/io/stream/InputStreamStreamInput.java +++ b/libs/core/src/main/java/org/opensearch/common/io/stream/InputStreamStreamInput.java @@ -32,8 +32,6 @@ package org.opensearch.common.io.stream; -import org.opensearch.common.io.Streams; - import java.io.EOFException; import java.io.IOException; import java.io.InputStream; @@ -80,7 +78,7 @@ public byte readByte() throws IOException { @Override public void readBytes(byte[] b, int offset, int len) throws IOException { if (len < 0) throw new IndexOutOfBoundsException(); - final int read = Streams.readFully(is, b, offset, len); + final int read = is.readNBytes(b, offset, len); if (read != len) { throw new EOFException(); } diff --git a/server/src/main/java/org/opensearch/common/io/stream/NamedWriteable.java b/libs/core/src/main/java/org/opensearch/common/io/stream/NamedWriteable.java similarity index 100% rename from server/src/main/java/org/opensearch/common/io/stream/NamedWriteable.java rename to libs/core/src/main/java/org/opensearch/common/io/stream/NamedWriteable.java diff --git a/server/src/main/java/org/opensearch/common/io/stream/NamedWriteableRegistry.java b/libs/core/src/main/java/org/opensearch/common/io/stream/NamedWriteableRegistry.java similarity index 99% rename from server/src/main/java/org/opensearch/common/io/stream/NamedWriteableRegistry.java rename to libs/core/src/main/java/org/opensearch/common/io/stream/NamedWriteableRegistry.java index 0240d0a0a8bb3..985b2ad113f22 100644 --- a/server/src/main/java/org/opensearch/common/io/stream/NamedWriteableRegistry.java +++ b/libs/core/src/main/java/org/opensearch/common/io/stream/NamedWriteableRegistry.java @@ -92,6 +92,7 @@ public NamedWriteableRegistry(List entries) { Map, Map>> registry = new HashMap<>(); Map> readers = null; + @SuppressWarnings("rawtypes") Class currentCategory = null; for (Entry entry : entries) { if (currentCategory != entry.categoryClass) { diff --git a/server/src/main/java/org/opensearch/common/io/stream/NotSerializableExceptionWrapper.java b/libs/core/src/main/java/org/opensearch/common/io/stream/NotSerializableExceptionWrapper.java similarity index 93% rename from server/src/main/java/org/opensearch/common/io/stream/NotSerializableExceptionWrapper.java rename to libs/core/src/main/java/org/opensearch/common/io/stream/NotSerializableExceptionWrapper.java index 636df65b8c319..967957afc8c20 100644 --- a/server/src/main/java/org/opensearch/common/io/stream/NotSerializableExceptionWrapper.java +++ b/libs/core/src/main/java/org/opensearch/common/io/stream/NotSerializableExceptionWrapper.java @@ -32,9 +32,8 @@ package org.opensearch.common.io.stream; -import org.opensearch.BaseExceptionsHelper; -import org.opensearch.OpenSearchException; import org.opensearch.ExceptionsHelper; +import org.opensearch.OpenSearchException; import org.opensearch.rest.RestStatus; import java.io.IOException; @@ -54,8 +53,8 @@ public final class NotSerializableExceptionWrapper extends OpenSearchException { private final RestStatus status; public NotSerializableExceptionWrapper(Throwable other) { - super(BaseExceptionsHelper.getExceptionName(other) + ": " + other.getMessage(), other.getCause()); - this.name = BaseExceptionsHelper.getExceptionName(other); + super(OpenSearchException.getExceptionName(other) + ": " + other.getMessage(), other.getCause()); + this.name = OpenSearchException.getExceptionName(other); this.status = ExceptionsHelper.status(other); setStackTrace(other.getStackTrace()); for (Throwable otherSuppressed : other.getSuppressed()) { diff --git a/server/src/main/java/org/opensearch/common/io/stream/StreamInput.java b/libs/core/src/main/java/org/opensearch/common/io/stream/StreamInput.java similarity index 74% rename from server/src/main/java/org/opensearch/common/io/stream/StreamInput.java rename to libs/core/src/main/java/org/opensearch/common/io/stream/StreamInput.java index 7e0ef07c7e602..c6915ae1f45b0 100644 --- a/server/src/main/java/org/opensearch/common/io/stream/StreamInput.java +++ b/libs/core/src/main/java/org/opensearch/common/io/stream/StreamInput.java @@ -37,8 +37,10 @@ import org.apache.lucene.index.IndexFormatTooOldException; import org.apache.lucene.store.AlreadyClosedException; import org.apache.lucene.store.LockObtainFailedException; +import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.BitUtil; import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.CharsRef; import org.opensearch.Build; import org.opensearch.OpenSearchException; import org.opensearch.Version; @@ -50,8 +52,6 @@ import org.opensearch.common.text.Text; import org.opensearch.common.unit.TimeValue; import org.opensearch.core.common.Strings; -import org.opensearch.core.common.io.stream.BaseStreamInput; -import org.opensearch.core.common.io.stream.BaseWriteable; import org.opensearch.core.concurrency.OpenSearchRejectedExecutionException; import java.io.ByteArrayInputStream; @@ -59,6 +59,7 @@ import java.io.FileNotFoundException; import java.io.FilterInputStream; import java.io.IOException; +import java.io.InputStream; import java.math.BigInteger; import java.nio.file.AccessDeniedException; import java.nio.file.AtomicMoveNotSupportedException; @@ -82,6 +83,7 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -102,7 +104,37 @@ * * @opensearch.internal */ -public abstract class StreamInput extends BaseStreamInput { +public abstract class StreamInput extends InputStream { + + private Version version = Version.CURRENT; + + /** + * The version of the node on the other side of this stream. + */ + public Version getVersion() { + return this.version; + } + + /** + * Set the version of the node on the other side of this stream. + */ + public void setVersion(Version version) { + this.version = version; + } + + /** + * Reads and returns a single byte. + */ + public abstract byte readByte() throws IOException; + + /** + * Reads a specified number of bytes into an array at the specified offset. + * + * @param b the array to read bytes into + * @param offset the offset in the array to start storing bytes + * @param len the number of bytes to read + */ + public abstract void readBytes(byte[] b, int offset, int len) throws IOException; /** * Reads a bytes reference from this stream, might hold an actual reference to the underlying @@ -145,6 +177,10 @@ public BytesRef readBytesRef() throws IOException { return readBytesRef(length); } + public void readFully(byte[] b) throws IOException { + readBytes(b, 0, b.length); + } + public BytesRef readBytesRef(int length) throws IOException { if (length == 0) { return new BytesRef(); @@ -158,6 +194,47 @@ public short readShort() throws IOException { return (short) (((readByte() & 0xFF) << 8) | (readByte() & 0xFF)); } + /** + * Reads four bytes and returns an int. + */ + public int readInt() throws IOException { + return ((readByte() & 0xFF) << 24) | ((readByte() & 0xFF) << 16) | ((readByte() & 0xFF) << 8) | (readByte() & 0xFF); + } + + /** + * Reads an int stored in variable-length format. Reads between one and + * five bytes. Smaller values take fewer bytes. Negative numbers + * will always use all 5 bytes and are therefore better serialized + * using {@link #readInt} + */ + public int readVInt() throws IOException { + byte b = readByte(); + int i = b & 0x7F; + if ((b & 0x80) == 0) { + return i; + } + b = readByte(); + i |= (b & 0x7F) << 7; + if ((b & 0x80) == 0) { + return i; + } + b = readByte(); + i |= (b & 0x7F) << 14; + if ((b & 0x80) == 0) { + return i; + } + b = readByte(); + i |= (b & 0x7F) << 21; + if ((b & 0x80) == 0) { + return i; + } + b = readByte(); + if ((b & 0x80) != 0) { + throw new IOException("Invalid vInt ((" + Integer.toHexString(b) + " & 0x7f) << 28) | " + Integer.toHexString(i)); + } + return i | ((b & 0x7F) << 28); + } + /** * Reads an optional {@link Integer}. */ @@ -282,6 +359,14 @@ public Text readText() throws IOException { return new Text(readBytesReference(length)); } + @Nullable + public String readOptionalString() throws IOException { + if (readBoolean()) { + return readString(); + } + return null; + } + @Nullable public SecureString readOptionalSecureString() throws IOException { SecureString value = null; @@ -305,6 +390,157 @@ public Float readOptionalFloat() throws IOException { return null; } + @Nullable + public Integer readOptionalVInt() throws IOException { + if (readBoolean()) { + return readVInt(); + } + return null; + } + + // Maximum char-count to de-serialize via the thread-local CharsRef buffer + private static final int SMALL_STRING_LIMIT = 1024; + + // Reusable bytes for deserializing strings + private static final ThreadLocal stringReadBuffer = ThreadLocal.withInitial(() -> new byte[1024]); + + // Thread-local buffer for smaller strings + private static final ThreadLocal smallSpare = ThreadLocal.withInitial(() -> new CharsRef(SMALL_STRING_LIMIT)); + + // Larger buffer used for long strings that can't fit into the thread-local buffer + // We don't use a CharsRefBuilder since we exactly know the size of the character array up front + // this prevents calling grow for every character since we don't need this + private CharsRef largeSpare; + + public String readString() throws IOException { + final int charCount = readArraySize(); + final CharsRef charsRef; + if (charCount > SMALL_STRING_LIMIT) { + if (largeSpare == null) { + largeSpare = new CharsRef(ArrayUtil.oversize(charCount, Character.BYTES)); + } else if (largeSpare.chars.length < charCount) { + // we don't use ArrayUtils.grow since there is no need to copy the array + largeSpare.chars = new char[ArrayUtil.oversize(charCount, Character.BYTES)]; + } + charsRef = largeSpare; + } else { + charsRef = smallSpare.get(); + } + charsRef.length = charCount; + int charsOffset = 0; + int offsetByteArray = 0; + int sizeByteArray = 0; + int missingFromPartial = 0; + final byte[] byteBuffer = stringReadBuffer.get(); + final char[] charBuffer = charsRef.chars; + for (; charsOffset < charCount;) { + final int charsLeft = charCount - charsOffset; + int bufferFree = byteBuffer.length - sizeByteArray; + // Determine the minimum amount of bytes that are left in the string + final int minRemainingBytes; + if (missingFromPartial > 0) { + // One byte for each remaining char except for the already partially read char + minRemainingBytes = missingFromPartial + charsLeft - 1; + missingFromPartial = 0; + } else { + // Each char has at least a single byte + minRemainingBytes = charsLeft; + } + final int toRead; + if (bufferFree < minRemainingBytes) { + // We don't have enough space left in the byte array to read as much as we'd like to so we free up as many bytes in the + // buffer by moving unused bytes that didn't make up a full char in the last iteration to the beginning of the buffer, + // if there are any + if (offsetByteArray > 0) { + sizeByteArray = sizeByteArray - offsetByteArray; + switch (sizeByteArray) { // We only have 0, 1 or 2 => no need to bother with a native call to System#arrayCopy + case 1: + byteBuffer[0] = byteBuffer[offsetByteArray]; + break; + case 2: + byteBuffer[0] = byteBuffer[offsetByteArray]; + byteBuffer[1] = byteBuffer[offsetByteArray + 1]; + break; + } + assert sizeByteArray <= 2 : "We never copy more than 2 bytes here since a char is 3 bytes max"; + toRead = Math.min(bufferFree + offsetByteArray, minRemainingBytes); + offsetByteArray = 0; + } else { + toRead = bufferFree; + } + } else { + toRead = minRemainingBytes; + } + readBytes(byteBuffer, sizeByteArray, toRead); + sizeByteArray += toRead; + // As long as we at least have three bytes buffered we don't need to do any bounds checking when getting the next char since we + // read 3 bytes per char/iteration at most + for (; offsetByteArray < sizeByteArray - 2; offsetByteArray++) { + final int c = byteBuffer[offsetByteArray] & 0xff; + switch (c >> 4) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + charBuffer[charsOffset++] = (char) c; + break; + case 12: + case 13: + charBuffer[charsOffset++] = (char) ((c & 0x1F) << 6 | byteBuffer[++offsetByteArray] & 0x3F); + break; + case 14: + charBuffer[charsOffset++] = (char) ((c & 0x0F) << 12 | (byteBuffer[++offsetByteArray] & 0x3F) << 6 + | (byteBuffer[++offsetByteArray] & 0x3F)); + break; + default: + throwOnBrokenChar(c); + } + } + // try to extract chars from remaining bytes with bounds checks for multi-byte chars + final int bufferedBytesRemaining = sizeByteArray - offsetByteArray; + for (int i = 0; i < bufferedBytesRemaining; i++) { + final int c = byteBuffer[offsetByteArray] & 0xff; + switch (c >> 4) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + charBuffer[charsOffset++] = (char) c; + offsetByteArray++; + break; + case 12: + case 13: + missingFromPartial = 2 - (bufferedBytesRemaining - i); + if (missingFromPartial == 0) { + offsetByteArray++; + charBuffer[charsOffset++] = (char) ((c & 0x1F) << 6 | byteBuffer[offsetByteArray++] & 0x3F); + } + ++i; + break; + case 14: + missingFromPartial = 3 - (bufferedBytesRemaining - i); + ++i; + break; + default: + throwOnBrokenChar(c); + } + } + } + return charsRef.toString(); + } + + private static void throwOnBrokenChar(int c) throws IOException { + throw new IOException("Invalid string; unexpected character: " + c + " hex: " + Integer.toHexString(c)); + } + public SecureString readSecureString() throws IOException { BytesReference bytesRef = readBytesReference(); byte[] bytes = BytesReference.toBytes(bytesRef); @@ -331,6 +567,43 @@ public final Double readOptionalDouble() throws IOException { return null; } + /** + * Reads a boolean. + */ + public final boolean readBoolean() throws IOException { + return readBoolean(readByte()); + } + + private boolean readBoolean(final byte value) { + if (value == 0) { + return false; + } else if (value == 1) { + return true; + } else { + final String message = String.format(Locale.ROOT, "unexpected byte [0x%02x]", value); + throw new IllegalStateException(message); + } + } + + @Nullable + public final Boolean readOptionalBoolean() throws IOException { + final byte value = readByte(); + if (value == 2) { + return null; + } else { + return readBoolean(value); + } + } + + /** + * Closes the stream to further operations. + */ + @Override + public abstract void close() throws IOException; + + @Override + public abstract int available() throws IOException; + public String[] readStringArray() throws IOException { int size = readArraySize(); if (size == 0) { @@ -409,7 +682,7 @@ public Map readMap() throws IOException { @Nullable public Object readGenericValue() throws IOException { byte type = readByte(); - BaseWriteable.Reader r = BaseWriteable.WriteableRegistry.getReader(type); + Writeable.Reader r = Writeable.WriteableRegistry.getReader(type); if (r != null) { return r.read(this); } @@ -489,7 +762,7 @@ public final Instant readOptionalInstant() throws IOException { return present ? readInstant() : null; } - @SuppressWarnings("unchecked") + @SuppressWarnings({ "rawtypes", "unchecked" }) private List readArrayList() throws IOException { int size = readArraySize(); if (size == 0) { @@ -521,6 +794,7 @@ private Object[] readArray() throws IOException { return list8; } + @SuppressWarnings({ "rawtypes", "unchecked" }) private Map readLinkedHashMap() throws IOException { int size9 = readArraySize(); if (size9 == 0) { @@ -533,6 +807,7 @@ private Map readLinkedHashMap() throws IOException { return map9; } + @SuppressWarnings({ "rawtypes", "unchecked" }) private Map readHashMap() throws IOException { int size10 = readArraySize(); if (size10 == 0) { @@ -873,7 +1148,7 @@ public C readOptionalNamedWriteable(Class category * @return the list of objects * @throws IOException if an I/O exception occurs reading the list */ - public List readList(final BaseWriteable.Reader reader) throws IOException { + public List readList(final Writeable.Reader reader) throws IOException { return readCollection(reader, ArrayList::new, Collections.emptyList()); } @@ -912,6 +1187,22 @@ public Set readSet(Writeable.Reader reader) throws IOException { return readCollection(reader, HashSet::new, Collections.emptySet()); } + /** + * Reads a collection of objects + */ + private > C readCollection(Writeable.Reader reader, IntFunction constructor, C empty) + throws IOException { + int count = readArraySize(); + if (count == 0) { + return empty; + } + C builder = constructor.apply(count); + for (int i = 0; i < count; i++) { + builder.add(reader.read(this)); + } + return builder; + } + /** * Reads a list of {@link NamedWriteable}s. If the returned list contains any entries it will be mutable. * If it is empty it might be immutable. @@ -967,11 +1258,29 @@ public static StreamInput wrap(byte[] bytes, int offset, int length) { return new InputStreamStreamInput(new ByteArrayInputStream(bytes, offset, length), length); } + /** + * Reads a vint via {@link #readVInt()} and applies basic checks to ensure the read array size is sane. + * This method uses {@link #ensureCanReadBytes(int)} to ensure this stream has enough bytes to read for the read array size. + */ + private int readArraySize() throws IOException { + final int arraySize = readVInt(); + if (arraySize > ArrayUtil.MAX_ARRAY_LENGTH) { + throw new IllegalStateException("array length must be <= to " + ArrayUtil.MAX_ARRAY_LENGTH + " but was: " + arraySize); + } + if (arraySize < 0) { + throw new NegativeArraySizeException("array size must be positive but was: " + arraySize); + } + // lets do a sanity check that if we are reading an array size that is bigger that the remaining bytes we can safely + // throw an exception instead of allocating the array based on the size. A simple corrutpted byte can make a node go OOM + // if the size is large and for perf reasons we allocate arrays ahead of time + ensureCanReadBytes(arraySize); + return arraySize; + } + /** * This method throws an {@link EOFException} if the given number of bytes can not be read from the this stream. This method might * be a no-op depending on the underlying implementation if the information of the remaining bytes is not present. */ - @Override protected abstract void ensureCanReadBytes(int length) throws EOFException; private static final TimeUnit[] TIME_UNITS = TimeUnit.values(); diff --git a/server/src/main/java/org/opensearch/common/io/stream/StreamOutput.java b/libs/core/src/main/java/org/opensearch/common/io/stream/StreamOutput.java similarity index 89% rename from server/src/main/java/org/opensearch/common/io/stream/StreamOutput.java rename to libs/core/src/main/java/org/opensearch/common/io/stream/StreamOutput.java index f12cbcc924750..888c7530c4146 100644 --- a/server/src/main/java/org/opensearch/common/io/stream/StreamOutput.java +++ b/libs/core/src/main/java/org/opensearch/common/io/stream/StreamOutput.java @@ -40,28 +40,24 @@ import org.apache.lucene.util.BitUtil; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRefBuilder; -import org.joda.time.DateTimeZone; -import org.joda.time.ReadableInstant; import org.opensearch.Build; import org.opensearch.OpenSearchException; import org.opensearch.Version; -import org.opensearch.cluster.ClusterState; -import org.opensearch.cluster.metadata.Metadata; import org.opensearch.common.CharArrays; import org.opensearch.common.Nullable; import org.opensearch.common.bytes.BytesArray; import org.opensearch.common.bytes.BytesReference; +import org.opensearch.common.io.stream.Writeable.WriteableRegistry; import org.opensearch.common.io.stream.Writeable.Writer; import org.opensearch.common.settings.SecureString; import org.opensearch.common.text.Text; import org.opensearch.common.unit.TimeValue; -import org.opensearch.core.common.io.stream.BaseStreamOutput; -import org.opensearch.core.common.io.stream.BaseWriteable; import org.opensearch.core.concurrency.OpenSearchRejectedExecutionException; import java.io.EOFException; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.OutputStream; import java.math.BigInteger; import java.nio.file.AccessDeniedException; import java.nio.file.AtomicMoveNotSupportedException; @@ -102,15 +98,30 @@ * * @opensearch.internal */ -public abstract class StreamOutput extends BaseStreamOutput { +public abstract class StreamOutput extends OutputStream { private static final int MAX_NESTED_EXCEPTION_LEVEL = 100; + private Version version = Version.CURRENT; private Set features = Collections.emptySet(); /** - * Test if the stream has the specified feature. Features are used when serializing {@link ClusterState.Custom} or - * {@link Metadata.Custom}; see also {@link ClusterState.FeatureAware}. + * The version of the node on the other side of this stream. + */ + public Version getVersion() { + return this.version; + } + + /** + * Set the version of the node on the other side of this stream. + */ + public void setVersion(Version version) { + this.version = version; + } + + /** + * Test if the stream has the specified feature. Features are used when serializing {@code ClusterState.Custom} or + * {@code Metadata.Custom}; see also {@code ClusterState.FeatureAware}. * * @param feature the feature to test * @return true if the stream has the specified feature @@ -141,6 +152,11 @@ public void seek(long position) throws IOException { throw new UnsupportedOperationException(); } + /** + * Writes a single byte. + */ + public abstract void writeByte(byte b) throws IOException; + /** * Writes an array of bytes. * @@ -160,6 +176,15 @@ public void writeBytes(byte[] b, int length) throws IOException { writeBytes(b, 0, length); } + /** + * Writes an array of bytes. + * + * @param b the bytes to write + * @param offset the offset in the byte array + * @param length the number of bytes to write + */ + public abstract void writeBytes(byte[] b, int offset, int length) throws IOException; + /** * Writes an array of bytes. * @@ -204,6 +229,8 @@ public void writeBytesRef(BytesRef bytes) throws IOException { write(bytes.bytes, bytes.offset, bytes.length); } + private static final ThreadLocal scratch = ThreadLocal.withInitial(() -> new byte[1024]); + public final void writeShort(short v) throws IOException { final byte[] buffer = scratch.get(); buffer[0] = (byte) (v >> 8); @@ -211,6 +238,49 @@ public final void writeShort(short v) throws IOException { writeBytes(buffer, 0, 2); } + /** + * Writes an int as four bytes. + */ + public void writeInt(int i) throws IOException { + final byte[] buffer = scratch.get(); + buffer[0] = (byte) (i >> 24); + buffer[1] = (byte) (i >> 16); + buffer[2] = (byte) (i >> 8); + buffer[3] = (byte) i; + writeBytes(buffer, 0, 4); + } + + /** + * Writes an int in a variable-length format. Writes between one and + * five bytes. Smaller values take fewer bytes. Negative numbers + * will always use all 5 bytes and are therefore better serialized + * using {@link #writeInt} + */ + public void writeVInt(int i) throws IOException { + /* + * Shortcut writing single byte because it is very, very common and + * can skip grabbing the scratch buffer. This is marginally slower + * than hand unrolling the entire encoding loop but hand unrolling + * the encoding loop blows out the method size so it can't be inlined. + * In that case benchmarks of the method itself are faster but + * benchmarks of methods that use this method are slower. + * This is philosophically in line with vint in general - it biases + * twoards being simple and fast for smaller numbers. + */ + if (Integer.numberOfLeadingZeros(i) >= 25) { + writeByte((byte) i); + return; + } + byte[] buffer = scratch.get(); + int index = 0; + do { + buffer[index++] = ((byte) ((i & 0x7f) | 0x80)); + i >>>= 7; + } while ((i & ~0x7F) != 0); + buffer[index++] = ((byte) i); + writeBytes(buffer, 0, index); + } + /** * Writes a long as eight bytes. */ @@ -252,7 +322,7 @@ public void writeOptionalVLong(@Nullable Long l) throws IOException { * Writes a long in a variable-length format without first checking if it is negative. Package private for testing. Use * {@link #writeVLong(long)} instead. */ - void writeVLongNoCheck(long i) throws IOException { + public void writeVLongNoCheck(long i) throws IOException { final byte[] buffer = scratch.get(); int index = 0; while ((i & ~0x7F) != 0) { @@ -314,6 +384,27 @@ public void writeOptionalSecureString(@Nullable SecureString secureStr) throws I } } + /** + * Writes an optional {@link Integer}. + */ + public void writeOptionalInt(@Nullable Integer integer) throws IOException { + if (integer == null) { + writeBoolean(false); + } else { + writeBoolean(true); + writeInt(integer); + } + } + + public void writeOptionalVInt(@Nullable Integer integer) throws IOException { + if (integer == null) { + writeBoolean(false); + } else { + writeBoolean(true); + writeVInt(integer); + } + } + public void writeOptionalFloat(@Nullable Float floatValue) throws IOException { if (floatValue == null) { writeBoolean(false); @@ -404,6 +495,39 @@ public final void writeBigInteger(BigInteger v) throws IOException { writeString(v.toString()); } + private static byte ZERO = 0; + private static byte ONE = 1; + private static byte TWO = 2; + + /** + * Writes a boolean. + */ + public void writeBoolean(boolean b) throws IOException { + writeByte(b ? ONE : ZERO); + } + + public void writeOptionalBoolean(@Nullable Boolean b) throws IOException { + if (b == null) { + writeByte(TWO); + } else { + writeBoolean(b); + } + } + + /** + * Forces any buffered output to be written. + */ + @Override + public abstract void flush() throws IOException; + + /** + * Closes this stream to further operations. + */ + @Override + public abstract void close() throws IOException; + + public abstract void reset() throws IOException; + @Override public void write(int b) throws IOException { writeByte((byte) b); @@ -534,10 +658,10 @@ public final void writeOptionalInstant(@Nullable Instant instant) throws IOExcep } } - private static final Map, BaseWriteable.Writer> WRITERS; + private static final Map, Writer> WRITERS; static { - Map, BaseWriteable.Writer> writers = new HashMap<>(); + Map, Writer> writers = new HashMap<>(); writers.put(String.class, (o, v) -> { o.writeByte((byte) 0); o.writeString((String) v); @@ -570,6 +694,7 @@ public final void writeOptionalInstant(@Nullable Instant instant) throws IOExcep }); writers.put(List.class, (o, v) -> { o.writeByte((byte) 7); + @SuppressWarnings("rawtypes") final List list = (List) v; o.writeVInt(list.size()); for (Object item : list) { @@ -606,12 +731,6 @@ public final void writeOptionalInstant(@Nullable Instant instant) throws IOExcep o.writeByte((byte) 12); o.writeLong(((Date) v).getTime()); }); - writers.put(ReadableInstant.class, (o, v) -> { - o.writeByte((byte) 13); - final ReadableInstant instant = (ReadableInstant) v; - o.writeString(instant.getZone().getID()); - o.writeLong(instant.getMillis()); - }); writers.put(BytesReference.class, (o, v) -> { o.writeByte((byte) 14); o.writeBytesReference((BytesReference) v); @@ -667,7 +786,10 @@ public final void writeOptionalInstant(@Nullable Instant instant) throws IOExcep } private static Class getGenericType(Object value) { - if (value instanceof List) { + Class registeredClass = WriteableRegistry.getCustomClassFromInstance(value); + if (registeredClass != null) { + return registeredClass; + } else if (value instanceof List) { return List.class; } else if (value instanceof Object[]) { return Object[].class; @@ -675,8 +797,6 @@ private static Class getGenericType(Object value) { return Map.class; } else if (value instanceof Set) { return Set.class; - } else if (value instanceof ReadableInstant) { - return ReadableInstant.class; } else if (value instanceof BytesReference) { return BytesReference.class; } else { @@ -696,7 +816,7 @@ public void writeGenericValue(@Nullable Object value) throws IOException { return; } final Class type = getGenericType(value); - BaseWriteable.Writer writer = BaseWriteable.WriteableRegistry.getWriter(type); + Writer writer = WriteableRegistry.getWriter(type); if (writer == null) { // fallback to this local hashmap // todo: move all writers to the registry @@ -984,7 +1104,7 @@ public void writeBuild(final Build build) throws IOException { writeString(build.getQualifiedVersion()); } - boolean failOnTooManyNestedExceptions(Throwable throwable) { + protected boolean failOnTooManyNestedExceptions(Throwable throwable) { throw new AssertionError("too many nested exceptions", throwable); } @@ -1008,13 +1128,6 @@ public void writeOptionalNamedWriteable(@Nullable NamedWriteable namedWriteable) } } - /** - * Write a {@linkplain DateTimeZone} to the stream. - */ - public void writeTimeZone(DateTimeZone timeZone) throws IOException { - writeString(timeZone.getID()); - } - /** * Write a {@linkplain ZoneId} to the stream. */ @@ -1022,18 +1135,6 @@ public void writeZoneId(ZoneId timeZone) throws IOException { writeString(timeZone.getId()); } - /** - * Write an optional {@linkplain DateTimeZone} to the stream. - */ - public void writeOptionalTimeZone(@Nullable DateTimeZone timeZone) throws IOException { - if (timeZone == null) { - writeBoolean(false); - } else { - writeBoolean(true); - writeTimeZone(timeZone); - } - } - /** * Write an optional {@linkplain ZoneId} to the stream. */ @@ -1048,7 +1149,7 @@ public void writeOptionalZoneId(@Nullable ZoneId timeZone) throws IOException { /** * Writes a collection to this stream. The corresponding collection can be read from a stream input using - * {@link StreamInput#readList(BaseWriteable.Reader)}. + * {@link StreamInput#readList(Writeable.Reader)}. * * @param collection the collection to write to this stream * @throws IOException if an I/O exception occurs writing the collection @@ -1079,7 +1180,7 @@ public void writeCollection(final Collection collection, final Writer /** * Writes a collection of a strings. The corresponding collection can be read from a stream input using - * {@link StreamInput#readList(BaseWriteable.Reader)}. + * {@link StreamInput#readList(Writeable.Reader)}. * * @param collection the collection of strings * @throws IOException if an I/O exception occurs writing the collection @@ -1090,7 +1191,7 @@ public void writeStringCollection(final Collection collection) throws IO /** * Writes an optional collection of a strings. The corresponding collection can be read from a stream input using - * {@link StreamInput#readList(BaseWriteable.Reader)}. + * {@link StreamInput#readList(Writeable.Reader)}. * * @param collection the collection of strings * @throws IOException if an I/O exception occurs writing the collection diff --git a/libs/core/src/main/java/org/opensearch/common/io/stream/Writeable.java b/libs/core/src/main/java/org/opensearch/common/io/stream/Writeable.java new file mode 100644 index 0000000000000..735413d3642ec --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/common/io/stream/Writeable.java @@ -0,0 +1,175 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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. + */ + +/* + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.common.io.stream; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Implementers can be written to a {@linkplain StreamOutput} and read from a {@linkplain StreamInput}. This allows them to be "thrown + * across the wire" using OpenSearch's internal protocol. If the implementer also implements equals and hashCode then a copy made by + * serializing and deserializing must be equal and have the same hashCode. It isn't required that such a copy be entirely unchanged. + * + * @opensearch.internal + */ +public interface Writeable { + /** + * A WriteableRegistry registers {@link Writer} methods for writing data types over a + * {@link StreamOutput} channel and {@link Reader} methods for reading data from a + * {@link StreamInput} channel. + * + * @opensearch.internal + */ + class WriteableRegistry { + private static final Map, Writer> WRITER_REGISTRY = new ConcurrentHashMap<>(); + private static final Map, Class> WRITER_CUSTOM_CLASS_MAP = new ConcurrentHashMap<>(); + private static final Map> READER_REGISTRY = new ConcurrentHashMap<>(); + + /** + * registers a streamable writer + * + * @opensearch.internal + */ + public static > void registerWriter(final Class clazz, final W writer) { + if (WRITER_REGISTRY.putIfAbsent(clazz, writer) != null) { + throw new IllegalArgumentException("Streamable writer already registered for type [" + clazz.getName() + "]"); + } + } + + /** + * registers a streamable reader + * + * @opensearch.internal + */ + public static > void registerReader(final byte ordinal, final R reader) { + if (READER_REGISTRY.putIfAbsent(ordinal, reader) != null) { + throw new IllegalArgumentException("Streamable reader already registered for ordinal [" + (int) ordinal + "]"); + } + } + + public static void registerClassAlias(final Class classInstance, final Class classGeneric) { + if (WRITER_CUSTOM_CLASS_MAP.putIfAbsent(classInstance, classGeneric) != null) { + throw new IllegalArgumentException("Streamable custom class already registered [" + classInstance.getClass() + "]"); + } + } + + /** + * Returns the registered writer keyed by the class type + */ + @SuppressWarnings("unchecked") + public static > W getWriter(final Class clazz) { + return (W) WRITER_REGISTRY.get(clazz); + } + + /** + * Returns the ristered reader keyed by the unique ordinal + */ + @SuppressWarnings("unchecked") + public static > R getReader(final byte b) { + return (R) READER_REGISTRY.get(b); + } + + public static Class getCustomClassFromInstance(final Object value) { + if (value == null) { + throw new IllegalArgumentException("Attempting to retrieve a class type from a null value"); + } + // rip through registered classes; return the class iff 'value' is an instance + // we do it this way to cover inheritance and interfaces (e.g., joda DateTime is an instanceof + // a ReadableInstant interface) + for (final Class clazz : WRITER_CUSTOM_CLASS_MAP.values()) { + if (clazz.isInstance(value)) { + return clazz; + } + } + return null; + } + } + + /** + * Write this into the {@linkplain StreamOutput}. + */ + void writeTo(StreamOutput out) throws IOException; + + /** + * Reference to a method that can write some object to a {@link StreamOutput}. + *

+ * By convention this is a method from {@link StreamOutput} itself (e.g., {@code StreamOutput#writeString}). If the value can be + * {@code null}, then the "optional" variant of methods should be used! + *

+ * Most classes should implement {@code Writeable} and the {@code Writeable#writeTo(StreamOutput)} method should use + * {@link StreamOutput} methods directly or this indirectly: + *


+     * public void writeTo(StreamOutput out) throws IOException {
+     *     out.writeVInt(someValue);
+     *     out.writeMapOfLists(someMap, StreamOutput::writeString, StreamOutput::writeString);
+     * }
+     * 
+ */ + @FunctionalInterface + interface Writer { + + /** + * Write {@code V}-type {@code value} to the {@code out}put stream. + * + * @param out Output to write the {@code value} too + * @param value The value to add + */ + void write(final StreamOutput out, V value) throws IOException; + } + + /** + * Reference to a method that can read some object from a stream. By convention this is a constructor that takes + * {@linkplain StreamInput} as an argument for most classes and a static method for things like enums. Returning null from one of these + * is always wrong - for that we use methods like {@code StreamInput#readOptionalWriteable(Reader)}. + *

+ * As most classes will implement this via a constructor (or a static method in the case of enumerations), it's something that should + * look like: + *


+     * public MyClass(final StreamInput in) throws IOException {
+     *     this.someValue = in.readVInt();
+     *     this.someMap = in.readMapOfLists(StreamInput::readString, StreamInput::readString);
+     * }
+     * 
+ */ + @FunctionalInterface + interface Reader { + + /** + * Read {@code V}-type value from a stream. + * + * @param in Input to read the value from + */ + V read(final StreamInput in) throws IOException; + } +} diff --git a/libs/core/src/main/java/org/opensearch/core/common/io/stream/package-info.java b/libs/core/src/main/java/org/opensearch/common/io/stream/package-info.java similarity index 83% rename from libs/core/src/main/java/org/opensearch/core/common/io/stream/package-info.java rename to libs/core/src/main/java/org/opensearch/common/io/stream/package-info.java index 76d0842466b96..c332f90371f60 100644 --- a/libs/core/src/main/java/org/opensearch/core/common/io/stream/package-info.java +++ b/libs/core/src/main/java/org/opensearch/common/io/stream/package-info.java @@ -5,5 +5,6 @@ * this file be licensed under the Apache-2.0 license or a * compatible open source license. */ + /** Core transport stream classes */ -package org.opensearch.core.common.io.stream; +package org.opensearch.common.io.stream; diff --git a/libs/core/src/main/java/org/opensearch/common/package-info.java b/libs/core/src/main/java/org/opensearch/common/package-info.java new file mode 100644 index 0000000000000..211cde81a3b88 --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/common/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** common core classes that require third party dependencies */ +package org.opensearch.common; diff --git a/server/src/main/java/org/opensearch/common/settings/SecureString.java b/libs/core/src/main/java/org/opensearch/common/settings/SecureString.java similarity index 100% rename from server/src/main/java/org/opensearch/common/settings/SecureString.java rename to libs/core/src/main/java/org/opensearch/common/settings/SecureString.java diff --git a/libs/core/src/main/java/org/opensearch/common/settings/package-info.java b/libs/core/src/main/java/org/opensearch/common/settings/package-info.java new file mode 100644 index 0000000000000..10c1d5bab5fc1 --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/common/settings/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Classes for core Settings module */ +package org.opensearch.common.settings; diff --git a/server/src/main/java/org/opensearch/common/text/Text.java b/libs/core/src/main/java/org/opensearch/common/text/Text.java similarity index 100% rename from server/src/main/java/org/opensearch/common/text/Text.java rename to libs/core/src/main/java/org/opensearch/common/text/Text.java diff --git a/libs/core/src/main/java/org/opensearch/common/text/package-info.java b/libs/core/src/main/java/org/opensearch/common/text/package-info.java new file mode 100644 index 0000000000000..d9ce2ebbc9340 --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/common/text/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Classes for core text module */ +package org.opensearch.common.text; diff --git a/server/src/main/java/org/opensearch/common/util/BigArray.java b/libs/core/src/main/java/org/opensearch/common/util/BigArray.java similarity index 100% rename from server/src/main/java/org/opensearch/common/util/BigArray.java rename to libs/core/src/main/java/org/opensearch/common/util/BigArray.java diff --git a/server/src/main/java/org/opensearch/common/util/ByteArray.java b/libs/core/src/main/java/org/opensearch/common/util/ByteArray.java similarity index 100% rename from server/src/main/java/org/opensearch/common/util/ByteArray.java rename to libs/core/src/main/java/org/opensearch/common/util/ByteArray.java diff --git a/libs/core/src/main/java/org/opensearch/common/util/package-info.java b/libs/core/src/main/java/org/opensearch/common/util/package-info.java new file mode 100644 index 0000000000000..f106d27c21881 --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/common/util/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Classes for core util module */ +package org.opensearch.common.util; diff --git a/server/src/main/java/org/opensearch/common/xcontent/XContentParserUtils.java b/libs/core/src/main/java/org/opensearch/common/xcontent/XContentParserUtils.java similarity index 100% rename from server/src/main/java/org/opensearch/common/xcontent/XContentParserUtils.java rename to libs/core/src/main/java/org/opensearch/common/xcontent/XContentParserUtils.java diff --git a/libs/core/src/main/java/org/opensearch/common/xcontent/package-info.java b/libs/core/src/main/java/org/opensearch/common/xcontent/package-info.java new file mode 100644 index 0000000000000..c4522c2ae6627 --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/common/xcontent/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Base XContent Core Classes */ +package org.opensearch.common.xcontent; diff --git a/libs/core/src/main/java/org/opensearch/core/common/io/package-info.java b/libs/core/src/main/java/org/opensearch/core/common/io/package-info.java new file mode 100644 index 0000000000000..7f5318f53dd35 --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/core/common/io/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Classes for core io module */ +package org.opensearch.core.common.io; diff --git a/libs/core/src/main/java/org/opensearch/core/common/io/stream/BaseStreamInput.java b/libs/core/src/main/java/org/opensearch/core/common/io/stream/BaseStreamInput.java deleted file mode 100644 index 178333d529cf6..0000000000000 --- a/libs/core/src/main/java/org/opensearch/core/common/io/stream/BaseStreamInput.java +++ /dev/null @@ -1,341 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ -package org.opensearch.core.common.io.stream; - -import org.apache.lucene.util.ArrayUtil; -import org.apache.lucene.util.CharsRef; -import org.opensearch.Version; -import org.opensearch.common.Nullable; - -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.util.Collection; -import java.util.Locale; -import java.util.function.IntFunction; - -/** - * Foundation class for reading core types off the transport stream - * - * todo: refactor {@code StreamInput} primitive readers to this class - * - * @opensearch.internal - */ -public abstract class BaseStreamInput extends InputStream { - // Maximum char-count to de-serialize via the thread-local CharsRef buffer - private static final int SMALL_STRING_LIMIT = 1024; - // Reusable bytes for deserializing strings - private static final ThreadLocal stringReadBuffer = ThreadLocal.withInitial(() -> new byte[1024]); - // Thread-local buffer for smaller strings - private static final ThreadLocal smallSpare = ThreadLocal.withInitial(() -> new CharsRef(SMALL_STRING_LIMIT)); - private Version version = Version.CURRENT; - // Larger buffer used for long strings that can't fit into the thread-local buffer - // We don't use a CharsRefBuilder since we exactly know the size of the character array up front - // this prevents calling grow for every character since we don't need this - private CharsRef largeSpare; - - /** - * The version of the node on the other side of this stream. - */ - public Version getVersion() { - return this.version; - } - - /** - * Set the version of the node on the other side of this stream. - */ - public void setVersion(Version version) { - this.version = version; - } - - /** - * Closes the stream to further operations. - */ - @Override - public abstract void close() throws IOException; - - @Override - public abstract int available() throws IOException; - - /** - * This method throws an {@link EOFException} if the given number of bytes can not be read from the this stream. This method might - * be a no-op depending on the underlying implementation if the information of the remaining bytes is not present. - */ - protected abstract void ensureCanReadBytes(int length) throws EOFException; - - /** - * Reads and returns a single byte. - */ - public abstract byte readByte() throws IOException; - - /** - * Reads a specified number of bytes into an array at the specified offset. - * - * @param b the array to read bytes into - * @param offset the offset in the array to start storing bytes - * @param len the number of bytes to read - */ - public abstract void readBytes(byte[] b, int offset, int len) throws IOException; - - public void readFully(byte[] b) throws IOException { - readBytes(b, 0, b.length); - } - - protected boolean readBoolean(final byte value) { - if (value == 0) { - return false; - } else if (value == 1) { - return true; - } else { - final String message = String.format(Locale.ROOT, "unexpected byte [0x%02x]", value); - throw new IllegalStateException(message); - } - } - - /** - * Reads a boolean. - */ - public final boolean readBoolean() throws IOException { - return readBoolean(readByte()); - } - - @Nullable - public final Boolean readOptionalBoolean() throws IOException { - final byte value = readByte(); - if (value == 2) { - return null; - } else { - return readBoolean(value); - } - } - - /** - * Reads four bytes and returns an int. - */ - public int readInt() throws IOException { - return ((readByte() & 0xFF) << 24) | ((readByte() & 0xFF) << 16) | ((readByte() & 0xFF) << 8) | (readByte() & 0xFF); - } - - /** - * Reads an int stored in variable-length format. Reads between one and - * five bytes. Smaller values take fewer bytes. Negative numbers - * will always use all 5 bytes and are therefore better serialized - * using {@link #readInt} - */ - public int readVInt() throws IOException { - byte b = readByte(); - int i = b & 0x7F; - if ((b & 0x80) == 0) { - return i; - } - b = readByte(); - i |= (b & 0x7F) << 7; - if ((b & 0x80) == 0) { - return i; - } - b = readByte(); - i |= (b & 0x7F) << 14; - if ((b & 0x80) == 0) { - return i; - } - b = readByte(); - i |= (b & 0x7F) << 21; - if ((b & 0x80) == 0) { - return i; - } - b = readByte(); - if ((b & 0x80) != 0) { - throw new IOException("Invalid vInt ((" + Integer.toHexString(b) + " & 0x7f) << 28) | " + Integer.toHexString(i)); - } - return i | ((b & 0x7F) << 28); - } - - @Nullable - public Integer readOptionalVInt() throws IOException { - if (readBoolean()) { - return readVInt(); - } - return null; - } - - public String readString() throws IOException { - final int charCount = readArraySize(); - final CharsRef charsRef; - if (charCount > SMALL_STRING_LIMIT) { - if (largeSpare == null) { - largeSpare = new CharsRef(ArrayUtil.oversize(charCount, Character.BYTES)); - } else if (largeSpare.chars.length < charCount) { - // we don't use ArrayUtils.grow since there is no need to copy the array - largeSpare.chars = new char[ArrayUtil.oversize(charCount, Character.BYTES)]; - } - charsRef = largeSpare; - } else { - charsRef = smallSpare.get(); - } - charsRef.length = charCount; - int charsOffset = 0; - int offsetByteArray = 0; - int sizeByteArray = 0; - int missingFromPartial = 0; - final byte[] byteBuffer = stringReadBuffer.get(); - final char[] charBuffer = charsRef.chars; - for (; charsOffset < charCount;) { - final int charsLeft = charCount - charsOffset; - int bufferFree = byteBuffer.length - sizeByteArray; - // Determine the minimum amount of bytes that are left in the string - final int minRemainingBytes; - if (missingFromPartial > 0) { - // One byte for each remaining char except for the already partially read char - minRemainingBytes = missingFromPartial + charsLeft - 1; - missingFromPartial = 0; - } else { - // Each char has at least a single byte - minRemainingBytes = charsLeft; - } - final int toRead; - if (bufferFree < minRemainingBytes) { - // We don't have enough space left in the byte array to read as much as we'd like to so we free up as many bytes in the - // buffer by moving unused bytes that didn't make up a full char in the last iteration to the beginning of the buffer, - // if there are any - if (offsetByteArray > 0) { - sizeByteArray = sizeByteArray - offsetByteArray; - switch (sizeByteArray) { // We only have 0, 1 or 2 => no need to bother with a native call to System#arrayCopy - case 1: - byteBuffer[0] = byteBuffer[offsetByteArray]; - break; - case 2: - byteBuffer[0] = byteBuffer[offsetByteArray]; - byteBuffer[1] = byteBuffer[offsetByteArray + 1]; - break; - } - assert sizeByteArray <= 2 : "We never copy more than 2 bytes here since a char is 3 bytes max"; - toRead = Math.min(bufferFree + offsetByteArray, minRemainingBytes); - offsetByteArray = 0; - } else { - toRead = bufferFree; - } - } else { - toRead = minRemainingBytes; - } - readBytes(byteBuffer, sizeByteArray, toRead); - sizeByteArray += toRead; - // As long as we at least have three bytes buffered we don't need to do any bounds checking when getting the next char since we - // read 3 bytes per char/iteration at most - for (; offsetByteArray < sizeByteArray - 2; offsetByteArray++) { - final int c = byteBuffer[offsetByteArray] & 0xff; - switch (c >> 4) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - charBuffer[charsOffset++] = (char) c; - break; - case 12: - case 13: - charBuffer[charsOffset++] = (char) ((c & 0x1F) << 6 | byteBuffer[++offsetByteArray] & 0x3F); - break; - case 14: - charBuffer[charsOffset++] = (char) ((c & 0x0F) << 12 | (byteBuffer[++offsetByteArray] & 0x3F) << 6 - | (byteBuffer[++offsetByteArray] & 0x3F)); - break; - default: - BaseStreamInput.throwOnBrokenChar(c); - } - } - // try to extract chars from remaining bytes with bounds checks for multi-byte chars - final int bufferedBytesRemaining = sizeByteArray - offsetByteArray; - for (int i = 0; i < bufferedBytesRemaining; i++) { - final int c = byteBuffer[offsetByteArray] & 0xff; - switch (c >> 4) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - charBuffer[charsOffset++] = (char) c; - offsetByteArray++; - break; - case 12: - case 13: - missingFromPartial = 2 - (bufferedBytesRemaining - i); - if (missingFromPartial == 0) { - offsetByteArray++; - charBuffer[charsOffset++] = (char) ((c & 0x1F) << 6 | byteBuffer[offsetByteArray++] & 0x3F); - } - ++i; - break; - case 14: - missingFromPartial = 3 - (bufferedBytesRemaining - i); - ++i; - break; - default: - BaseStreamInput.throwOnBrokenChar(c); - } - } - } - return charsRef.toString(); - } - - @Nullable - public String readOptionalString() throws IOException { - if (readBoolean()) { - return readString(); - } - return null; - } - - private static void throwOnBrokenChar(int c) throws IOException { - throw new IOException("Invalid string; unexpected character: " + c + " hex: " + Integer.toHexString(c)); - } - - /** - * Reads a vint via {@link #readVInt()} and applies basic checks to ensure the read array size is sane. - * This method uses {@link #ensureCanReadBytes(int)} to ensure this stream has enough bytes to read for the read array size. - */ - protected int readArraySize() throws IOException { - final int arraySize = readVInt(); - if (arraySize > ArrayUtil.MAX_ARRAY_LENGTH) { - throw new IllegalStateException("array length must be <= to " + ArrayUtil.MAX_ARRAY_LENGTH + " but was: " + arraySize); - } - if (arraySize < 0) { - throw new NegativeArraySizeException("array size must be positive but was: " + arraySize); - } - // lets do a sanity check that if we are reading an array size that is bigger that the remaining bytes we can safely - // throw an exception instead of allocating the array based on the size. A simple corrutpted byte can make a node go OOM - // if the size is large and for perf reasons we allocate arrays ahead of time - ensureCanReadBytes(arraySize); - return arraySize; - } - - /** - * Reads a collection of objects - */ - @SuppressWarnings("unchecked") - protected > C readCollection( - BaseWriteable.Reader reader, - IntFunction constructor, - C empty - ) throws IOException { - int count = readArraySize(); - if (count == 0) { - return empty; - } - C builder = constructor.apply(count); - for (int i = 0; i < count; i++) { - builder.add(reader.read((S) this)); - } - return builder; - } -} diff --git a/libs/core/src/main/java/org/opensearch/core/common/io/stream/BaseStreamOutput.java b/libs/core/src/main/java/org/opensearch/core/common/io/stream/BaseStreamOutput.java deleted file mode 100644 index e2d4edf0a6023..0000000000000 --- a/libs/core/src/main/java/org/opensearch/core/common/io/stream/BaseStreamOutput.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ -package org.opensearch.core.common.io.stream; - -import org.opensearch.Version; -import org.opensearch.common.Nullable; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Foundation class for writing core types over the transport stream - * - * todo: refactor {@code StreamOutput} primitive writers to this class - * - * @opensearch.internal - */ -public abstract class BaseStreamOutput extends OutputStream { - protected static final ThreadLocal scratch = ThreadLocal.withInitial(() -> new byte[1024]); - private static byte ZERO = 0; - private static byte ONE = 1; - private static byte TWO = 2; - protected Version version = Version.CURRENT; - - /** - * The version of the node on the other side of this stream. - */ - public Version getVersion() { - return this.version; - } - - /** - * Set the version of the node on the other side of this stream. - */ - public void setVersion(Version version) { - this.version = version; - } - - /** - * Closes this stream to further operations. - */ - @Override - public abstract void close() throws IOException; - - /** - * Forces any buffered output to be written. - */ - @Override - public abstract void flush() throws IOException; - - public abstract void reset() throws IOException; - - /** - * Writes a single byte. - */ - public abstract void writeByte(byte b) throws IOException; - - /** - * Writes an array of bytes. - * - * @param b the bytes to write - * @param offset the offset in the byte array - * @param length the number of bytes to write - */ - public abstract void writeBytes(byte[] b, int offset, int length) throws IOException; - - /** - * Writes a boolean. - */ - public void writeBoolean(boolean b) throws IOException { - writeByte(b ? ONE : ZERO); - } - - public void writeOptionalBoolean(@Nullable Boolean b) throws IOException { - if (b == null) { - writeByte(TWO); - } else { - writeBoolean(b); - } - } - - /** - * Writes an int as four bytes. - */ - public void writeInt(int i) throws IOException { - final byte[] buffer = scratch.get(); - buffer[0] = (byte) (i >> 24); - buffer[1] = (byte) (i >> 16); - buffer[2] = (byte) (i >> 8); - buffer[3] = (byte) i; - writeBytes(buffer, 0, 4); - } - - /** - * Writes an optional {@link Integer}. - */ - public void writeOptionalInt(@Nullable Integer integer) throws IOException { - if (integer == null) { - writeBoolean(false); - } else { - writeBoolean(true); - writeInt(integer); - } - } - - /** - * Writes an int in a variable-length format. Writes between one and - * five bytes. Smaller values take fewer bytes. Negative numbers - * will always use all 5 bytes and are therefore better serialized - * using {@link #writeInt} - */ - public void writeVInt(int i) throws IOException { - /* - * Shortcut writing single byte because it is very, very common and - * can skip grabbing the scratch buffer. This is marginally slower - * than hand unrolling the entire encoding loop but hand unrolling - * the encoding loop blows out the method size so it can't be inlined. - * In that case benchmarks of the method itself are faster but - * benchmarks of methods that use this method are slower. - * This is philosophically in line with vint in general - it biases - * twoards being simple and fast for smaller numbers. - */ - if (Integer.numberOfLeadingZeros(i) >= 25) { - writeByte((byte) i); - return; - } - byte[] buffer = scratch.get(); - int index = 0; - do { - buffer[index++] = ((byte) ((i & 0x7f) | 0x80)); - i >>>= 7; - } while ((i & ~0x7F) != 0); - buffer[index++] = ((byte) i); - writeBytes(buffer, 0, index); - } - - public void writeOptionalVInt(@Nullable Integer integer) throws IOException { - if (integer == null) { - writeBoolean(false); - } else { - writeBoolean(true); - writeVInt(integer); - } - } -} diff --git a/libs/core/src/main/java/org/opensearch/core/common/io/stream/BaseWriteable.java b/libs/core/src/main/java/org/opensearch/core/common/io/stream/BaseWriteable.java deleted file mode 100644 index 56172e7c6a50e..0000000000000 --- a/libs/core/src/main/java/org/opensearch/core/common/io/stream/BaseWriteable.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ -package org.opensearch.core.common.io.stream; - -import java.io.IOException; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Implementers can be written to a {@code StreamOutput} and read from a {@code StreamInput}. This allows them to be "thrown - * across the wire" using OpenSearch's internal protocol. If the implementer also implements equals and hashCode then a copy made by - * serializing and deserializing must be equal and have the same hashCode. It isn't required that such a copy be entirely unchanged. - * - * @opensearch.internal - */ -public interface BaseWriteable { - /** - * A WriteableRegistry registers {@link Writer} methods for writing data types over a - * {@link BaseStreamOutput} channel and {@link Reader} methods for reading data from a - * {@link BaseStreamInput} channel. - * - * @opensearch.internal - */ - class WriteableRegistry { - private static final Map, Writer> WRITER_REGISTRY = new ConcurrentHashMap<>(); - private static final Map> READER_REGISTRY = new ConcurrentHashMap<>(); - - /** - * registers a streamable writer - * - * @opensearch.internal - */ - public static > void registerWriter(final Class clazz, final W writer) { - if (WRITER_REGISTRY.containsKey(clazz)) { - throw new IllegalArgumentException("Streamable writer already registered for type [" + clazz.getName() + "]"); - } - WRITER_REGISTRY.put(clazz, writer); - } - - /** - * registers a streamable reader - * - * @opensearch.internal - */ - public static > void registerReader(final byte ordinal, final R reader) { - if (READER_REGISTRY.containsKey(ordinal)) { - throw new IllegalArgumentException("Streamable reader already registered for ordinal [" + (int) ordinal + "]"); - } - READER_REGISTRY.put(ordinal, reader); - } - - /** - * Returns the registered writer keyed by the class type - */ - @SuppressWarnings("unchecked") - public static > W getWriter(final Class clazz) { - return (W) WRITER_REGISTRY.get(clazz); - } - - /** - * Returns the ristered reader keyed by the unique ordinal - */ - @SuppressWarnings("unchecked") - public static > R getReader(final byte b) { - return (R) READER_REGISTRY.get(b); - } - } - - /** - * Write this into the {@linkplain BaseStreamOutput}. - */ - void writeTo(final S out) throws IOException; - - /** - * Reference to a method that can write some object to a {@link BaseStreamOutput}. - *

- * By convention this is a method from {@link BaseStreamOutput} itself (e.g., {@code StreamOutput#writeString}). If the value can be - * {@code null}, then the "optional" variant of methods should be used! - *

- * Most classes should implement {@code Writeable} and the {@code Writeable#writeTo(BaseStreamOutput)} method should use - * {@link BaseStreamOutput} methods directly or this indirectly: - *


-     * public void writeTo(StreamOutput out) throws IOException {
-     *     out.writeVInt(someValue);
-     *     out.writeMapOfLists(someMap, StreamOutput::writeString, StreamOutput::writeString);
-     * }
-     * 
- */ - @FunctionalInterface - interface Writer { - - /** - * Write {@code V}-type {@code value} to the {@code out}put stream. - * - * @param out Output to write the {@code value} too - * @param value The value to add - */ - void write(final S out, V value) throws IOException; - } - - /** - * Reference to a method that can read some object from a stream. By convention this is a constructor that takes - * {@linkplain BaseStreamInput} as an argument for most classes and a static method for things like enums. Returning null from one of these - * is always wrong - for that we use methods like {@code StreamInput#readOptionalWriteable(Reader)}. - *

- * As most classes will implement this via a constructor (or a static method in the case of enumerations), it's something that should - * look like: - *


-     * public MyClass(final StreamInput in) throws IOException {
-     *     this.someValue = in.readVInt();
-     *     this.someMap = in.readMapOfLists(StreamInput::readString, StreamInput::readString);
-     * }
-     * 
- */ - @FunctionalInterface - interface Reader { - - /** - * Read {@code V}-type value from a stream. - * - * @param in Input to read the value from - */ - V read(final S in) throws IOException; - } -} diff --git a/server/src/main/java/org/opensearch/index/Index.java b/libs/core/src/main/java/org/opensearch/index/Index.java similarity index 100% rename from server/src/main/java/org/opensearch/index/Index.java rename to libs/core/src/main/java/org/opensearch/index/Index.java diff --git a/libs/core/src/main/java/org/opensearch/index/package-info.java b/libs/core/src/main/java/org/opensearch/index/package-info.java new file mode 100644 index 0000000000000..bcb93e8c78856 --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/index/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Classes for core index module */ +package org.opensearch.index; diff --git a/server/src/main/java/org/opensearch/index/shard/ShardId.java b/libs/core/src/main/java/org/opensearch/index/shard/ShardId.java similarity index 96% rename from server/src/main/java/org/opensearch/index/shard/ShardId.java rename to libs/core/src/main/java/org/opensearch/index/shard/ShardId.java index 9f226cd2df76a..ac24130ed90c9 100644 --- a/server/src/main/java/org/opensearch/index/shard/ShardId.java +++ b/libs/core/src/main/java/org/opensearch/index/shard/ShardId.java @@ -32,7 +32,7 @@ package org.opensearch.index.shard; -import org.opensearch.cluster.metadata.IndexMetadata; +import org.opensearch.core.common.Strings; import org.opensearch.common.io.stream.StreamInput; import org.opensearch.common.io.stream.StreamOutput; import org.opensearch.common.io.stream.Writeable; @@ -109,7 +109,7 @@ public static ShardId fromString(String shardIdString) { } String indexName = shardIdString.substring(1, splitPosition); int shardId = Integer.parseInt(shardIdString.substring(splitPosition + 2, shardIdString.length() - 1)); - return new ShardId(new Index(indexName, IndexMetadata.INDEX_UUID_NA_VALUE), shardId); + return new ShardId(new Index(indexName, Strings.UNKNOWN_UUID_VALUE), shardId); } @Override diff --git a/libs/core/src/main/java/org/opensearch/index/shard/package-info.java b/libs/core/src/main/java/org/opensearch/index/shard/package-info.java new file mode 100644 index 0000000000000..3ae1d95494bd6 --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/index/shard/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Classes for core index/shard module */ +package org.opensearch.index.shard; diff --git a/server/src/main/java/org/opensearch/index/snapshots/IndexShardSnapshotException.java b/libs/core/src/main/java/org/opensearch/index/snapshots/IndexShardSnapshotException.java similarity index 100% rename from server/src/main/java/org/opensearch/index/snapshots/IndexShardSnapshotException.java rename to libs/core/src/main/java/org/opensearch/index/snapshots/IndexShardSnapshotException.java diff --git a/server/src/main/java/org/opensearch/index/snapshots/IndexShardSnapshotFailedException.java b/libs/core/src/main/java/org/opensearch/index/snapshots/IndexShardSnapshotFailedException.java similarity index 100% rename from server/src/main/java/org/opensearch/index/snapshots/IndexShardSnapshotFailedException.java rename to libs/core/src/main/java/org/opensearch/index/snapshots/IndexShardSnapshotFailedException.java diff --git a/libs/core/src/main/java/org/opensearch/index/snapshots/package-info.java b/libs/core/src/main/java/org/opensearch/index/snapshots/package-info.java new file mode 100644 index 0000000000000..7102459987dbf --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/index/snapshots/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Classes for core snapshots module */ +package org.opensearch.index.snapshots; diff --git a/server/src/main/java/org/opensearch/rest/RestStatus.java b/libs/core/src/main/java/org/opensearch/rest/RestStatus.java similarity index 100% rename from server/src/main/java/org/opensearch/rest/RestStatus.java rename to libs/core/src/main/java/org/opensearch/rest/RestStatus.java diff --git a/libs/core/src/main/java/org/opensearch/rest/package-info.java b/libs/core/src/main/java/org/opensearch/rest/package-info.java new file mode 100644 index 0000000000000..a629540e3858c --- /dev/null +++ b/libs/core/src/main/java/org/opensearch/rest/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Classes for core REST module */ +package org.opensearch.rest; diff --git a/modules/geo/src/test/java/org/opensearch/geo/search/aggregations/bucket/geogrid/GeoTileGridParserTests.java b/modules/geo/src/test/java/org/opensearch/geo/search/aggregations/bucket/geogrid/GeoTileGridParserTests.java index a39f66f571d0a..0bf41f37c45a7 100644 --- a/modules/geo/src/test/java/org/opensearch/geo/search/aggregations/bucket/geogrid/GeoTileGridParserTests.java +++ b/modules/geo/src/test/java/org/opensearch/geo/search/aggregations/bucket/geogrid/GeoTileGridParserTests.java @@ -31,7 +31,7 @@ package org.opensearch.geo.search.aggregations.bucket.geogrid; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.core.xcontent.XContentParseException; import org.opensearch.core.xcontent.XContentParser; import org.opensearch.common.xcontent.json.JsonXContent; @@ -77,7 +77,7 @@ public void testParseErrorOnBooleanPrecision() throws Exception { () -> GeoTileGridAggregationBuilder.PARSER.parse(stParser, "geotile_grid") ); assertThat( - BaseExceptionsHelper.detailedMessage(e), + ExceptionsHelper.detailedMessage(e), containsString("[geotile_grid] precision doesn't support values of type: VALUE_BOOLEAN") ); } diff --git a/modules/lang-mustache/src/main/java/org/opensearch/script/mustache/MultiSearchTemplateResponse.java b/modules/lang-mustache/src/main/java/org/opensearch/script/mustache/MultiSearchTemplateResponse.java index 5fd2f9085539e..e626d996b0cc4 100644 --- a/modules/lang-mustache/src/main/java/org/opensearch/script/mustache/MultiSearchTemplateResponse.java +++ b/modules/lang-mustache/src/main/java/org/opensearch/script/mustache/MultiSearchTemplateResponse.java @@ -33,7 +33,7 @@ package org.opensearch.script.mustache; import org.opensearch.LegacyESVersion; -import org.opensearch.BaseOpenSearchException; +import org.opensearch.OpenSearchException; import org.opensearch.action.ActionResponse; import org.opensearch.action.search.MultiSearchResponse; import org.opensearch.common.Nullable; @@ -173,7 +173,7 @@ public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params par for (Item item : items) { if (item.isFailure()) { builder.startObject(); - BaseOpenSearchException.generateFailureXContent(builder, params, item.getFailure(), true); + OpenSearchException.generateFailureXContent(builder, params, item.getFailure(), true); builder.endObject(); } else { item.getResponse().toXContent(builder, params); diff --git a/modules/rank-eval/src/internalClusterTest/java/org/opensearch/index/rankeval/RankEvalRequestIT.java b/modules/rank-eval/src/internalClusterTest/java/org/opensearch/index/rankeval/RankEvalRequestIT.java index cacccafde2d47..ea80b59711b8a 100644 --- a/modules/rank-eval/src/internalClusterTest/java/org/opensearch/index/rankeval/RankEvalRequestIT.java +++ b/modules/rank-eval/src/internalClusterTest/java/org/opensearch/index/rankeval/RankEvalRequestIT.java @@ -32,7 +32,7 @@ package org.opensearch.index.rankeval; -import org.opensearch.BaseOpenSearchException; +import org.opensearch.OpenSearchException; import org.opensearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions; import org.opensearch.action.search.SearchRequest; import org.opensearch.action.support.IndicesOptions; @@ -274,7 +274,7 @@ public void testBadQuery() { RankEvalResponse response = client().execute(RankEvalAction.INSTANCE, builder.request()).actionGet(); assertEquals(1, response.getFailures().size()); - BaseOpenSearchException[] rootCauses = BaseOpenSearchException.guessRootCauses(response.getFailures().get("broken_query")); + OpenSearchException[] rootCauses = OpenSearchException.guessRootCauses(response.getFailures().get("broken_query")); assertEquals("java.lang.NumberFormatException: For input string: \"noStringOnNumericFields\"", rootCauses[0].getCause().toString()); } diff --git a/modules/rank-eval/src/main/java/org/opensearch/index/rankeval/RankEvalResponse.java b/modules/rank-eval/src/main/java/org/opensearch/index/rankeval/RankEvalResponse.java index 58a940e1618da..180069ab91bd6 100644 --- a/modules/rank-eval/src/main/java/org/opensearch/index/rankeval/RankEvalResponse.java +++ b/modules/rank-eval/src/main/java/org/opensearch/index/rankeval/RankEvalResponse.java @@ -32,7 +32,6 @@ package org.opensearch.index.rankeval; -import org.opensearch.BaseOpenSearchException; import org.opensearch.OpenSearchException; import org.opensearch.action.ActionResponse; import org.opensearch.core.ParseField; @@ -137,7 +136,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.startObject("failures"); for (String key : failures.keySet()) { builder.startObject(key); - BaseOpenSearchException.generateFailureXContent(builder, params, failures.get(key), true); + OpenSearchException.generateFailureXContent(builder, params, failures.get(key), true); builder.endObject(); } builder.endObject(); diff --git a/modules/reindex/src/main/java/org/opensearch/index/reindex/remote/RemoteResponseParsers.java b/modules/reindex/src/main/java/org/opensearch/index/reindex/remote/RemoteResponseParsers.java index b1e4d53c90d92..5a4674e146585 100644 --- a/modules/reindex/src/main/java/org/opensearch/index/reindex/remote/RemoteResponseParsers.java +++ b/modules/reindex/src/main/java/org/opensearch/index/reindex/remote/RemoteResponseParsers.java @@ -35,9 +35,9 @@ import org.apache.lucene.search.TotalHits; import org.opensearch.LegacyESVersion; import org.opensearch.Version; +import org.opensearch.common.bytes.BytesReference; import org.opensearch.core.ParseField; import org.opensearch.common.ParsingException; -import org.opensearch.common.bytes.BytesReference; import org.opensearch.common.collect.Tuple; import org.opensearch.core.concurrency.OpenSearchRejectedExecutionException; import org.opensearch.core.xcontent.ConstructingObjectParser; diff --git a/modules/reindex/src/test/java/org/opensearch/index/reindex/AsyncBulkByScrollActionTests.java b/modules/reindex/src/test/java/org/opensearch/index/reindex/AsyncBulkByScrollActionTests.java index e11ad3b5013c1..61336156a83d0 100644 --- a/modules/reindex/src/test/java/org/opensearch/index/reindex/AsyncBulkByScrollActionTests.java +++ b/modules/reindex/src/test/java/org/opensearch/index/reindex/AsyncBulkByScrollActionTests.java @@ -33,7 +33,6 @@ package org.opensearch.index.reindex; import org.apache.lucene.search.TotalHits; -import org.opensearch.BaseExceptionsHelper; import org.opensearch.OpenSearchException; import org.opensearch.ExceptionsHelper; import org.opensearch.Version; @@ -216,7 +215,7 @@ public void testStartRetriesOnRejectionButFailsOnTooManyRejections() throws Exce assertBusy(() -> assertEquals(testRequest.getMaxRetries() + 1, client.searchAttempts.get())); assertBusy(() -> assertTrue(listener.isDone())); ExecutionException e = expectThrows(ExecutionException.class, () -> listener.get()); - assertThat(BaseExceptionsHelper.stackTrace(e), containsString(OpenSearchRejectedExecutionException.class.getSimpleName())); + assertThat(ExceptionsHelper.stackTrace(e), containsString(OpenSearchRejectedExecutionException.class.getSimpleName())); assertNull("There shouldn't be a search attempt pending that we didn't reject", client.lastSearch.get()); assertEquals(testRequest.getMaxRetries(), testTask.getStatus().getSearchRetries()); } diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/DetailedErrorsEnabledIT.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/DetailedErrorsEnabledIT.java index 090a572ef0d6a..d91a96e0174fc 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/DetailedErrorsEnabledIT.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/DetailedErrorsEnabledIT.java @@ -57,7 +57,7 @@ public void testThatErrorTraceWorksByDefault() throws IOException { Response response = e.getResponse(); assertThat(response.getHeader("Content-Type"), containsString("application/json")); assertThat(EntityUtils.toString(response.getEntity()), - containsString("\"stack_trace\":\"[Validation Failed: 1: index / indices is missing;]; " + + containsString("\"stack_trace\":\"OpenSearchException[Validation Failed: 1: index / indices is missing;]; " + "nested: ActionRequestValidationException[Validation Failed: 1:")); } diff --git a/server/src/internalClusterTest/java/org/opensearch/action/RejectionActionIT.java b/server/src/internalClusterTest/java/org/opensearch/action/RejectionActionIT.java index f2f55b238ab7c..bda24b48b7f10 100644 --- a/server/src/internalClusterTest/java/org/opensearch/action/RejectionActionIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/action/RejectionActionIT.java @@ -32,7 +32,7 @@ package org.opensearch.action; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.action.search.SearchPhaseExecutionException; import org.opensearch.action.search.SearchResponse; import org.opensearch.action.search.SearchType; @@ -105,7 +105,7 @@ public void onFailure(Exception e) { } } else { Exception t = (Exception) response; - Throwable unwrap = BaseExceptionsHelper.unwrapCause(t); + Throwable unwrap = ExceptionsHelper.unwrapCause(t); if (unwrap instanceof SearchPhaseExecutionException) { SearchPhaseExecutionException e = (SearchPhaseExecutionException) unwrap; for (ShardSearchFailure failure : e.shardFailures()) { diff --git a/server/src/internalClusterTest/java/org/opensearch/action/search/TransportSearchIT.java b/server/src/internalClusterTest/java/org/opensearch/action/search/TransportSearchIT.java index 895d7ebea88b6..8cd7bdeb0c822 100644 --- a/server/src/internalClusterTest/java/org/opensearch/action/search/TransportSearchIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/action/search/TransportSearchIT.java @@ -36,7 +36,7 @@ import org.apache.lucene.search.CollectionTerminatedException; import org.apache.lucene.search.ScoreMode; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.action.ActionListener; import org.opensearch.action.admin.cluster.node.stats.NodeStats; import org.opensearch.action.admin.cluster.node.stats.NodesStatsRequest; @@ -415,7 +415,7 @@ public void onFailure(Exception e) { SearchPhaseExecutionException.class, () -> client.prepareSearch("test").addAggregation(new TestAggregationBuilder("test")).get() ); - assertThat(BaseExceptionsHelper.unwrapCause(exc).getCause().getMessage(), containsString("")); + assertThat(ExceptionsHelper.unwrapCause(exc).getCause().getMessage(), containsString("")); }); final AtomicArray exceptions = new AtomicArray<>(10); @@ -443,7 +443,7 @@ public void onFailure(Exception exc) { latch.await(); assertThat(exceptions.asList().size(), equalTo(10)); for (Exception exc : exceptions.asList()) { - assertThat(BaseExceptionsHelper.unwrapCause(exc).getCause().getMessage(), containsString("")); + assertThat(ExceptionsHelper.unwrapCause(exc).getCause().getMessage(), containsString("")); } assertBusy(() -> assertThat(requestBreakerUsed(), equalTo(0L))); } finally { @@ -482,7 +482,7 @@ public void onFailure(Exception exc) { latch.await(); assertThat(exceptions.asList().size(), equalTo(10)); for (Exception exc : exceptions.asList()) { - assertThat(BaseExceptionsHelper.unwrapCause(exc).getCause().getMessage(), containsString("boom")); + assertThat(ExceptionsHelper.unwrapCause(exc).getCause().getMessage(), containsString("boom")); } assertBusy(() -> assertThat(requestBreakerUsed(), equalTo(0L))); } diff --git a/server/src/internalClusterTest/java/org/opensearch/blocks/SimpleBlocksIT.java b/server/src/internalClusterTest/java/org/opensearch/blocks/SimpleBlocksIT.java index 872da7bb12b8e..8ede3e25b2e1a 100644 --- a/server/src/internalClusterTest/java/org/opensearch/blocks/SimpleBlocksIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/blocks/SimpleBlocksIT.java @@ -32,7 +32,7 @@ package org.opensearch.blocks; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.action.ActionRequestValidationException; import org.opensearch.action.admin.indices.create.CreateIndexResponse; import org.opensearch.action.admin.indices.exists.indices.IndicesExistsResponse; @@ -428,7 +428,7 @@ public void testAddBlockWhileIndexingDocuments() throws Exception { try { try (BackgroundIndexer indexer = new BackgroundIndexer(indexName, "_doc", client(), 1000)) { indexer.setFailureAssertion(t -> { - Throwable cause = BaseExceptionsHelper.unwrapCause(t); + Throwable cause = ExceptionsHelper.unwrapCause(t); assertThat(cause, instanceOf(ClusterBlockException.class)); ClusterBlockException e = (ClusterBlockException) cause; assertThat(e.blocks(), hasSize(1)); @@ -474,7 +474,7 @@ public void testAddBlockWhileDeletingIndices() throws Exception { final APIBlock block = randomAddableBlock(); Consumer exceptionConsumer = t -> { - Throwable cause = BaseExceptionsHelper.unwrapCause(t); + Throwable cause = ExceptionsHelper.unwrapCause(t); if (cause instanceof ClusterBlockException) { ClusterBlockException e = (ClusterBlockException) cause; assertThat(e.blocks(), hasSize(1)); diff --git a/server/src/internalClusterTest/java/org/opensearch/indices/memory/breaker/CircuitBreakerServiceIT.java b/server/src/internalClusterTest/java/org/opensearch/indices/memory/breaker/CircuitBreakerServiceIT.java index 6ef3848cec9bb..2dc6b2085b866 100644 --- a/server/src/internalClusterTest/java/org/opensearch/indices/memory/breaker/CircuitBreakerServiceIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/indices/memory/breaker/CircuitBreakerServiceIT.java @@ -32,7 +32,7 @@ package org.opensearch.indices.memory.breaker; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.action.admin.cluster.node.stats.NodeStats; import org.opensearch.action.admin.cluster.node.stats.NodesStatsResponse; import org.opensearch.action.bulk.BulkItemResponse; @@ -421,7 +421,7 @@ public void testLimitsRequestSize() { } else { // each item must have failed with CircuitBreakingException for (BulkItemResponse bulkItemResponse : response) { - Throwable cause = BaseExceptionsHelper.unwrapCause(bulkItemResponse.getFailure().getCause()); + Throwable cause = ExceptionsHelper.unwrapCause(bulkItemResponse.getFailure().getCause()); assertThat(cause, instanceOf(CircuitBreakingException.class)); assertEquals(((CircuitBreakingException) cause).getByteLimit(), inFlightRequestsLimit.getBytes()); } diff --git a/server/src/internalClusterTest/java/org/opensearch/indices/state/CloseIndexIT.java b/server/src/internalClusterTest/java/org/opensearch/indices/state/CloseIndexIT.java index 995f11bcd79c6..28bd5a6ae252d 100644 --- a/server/src/internalClusterTest/java/org/opensearch/indices/state/CloseIndexIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/indices/state/CloseIndexIT.java @@ -32,7 +32,7 @@ package org.opensearch.indices.state; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.action.ActionRequestValidationException; import org.opensearch.action.admin.indices.close.CloseIndexRequestBuilder; import org.opensearch.action.admin.indices.close.CloseIndexResponse; @@ -647,7 +647,7 @@ static void assertIndexIsOpened(final String... indices) { } static void assertException(final Throwable throwable, final String indexName) { - final Throwable t = BaseExceptionsHelper.unwrapCause(throwable); + final Throwable t = ExceptionsHelper.unwrapCause(throwable); if (t instanceof ClusterBlockException) { ClusterBlockException clusterBlockException = (ClusterBlockException) t; assertThat(clusterBlockException.blocks(), hasSize(1)); diff --git a/server/src/internalClusterTest/java/org/opensearch/search/aggregations/AggregationsIntegrationIT.java b/server/src/internalClusterTest/java/org/opensearch/search/aggregations/AggregationsIntegrationIT.java index 60a7da4f4912a..b73b7722f9728 100644 --- a/server/src/internalClusterTest/java/org/opensearch/search/aggregations/AggregationsIntegrationIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/search/aggregations/AggregationsIntegrationIT.java @@ -32,7 +32,7 @@ package org.opensearch.search.aggregations; -import org.opensearch.BaseOpenSearchException; +import org.opensearch.OpenSearchException; import org.opensearch.action.index.IndexRequestBuilder; import org.opensearch.action.search.SearchPhaseExecutionException; import org.opensearch.action.search.SearchResponse; @@ -137,7 +137,7 @@ private void runLargeStringAggregationTest(AggregationBuilder aggregation) { exceptionThrown = true; Throwable nestedException = ex.getCause(); assertNotNull(nestedException); - assertTrue(nestedException instanceof BaseOpenSearchException); + assertTrue(nestedException instanceof OpenSearchException); assertNotNull(nestedException.getCause()); assertTrue(nestedException.getCause() instanceof IllegalArgumentException); String actualExceptionMessage = nestedException.getCause().getMessage(); diff --git a/server/src/internalClusterTest/java/org/opensearch/search/aggregations/bucket/DateHistogramIT.java b/server/src/internalClusterTest/java/org/opensearch/search/aggregations/bucket/DateHistogramIT.java index 6f97b8ef40ffe..617c5745c9bba 100644 --- a/server/src/internalClusterTest/java/org/opensearch/search/aggregations/bucket/DateHistogramIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/search/aggregations/bucket/DateHistogramIT.java @@ -31,7 +31,7 @@ package org.opensearch.search.aggregations.bucket; -import org.opensearch.BaseOpenSearchException; +import org.opensearch.OpenSearchException; import org.opensearch.action.index.IndexRequestBuilder; import org.opensearch.action.search.SearchPhaseExecutionException; import org.opensearch.action.search.SearchResponse; @@ -650,9 +650,9 @@ public void testSingleValuedFieldOrderedByIllegalAgg() throws Exception { .get(); fail("Expected an exception"); } catch (SearchPhaseExecutionException e) { - BaseOpenSearchException[] rootCauses = e.guessRootCauses(); + OpenSearchException[] rootCauses = e.guessRootCauses(); if (rootCauses.length == 1) { - BaseOpenSearchException rootCause = rootCauses[0]; + OpenSearchException rootCause = rootCauses[0]; if (rootCause instanceof AggregationExecutionException) { AggregationExecutionException aggException = (AggregationExecutionException) rootCause; assertThat(aggException.getMessage(), Matchers.startsWith("Invalid aggregation order path")); diff --git a/server/src/internalClusterTest/java/org/opensearch/search/aggregations/bucket/HistogramIT.java b/server/src/internalClusterTest/java/org/opensearch/search/aggregations/bucket/HistogramIT.java index e56c2b3c713bd..dae788abe0d10 100644 --- a/server/src/internalClusterTest/java/org/opensearch/search/aggregations/bucket/HistogramIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/search/aggregations/bucket/HistogramIT.java @@ -32,7 +32,7 @@ package org.opensearch.search.aggregations.bucket; import com.carrotsearch.hppc.LongHashSet; -import org.opensearch.BaseOpenSearchException; +import org.opensearch.OpenSearchException; import org.opensearch.action.index.IndexRequestBuilder; import org.opensearch.action.search.SearchPhaseExecutionException; import org.opensearch.action.search.SearchResponse; @@ -689,9 +689,9 @@ public void testSingleValuedFieldOrderedByIllegalAgg() throws Exception { .get(); fail("Expected an exception"); } catch (SearchPhaseExecutionException e) { - BaseOpenSearchException[] rootCauses = e.guessRootCauses(); + OpenSearchException[] rootCauses = e.guessRootCauses(); if (rootCauses.length == 1) { - BaseOpenSearchException rootCause = rootCauses[0]; + OpenSearchException rootCause = rootCauses[0]; if (rootCause instanceof AggregationExecutionException) { AggregationExecutionException aggException = (AggregationExecutionException) rootCause; assertThat(aggException.getMessage(), Matchers.startsWith("Invalid aggregation order path")); diff --git a/server/src/internalClusterTest/java/org/opensearch/search/aggregations/bucket/terms/StringTermsIT.java b/server/src/internalClusterTest/java/org/opensearch/search/aggregations/bucket/terms/StringTermsIT.java index 96b256dc81ce1..fa8e823545b36 100644 --- a/server/src/internalClusterTest/java/org/opensearch/search/aggregations/bucket/terms/StringTermsIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/search/aggregations/bucket/terms/StringTermsIT.java @@ -31,7 +31,6 @@ package org.opensearch.search.aggregations.bucket.terms; -import org.opensearch.BaseOpenSearchException; import org.opensearch.OpenSearchException; import org.opensearch.action.search.SearchPhaseExecutionException; import org.opensearch.action.search.SearchResponse; @@ -421,9 +420,9 @@ public void testSingleValuedFieldOrderedByIllegalAgg() throws Exception { .get(); fail("Expected an exception"); } catch (SearchPhaseExecutionException e) { - BaseOpenSearchException[] rootCauses = e.guessRootCauses(); + OpenSearchException[] rootCauses = e.guessRootCauses(); if (rootCauses.length == 1) { - BaseOpenSearchException rootCause = rootCauses[0]; + OpenSearchException rootCause = rootCauses[0]; if (rootCause instanceof AggregationExecutionException) { AggregationExecutionException aggException = (AggregationExecutionException) rootCause; assertThat(aggException.getMessage(), startsWith("Invalid aggregation order path")); diff --git a/server/src/internalClusterTest/java/org/opensearch/search/aggregations/pipeline/DerivativeIT.java b/server/src/internalClusterTest/java/org/opensearch/search/aggregations/pipeline/DerivativeIT.java index eb6153493323c..406c57d044259 100644 --- a/server/src/internalClusterTest/java/org/opensearch/search/aggregations/pipeline/DerivativeIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/search/aggregations/pipeline/DerivativeIT.java @@ -32,7 +32,7 @@ package org.opensearch.search.aggregations.pipeline; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.action.index.IndexRequestBuilder; import org.opensearch.action.search.SearchPhaseExecutionException; import org.opensearch.action.search.SearchResponse; @@ -639,7 +639,7 @@ public void testSingleValueAggDerivative_invalidPath() throws Exception { .get(); fail("Expected an Exception but didn't get one"); } catch (Exception e) { - Throwable cause = BaseExceptionsHelper.unwrapCause(e); + Throwable cause = ExceptionsHelper.unwrapCause(e); if (cause == null) { throw e; } else if (cause instanceof SearchPhaseExecutionException) { diff --git a/server/src/internalClusterTest/java/org/opensearch/search/aggregations/pipeline/ExtendedStatsBucketIT.java b/server/src/internalClusterTest/java/org/opensearch/search/aggregations/pipeline/ExtendedStatsBucketIT.java index fc4a2908ae563..85fe794b05fc6 100644 --- a/server/src/internalClusterTest/java/org/opensearch/search/aggregations/pipeline/ExtendedStatsBucketIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/search/aggregations/pipeline/ExtendedStatsBucketIT.java @@ -32,7 +32,7 @@ package org.opensearch.search.aggregations.pipeline; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.action.index.IndexRequestBuilder; import org.opensearch.action.search.SearchPhaseExecutionException; import org.opensearch.action.search.SearchResponse; @@ -489,7 +489,7 @@ public void testBadSigmaAsSubAgg() throws Exception { ) .get() ); - Throwable cause = BaseExceptionsHelper.unwrapCause(ex); + Throwable cause = ExceptionsHelper.unwrapCause(ex); if (cause == null) { throw ex; } else if (cause instanceof SearchPhaseExecutionException) { diff --git a/server/src/internalClusterTest/java/org/opensearch/search/aggregations/pipeline/PercentilesBucketIT.java b/server/src/internalClusterTest/java/org/opensearch/search/aggregations/pipeline/PercentilesBucketIT.java index 4d7fa05ba5043..1da079781dc63 100644 --- a/server/src/internalClusterTest/java/org/opensearch/search/aggregations/pipeline/PercentilesBucketIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/search/aggregations/pipeline/PercentilesBucketIT.java @@ -32,7 +32,7 @@ package org.opensearch.search.aggregations.pipeline; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.action.index.IndexRequestBuilder; import org.opensearch.action.search.SearchPhaseExecutionException; import org.opensearch.action.search.SearchResponse; @@ -439,7 +439,7 @@ public void testBadPercents() throws Exception { fail("Illegal percent's were provided but no exception was thrown."); } catch (Exception e) { - Throwable cause = BaseExceptionsHelper.unwrapCause(e); + Throwable cause = ExceptionsHelper.unwrapCause(e); if (cause == null) { throw e; } else if (cause instanceof SearchPhaseExecutionException) { @@ -474,7 +474,7 @@ public void testBadPercents_asSubAgg() throws Exception { fail("Illegal percent's were provided but no exception was thrown."); } catch (Exception e) { - Throwable cause = BaseExceptionsHelper.unwrapCause(e); + Throwable cause = ExceptionsHelper.unwrapCause(e); if (cause == null) { throw e; } else if (cause instanceof SearchPhaseExecutionException) { diff --git a/server/src/internalClusterTest/java/org/opensearch/snapshots/SharedClusterSnapshotRestoreIT.java b/server/src/internalClusterTest/java/org/opensearch/snapshots/SharedClusterSnapshotRestoreIT.java index 27dd72ae3d022..f1df031674e48 100644 --- a/server/src/internalClusterTest/java/org/opensearch/snapshots/SharedClusterSnapshotRestoreIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/snapshots/SharedClusterSnapshotRestoreIT.java @@ -34,7 +34,7 @@ import org.apache.lucene.util.BytesRef; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.OpenSearchException; import org.opensearch.Version; import org.opensearch.action.ActionFuture; @@ -1986,7 +1986,7 @@ public void testSnapshotSucceedsAfterSnapshotFailure() throws Exception { } } catch (SnapshotException | RepositoryException ex) { // sometimes, the snapshot will fail with a top level I/O exception - assertThat(BaseExceptionsHelper.stackTrace(ex), containsString("Random IOException")); + assertThat(ExceptionsHelper.stackTrace(ex), containsString("Random IOException")); } logger.info("--> snapshot with no I/O failures"); diff --git a/server/src/main/java/org/opensearch/OpenSearchException.java b/server/src/main/java/org/opensearch/OpenSearchServerException.java similarity index 69% rename from server/src/main/java/org/opensearch/OpenSearchException.java rename to server/src/main/java/org/opensearch/OpenSearchServerException.java index 738d7bb696f95..bb74331d15eba 100644 --- a/server/src/main/java/org/opensearch/OpenSearchException.java +++ b/server/src/main/java/org/opensearch/OpenSearchServerException.java @@ -6,91 +6,35 @@ * compatible open source license. */ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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. - */ - -/* - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - package org.opensearch; -import org.opensearch.action.support.replication.ReplicationOperation; -import org.opensearch.cluster.action.shard.ShardStateAction; -import org.opensearch.common.CheckedFunction; -import org.opensearch.common.collect.Tuple; -import org.opensearch.common.io.stream.StreamInput; -import org.opensearch.common.io.stream.StreamOutput; -import org.opensearch.common.io.stream.Writeable; -import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.core.xcontent.XContentParser; -import org.opensearch.index.Index; -import org.opensearch.index.shard.ShardId; -import org.opensearch.rest.RestStatus; -import org.opensearch.search.aggregations.MultiBucketConsumerService; -import org.opensearch.transport.TcpTransport; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Pattern; - -import static org.opensearch.BaseOpenSearchException.OpenSearchExceptionHandleRegistry.registerExceptionHandle; +import static org.opensearch.OpenSearchException.OpenSearchExceptionHandle; +import static org.opensearch.OpenSearchException.OpenSearchExceptionHandleRegistry.registerExceptionHandle; +import static org.opensearch.OpenSearchException.UNKNOWN_VERSION_ADDED; import static org.opensearch.Version.V_2_1_0; import static org.opensearch.Version.V_2_3_0; import static org.opensearch.Version.V_2_4_0; import static org.opensearch.Version.V_2_5_0; import static org.opensearch.Version.V_2_6_0; import static org.opensearch.Version.V_2_7_0; -import static org.opensearch.cluster.metadata.IndexMetadata.INDEX_UUID_NA_VALUE; -import static org.opensearch.common.xcontent.XContentParserUtils.ensureExpectedToken; -import static org.opensearch.common.xcontent.XContentParserUtils.ensureFieldName; /** - * A base class for all opensearch exceptions. + * Utility class to register server exceptions * * @opensearch.internal */ -public class OpenSearchException extends BaseOpenSearchException implements Writeable { +public final class OpenSearchServerException { + + private OpenSearchServerException() { + // no ctor: + } /** * Setting a higher base exception id to avoid conflicts. */ private static final int CUSTOM_ELASTICSEARCH_EXCEPTIONS_BASE_ID = 10000; - private static final Pattern OS_METADATA = Pattern.compile("^opensearch\\."); - private static final Pattern ES_METADATA = Pattern.compile("^es\\."); - - static { - registerExceptionHandle( - new OpenSearchExceptionHandle( - org.opensearch.index.snapshots.IndexShardSnapshotFailedException.class, - org.opensearch.index.snapshots.IndexShardSnapshotFailedException::new, - 0, - UNKNOWN_VERSION_ADDED - ) - ); + public static void registerExceptions() { registerExceptionHandle( new OpenSearchExceptionHandle( org.opensearch.search.dfs.DfsPhaseExecutionException.class, @@ -382,14 +326,6 @@ public class OpenSearchException extends BaseOpenSearchException implements Writ UNKNOWN_VERSION_ADDED ) ); - registerExceptionHandle( - new OpenSearchExceptionHandle( - org.opensearch.common.ParsingException.class, - org.opensearch.common.ParsingException::new, - 40, - UNKNOWN_VERSION_ADDED - ) - ); registerExceptionHandle( new OpenSearchExceptionHandle( org.opensearch.index.shard.IndexShardClosedException.class, @@ -516,14 +452,6 @@ public class OpenSearchException extends BaseOpenSearchException implements Writ // 59 used to be OpenSearchRejectedExecutionException // 60 used to be for EarlyTerminationException // 61 used to be for RoutingValidationException - registerExceptionHandle( - new OpenSearchExceptionHandle( - org.opensearch.common.io.stream.NotSerializableExceptionWrapper.class, - org.opensearch.common.io.stream.NotSerializableExceptionWrapper::new, - 62, - UNKNOWN_VERSION_ADDED - ) - ); registerExceptionHandle( new OpenSearchExceptionHandle( org.opensearch.indices.AliasFilterParsingException.class, @@ -558,7 +486,12 @@ public class OpenSearchException extends BaseOpenSearchException implements Writ ) ); registerExceptionHandle( - new OpenSearchExceptionHandle(OpenSearchException.class, OpenSearchException::new, 68, UNKNOWN_VERSION_ADDED) + new OpenSearchExceptionHandle( + org.opensearch.OpenSearchException.class, + org.opensearch.OpenSearchException::new, + 68, + UNKNOWN_VERSION_ADDED + ) ); registerExceptionHandle( new OpenSearchExceptionHandle( @@ -887,8 +820,8 @@ public class OpenSearchException extends BaseOpenSearchException implements Writ ); registerExceptionHandle( new OpenSearchExceptionHandle( - ReplicationOperation.RetryOnPrimaryException.class, - ReplicationOperation.RetryOnPrimaryException::new, + org.opensearch.action.support.replication.ReplicationOperation.RetryOnPrimaryException.class, + org.opensearch.action.support.replication.ReplicationOperation.RetryOnPrimaryException::new, 117, UNKNOWN_VERSION_ADDED ) @@ -937,8 +870,8 @@ public class OpenSearchException extends BaseOpenSearchException implements Writ // 124 used to be Script.ScriptParseException registerExceptionHandle( new OpenSearchExceptionHandle( - TcpTransport.HttpRequestOnTransportException.class, - TcpTransport.HttpRequestOnTransportException::new, + org.opensearch.transport.TcpTransport.HttpRequestOnTransportException.class, + org.opensearch.transport.TcpTransport.HttpRequestOnTransportException::new, 125, UNKNOWN_VERSION_ADDED ) @@ -1043,8 +976,8 @@ public class OpenSearchException extends BaseOpenSearchException implements Writ ); registerExceptionHandle( new OpenSearchExceptionHandle( - ShardStateAction.NoLongerPrimaryShardException.class, - ShardStateAction.NoLongerPrimaryShardException::new, + org.opensearch.cluster.action.shard.ShardStateAction.NoLongerPrimaryShardException.class, + org.opensearch.cluster.action.shard.ShardStateAction.NoLongerPrimaryShardException::new, 142, UNKNOWN_VERSION_ADDED ) @@ -1092,8 +1025,8 @@ public class OpenSearchException extends BaseOpenSearchException implements Writ // 148 was UnknownNamedObjectException registerExceptionHandle( new OpenSearchExceptionHandle( - MultiBucketConsumerService.TooManyBucketsException.class, - MultiBucketConsumerService.TooManyBucketsException::new, + org.opensearch.search.aggregations.MultiBucketConsumerService.TooManyBucketsException.class, + org.opensearch.search.aggregations.MultiBucketConsumerService.TooManyBucketsException::new, 149, UNKNOWN_VERSION_ADDED ) @@ -1275,367 +1208,4 @@ public class OpenSearchException extends BaseOpenSearchException implements Writ ) ); } - - /** - * Construct a OpenSearchException with the specified cause exception. - */ - public OpenSearchException(Throwable cause) { - super(cause); - } - - /** - * Construct a OpenSearchException with the specified detail message. - * - * The message can be parameterized using {} as placeholders for the given - * arguments - * - * @param msg the detail message - * @param args the arguments for the message - */ - public OpenSearchException(String msg, Object... args) { - super(msg, args); - } - - /** - * Construct a OpenSearchException with the specified detail message - * and nested exception. - * - * The message can be parameterized using {} as placeholders for the given - * arguments - * - * @param msg the detail message - * @param cause the nested exception - * @param args the arguments for the message - */ - public OpenSearchException(String msg, Throwable cause, Object... args) { - super(msg, cause, args); - } - - public OpenSearchException(StreamInput in) throws IOException { - super(in.readOptionalString(), in.readException()); - readStackTrace(this, in); - headers.putAll(in.readMapOfLists(StreamInput::readString, StreamInput::readString)); - metadata.putAll(in.readMapOfLists(OpenSearchException::readAndReplace, StreamInput::readString)); - } - - private static String readAndReplace(StreamInput in) throws IOException { - String str = in.readString(); - return in.getVersion().onOrBefore(LegacyESVersion.V_7_10_2) ? ES_METADATA.matcher(str).replaceFirst("opensearch.") : str; - } - - private static void replaceAndWrite(StreamOutput out, String str) throws IOException { - out.writeString(out.getVersion().onOrBefore(LegacyESVersion.V_7_10_2) ? OS_METADATA.matcher(str).replaceFirst("es.") : str); - } - - /** - * Returns the rest status code associated with this exception. - */ - public RestStatus status() { - Throwable cause = unwrapCause(); - if (cause == this) { - return RestStatus.INTERNAL_SERVER_ERROR; - } else { - return ExceptionsHelper.status(cause); - } - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeOptionalString(this.getMessage()); - out.writeException(this.getCause()); - writeStackTraces(this, out, StreamOutput::writeException); - out.writeMapOfLists(headers, StreamOutput::writeString, StreamOutput::writeString); - out.writeMapOfLists(metadata, StreamOutput::writeString, StreamOutput::writeString); - } - - /** - * Returns true iff the given class is a registered for an exception to be read. - */ - public static boolean isRegistered(final Class exception, Version version) { - return OpenSearchExceptionHandleRegistry.isRegistered(exception, version); - } - - static Set> getRegisteredKeys() { // for testing - return OpenSearchExceptionHandleRegistry.getRegisteredKeys(); - } - - /** - * Returns the serialization id the given exception. - */ - public static int getId(final Class exception) { - return OpenSearchExceptionHandleRegistry.getId(exception); - } - - /** - * Generate a {@link OpenSearchException} from a {@link XContentParser}. This does not - * return the original exception type (ie NodeClosedException for example) but just wraps - * the type, the reason and the cause of the exception. It also recursively parses the - * tree structure of the cause, returning it as a tree structure of {@link OpenSearchException} - * instances. - */ - public static OpenSearchException fromXContent(XContentParser parser) throws IOException { - XContentParser.Token token = parser.nextToken(); - ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser); - return innerFromXContent(parser, false); - } - - public static OpenSearchException innerFromXContent(XContentParser parser, boolean parseRootCauses) throws IOException { - XContentParser.Token token = parser.currentToken(); - ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser); - - String type = null, reason = null, stack = null; - OpenSearchException cause = null; - Map> metadata = new HashMap<>(); - Map> headers = new HashMap<>(); - List rootCauses = new ArrayList<>(); - List suppressed = new ArrayList<>(); - - for (; token == XContentParser.Token.FIELD_NAME; token = parser.nextToken()) { - String currentFieldName = parser.currentName(); - token = parser.nextToken(); - - if (token.isValue()) { - if (BaseExceptionsHelper.TYPE.equals(currentFieldName)) { - type = parser.text(); - } else if (BaseExceptionsHelper.REASON.equals(currentFieldName)) { - reason = parser.text(); - } else if (BaseExceptionsHelper.STACK_TRACE.equals(currentFieldName)) { - stack = parser.text(); - } else if (token == XContentParser.Token.VALUE_STRING) { - metadata.put(currentFieldName, Collections.singletonList(parser.text())); - } - } else if (token == XContentParser.Token.START_OBJECT) { - if (BaseExceptionsHelper.CAUSED_BY.equals(currentFieldName)) { - cause = fromXContent(parser); - } else if (BaseExceptionsHelper.HEADER.equals(currentFieldName)) { - while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { - if (token == XContentParser.Token.FIELD_NAME) { - currentFieldName = parser.currentName(); - } else { - List values = headers.getOrDefault(currentFieldName, new ArrayList<>()); - if (token == XContentParser.Token.VALUE_STRING) { - values.add(parser.text()); - } else if (token == XContentParser.Token.START_ARRAY) { - while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { - if (token == XContentParser.Token.VALUE_STRING) { - values.add(parser.text()); - } else { - parser.skipChildren(); - } - } - } else if (token == XContentParser.Token.START_OBJECT) { - parser.skipChildren(); - } - headers.put(currentFieldName, values); - } - } - } else { - // Any additional metadata object added by the metadataToXContent method is ignored - // and skipped, so that the parser does not fail on unknown fields. The parser only - // support metadata key-pairs and metadata arrays of values. - parser.skipChildren(); - } - } else if (token == XContentParser.Token.START_ARRAY) { - if (parseRootCauses && ROOT_CAUSE.equals(currentFieldName)) { - while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { - rootCauses.add(fromXContent(parser)); - } - } else if (BaseExceptionsHelper.SUPPRESSED.match(currentFieldName, parser.getDeprecationHandler())) { - while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { - suppressed.add(fromXContent(parser)); - } - } else { - // Parse the array and add each item to the corresponding list of metadata. - // Arrays of objects are not supported yet and just ignored and skipped. - List values = new ArrayList<>(); - while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { - if (token == XContentParser.Token.VALUE_STRING) { - values.add(parser.text()); - } else { - parser.skipChildren(); - } - } - if (values.size() > 0) { - if (metadata.containsKey(currentFieldName)) { - values.addAll(metadata.get(currentFieldName)); - } - metadata.put(currentFieldName, values); - } - } - } - } - - OpenSearchException e = new OpenSearchException(buildMessage(type, reason, stack), cause); - for (Map.Entry> entry : metadata.entrySet()) { - // subclasses can print out additional metadata through the metadataToXContent method. Simple key-value pairs will be - // parsed back and become part of this metadata set, while objects and arrays are not supported when parsing back. - // Those key-value pairs become part of the metadata set and inherit the "opensearch." prefix as that is currently required - // by addMetadata. The prefix will get stripped out when printing metadata out so it will be effectively invisible. - // TODO move subclasses that print out simple metadata to using addMetadata directly and support also numbers and booleans. - // TODO rename metadataToXContent and have only SearchPhaseExecutionException use it, which prints out complex objects - e.addMetadata(BaseExceptionsHelper.OPENSEARCH_PREFIX_KEY + entry.getKey(), entry.getValue()); - } - for (Map.Entry> header : headers.entrySet()) { - e.addHeader(header.getKey(), header.getValue()); - } - - // Adds root causes as suppressed exception. This way they are not lost - // after parsing and can be retrieved using getSuppressed() method. - for (OpenSearchException rootCause : rootCauses) { - e.addSuppressed(rootCause); - } - for (OpenSearchException s : suppressed) { - e.addSuppressed(s); - } - return e; - } - - /** - * Parses the output of {@link #generateFailureXContent(XContentBuilder, Params, Exception, boolean)} - */ - public static OpenSearchException failureFromXContent(XContentParser parser) throws IOException { - XContentParser.Token token = parser.currentToken(); - ensureFieldName(parser, token, ERROR); - - token = parser.nextToken(); - if (token.isValue()) { - return new OpenSearchException(buildMessage("exception", parser.text(), null)); - } - - ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser); - token = parser.nextToken(); - - // Root causes are parsed in the innerFromXContent() and are added as suppressed exceptions. - return innerFromXContent(parser, true); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - if (metadata.containsKey(INDEX_METADATA_KEY)) { - builder.append(getIndex()); - if (metadata.containsKey(SHARD_METADATA_KEY)) { - builder.append('[').append(getShardId()).append(']'); - } - builder.append(' '); - } - return builder.append(BaseExceptionsHelper.detailedMessage(this).trim()).toString(); - } - - /** - * Deserializes stacktrace elements as well as suppressed exceptions from the given output stream and - * adds it to the given exception. - */ - public static T readStackTrace(T throwable, StreamInput in) throws IOException { - throwable.setStackTrace(in.readArray(i -> { - final String declaringClasss = i.readString(); - final String fileName = i.readOptionalString(); - final String methodName = i.readString(); - final int lineNumber = i.readVInt(); - return new StackTraceElement(declaringClasss, methodName, fileName, lineNumber); - }, StackTraceElement[]::new)); - - int numSuppressed = in.readVInt(); - for (int i = 0; i < numSuppressed; i++) { - throwable.addSuppressed(in.readException()); - } - return throwable; - } - - /** - * Serializes the given exceptions stacktrace elements as well as it's suppressed exceptions to the given output stream. - */ - public static T writeStackTraces(T throwable, StreamOutput out, Writer exceptionWriter) - throws IOException { - out.writeArray((o, v) -> { - o.writeString(v.getClassName()); - o.writeOptionalString(v.getFileName()); - o.writeString(v.getMethodName()); - o.writeVInt(v.getLineNumber()); - }, throwable.getStackTrace()); - out.writeArray(exceptionWriter, throwable.getSuppressed()); - return throwable; - } - - /** - * This is the list of Exceptions OpenSearch can throw over the wire or save into a corruption marker. Each value in the enum is a - * single exception tying the Class to an id for use of the encode side and the id back to a constructor for use on the decode side. As - * such its ok if the exceptions to change names so long as their constructor can still read the exception. Each exception is listed - * in id order below. If you want to remove an exception leave a tombstone comment and mark the id as null in - * ExceptionSerializationTests.testIds.ids. - */ - protected static class OpenSearchExceptionHandle extends BaseOpenSearchExceptionHandle { - OpenSearchExceptionHandle( - final Class exceptionClass, - final CheckedFunction constructor, - final int id, - final Version versionAdded - ) { - super(exceptionClass, constructor, id, versionAdded); - OpenSearchExceptionHandleRegistry.registerExceptionHandle(this); - } - } - - /** - * Returns an array of all registered handle IDs. These are the IDs for every registered - * exception. - * - * @return an array of all registered handle IDs - */ - static int[] ids() { - return OpenSearchExceptionHandleRegistry.ids().stream().mapToInt(i -> i).toArray(); - } - - /** - * Returns an array of all registered pairs of handle IDs and exception classes. These pairs are - * provided for every registered exception. - * - * @return an array of all registered pairs of handle IDs and exception classes - */ - static Tuple>[] classes() { - final Tuple>[] ts = OpenSearchExceptionHandleRegistry.handles() - .stream() - .map(h -> Tuple.tuple(h.id, h.exceptionClass)) - .toArray(Tuple[]::new); - return ts; - } - - public Index getIndex() { - List index = getMetadata(INDEX_METADATA_KEY); - if (index != null && index.isEmpty() == false) { - List index_uuid = getMetadata(INDEX_METADATA_KEY_UUID); - return new Index(index.get(0), index_uuid.get(0)); - } - - return null; - } - - public ShardId getShardId() { - List shard = getMetadata(SHARD_METADATA_KEY); - if (shard != null && shard.isEmpty() == false) { - return new ShardId(getIndex(), Integer.parseInt(shard.get(0))); - } - return null; - } - - public void setIndex(Index index) { - if (index != null) { - addMetadata(INDEX_METADATA_KEY, index.getName()); - addMetadata(INDEX_METADATA_KEY_UUID, index.getUUID()); - } - } - - public void setIndex(String index) { - if (index != null) { - setIndex(new Index(index, INDEX_UUID_NA_VALUE)); - } - } - - public void setShard(ShardId shardId) { - if (shardId != null) { - setIndex(shardId.getIndex()); - addMetadata(SHARD_METADATA_KEY, Integer.toString(shardId.id())); - } - } - } diff --git a/server/src/main/java/org/opensearch/action/TaskOperationFailure.java b/server/src/main/java/org/opensearch/action/TaskOperationFailure.java index e1cf77fb3d530..25e1ab1bb3d6f 100644 --- a/server/src/main/java/org/opensearch/action/TaskOperationFailure.java +++ b/server/src/main/java/org/opensearch/action/TaskOperationFailure.java @@ -32,9 +32,8 @@ package org.opensearch.action; -import org.opensearch.BaseExceptionsHelper; -import org.opensearch.OpenSearchException; import org.opensearch.ExceptionsHelper; +import org.opensearch.OpenSearchException; import org.opensearch.core.ParseField; import org.opensearch.common.io.stream.StreamInput; import org.opensearch.common.io.stream.StreamOutput; @@ -145,7 +144,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws if (reason != null) { builder.field(REASON); builder.startObject(); - BaseExceptionsHelper.generateThrowableXContent(builder, params, reason); + OpenSearchException.generateThrowableXContent(builder, params, reason); builder.endObject(); } return builder; diff --git a/server/src/main/java/org/opensearch/action/admin/cluster/node/reload/NodesReloadSecureSettingsResponse.java b/server/src/main/java/org/opensearch/action/admin/cluster/node/reload/NodesReloadSecureSettingsResponse.java index 874f6c9f13ac7..f6d9a5c7b6453 100644 --- a/server/src/main/java/org/opensearch/action/admin/cluster/node/reload/NodesReloadSecureSettingsResponse.java +++ b/server/src/main/java/org/opensearch/action/admin/cluster/node/reload/NodesReloadSecureSettingsResponse.java @@ -32,7 +32,7 @@ package org.opensearch.action.admin.cluster.node.reload; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.OpenSearchException; import org.opensearch.action.FailedNodeException; import org.opensearch.action.support.nodes.BaseNodeResponse; import org.opensearch.action.support.nodes.BaseNodesResponse; @@ -83,7 +83,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws final Exception e = node.reloadException(); if (e != null) { builder.startObject("reload_exception"); - BaseExceptionsHelper.generateThrowableXContent(builder, params, e); + OpenSearchException.generateThrowableXContent(builder, params, e); builder.endObject(); } builder.endObject(); diff --git a/server/src/main/java/org/opensearch/action/admin/indices/close/CloseIndexResponse.java b/server/src/main/java/org/opensearch/action/admin/indices/close/CloseIndexResponse.java index 4cafd076d5d48..09d1780595165 100644 --- a/server/src/main/java/org/opensearch/action/admin/indices/close/CloseIndexResponse.java +++ b/server/src/main/java/org/opensearch/action/admin/indices/close/CloseIndexResponse.java @@ -32,7 +32,7 @@ package org.opensearch.action.admin.indices.close; import org.opensearch.LegacyESVersion; -import org.opensearch.BaseOpenSearchException; +import org.opensearch.OpenSearchException; import org.opensearch.action.support.DefaultShardOperationFailedException; import org.opensearch.action.support.master.ShardsAcknowledgedResponse; import org.opensearch.common.Nullable; @@ -182,7 +182,7 @@ public XContentBuilder toXContent(final XContentBuilder builder, final Params pa builder.field("closed", false); if (exception != null) { builder.startObject("exception"); - BaseOpenSearchException.generateFailureXContent(builder, params, exception, true); + OpenSearchException.generateFailureXContent(builder, params, exception, true); builder.endObject(); } else { builder.startObject("failedShards"); diff --git a/server/src/main/java/org/opensearch/action/admin/indices/readonly/AddIndexBlockResponse.java b/server/src/main/java/org/opensearch/action/admin/indices/readonly/AddIndexBlockResponse.java index 6d31dfb98b7c8..6d89170fefd7c 100644 --- a/server/src/main/java/org/opensearch/action/admin/indices/readonly/AddIndexBlockResponse.java +++ b/server/src/main/java/org/opensearch/action/admin/indices/readonly/AddIndexBlockResponse.java @@ -31,7 +31,7 @@ package org.opensearch.action.admin.indices.readonly; -import org.opensearch.BaseOpenSearchException; +import org.opensearch.OpenSearchException; import org.opensearch.action.support.DefaultShardOperationFailedException; import org.opensearch.action.support.master.ShardsAcknowledgedResponse; import org.opensearch.common.Nullable; @@ -172,7 +172,7 @@ public XContentBuilder toXContent(final XContentBuilder builder, final Params pa if (hasFailures()) { if (exception != null) { builder.startObject("exception"); - BaseOpenSearchException.generateFailureXContent(builder, params, exception, true); + OpenSearchException.generateFailureXContent(builder, params, exception, true); builder.endObject(); } else { builder.startArray("failed_shards"); diff --git a/server/src/main/java/org/opensearch/action/admin/indices/shards/IndicesShardStoresResponse.java b/server/src/main/java/org/opensearch/action/admin/indices/shards/IndicesShardStoresResponse.java index a03c6e9045a6b..8da11b34c20de 100644 --- a/server/src/main/java/org/opensearch/action/admin/indices/shards/IndicesShardStoresResponse.java +++ b/server/src/main/java/org/opensearch/action/admin/indices/shards/IndicesShardStoresResponse.java @@ -33,8 +33,8 @@ package org.opensearch.action.admin.indices.shards; import com.carrotsearch.hppc.cursors.IntObjectCursor; -import org.opensearch.BaseExceptionsHelper; import org.opensearch.LegacyESVersion; +import org.opensearch.OpenSearchException; import org.opensearch.action.ActionResponse; import org.opensearch.action.support.DefaultShardOperationFailedException; import org.opensearch.cluster.node.DiscoveryNode; @@ -203,7 +203,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.field(Fields.ALLOCATED, allocationStatus.value()); if (storeException != null) { builder.startObject(Fields.STORE_EXCEPTION); - BaseExceptionsHelper.generateThrowableXContent(builder, params, storeException); + OpenSearchException.generateThrowableXContent(builder, params, storeException); builder.endObject(); } return builder; diff --git a/server/src/main/java/org/opensearch/action/bulk/BulkItemResponse.java b/server/src/main/java/org/opensearch/action/bulk/BulkItemResponse.java index 1ffc6e867df45..e9534bf224d77 100644 --- a/server/src/main/java/org/opensearch/action/bulk/BulkItemResponse.java +++ b/server/src/main/java/org/opensearch/action/bulk/BulkItemResponse.java @@ -32,7 +32,6 @@ package org.opensearch.action.bulk; -import org.opensearch.BaseExceptionsHelper; import org.opensearch.ExceptionsHelper; import org.opensearch.LegacyESVersion; import org.opensearch.OpenSearchException; @@ -96,7 +95,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.field(_ID, failure.getId()); builder.field(STATUS, failure.getStatus().getStatus()); builder.startObject(ERROR); - BaseExceptionsHelper.generateThrowableXContent(builder, params, failure.getCause()); + OpenSearchException.generateThrowableXContent(builder, params, failure.getCause()); builder.endObject(); } builder.endObject(); @@ -364,7 +363,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.field(ID_FIELD, id); } builder.startObject(CAUSE_FIELD); - BaseExceptionsHelper.generateThrowableXContent(builder, params, cause); + OpenSearchException.generateThrowableXContent(builder, params, cause); builder.endObject(); builder.field(STATUS_FIELD, status.getStatus()); return builder; diff --git a/server/src/main/java/org/opensearch/action/bulk/TransportBulkAction.java b/server/src/main/java/org/opensearch/action/bulk/TransportBulkAction.java index e71c3aef35c9a..18a39afc48079 100644 --- a/server/src/main/java/org/opensearch/action/bulk/TransportBulkAction.java +++ b/server/src/main/java/org/opensearch/action/bulk/TransportBulkAction.java @@ -35,7 +35,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.lucene.util.SparseFixedBitSet; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.LegacyESVersion; import org.opensearch.core.Assertions; import org.opensearch.OpenSearchParseException; @@ -326,7 +326,7 @@ protected void doRun() { @Override public void onFailure(Exception e) { - if (!(BaseExceptionsHelper.unwrapCause(e) instanceof ResourceAlreadyExistsException)) { + if (!(ExceptionsHelper.unwrapCause(e) instanceof ResourceAlreadyExistsException)) { // fail all requests involving this index, if create didn't work for (int i = 0; i < bulkRequest.requests.size(); i++) { DocWriteRequest request = bulkRequest.requests.get(i); diff --git a/server/src/main/java/org/opensearch/action/bulk/TransportShardBulkAction.java b/server/src/main/java/org/opensearch/action/bulk/TransportShardBulkAction.java index ff9226e5e6317..cbb30714ee8e1 100644 --- a/server/src/main/java/org/opensearch/action/bulk/TransportShardBulkAction.java +++ b/server/src/main/java/org/opensearch/action/bulk/TransportShardBulkAction.java @@ -36,7 +36,7 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.util.MessageSupplier; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.action.ActionListener; import org.opensearch.action.ActionListenerResponseHandler; import org.opensearch.action.ActionRunnable; @@ -719,7 +719,7 @@ && isConflictException(executionResult.getFailure().getCause()) } private static boolean isConflictException(final Exception e) { - return BaseExceptionsHelper.unwrapCause(e) instanceof VersionConflictEngineException; + return ExceptionsHelper.unwrapCause(e) instanceof VersionConflictEngineException; } /** diff --git a/server/src/main/java/org/opensearch/action/get/MultiGetResponse.java b/server/src/main/java/org/opensearch/action/get/MultiGetResponse.java index 3e2aa1316a7cc..88f78d2ca6815 100644 --- a/server/src/main/java/org/opensearch/action/get/MultiGetResponse.java +++ b/server/src/main/java/org/opensearch/action/get/MultiGetResponse.java @@ -32,7 +32,6 @@ package org.opensearch.action.get; -import org.opensearch.BaseOpenSearchException; import org.opensearch.OpenSearchException; import org.opensearch.Version; import org.opensearch.action.ActionResponse; @@ -131,7 +130,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.startObject(); builder.field(INDEX.getPreferredName(), index); builder.field(ID.getPreferredName(), id); - BaseOpenSearchException.generateFailureXContent(builder, params, exception, true); + OpenSearchException.generateFailureXContent(builder, params, exception, true); builder.endObject(); return builder; } diff --git a/server/src/main/java/org/opensearch/action/ingest/SimulateDocumentBaseResult.java b/server/src/main/java/org/opensearch/action/ingest/SimulateDocumentBaseResult.java index e15021d8db168..463f843f2547a 100644 --- a/server/src/main/java/org/opensearch/action/ingest/SimulateDocumentBaseResult.java +++ b/server/src/main/java/org/opensearch/action/ingest/SimulateDocumentBaseResult.java @@ -31,7 +31,6 @@ package org.opensearch.action.ingest; -import org.opensearch.BaseOpenSearchException; import org.opensearch.LegacyESVersion; import org.opensearch.OpenSearchException; import org.opensearch.core.ParseField; @@ -147,7 +146,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws if (failure == null) { ingestDocument.toXContent(builder, params); } else { - BaseOpenSearchException.generateFailureXContent(builder, params, failure, true); + OpenSearchException.generateFailureXContent(builder, params, failure, true); } builder.endObject(); return builder; diff --git a/server/src/main/java/org/opensearch/action/ingest/SimulateProcessorResult.java b/server/src/main/java/org/opensearch/action/ingest/SimulateProcessorResult.java index 3f0774cb13210..a44da4eeae4d5 100644 --- a/server/src/main/java/org/opensearch/action/ingest/SimulateProcessorResult.java +++ b/server/src/main/java/org/opensearch/action/ingest/SimulateProcessorResult.java @@ -31,7 +31,6 @@ package org.opensearch.action.ingest; -import org.opensearch.BaseOpenSearchException; import org.opensearch.LegacyESVersion; import org.opensearch.OpenSearchException; import org.opensearch.core.ParseField; @@ -284,10 +283,10 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws if (failure != null && ingestDocument != null) { builder.startObject(IGNORED_ERROR_FIELD); - BaseOpenSearchException.generateFailureXContent(builder, params, failure, true); + OpenSearchException.generateFailureXContent(builder, params, failure, true); builder.endObject(); } else if (failure != null) { - BaseOpenSearchException.generateFailureXContent(builder, params, failure, true); + OpenSearchException.generateFailureXContent(builder, params, failure, true); } if (ingestDocument != null) { diff --git a/server/src/main/java/org/opensearch/action/search/AbstractSearchAsyncAction.java b/server/src/main/java/org/opensearch/action/search/AbstractSearchAsyncAction.java index 5c03a12984aee..48fac9e8c8d38 100644 --- a/server/src/main/java/org/opensearch/action/search/AbstractSearchAsyncAction.java +++ b/server/src/main/java/org/opensearch/action/search/AbstractSearchAsyncAction.java @@ -34,8 +34,8 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.ParameterizedMessage; -import org.opensearch.BaseOpenSearchException; import org.opensearch.ExceptionsHelper; +import org.opensearch.OpenSearchException; import org.opensearch.Version; import org.opensearch.action.ActionListener; import org.opensearch.action.NoShardAvailableActionException; @@ -368,7 +368,7 @@ public final void executeNextPhase(SearchPhase currentPhase, SearchPhase nextPha final ShardOperationFailedException[] shardSearchFailures = ExceptionsHelper.groupBy(buildShardFailures()); Throwable cause = shardSearchFailures.length == 0 ? null - : BaseOpenSearchException.guessRootCauses(shardSearchFailures[0].getCause())[0]; + : OpenSearchException.guessRootCauses(shardSearchFailures[0].getCause())[0]; logger.debug(() -> new ParameterizedMessage("All shards failed for phase: [{}]", getName()), cause); onPhaseFailure(currentPhase, "all shards failed", cause); } else { @@ -382,7 +382,7 @@ public final void executeNextPhase(SearchPhase currentPhase, SearchPhase nextPha if (logger.isDebugEnabled()) { int numShardFailures = shardSearchFailures.length; shardSearchFailures = ExceptionsHelper.groupBy(shardSearchFailures); - Throwable cause = BaseOpenSearchException.guessRootCauses(shardSearchFailures[0].getCause())[0]; + Throwable cause = OpenSearchException.guessRootCauses(shardSearchFailures[0].getCause())[0]; logger.debug( () -> new ParameterizedMessage("{} shards failed for phase: [{}]", numShardFailures, getName()), cause diff --git a/server/src/main/java/org/opensearch/action/search/MultiSearchResponse.java b/server/src/main/java/org/opensearch/action/search/MultiSearchResponse.java index c372e82c094cf..52fa71c5e70fb 100644 --- a/server/src/main/java/org/opensearch/action/search/MultiSearchResponse.java +++ b/server/src/main/java/org/opensearch/action/search/MultiSearchResponse.java @@ -32,10 +32,10 @@ package org.opensearch.action.search; -import org.opensearch.BaseOpenSearchException; import org.opensearch.LegacyESVersion; import org.opensearch.OpenSearchException; import org.opensearch.ExceptionsHelper; +import org.opensearch.OpenSearchException; import org.opensearch.action.ActionResponse; import org.opensearch.common.Nullable; import org.opensearch.common.Strings; @@ -199,7 +199,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws for (Item item : items) { builder.startObject(); if (item.isFailure()) { - BaseOpenSearchException.generateFailureXContent(builder, params, item.getFailure(), true); + OpenSearchException.generateFailureXContent(builder, params, item.getFailure(), true); builder.field(Fields.STATUS, ExceptionsHelper.status(item.getFailure()).getStatus()); } else { item.getResponse().innerToXContent(builder, params); diff --git a/server/src/main/java/org/opensearch/action/search/SearchPhaseExecutionException.java b/server/src/main/java/org/opensearch/action/search/SearchPhaseExecutionException.java index 891d9a1e2e924..65c876cbd7c61 100644 --- a/server/src/main/java/org/opensearch/action/search/SearchPhaseExecutionException.java +++ b/server/src/main/java/org/opensearch/action/search/SearchPhaseExecutionException.java @@ -32,8 +32,6 @@ package org.opensearch.action.search; -import org.opensearch.BaseExceptionsHelper; -import org.opensearch.BaseOpenSearchException; import org.opensearch.OpenSearchException; import org.opensearch.ExceptionsHelper; import org.opensearch.action.ShardOperationFailedException; @@ -123,7 +121,7 @@ public Throwable getCause() { Throwable cause = super.getCause(); if (cause == null) { // fall back to guessed root cause - for (BaseOpenSearchException rootCause : guessRootCauses()) { + for (OpenSearchException rootCause : guessRootCauses()) { return rootCause; } } @@ -161,14 +159,14 @@ protected void metadataToXContent(XContentBuilder builder, Params params) throws @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - Throwable ex = BaseExceptionsHelper.unwrapCause(this); + Throwable ex = ExceptionsHelper.unwrapCause(this); if (ex != this) { - BaseExceptionsHelper.generateThrowableXContent(builder, params, this); + OpenSearchException.generateThrowableXContent(builder, params, this); } else { // We don't have a cause when all shards failed, but we do have shards failures so we can "guess" a cause // (see {@link #getCause()}). Here, we use super.getCause() because we don't want the guessed exception to // be rendered twice (one in the "cause" field, one in "failed_shards") - BaseExceptionsHelper.innerToXContent( + OpenSearchException.innerToXContent( builder, params, this, @@ -183,14 +181,14 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws } @Override - public BaseOpenSearchException[] guessRootCauses() { + public OpenSearchException[] guessRootCauses() { ShardOperationFailedException[] failures = ExceptionsHelper.groupBy(shardFailures); - List rootCauses = new ArrayList<>(failures.length); + List rootCauses = new ArrayList<>(failures.length); for (ShardOperationFailedException failure : failures) { - BaseOpenSearchException[] guessRootCauses = BaseOpenSearchException.guessRootCauses(failure.getCause()); + OpenSearchException[] guessRootCauses = OpenSearchException.guessRootCauses(failure.getCause()); rootCauses.addAll(Arrays.asList(guessRootCauses)); } - return rootCauses.toArray(new BaseOpenSearchException[0]); + return rootCauses.toArray(new OpenSearchException[0]); } @Override diff --git a/server/src/main/java/org/opensearch/action/search/ShardSearchFailure.java b/server/src/main/java/org/opensearch/action/search/ShardSearchFailure.java index c820b7ada427a..891f7f3119541 100644 --- a/server/src/main/java/org/opensearch/action/search/ShardSearchFailure.java +++ b/server/src/main/java/org/opensearch/action/search/ShardSearchFailure.java @@ -32,7 +32,6 @@ package org.opensearch.action.search; -import org.opensearch.BaseExceptionsHelper; import org.opensearch.ExceptionsHelper; import org.opensearch.OpenSearchException; import org.opensearch.action.OriginalIndices; @@ -86,14 +85,14 @@ public ShardSearchFailure(Exception e) { } public ShardSearchFailure(Exception e, @Nullable SearchShardTarget shardTarget) { - this(e, BaseExceptionsHelper.unwrapCause(e), shardTarget); + this(e, ExceptionsHelper.unwrapCause(e), shardTarget); } private ShardSearchFailure(final Exception e, final Throwable unwrappedCause, @Nullable SearchShardTarget shardTarget) { super( shardTarget == null ? null : shardTarget.getFullyQualifiedIndexName(), shardTarget == null ? -1 : shardTarget.getShardId().getId(), - BaseExceptionsHelper.detailedMessage(e), + ExceptionsHelper.detailedMessage(e), ExceptionsHelper.status(unwrappedCause), unwrappedCause ); @@ -120,7 +119,7 @@ public String toString() { + "], reason [" + reason + "], cause [" - + (cause == null ? "_na" : BaseExceptionsHelper.stackTrace(cause)) + + (cause == null ? "_na" : ExceptionsHelper.stackTrace(cause)) + "]"; } @@ -148,7 +147,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws } builder.field(REASON_FIELD); builder.startObject(); - BaseExceptionsHelper.generateThrowableXContent(builder, params, cause); + OpenSearchException.generateThrowableXContent(builder, params, cause); builder.endObject(); } builder.endObject(); diff --git a/server/src/main/java/org/opensearch/action/support/TransportActions.java b/server/src/main/java/org/opensearch/action/support/TransportActions.java index 62059ca3f0754..03e7509b3b8e3 100644 --- a/server/src/main/java/org/opensearch/action/support/TransportActions.java +++ b/server/src/main/java/org/opensearch/action/support/TransportActions.java @@ -33,7 +33,7 @@ package org.opensearch.action.support; import org.apache.lucene.store.AlreadyClosedException; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.action.NoShardAvailableActionException; import org.opensearch.action.UnavailableShardsException; import org.opensearch.index.IndexNotFoundException; @@ -48,7 +48,7 @@ public class TransportActions { public static boolean isShardNotAvailableException(final Throwable e) { - final Throwable actual = BaseExceptionsHelper.unwrapCause(e); + final Throwable actual = ExceptionsHelper.unwrapCause(e); return (actual instanceof ShardNotFoundException || actual instanceof IndexNotFoundException || actual instanceof IllegalIndexShardStateException diff --git a/server/src/main/java/org/opensearch/action/support/replication/ReplicationOperation.java b/server/src/main/java/org/opensearch/action/support/replication/ReplicationOperation.java index 3cec823422eb2..a7c7a799883a6 100644 --- a/server/src/main/java/org/opensearch/action/support/replication/ReplicationOperation.java +++ b/server/src/main/java/org/opensearch/action/support/replication/ReplicationOperation.java @@ -34,9 +34,8 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.lucene.store.AlreadyClosedException; -import org.opensearch.BaseExceptionsHelper; -import org.opensearch.core.Assertions; import org.opensearch.ExceptionsHelper; +import org.opensearch.core.Assertions; import org.opensearch.OpenSearchException; import org.opensearch.action.ActionListener; import org.opensearch.action.UnavailableShardsException; @@ -334,7 +333,7 @@ public void onFinished() { @Override public boolean shouldRetry(Exception e) { - final Throwable cause = BaseExceptionsHelper.unwrapCause(e); + final Throwable cause = ExceptionsHelper.unwrapCause(e); return cause instanceof CircuitBreakingException || cause instanceof OpenSearchRejectedExecutionException || cause instanceof ConnectTransportException; @@ -359,7 +358,7 @@ private void updateCheckPoints(ShardRouting shard, LongSupplier localCheckpointS } private void onNoLongerPrimary(Exception failure) { - final Throwable cause = BaseExceptionsHelper.unwrapCause(failure); + final Throwable cause = ExceptionsHelper.unwrapCause(failure); final boolean nodeIsClosing = cause instanceof NodeClosedException; final String message; if (nodeIsClosing) { diff --git a/server/src/main/java/org/opensearch/action/support/replication/ReplicationResponse.java b/server/src/main/java/org/opensearch/action/support/replication/ReplicationResponse.java index 063e657b25f21..1e0adfe326918 100644 --- a/server/src/main/java/org/opensearch/action/support/replication/ReplicationResponse.java +++ b/server/src/main/java/org/opensearch/action/support/replication/ReplicationResponse.java @@ -32,7 +32,7 @@ package org.opensearch.action.support.replication; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.OpenSearchException; import org.opensearch.action.ActionResponse; import org.opensearch.action.ShardOperationFailedException; @@ -261,7 +261,7 @@ public Failure(StreamInput in) throws IOException { } public Failure(ShardId shardId, @Nullable String nodeId, Exception cause, RestStatus status, boolean primary) { - super(shardId.getIndexName(), shardId.getId(), BaseExceptionsHelper.detailedMessage(cause), status, cause); + super(shardId.getIndexName(), shardId.getId(), ExceptionsHelper.detailedMessage(cause), status, cause); this.shardId = shardId; this.nodeId = nodeId; this.primary = primary; @@ -304,7 +304,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.field(_NODE, nodeId); builder.field(REASON); builder.startObject(); - BaseExceptionsHelper.generateThrowableXContent(builder, params, cause); + OpenSearchException.generateThrowableXContent(builder, params, cause); builder.endObject(); builder.field(STATUS, status); builder.field(PRIMARY, primary); diff --git a/server/src/main/java/org/opensearch/action/termvectors/MultiTermVectorsResponse.java b/server/src/main/java/org/opensearch/action/termvectors/MultiTermVectorsResponse.java index f1e05592731a5..ff84ceb22e043 100644 --- a/server/src/main/java/org/opensearch/action/termvectors/MultiTermVectorsResponse.java +++ b/server/src/main/java/org/opensearch/action/termvectors/MultiTermVectorsResponse.java @@ -32,7 +32,7 @@ package org.opensearch.action.termvectors; -import org.opensearch.BaseOpenSearchException; +import org.opensearch.OpenSearchException; import org.opensearch.Version; import org.opensearch.action.ActionResponse; import org.opensearch.common.io.stream.StreamInput; @@ -141,7 +141,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws Failure failure = response.getFailure(); builder.field(Fields._INDEX, failure.getIndex()); builder.field(Fields._ID, failure.getId()); - BaseOpenSearchException.generateFailureXContent(builder, params, failure.getCause(), true); + OpenSearchException.generateFailureXContent(builder, params, failure.getCause(), true); builder.endObject(); } else { TermVectorsResponse getResponse = response.getResponse(); diff --git a/server/src/main/java/org/opensearch/cluster/action/shard/ShardStateAction.java b/server/src/main/java/org/opensearch/cluster/action/shard/ShardStateAction.java index 853690fa1e242..002c5fd3b89db 100644 --- a/server/src/main/java/org/opensearch/cluster/action/shard/ShardStateAction.java +++ b/server/src/main/java/org/opensearch/cluster/action/shard/ShardStateAction.java @@ -35,7 +35,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.ParameterizedMessage; -import org.opensearch.BaseExceptionsHelper; import org.opensearch.OpenSearchException; import org.opensearch.ExceptionsHelper; import org.opensearch.action.ActionListener; @@ -630,7 +629,7 @@ public String toString() { components.add("primary term [" + primaryTerm + "]"); components.add("message [" + message + "]"); if (failure != null) { - components.add("failure [" + BaseExceptionsHelper.detailedMessage(failure) + "]"); + components.add("failure [" + ExceptionsHelper.detailedMessage(failure) + "]"); } components.add("markAsStale [" + markAsStale + "]"); return String.join(", ", components); diff --git a/server/src/main/java/org/opensearch/cluster/routing/UnassignedInfo.java b/server/src/main/java/org/opensearch/cluster/routing/UnassignedInfo.java index 117cadd648438..64c1c28fe63a0 100644 --- a/server/src/main/java/org/opensearch/cluster/routing/UnassignedInfo.java +++ b/server/src/main/java/org/opensearch/cluster/routing/UnassignedInfo.java @@ -32,7 +32,7 @@ package org.opensearch.cluster.routing; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.LegacyESVersion; import org.opensearch.cluster.ClusterState; import org.opensearch.cluster.metadata.Metadata; @@ -401,7 +401,7 @@ public String getDetails() { if (message == null) { return null; } - return message + (failure == null ? "" : ", failure " + BaseExceptionsHelper.detailedMessage(failure)); + return message + (failure == null ? "" : ", failure " + ExceptionsHelper.detailedMessage(failure)); } /** diff --git a/server/src/main/java/org/opensearch/cluster/routing/allocation/FailedShard.java b/server/src/main/java/org/opensearch/cluster/routing/allocation/FailedShard.java index d08dbba3a249d..61ca0f50e93b9 100644 --- a/server/src/main/java/org/opensearch/cluster/routing/allocation/FailedShard.java +++ b/server/src/main/java/org/opensearch/cluster/routing/allocation/FailedShard.java @@ -32,7 +32,7 @@ package org.opensearch.cluster.routing.allocation; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.cluster.routing.ShardRouting; import org.opensearch.common.Nullable; @@ -62,7 +62,7 @@ public String toString() { + ", message [" + message + "], failure [" - + (failure == null ? "null" : BaseExceptionsHelper.detailedMessage(failure)) + + (failure == null ? "null" : ExceptionsHelper.detailedMessage(failure)) + "], markAsStale [" + markAsStale + "]"; diff --git a/server/src/main/java/org/opensearch/cluster/routing/allocation/NodeAllocationResult.java b/server/src/main/java/org/opensearch/cluster/routing/allocation/NodeAllocationResult.java index ab1d56cbf7a9e..d50a474838a6b 100644 --- a/server/src/main/java/org/opensearch/cluster/routing/allocation/NodeAllocationResult.java +++ b/server/src/main/java/org/opensearch/cluster/routing/allocation/NodeAllocationResult.java @@ -32,7 +32,7 @@ package org.opensearch.cluster.routing.allocation; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.OpenSearchException; import org.opensearch.cluster.node.DiscoveryNode; import org.opensearch.cluster.routing.allocation.decider.Decision; import org.opensearch.common.Nullable; @@ -300,7 +300,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws } if (storeException != null) { builder.startObject("store_exception"); - BaseExceptionsHelper.generateThrowableXContent(builder, params, storeException); + OpenSearchException.generateThrowableXContent(builder, params, storeException); builder.endObject(); } } diff --git a/server/src/main/java/org/opensearch/common/Strings.java b/server/src/main/java/org/opensearch/common/Strings.java index 0bec840a15f40..15a4b17252450 100644 --- a/server/src/main/java/org/opensearch/common/Strings.java +++ b/server/src/main/java/org/opensearch/common/Strings.java @@ -33,7 +33,7 @@ package org.opensearch.common; import org.apache.lucene.util.BytesRefBuilder; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.OpenSearchException; import org.opensearch.common.bytes.BytesReference; import org.opensearch.common.util.CollectionUtils; @@ -280,7 +280,7 @@ private static String toString(MediaType mediaType, ToXContent toXContent, ToXCo XContentBuilder builder = createBuilder(mediaType, pretty, human); builder.startObject(); builder.field("error", "error building toString out of XContent: " + e.getMessage()); - builder.field("stack_trace", BaseExceptionsHelper.stackTrace(e)); + builder.field("stack_trace", ExceptionsHelper.stackTrace(e)); builder.endObject(); return toString(builder); } catch (IOException e2) { diff --git a/server/src/main/java/org/opensearch/common/geo/GeoPoint.java b/server/src/main/java/org/opensearch/common/geo/GeoPoint.java index 874f0ffb80be1..2e03f60481509 100644 --- a/server/src/main/java/org/opensearch/common/geo/GeoPoint.java +++ b/server/src/main/java/org/opensearch/common/geo/GeoPoint.java @@ -42,9 +42,6 @@ import org.opensearch.common.geo.GeoUtils.EffectivePoint; import org.opensearch.common.io.stream.StreamInput; import org.opensearch.common.io.stream.StreamOutput; -import org.opensearch.core.common.io.stream.BaseWriteable.Reader; -import org.opensearch.core.common.io.stream.BaseWriteable.Writer; -import org.opensearch.core.common.io.stream.BaseWriteable.WriteableRegistry; import org.opensearch.core.xcontent.ToXContentFragment; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.geometry.Geometry; @@ -97,17 +94,6 @@ public GeoPoint(final StreamInput in) throws IOException { this.lon = in.readDouble(); } - /** - * Register this type as a streamable so it can be serialized over the wire - */ - public static void registerStreamables() { - WriteableRegistry.>registerWriter(GeoPoint.class, (o, v) -> { - o.writeByte((byte) 22); - ((GeoPoint) v).writeTo(o); - }); - WriteableRegistry.>registerReader(Byte.valueOf((byte) 22), GeoPoint::new); - } - public GeoPoint reset(double lat, double lon) { this.lat = lat; this.lon = lon; diff --git a/server/src/main/java/org/opensearch/common/io/Streams.java b/server/src/main/java/org/opensearch/common/io/Streams.java index 00e9c84e4c2aa..6e44f18b7f4d5 100644 --- a/server/src/main/java/org/opensearch/common/io/Streams.java +++ b/server/src/main/java/org/opensearch/common/io/Streams.java @@ -162,36 +162,9 @@ public static String copyToString(Reader in) throws IOException { return out.toString(); } - public static int readFully(Reader reader, char[] dest) throws IOException { - return readFully(reader, dest, 0, dest.length); - } - - public static int readFully(Reader reader, char[] dest, int offset, int len) throws IOException { - int read = 0; - while (read < len) { - final int r = reader.read(dest, offset + read, len - read); - if (r == -1) { - break; - } - read += r; - } - return read; - } - + @Deprecated public static int readFully(InputStream reader, byte[] dest) throws IOException { - return readFully(reader, dest, 0, dest.length); - } - - public static int readFully(InputStream reader, byte[] dest, int offset, int len) throws IOException { - int read = 0; - while (read < len) { - final int r = reader.read(dest, offset + read, len - read); - if (r == -1) { - break; - } - read += r; - } - return read; + return reader.readNBytes(dest, 0, dest.length); } /** diff --git a/server/src/main/java/org/opensearch/common/io/stream/Streamables.java b/server/src/main/java/org/opensearch/common/io/stream/Streamables.java new file mode 100644 index 0000000000000..e594247be708e --- /dev/null +++ b/server/src/main/java/org/opensearch/common/io/stream/Streamables.java @@ -0,0 +1,88 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.common.io.stream; + +import org.joda.time.DateTimeZone; +import org.joda.time.ReadableInstant; +import org.opensearch.common.geo.GeoPoint; +import org.opensearch.common.time.DateUtils; +import org.opensearch.common.io.stream.Writeable.WriteableRegistry; +import org.opensearch.script.JodaCompatibleZonedDateTime; + +import java.time.Instant; +import java.time.ZoneId; + +/** + * This utility class registers generic types for streaming over the wire using + * {@linkplain StreamOutput#writeGenericValue(Object)} and {@linkplain StreamInput#readGenericValue()} + * + * In this manner we can register any type across OpenSearch modules, plugins, or libraries without requiring + * the implementation reside in the server module. + * + * @opensearch.internal + */ +public final class Streamables { + + // no instance: + private Streamables() {} + + /** + * Called when {@linkplain org.opensearch.transport.TransportService} is loaded by the classloader + * We do this because streamables depend on the TransportService being loaded + */ + public static void registerStreamables() { + registerWriters(); + registerReaders(); + } + + /** + * Registers writers by class type + */ + private static void registerWriters() { + /** {@link ReadableInstant} */ + WriteableRegistry.registerWriter(ReadableInstant.class, (o, v) -> { + o.writeByte((byte) 13); + final ReadableInstant instant = (ReadableInstant) v; + o.writeString(instant.getZone().getID()); + o.writeLong(instant.getMillis()); + }); + WriteableRegistry.registerClassAlias(ReadableInstant.class, ReadableInstant.class); + /** {@link JodaCompatibleZonedDateTime} */ + WriteableRegistry.registerWriter(JodaCompatibleZonedDateTime.class, (o, v) -> { + // write the joda compatibility datetime as joda datetime + o.writeByte((byte) 13); + final JodaCompatibleZonedDateTime zonedDateTime = (JodaCompatibleZonedDateTime) v; + String zoneId = zonedDateTime.getZonedDateTime().getZone().getId(); + // joda does not understand "Z" for utc, so we must special case + o.writeString(zoneId.equals("Z") ? DateTimeZone.UTC.getID() : zoneId); + o.writeLong(zonedDateTime.toInstant().toEpochMilli()); + }); + /** {@link GeoPoint} */ + WriteableRegistry.registerWriter(GeoPoint.class, (o, v) -> { + o.writeByte((byte) 22); + ((GeoPoint) v).writeTo(o); + }); + } + + /** + * Registers a reader function mapped by ordinal values that are written by {@linkplain StreamOutput} + * + * NOTE: see {@code StreamOutput#WRITERS} for all registered ordinals + */ + private static void registerReaders() { + /** {@link JodaCompatibleZonedDateTime */ + WriteableRegistry.registerReader(Byte.valueOf((byte) 13), (i) -> { + final ZoneId zoneId = DateUtils.dateTimeZoneToZoneId(DateTimeZone.forID(i.readString())); + long millis = i.readLong(); + return new JodaCompatibleZonedDateTime(Instant.ofEpochMilli(millis), zoneId); + }); + /** {@link GeoPoint} */ + WriteableRegistry.registerReader(Byte.valueOf((byte) 22), GeoPoint::new); + } +} diff --git a/server/src/main/java/org/opensearch/common/io/stream/Writeable.java b/server/src/main/java/org/opensearch/common/io/stream/Writeable.java deleted file mode 100644 index c04cd7977fdc0..0000000000000 --- a/server/src/main/java/org/opensearch/common/io/stream/Writeable.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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. - */ - -/* - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.common.io.stream; - -import org.opensearch.core.common.io.stream.BaseWriteable; - -import java.io.IOException; - -/** - * Implementers can be written to a {@linkplain StreamOutput} and read from a {@linkplain StreamInput}. This allows them to be "thrown - * across the wire" using OpenSearch's internal protocol. If the implementer also implements equals and hashCode then a copy made by - * serializing and deserializing must be equal and have the same hashCode. It isn't required that such a copy be entirely unchanged. - * - * @opensearch.internal - */ -public interface Writeable extends BaseWriteable { - - /** - * Write this into the {@linkplain StreamOutput}. - */ - void writeTo(StreamOutput out) throws IOException; - - /** - * Reference to a method that can write some object to a {@link StreamOutput}. - *

- * By convention this is a method from {@link StreamOutput} itself (e.g., {@link StreamOutput#writeString}). If the value can be - * {@code null}, then the "optional" variant of methods should be used! - *

- * Most classes should implement {@link Writeable} and the {@link Writeable#writeTo(StreamOutput)} method should use - * {@link StreamOutput} methods directly or this indirectly: - *


-     * public void writeTo(StreamOutput out) throws IOException {
-     *     out.writeVInt(someValue);
-     *     out.writeMapOfLists(someMap, StreamOutput::writeString, StreamOutput::writeString);
-     * }
-     * 
- */ - @FunctionalInterface - interface Writer extends BaseWriteable.Writer {} - - /** - * Reference to a method that can read some object from a stream. By convention this is a constructor that takes - * {@linkplain StreamInput} as an argument for most classes and a static method for things like enums. Returning null from one of these - * is always wrong - for that we use methods like {@link StreamInput#readOptionalWriteable(Reader)}. - *

- * As most classes will implement this via a constructor (or a static method in the case of enumerations), it's something that should - * look like: - *


-     * public MyClass(final StreamInput in) throws IOException {
-     *     this.someValue = in.readVInt();
-     *     this.someMap = in.readMapOfLists(StreamInput::readString, StreamInput::readString);
-     * }
-     * 
- */ - @FunctionalInterface - interface Reader extends BaseWriteable.Reader {} - -} diff --git a/server/src/main/java/org/opensearch/common/lucene/search/Queries.java b/server/src/main/java/org/opensearch/common/lucene/search/Queries.java index fdb4753650531..8b64a45b9db25 100644 --- a/server/src/main/java/org/opensearch/common/lucene/search/Queries.java +++ b/server/src/main/java/org/opensearch/common/lucene/search/Queries.java @@ -47,7 +47,7 @@ import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.OpenSearchException; import org.opensearch.common.Nullable; import org.opensearch.index.mapper.SeqNoFieldMapper; @@ -83,7 +83,7 @@ public static Query newUnmappedFieldsQuery(Collection fields) { } public static Query newLenientFieldQuery(String field, RuntimeException e) { - String message = BaseExceptionsHelper.getExceptionName(e) + ":[" + e.getMessage() + "]"; + String message = OpenSearchException.getExceptionName(e) + ":[" + e.getMessage() + "]"; return Queries.newMatchNoDocsQuery("failed [" + field + "] query, caused by " + message); } diff --git a/server/src/main/java/org/opensearch/common/util/PageCacheRecycler.java b/server/src/main/java/org/opensearch/common/util/PageCacheRecycler.java index 6d786e85bab1c..429dce6a69e75 100644 --- a/server/src/main/java/org/opensearch/common/util/PageCacheRecycler.java +++ b/server/src/main/java/org/opensearch/common/util/PageCacheRecycler.java @@ -33,6 +33,7 @@ package org.opensearch.common.util; import org.apache.lucene.util.RamUsageEstimator; +import org.opensearch.common.bytes.PagedBytesReference; import org.opensearch.common.recycler.AbstractRecyclerC; import org.opensearch.common.recycler.Recycler; import org.opensearch.common.settings.Setting; @@ -94,7 +95,7 @@ public class PageCacheRecycler { ); /** Page size in bytes: 16KB */ - public static final int PAGE_SIZE_IN_BYTES = 1 << 14; + public static final int PAGE_SIZE_IN_BYTES = PagedBytesReference.PAGE_SIZE_IN_BYTES; public static final int OBJECT_PAGE_SIZE = PAGE_SIZE_IN_BYTES / RamUsageEstimator.NUM_BYTES_OBJECT_REF; public static final int LONG_PAGE_SIZE = PAGE_SIZE_IN_BYTES / Long.BYTES; public static final int INT_PAGE_SIZE = PAGE_SIZE_IN_BYTES / Integer.BYTES; diff --git a/server/src/main/java/org/opensearch/gateway/AsyncShardFetch.java b/server/src/main/java/org/opensearch/gateway/AsyncShardFetch.java index 35272d9f54dc6..e4df2e604c320 100644 --- a/server/src/main/java/org/opensearch/gateway/AsyncShardFetch.java +++ b/server/src/main/java/org/opensearch/gateway/AsyncShardFetch.java @@ -33,7 +33,7 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.ParameterizedMessage; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.OpenSearchTimeoutException; import org.opensearch.action.ActionListener; import org.opensearch.action.FailedNodeException; @@ -251,7 +251,7 @@ protected synchronized void processAsyncFetch(List responses, List searchLookup) { throw new IllegalArgumentException("Fielddata is not supported on field [" + name() + "] of type [" + typeName() + "]"); @@ -411,7 +412,7 @@ public Relation isFieldWithinQuery( /** @throws IllegalArgumentException if the fielddata is not supported on this type. * An IllegalArgumentException is needed in order to return an http error 400 - * when this error occurs in a request. see: {@link org.opensearch.ExceptionsHelper#status} + * when this error occurs in a request. see: {@link ExceptionsHelper#status} **/ protected final void failIfNoDocValues() { if (hasDocValues() == false) { diff --git a/server/src/main/java/org/opensearch/index/query/MoreLikeThisQueryBuilder.java b/server/src/main/java/org/opensearch/index/query/MoreLikeThisQueryBuilder.java index abe352bb48966..23411a64d80a7 100644 --- a/server/src/main/java/org/opensearch/index/query/MoreLikeThisQueryBuilder.java +++ b/server/src/main/java/org/opensearch/index/query/MoreLikeThisQueryBuilder.java @@ -37,7 +37,6 @@ import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.Query; -import org.opensearch.BaseExceptionsHelper; import org.opensearch.OpenSearchParseException; import org.opensearch.ExceptionsHelper; import org.opensearch.Version; @@ -449,7 +448,7 @@ public String toString() { toXContent(builder, EMPTY_PARAMS); return Strings.toString(builder); } catch (Exception e) { - return "{ \"error\" : \"" + BaseExceptionsHelper.detailedMessage(e) + "\"}"; + return "{ \"error\" : \"" + ExceptionsHelper.detailedMessage(e) + "\"}"; } } diff --git a/server/src/main/java/org/opensearch/index/reindex/BulkByScrollTask.java b/server/src/main/java/org/opensearch/index/reindex/BulkByScrollTask.java index be9cade4925eb..2fe0fe0259c33 100644 --- a/server/src/main/java/org/opensearch/index/reindex/BulkByScrollTask.java +++ b/server/src/main/java/org/opensearch/index/reindex/BulkByScrollTask.java @@ -32,7 +32,6 @@ package org.opensearch.index.reindex; -import org.opensearch.BaseExceptionsHelper; import org.opensearch.OpenSearchException; import org.opensearch.common.Nullable; import org.opensearch.core.ParseField; @@ -1000,7 +999,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws status.toXContent(builder, params); } else { builder.startObject(); - BaseExceptionsHelper.generateThrowableXContent(builder, params, exception); + OpenSearchException.generateThrowableXContent(builder, params, exception); builder.endObject(); } return builder; diff --git a/server/src/main/java/org/opensearch/index/reindex/ReindexRequest.java b/server/src/main/java/org/opensearch/index/reindex/ReindexRequest.java index 1f89e2055ffd8..765de7b889f46 100644 --- a/server/src/main/java/org/opensearch/index/reindex/ReindexRequest.java +++ b/server/src/main/java/org/opensearch/index/reindex/ReindexRequest.java @@ -36,8 +36,8 @@ import org.opensearch.action.CompositeIndicesRequest; import org.opensearch.action.index.IndexRequest; import org.opensearch.action.search.SearchRequest; -import org.opensearch.core.ParseField; import org.opensearch.common.bytes.BytesReference; +import org.opensearch.core.ParseField; import org.opensearch.common.io.stream.StreamInput; import org.opensearch.common.io.stream.StreamOutput; import org.opensearch.common.logging.DeprecationLogger; diff --git a/server/src/main/java/org/opensearch/index/reindex/ScrollableHitSource.java b/server/src/main/java/org/opensearch/index/reindex/ScrollableHitSource.java index 8628bd84da35a..81560de78b336 100644 --- a/server/src/main/java/org/opensearch/index/reindex/ScrollableHitSource.java +++ b/server/src/main/java/org/opensearch/index/reindex/ScrollableHitSource.java @@ -33,8 +33,8 @@ package org.opensearch.index.reindex; import org.apache.logging.log4j.Logger; -import org.opensearch.BaseExceptionsHelper; import org.opensearch.ExceptionsHelper; +import org.opensearch.OpenSearchException; import org.opensearch.action.ActionListener; import org.opensearch.action.bulk.BackoffPolicy; import org.opensearch.action.bulk.BulkItemResponse; @@ -489,7 +489,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.field(REASON_FIELD); { builder.startObject(); - BaseExceptionsHelper.generateThrowableXContent(builder, params, reason); + OpenSearchException.generateThrowableXContent(builder, params, reason); builder.endObject(); } builder.endObject(); diff --git a/server/src/main/java/org/opensearch/index/shard/StoreRecovery.java b/server/src/main/java/org/opensearch/index/shard/StoreRecovery.java index 4a85b17b5c94a..da4e9113143af 100644 --- a/server/src/main/java/org/opensearch/index/shard/StoreRecovery.java +++ b/server/src/main/java/org/opensearch/index/shard/StoreRecovery.java @@ -42,7 +42,7 @@ import org.apache.lucene.store.FilterDirectory; import org.apache.lucene.store.IOContext; import org.apache.lucene.store.IndexInput; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.action.ActionListener; import org.opensearch.action.StepListener; import org.opensearch.cluster.metadata.IndexMetadata; @@ -576,7 +576,7 @@ private void internalRecoverFromStore(IndexShard indexShard) throws IndexShardRe files = Arrays.toString(store.directory().listAll()); } catch (Exception inner) { inner.addSuppressed(e); - files += " (failure=" + BaseExceptionsHelper.detailedMessage(inner) + ")"; + files += " (failure=" + ExceptionsHelper.detailedMessage(inner) + ")"; } if (indexShouldExists) { throw new IndexShardRecoveryException( diff --git a/server/src/main/java/org/opensearch/index/store/Store.java b/server/src/main/java/org/opensearch/index/store/Store.java index 2c0d5decebba8..90832b4c77756 100644 --- a/server/src/main/java/org/opensearch/index/store/Store.java +++ b/server/src/main/java/org/opensearch/index/store/Store.java @@ -67,7 +67,6 @@ import org.opensearch.common.Nullable; import org.opensearch.common.UUIDs; import org.opensearch.common.bytes.BytesReference; -import org.opensearch.common.io.Streams; import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.common.io.stream.StreamInput; import org.opensearch.common.io.stream.StreamOutput; @@ -1240,7 +1239,7 @@ public static void hashFile(BytesRefBuilder fileHash, InputStream in, long size) final int len = (int) Math.min(1024 * 1024, size); // for safety we limit this to 1MB fileHash.grow(len); fileHash.setLength(len); - final int readBytes = Streams.readFully(in, fileHash.bytes(), 0, len); + final int readBytes = in.readNBytes(fileHash.bytes(), 0, len); assert readBytes == len : Integer.toString(readBytes) + " != " + Integer.toString(len); assert fileHash.length() == len : Integer.toString(fileHash.length()) + " != " + Integer.toString(len); } diff --git a/server/src/main/java/org/opensearch/indices/recovery/PeerRecoveryTargetService.java b/server/src/main/java/org/opensearch/indices/recovery/PeerRecoveryTargetService.java index 5c6e3de662be3..66ca923ead027 100644 --- a/server/src/main/java/org/opensearch/indices/recovery/PeerRecoveryTargetService.java +++ b/server/src/main/java/org/opensearch/indices/recovery/PeerRecoveryTargetService.java @@ -36,7 +36,7 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.lucene.store.AlreadyClosedException; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.LegacyESVersion; import org.opensearch.OpenSearchException; import org.opensearch.OpenSearchTimeoutException; @@ -680,7 +680,7 @@ private void onException(Exception e) { e ); } - Throwable cause = BaseExceptionsHelper.unwrapCause(e); + Throwable cause = ExceptionsHelper.unwrapCause(e); if (cause instanceof CancellableThreads.ExecutionCancelledException) { // this can also come from the source wrapped in a RemoteTransportException onGoingRecoveries.fail(recoveryId, new RecoveryFailedException(request, "source has canceled the recovery", cause), false); @@ -691,7 +691,7 @@ private void onException(Exception e) { cause = cause.getCause(); } // do it twice, in case we have double transport exception - cause = BaseExceptionsHelper.unwrapCause(cause); + cause = ExceptionsHelper.unwrapCause(cause); if (cause instanceof RecoveryEngineException) { // unwrap an exception that was thrown as part of the recovery cause = cause.getCause(); diff --git a/server/src/main/java/org/opensearch/indices/recovery/RetryableTransportClient.java b/server/src/main/java/org/opensearch/indices/recovery/RetryableTransportClient.java index 3130721d22328..1e378cbeeba3d 100644 --- a/server/src/main/java/org/opensearch/indices/recovery/RetryableTransportClient.java +++ b/server/src/main/java/org/opensearch/indices/recovery/RetryableTransportClient.java @@ -9,7 +9,7 @@ package org.opensearch.indices.recovery; import org.apache.logging.log4j.Logger; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.LegacyESVersion; import org.opensearch.action.ActionListener; import org.opensearch.action.ActionListenerResponseHandler; @@ -128,10 +128,10 @@ private static boolean retryableException(Exception e) { if (e instanceof ConnectTransportException) { return true; } else if (e instanceof SendRequestTransportException) { - final Throwable cause = BaseExceptionsHelper.unwrapCause(e); + final Throwable cause = ExceptionsHelper.unwrapCause(e); return cause instanceof ConnectTransportException; } else if (e instanceof RemoteTransportException) { - final Throwable cause = BaseExceptionsHelper.unwrapCause(e); + final Throwable cause = ExceptionsHelper.unwrapCause(e); return cause instanceof CircuitBreakingException || cause instanceof OpenSearchRejectedExecutionException; } return false; diff --git a/server/src/main/java/org/opensearch/indices/replication/SegmentReplicationTargetService.java b/server/src/main/java/org/opensearch/indices/replication/SegmentReplicationTargetService.java index 2931caa353bc6..a7e0c0ec887ab 100644 --- a/server/src/main/java/org/opensearch/indices/replication/SegmentReplicationTargetService.java +++ b/server/src/main/java/org/opensearch/indices/replication/SegmentReplicationTargetService.java @@ -11,7 +11,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.ParameterizedMessage; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.action.ActionListener; import org.opensearch.cluster.node.DiscoveryNode; import org.opensearch.cluster.routing.ShardRouting; @@ -444,7 +444,7 @@ public void onResponse(Void o) { @Override public void onFailure(Exception e) { - Throwable cause = BaseExceptionsHelper.unwrapCause(e); + Throwable cause = ExceptionsHelper.unwrapCause(e); if (cause instanceof CancellableThreads.ExecutionCancelledException) { if (onGoingReplications.getTarget(replicationId) != null) { IndexShard indexShard = onGoingReplications.getTarget(replicationId).indexShard(); diff --git a/server/src/main/java/org/opensearch/indices/replication/common/ReplicationTarget.java b/server/src/main/java/org/opensearch/indices/replication/common/ReplicationTarget.java index ef543bdbaf6f2..815ae29114bae 100644 --- a/server/src/main/java/org/opensearch/indices/replication/common/ReplicationTarget.java +++ b/server/src/main/java/org/opensearch/indices/replication/common/ReplicationTarget.java @@ -10,7 +10,7 @@ import org.apache.logging.log4j.Logger; import org.apache.lucene.store.RateLimiter; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.OpenSearchException; import org.opensearch.action.ActionListener; import org.opensearch.action.support.ChannelActionListener; @@ -176,7 +176,7 @@ public void fail(ReplicationFailedException e, boolean sendShardFailure) { notifyListener(e, sendShardFailure); } finally { try { - cancellableThreads.cancel("failed" + description() + "[" + BaseExceptionsHelper.stackTrace(e) + "]"); + cancellableThreads.cancel("failed" + description() + "[" + ExceptionsHelper.stackTrace(e) + "]"); } finally { // release the initial reference. replication files will be cleaned as soon as ref count goes to zero, potentially now decRef(); diff --git a/server/src/main/java/org/opensearch/rest/BytesRestResponse.java b/server/src/main/java/org/opensearch/rest/BytesRestResponse.java index a5af9226ad831..3bb094bcd4ba0 100644 --- a/server/src/main/java/org/opensearch/rest/BytesRestResponse.java +++ b/server/src/main/java/org/opensearch/rest/BytesRestResponse.java @@ -36,11 +36,9 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.util.Supplier; -import org.opensearch.BaseExceptionsHelper; -import org.opensearch.BaseOpenSearchException; +import org.opensearch.ExceptionsHelper; import org.opensearch.OpenSearchException; import org.opensearch.OpenSearchStatusException; -import org.opensearch.ExceptionsHelper; import org.opensearch.common.bytes.BytesArray; import org.opensearch.common.bytes.BytesReference; import org.opensearch.core.xcontent.ToXContent; @@ -113,8 +111,8 @@ public BytesRestResponse(RestChannel channel, Exception e) throws IOException { public BytesRestResponse(RestChannel channel, RestStatus status, Exception e) throws IOException { ToXContent.Params params = paramsFromRequest(channel.request()); if (params.paramAsBoolean( - BaseExceptionsHelper.REST_EXCEPTION_SKIP_STACK_TRACE, - BaseExceptionsHelper.REST_EXCEPTION_SKIP_STACK_TRACE_DEFAULT + OpenSearchException.REST_EXCEPTION_SKIP_STACK_TRACE, + OpenSearchException.REST_EXCEPTION_SKIP_STACK_TRACE_DEFAULT ) && e != null) { // log exception only if it is not returned in the response Supplier messageSupplier = () -> new ParameterizedMessage( @@ -156,12 +154,9 @@ public RestStatus status() { private ToXContent.Params paramsFromRequest(RestRequest restRequest) { ToXContent.Params params = restRequest; - if (params.paramAsBoolean("error_trace", !BaseExceptionsHelper.REST_EXCEPTION_SKIP_STACK_TRACE_DEFAULT) + if (params.paramAsBoolean("error_trace", OpenSearchException.REST_EXCEPTION_SKIP_STACK_TRACE_DEFAULT == false) && false == skipStackTrace()) { - params = new ToXContent.DelegatingMapParams( - singletonMap(BaseExceptionsHelper.REST_EXCEPTION_SKIP_STACK_TRACE, "false"), - params - ); + params = new ToXContent.DelegatingMapParams(singletonMap(OpenSearchException.REST_EXCEPTION_SKIP_STACK_TRACE, "false"), params); } return params; } @@ -173,7 +168,7 @@ protected boolean skipStackTrace() { private void build(XContentBuilder builder, ToXContent.Params params, RestStatus status, boolean detailedErrorsEnabled, Exception e) throws IOException { builder.startObject(); - BaseOpenSearchException.generateFailureXContent(builder, params, e, detailedErrorsEnabled); + OpenSearchException.generateFailureXContent(builder, params, e, detailedErrorsEnabled); builder.field(STATUS, status.getStatus()); builder.endObject(); } diff --git a/server/src/main/java/org/opensearch/script/JodaCompatibleZonedDateTime.java b/server/src/main/java/org/opensearch/script/JodaCompatibleZonedDateTime.java index 1359357dc1bc3..8f48da739359a 100644 --- a/server/src/main/java/org/opensearch/script/JodaCompatibleZonedDateTime.java +++ b/server/src/main/java/org/opensearch/script/JodaCompatibleZonedDateTime.java @@ -33,18 +33,12 @@ package org.opensearch.script; import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; import org.opensearch.common.SuppressForbidden; import org.opensearch.common.SuppressLoggerChecks; import org.opensearch.common.logging.DeprecationLogger; -import org.opensearch.common.io.stream.StreamInput; -import org.opensearch.common.io.stream.StreamOutput; -import org.opensearch.core.common.io.stream.BaseWriteable.Reader; -import org.opensearch.core.common.io.stream.BaseWriteable.Writer; import org.opensearch.common.time.DateFormatter; import org.opensearch.common.time.DateFormatters; import org.opensearch.common.time.DateUtils; -import org.opensearch.core.common.io.stream.BaseWriteable.WriteableRegistry; import java.security.AccessController; import java.security.PrivilegedAction; @@ -109,26 +103,6 @@ public JodaCompatibleZonedDateTime(Instant instant, ZoneId zone) { this.dt = ZonedDateTime.ofInstant(instant, zone); } - /** - * Register this type as a streamable so it can be serialized over the wire - */ - public static void registerStreamables() { - WriteableRegistry.>registerWriter(JodaCompatibleZonedDateTime.class, (o, v) -> { - // write the joda compatibility datetime as joda datetime - o.writeByte((byte) 13); - final JodaCompatibleZonedDateTime zonedDateTime = (JodaCompatibleZonedDateTime) v; - String zoneId = zonedDateTime.getZonedDateTime().getZone().getId(); - // joda does not understand "Z" for utc, so we must special case - o.writeString(zoneId.equals("Z") ? DateTimeZone.UTC.getID() : zoneId); - o.writeLong(zonedDateTime.toInstant().toEpochMilli()); - }); - WriteableRegistry.>registerReader(Byte.valueOf((byte) 13), (i) -> { - final ZoneId zoneId = DateUtils.dateTimeZoneToZoneId(DateTimeZone.forID(i.readString())); - long millis = i.readLong(); - return new JodaCompatibleZonedDateTime(Instant.ofEpochMilli(millis), zoneId); - }); - } - // access the underlying ZonedDateTime public ZonedDateTime getZonedDateTime() { return dt; diff --git a/server/src/main/java/org/opensearch/script/Script.java b/server/src/main/java/org/opensearch/script/Script.java index 6580bfe8326f6..7f6c41575ccb8 100644 --- a/server/src/main/java/org/opensearch/script/Script.java +++ b/server/src/main/java/org/opensearch/script/Script.java @@ -33,10 +33,10 @@ package org.opensearch.script; import org.opensearch.OpenSearchParseException; +import org.opensearch.common.bytes.BytesReference; import org.opensearch.core.ParseField; import org.opensearch.common.Strings; import org.opensearch.common.bytes.BytesArray; -import org.opensearch.common.bytes.BytesReference; import org.opensearch.common.io.stream.StreamInput; import org.opensearch.common.io.stream.StreamOutput; import org.opensearch.common.io.stream.Writeable; diff --git a/server/src/main/java/org/opensearch/search/aggregations/support/BaseMultiValuesSourceFieldConfig.java b/server/src/main/java/org/opensearch/search/aggregations/support/BaseMultiValuesSourceFieldConfig.java index fab82eafb93f0..e0e8b01fd9238 100644 --- a/server/src/main/java/org/opensearch/search/aggregations/support/BaseMultiValuesSourceFieldConfig.java +++ b/server/src/main/java/org/opensearch/search/aggregations/support/BaseMultiValuesSourceFieldConfig.java @@ -105,7 +105,7 @@ public void writeTo(StreamOutput out) throws IOException { out.writeGenericValue(missing); out.writeOptionalWriteable(script); if (out.getVersion().before(LegacyESVersion.V_7_0_0)) { - out.writeOptionalTimeZone(DateUtils.zoneIdToDateTimeZone(timeZone)); + Joda.writeOptionalTimeZone(out, DateUtils.zoneIdToDateTimeZone(timeZone)); } else { out.writeOptionalZoneId(timeZone); } diff --git a/server/src/main/java/org/opensearch/search/aggregations/support/ValuesSourceAggregationBuilder.java b/server/src/main/java/org/opensearch/search/aggregations/support/ValuesSourceAggregationBuilder.java index 372ef706f72cd..4decbbd976320 100644 --- a/server/src/main/java/org/opensearch/search/aggregations/support/ValuesSourceAggregationBuilder.java +++ b/server/src/main/java/org/opensearch/search/aggregations/support/ValuesSourceAggregationBuilder.java @@ -261,7 +261,7 @@ protected final void doWriteTo(StreamOutput out) throws IOException { out.writeOptionalString(format); out.writeGenericValue(missing); if (out.getVersion().before(LegacyESVersion.V_7_0_0)) { - out.writeOptionalTimeZone(DateUtils.zoneIdToDateTimeZone(timeZone)); + Joda.writeOptionalTimeZone(out, DateUtils.zoneIdToDateTimeZone(timeZone)); } else { out.writeOptionalZoneId(timeZone); } diff --git a/server/src/main/java/org/opensearch/search/suggest/phrase/DirectCandidateGeneratorBuilder.java b/server/src/main/java/org/opensearch/search/suggest/phrase/DirectCandidateGeneratorBuilder.java index dc75088d4c85b..afd46f1a8164c 100644 --- a/server/src/main/java/org/opensearch/search/suggest/phrase/DirectCandidateGeneratorBuilder.java +++ b/server/src/main/java/org/opensearch/search/suggest/phrase/DirectCandidateGeneratorBuilder.java @@ -40,7 +40,7 @@ import org.apache.lucene.search.spell.StringDistance; import org.apache.lucene.search.spell.SuggestMode; import org.apache.lucene.util.automaton.LevenshteinAutomata; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.core.ParseField; import org.opensearch.common.Strings; import org.opensearch.common.io.stream.StreamInput; @@ -510,7 +510,7 @@ public String toString() { toXContent(builder, EMPTY_PARAMS); return Strings.toString(builder); } catch (Exception e) { - return "{ \"error\" : \"" + BaseExceptionsHelper.detailedMessage(e) + "\"}"; + return "{ \"error\" : \"" + ExceptionsHelper.detailedMessage(e) + "\"}"; } } diff --git a/server/src/main/java/org/opensearch/tasks/TaskCancellationService.java b/server/src/main/java/org/opensearch/tasks/TaskCancellationService.java index b7165cf0bba82..4073a48bcde0d 100644 --- a/server/src/main/java/org/opensearch/tasks/TaskCancellationService.java +++ b/server/src/main/java/org/opensearch/tasks/TaskCancellationService.java @@ -34,7 +34,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.LegacyESVersion; import org.opensearch.OpenSearchSecurityException; import org.opensearch.action.ActionListener; @@ -157,7 +157,7 @@ public void handleResponse(TransportResponse.Empty response) { @Override public void handleException(TransportException exp) { - assert BaseExceptionsHelper.unwrapCause(exp) instanceof OpenSearchSecurityException == false; + assert ExceptionsHelper.unwrapCause(exp) instanceof OpenSearchSecurityException == false; logger.warn("Cannot send ban for tasks with the parent [{}] to the node [{}]", taskId, node); groupedListener.onFailure(exp); } @@ -173,7 +173,7 @@ private void removeBanOnNodes(CancellableTask task, Collection ch transportService.sendRequest(node, BAN_PARENT_ACTION_NAME, request, new EmptyTransportResponseHandler(ThreadPool.Names.SAME) { @Override public void handleException(TransportException exp) { - assert BaseExceptionsHelper.unwrapCause(exp) instanceof OpenSearchSecurityException == false; + assert ExceptionsHelper.unwrapCause(exp) instanceof OpenSearchSecurityException == false; logger.info("failed to remove the parent ban for task {} on node {}", request.parentTaskId, node); } }); diff --git a/server/src/main/java/org/opensearch/tasks/TaskManager.java b/server/src/main/java/org/opensearch/tasks/TaskManager.java index 443a6c0853884..f243cf392bbb8 100644 --- a/server/src/main/java/org/opensearch/tasks/TaskManager.java +++ b/server/src/main/java/org/opensearch/tasks/TaskManager.java @@ -37,7 +37,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.ParameterizedMessage; -import org.opensearch.BaseExceptionsHelper; import org.opensearch.core.Assertions; import org.opensearch.ExceptionsHelper; import org.opensearch.OpenSearchException; @@ -370,7 +369,7 @@ public void storeResult(Task task, Exception e try { taskResult = task.result(localNode, error); } catch (IOException ex) { - logger.warn(() -> new ParameterizedMessage("couldn't store error {}", BaseExceptionsHelper.detailedMessage(error)), ex); + logger.warn(() -> new ParameterizedMessage("couldn't store error {}", ExceptionsHelper.detailedMessage(error)), ex); listener.onFailure(ex); return; } @@ -382,7 +381,7 @@ public void onResponse(Void aVoid) { @Override public void onFailure(Exception e) { - logger.warn(() -> new ParameterizedMessage("couldn't store error {}", BaseExceptionsHelper.detailedMessage(error)), e); + logger.warn(() -> new ParameterizedMessage("couldn't store error {}", ExceptionsHelper.detailedMessage(error)), e); listener.onFailure(e); } }); diff --git a/server/src/main/java/org/opensearch/tasks/TaskResult.java b/server/src/main/java/org/opensearch/tasks/TaskResult.java index 11ea9a9a82861..2387de173c924 100644 --- a/server/src/main/java/org/opensearch/tasks/TaskResult.java +++ b/server/src/main/java/org/opensearch/tasks/TaskResult.java @@ -31,7 +31,7 @@ package org.opensearch.tasks; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.OpenSearchException; import org.opensearch.client.Requests; import org.opensearch.common.Nullable; import org.opensearch.core.ParseField; @@ -240,7 +240,7 @@ public int hashCode() { private static BytesReference toXContent(Exception error) throws IOException { try (XContentBuilder builder = XContentFactory.contentBuilder(Requests.INDEX_CONTENT_TYPE)) { builder.startObject(); - BaseExceptionsHelper.generateThrowableXContent(builder, ToXContent.EMPTY_PARAMS, error); + OpenSearchException.generateThrowableXContent(builder, ToXContent.EMPTY_PARAMS, error); builder.endObject(); return BytesReference.bytes(builder); } diff --git a/server/src/main/java/org/opensearch/tasks/TaskResultsService.java b/server/src/main/java/org/opensearch/tasks/TaskResultsService.java index 329fc55431bc8..1feb115cb585a 100644 --- a/server/src/main/java/org/opensearch/tasks/TaskResultsService.java +++ b/server/src/main/java/org/opensearch/tasks/TaskResultsService.java @@ -34,7 +34,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.ParameterizedMessage; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.OpenSearchException; import org.opensearch.ResourceAlreadyExistsException; import org.opensearch.action.ActionListener; @@ -126,7 +126,7 @@ public void onResponse(CreateIndexResponse result) { @Override public void onFailure(Exception e) { - if (BaseExceptionsHelper.unwrapCause(e) instanceof ResourceAlreadyExistsException) { + if (ExceptionsHelper.unwrapCause(e) instanceof ResourceAlreadyExistsException) { // we have the index, do it try { doStoreResult(taskResult, listener); diff --git a/server/src/main/java/org/opensearch/transport/TransportService.java b/server/src/main/java/org/opensearch/transport/TransportService.java index cfa4397d5945e..101d503dc6831 100644 --- a/server/src/main/java/org/opensearch/transport/TransportService.java +++ b/server/src/main/java/org/opensearch/transport/TransportService.java @@ -35,6 +35,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.ParameterizedMessage; +import org.opensearch.OpenSearchServerException; import org.opensearch.LegacyESVersion; import org.opensearch.Version; import org.opensearch.action.ActionListener; @@ -45,9 +46,9 @@ import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.common.Nullable; import org.opensearch.common.component.AbstractLifecycleComponent; -import org.opensearch.common.geo.GeoPoint; import org.opensearch.common.io.stream.StreamInput; import org.opensearch.common.io.stream.StreamOutput; +import org.opensearch.common.io.stream.Streamables; import org.opensearch.common.io.stream.Writeable; import org.opensearch.common.logging.Loggers; import org.opensearch.common.regex.Regex; @@ -64,7 +65,6 @@ import org.opensearch.core.concurrency.OpenSearchRejectedExecutionException; import org.opensearch.node.NodeClosedException; import org.opensearch.node.ReportingService; -import org.opensearch.script.JodaCompatibleZonedDateTime; import org.opensearch.tasks.Task; import org.opensearch.tasks.TaskManager; import org.opensearch.threadpool.Scheduler; @@ -167,11 +167,15 @@ public void close() {} }; static { - // registers server specific streamables - registerStreamables(); + /** + * Registers server specific types as a streamables for serialization + * over the {@link StreamOutput} and {@link StreamInput} wire + */ + Streamables.registerStreamables(); + OpenSearchServerException.registerExceptions(); } - /** does nothing. easy way to ensure class is loaded */ + /** does nothing. easy way to ensure class is loaded so the above static block is called to register the streamables */ public static void ensureClassloaded() {} /** @@ -244,15 +248,6 @@ public TransportService( ); } - /** - * Registers server specific types as a streamables for serialization - * over the {@link StreamOutput} and {@link StreamInput} wire - */ - private static void registerStreamables() { - JodaCompatibleZonedDateTime.registerStreamables(); - GeoPoint.registerStreamables(); - } - public RemoteClusterService getRemoteClusterService() { return remoteClusterService; } diff --git a/server/src/test/java/org/opensearch/ExceptionSerializationTests.java b/server/src/test/java/org/opensearch/ExceptionSerializationTests.java index 77076ff8c6747..7d1eb02ae3a3a 100644 --- a/server/src/test/java/org/opensearch/ExceptionSerializationTests.java +++ b/server/src/test/java/org/opensearch/ExceptionSerializationTests.java @@ -161,7 +161,8 @@ public void testExceptionRegistration() throws ClassNotFoundException, IOExcepti final Set> hasDedicatedWrite = new HashSet<>(); final Set> registered = new HashSet<>(); final String path = "/org/opensearch"; - final Path startPath = PathUtils.get(OpenSearchException.class.getProtectionDomain().getCodeSource().getLocation().toURI()) + final Path coreLibStartPath = PathUtils.get(OpenSearchException.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + final Path startPath = PathUtils.get(OpenSearchServerException.class.getProtectionDomain().getCodeSource().getLocation().toURI()) .resolve("org") .resolve("opensearch"); final Set ignore = Sets.newHashSet( @@ -243,6 +244,9 @@ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOEx } }; + // walk the core library start path + Files.walkFileTree(coreLibStartPath, visitor); + // walk the server module start path Files.walkFileTree(startPath, visitor); final Path testStartPath = PathUtils.get(ExceptionSerializationTests.class.getResource(path).toURI()); Files.walkFileTree(testStartPath, visitor); @@ -897,7 +901,7 @@ public void testIds() { } } - for (final Tuple> tuple : OpenSearchException.classes()) { + for (final Tuple> tuple : OpenSearchException.classes()) { assertNotNull(tuple.v1()); assertNotNull( tuple.v2().getName() + " not found in ExceptionSerializationTests.testIds. Please add it.", diff --git a/server/src/test/java/org/opensearch/ExceptionsHelperTests.java b/server/src/test/java/org/opensearch/ExceptionsHelperTests.java index 395c5ec14c8a3..4c65eadf46e89 100644 --- a/server/src/test/java/org/opensearch/ExceptionsHelperTests.java +++ b/server/src/test/java/org/opensearch/ExceptionsHelperTests.java @@ -114,9 +114,9 @@ public void testStatus() { } public void testSummaryMessage() { - assertThat(BaseExceptionsHelper.summaryMessage(new IllegalArgumentException("illegal")), equalTo("Invalid argument")); - assertThat(BaseExceptionsHelper.summaryMessage(new JsonParseException(null, "illegal")), equalTo("Failed to parse JSON")); - assertThat(BaseExceptionsHelper.summaryMessage(new OpenSearchRejectedExecutionException("rejected")), equalTo("Too many requests")); + assertThat(ExceptionsHelper.summaryMessage(new IllegalArgumentException("illegal")), equalTo("Invalid argument")); + assertThat(ExceptionsHelper.summaryMessage(new JsonParseException(null, "illegal")), equalTo("Failed to parse JSON")); + assertThat(ExceptionsHelper.summaryMessage(new OpenSearchRejectedExecutionException("rejected")), equalTo("Too many requests")); } public void testGroupBy() { diff --git a/server/src/test/java/org/opensearch/OpenSearchExceptionTests.java b/server/src/test/java/org/opensearch/OpenSearchExceptionTests.java index d584e9130e20e..a0bd8202abbbe 100644 --- a/server/src/test/java/org/opensearch/OpenSearchExceptionTests.java +++ b/server/src/test/java/org/opensearch/OpenSearchExceptionTests.java @@ -127,9 +127,9 @@ public void testGuessRootCause() { "foo", new OpenSearchException("bar", new IndexNotFoundException("foo", new RuntimeException("foobar"))) ); - BaseOpenSearchException[] rootCauses = exception.guessRootCauses(); + OpenSearchException[] rootCauses = exception.guessRootCauses(); assertEquals(rootCauses.length, 1); - assertEquals(BaseExceptionsHelper.getExceptionName(rootCauses[0]), "index_not_found_exception"); + assertEquals(OpenSearchException.getExceptionName(rootCauses[0]), "index_not_found_exception"); assertEquals("no such index [foo]", rootCauses[0].getMessage()); ShardSearchFailure failure = new ShardSearchFailure( new ParsingException(1, 2, "foobar", null), @@ -147,14 +147,14 @@ public void testGuessRootCause() { if (randomBoolean()) { rootCauses = (randomBoolean() ? new RemoteTransportException("remoteboom", ex) : ex).guessRootCauses(); } else { - rootCauses = BaseOpenSearchException.guessRootCauses(randomBoolean() ? new RemoteTransportException("remoteboom", ex) : ex); + rootCauses = OpenSearchException.guessRootCauses(randomBoolean() ? new RemoteTransportException("remoteboom", ex) : ex); } - assertEquals("parsing_exception", BaseExceptionsHelper.getExceptionName(rootCauses[0])); + assertEquals("parsing_exception", OpenSearchException.getExceptionName(rootCauses[0])); assertEquals("foobar", rootCauses[0].getMessage()); OpenSearchException oneLevel = new OpenSearchException("foo", new RuntimeException("foobar")); rootCauses = oneLevel.guessRootCauses(); - assertEquals("exception", BaseExceptionsHelper.getExceptionName(rootCauses[0])); + assertEquals("exception", OpenSearchException.getExceptionName(rootCauses[0])); assertEquals("foo", rootCauses[0].getMessage()); } { @@ -175,32 +175,32 @@ public void testGuessRootCause() { "all shards failed", new ShardSearchFailure[] { failure, failure1, failure2 } ); - final BaseOpenSearchException[] rootCauses = ex.guessRootCauses(); + final OpenSearchException[] rootCauses = ex.guessRootCauses(); assertEquals(rootCauses.length, 2); - assertEquals(BaseExceptionsHelper.getExceptionName(rootCauses[0]), "parsing_exception"); + assertEquals(OpenSearchException.getExceptionName(rootCauses[0]), "parsing_exception"); assertEquals(rootCauses[0].getMessage(), "foobar"); assertEquals(1, ((ParsingException) rootCauses[0]).getLineNumber()); assertEquals(2, ((ParsingException) rootCauses[0]).getColumnNumber()); - assertEquals("query_shard_exception", BaseExceptionsHelper.getExceptionName(rootCauses[1])); - assertEquals("foo1", rootCauses[1].getIndexName()); + assertEquals("query_shard_exception", OpenSearchException.getExceptionName(rootCauses[1])); + assertEquals("foo1", rootCauses[1].getIndex().getName()); assertEquals("foobar", rootCauses[1].getMessage()); } { - final BaseOpenSearchException[] foobars = BaseOpenSearchException.guessRootCauses(new IllegalArgumentException("foobar")); + final OpenSearchException[] foobars = OpenSearchException.guessRootCauses(new IllegalArgumentException("foobar")); assertEquals(foobars.length, 1); - assertThat(foobars[0], instanceOf(BaseOpenSearchException.class)); + assertThat(foobars[0], instanceOf(OpenSearchException.class)); assertEquals("foobar", foobars[0].getMessage()); assertEquals(IllegalArgumentException.class, foobars[0].getCause().getClass()); assertEquals("illegal_argument_exception", foobars[0].getExceptionName()); } { - final BaseOpenSearchException[] foobars = BaseOpenSearchException.guessRootCauses( + final OpenSearchException[] foobars = OpenSearchException.guessRootCauses( new RemoteTransportException("abc", new IllegalArgumentException("foobar")) ); assertEquals(foobars.length, 1); - assertThat(foobars[0], instanceOf(BaseOpenSearchException.class)); + assertThat(foobars[0], instanceOf(OpenSearchException.class)); assertEquals("foobar", foobars[0].getMessage()); assertEquals(IllegalArgumentException.class, foobars[0].getCause().getClass()); assertEquals("illegal_argument_exception", foobars[0].getExceptionName()); @@ -209,9 +209,9 @@ public void testGuessRootCause() { { XContentParseException inner = new XContentParseException(null, "inner"); XContentParseException outer = new XContentParseException(null, "outer", inner); - final BaseOpenSearchException[] causes = BaseOpenSearchException.guessRootCauses(outer); + final OpenSearchException[] causes = OpenSearchException.guessRootCauses(outer); assertEquals(causes.length, 1); - assertThat(causes[0], instanceOf(BaseOpenSearchException.class)); + assertThat(causes[0], instanceOf(OpenSearchException.class)); assertEquals("inner", causes[0].getMessage()); assertEquals("x_content_parse_exception", causes[0].getExceptionName()); } @@ -219,9 +219,9 @@ public void testGuessRootCause() { { OpenSearchException inner = new OpenSearchException("inner"); XContentParseException outer = new XContentParseException(null, "outer", inner); - final BaseOpenSearchException[] causes = BaseOpenSearchException.guessRootCauses(outer); + final OpenSearchException[] causes = OpenSearchException.guessRootCauses(outer); assertEquals(causes.length, 1); - assertThat(causes[0], instanceOf(BaseOpenSearchException.class)); + assertThat(causes[0], instanceOf(OpenSearchException.class)); assertEquals("inner", causes[0].getMessage()); assertEquals("exception", causes[0].getExceptionName()); } @@ -409,7 +409,7 @@ public void testToXContent() throws IOException { // Test the same exception but with the "rest.exception.stacktrace.skip" parameter disabled: the stack_trace must be present // in the JSON. Since the stack can be large, it only checks the beginning of the JSON. ToXContent.Params params = new ToXContent.MapParams( - Collections.singletonMap(BaseExceptionsHelper.REST_EXCEPTION_SKIP_STACK_TRACE, "false") + Collections.singletonMap(OpenSearchException.REST_EXCEPTION_SKIP_STACK_TRACE, "false") ); String actual; try (XContentBuilder builder = XContentBuilder.builder(XContentType.JSON.xContent())) { @@ -451,7 +451,7 @@ public void testGenerateThrowableToXContent() throws IOException { OpenSearchException ex = new RemoteTransportException("foobar", new FileNotFoundException("foo not found")); String toXContentString = Strings.toString(XContentType.JSON, ex); String throwableString = Strings.toString(XContentType.JSON, (builder, params) -> { - BaseExceptionsHelper.generateThrowableXContent(builder, params, ex); + OpenSearchException.generateThrowableXContent(builder, params, ex); return builder; }); @@ -740,7 +740,7 @@ public void testThrowableToAndFromXContent() throws IOException { } BytesReference throwableBytes = toShuffledXContent((builder, params) -> { - BaseExceptionsHelper.generateThrowableXContent(builder, params, throwable); + OpenSearchException.generateThrowableXContent(builder, params, throwable); return builder; }, xContent.mediaType(), ToXContent.EMPTY_PARAMS, randomBoolean()); @@ -756,7 +756,7 @@ public void testThrowableToAndFromXContent() throws IOException { if (suppressedCount > 0) { XContentBuilder builder = XContentBuilder.builder(xContent); builder.startObject(); - BaseExceptionsHelper.generateThrowableXContent(builder, ToXContent.EMPTY_PARAMS, throwable); + OpenSearchException.generateThrowableXContent(builder, ToXContent.EMPTY_PARAMS, throwable); builder.endObject(); throwableBytes = BytesReference.bytes(builder); try (XContentParser parser = createParser(xContent, throwableBytes)) { @@ -772,7 +772,7 @@ public void testUnknownFailureToAndFromXContent() throws IOException { BytesReference failureBytes = toShuffledXContent((builder, params) -> { // Prints a null failure using generateFailureXContent() - BaseOpenSearchException.generateFailureXContent(builder, params, null, randomBoolean()); + OpenSearchException.generateFailureXContent(builder, params, null, randomBoolean()); return builder; }, xContent.mediaType(), ToXContent.EMPTY_PARAMS, randomBoolean()); @@ -796,7 +796,7 @@ public void testFailureToAndFromXContentWithNoDetails() throws IOException { final Exception failure = (Exception) randomExceptions().v1(); BytesReference failureBytes = toShuffledXContent((builder, params) -> { - BaseOpenSearchException.generateFailureXContent(builder, params, failure, false); + OpenSearchException.generateFailureXContent(builder, params, failure, false); return builder; }, xContent.mediaType(), ToXContent.EMPTY_PARAMS, randomBoolean()); @@ -814,8 +814,8 @@ public void testFailureToAndFromXContentWithNoDetails() throws IOException { } assertNotNull(parsedFailure); - String reason = BaseExceptionsHelper.summaryMessage(failure); - assertEquals(BaseOpenSearchException.buildMessage("exception", reason, null), parsedFailure.getMessage()); + String reason = ExceptionsHelper.summaryMessage(failure); + assertEquals(OpenSearchException.buildMessage("exception", reason, null), parsedFailure.getMessage()); assertEquals(0, parsedFailure.getHeaders().size()); assertEquals(0, parsedFailure.getMetadata().size()); assertNull(parsedFailure.getCause()); @@ -950,7 +950,7 @@ public void testFailureToAndFromXContentWithDetails() throws IOException { Exception finalFailure = failure; BytesReference failureBytes = toShuffledXContent((builder, params) -> { - BaseOpenSearchException.generateFailureXContent(builder, params, finalFailure, true); + OpenSearchException.generateFailureXContent(builder, params, finalFailure, true); return builder; }, xContent.mediaType(), ToXContent.EMPTY_PARAMS, randomBoolean()); @@ -983,7 +983,7 @@ private static void assertToXContentAsJson(ToXContent e, String expectedJson) th private static void assertExceptionAsJson(Exception e, String expectedJson) throws IOException { assertToXContentAsJson((builder, params) -> { - BaseExceptionsHelper.generateThrowableXContent(builder, params, e); + OpenSearchException.generateThrowableXContent(builder, params, e); return builder; }, expectedJson); } diff --git a/server/src/test/java/org/opensearch/action/bulk/BulkItemResponseTests.java b/server/src/test/java/org/opensearch/action/bulk/BulkItemResponseTests.java index 88c6b466059bc..3e5a7d5ad5242 100644 --- a/server/src/test/java/org/opensearch/action/bulk/BulkItemResponseTests.java +++ b/server/src/test/java/org/opensearch/action/bulk/BulkItemResponseTests.java @@ -32,8 +32,8 @@ package org.opensearch.action.bulk; -import org.opensearch.OpenSearchException; import org.opensearch.ExceptionsHelper; +import org.opensearch.OpenSearchException; import org.opensearch.action.DocWriteRequest; import org.opensearch.action.DocWriteResponse; import org.opensearch.action.bulk.BulkItemResponse.Failure; diff --git a/server/src/test/java/org/opensearch/action/bulk/BulkResponseTests.java b/server/src/test/java/org/opensearch/action/bulk/BulkResponseTests.java index ef930b61f890b..aca2419e2d325 100644 --- a/server/src/test/java/org/opensearch/action/bulk/BulkResponseTests.java +++ b/server/src/test/java/org/opensearch/action/bulk/BulkResponseTests.java @@ -32,8 +32,8 @@ package org.opensearch.action.bulk; -import org.opensearch.OpenSearchException; import org.opensearch.ExceptionsHelper; +import org.opensearch.OpenSearchException; import org.opensearch.action.DocWriteRequest; import org.opensearch.action.DocWriteResponse; import org.opensearch.action.delete.DeleteResponseTests; diff --git a/server/src/test/java/org/opensearch/action/search/MultiSearchRequestTests.java b/server/src/test/java/org/opensearch/action/search/MultiSearchRequestTests.java index 4bf7a4ed8762c..36e996dca7c4d 100644 --- a/server/src/test/java/org/opensearch/action/search/MultiSearchRequestTests.java +++ b/server/src/test/java/org/opensearch/action/search/MultiSearchRequestTests.java @@ -36,10 +36,10 @@ import org.opensearch.action.support.IndicesOptions; import org.opensearch.common.CheckedBiConsumer; import org.opensearch.common.CheckedRunnable; +import org.opensearch.common.bytes.BytesReference; import org.opensearch.core.ParseField; import org.opensearch.common.Strings; import org.opensearch.common.bytes.BytesArray; -import org.opensearch.common.bytes.BytesReference; import org.opensearch.common.io.stream.NamedWriteableRegistry; import org.opensearch.common.logging.DeprecationLogger; import org.opensearch.common.unit.TimeValue; diff --git a/server/src/test/java/org/opensearch/client/AbstractClientHeadersTestCase.java b/server/src/test/java/org/opensearch/client/AbstractClientHeadersTestCase.java index f40227beb59b7..92a88aa7940ee 100644 --- a/server/src/test/java/org/opensearch/client/AbstractClientHeadersTestCase.java +++ b/server/src/test/java/org/opensearch/client/AbstractClientHeadersTestCase.java @@ -32,7 +32,7 @@ package org.opensearch.client; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.action.ActionType; import org.opensearch.action.ActionListener; import org.opensearch.action.admin.cluster.reroute.ClusterRerouteAction; @@ -244,7 +244,7 @@ public Throwable unwrap(Throwable t, Class exceptionType) { } if (counter++ > 10) { // dear god, if we got more than 10 levels down, WTF? just bail - fail("Exception cause unwrapping ran for 10 levels: " + BaseExceptionsHelper.stackTrace(t)); + fail("Exception cause unwrapping ran for 10 levels: " + ExceptionsHelper.stackTrace(t)); return null; } result = result.getCause(); diff --git a/server/src/test/java/org/opensearch/common/io/stream/BytesStreamsTests.java b/server/src/test/java/org/opensearch/common/io/stream/BytesStreamsTests.java index 34c4ed936c565..111354f2b14db 100644 --- a/server/src/test/java/org/opensearch/common/io/stream/BytesStreamsTests.java +++ b/server/src/test/java/org/opensearch/common/io/stream/BytesStreamsTests.java @@ -321,9 +321,9 @@ public void testSimpleStreams() throws Exception { out.writeOptionalBytesReference(new BytesArray("test")); out.writeOptionalDouble(null); out.writeOptionalDouble(1.2); - out.writeTimeZone(DateTimeZone.forID("CET")); - out.writeOptionalTimeZone(DateTimeZone.getDefault()); - out.writeOptionalTimeZone(null); + Joda.writeTimeZone(out, DateTimeZone.forID("CET")); + Joda.writeOptionalTimeZone(out, DateTimeZone.getDefault()); + Joda.writeOptionalTimeZone(out, null); out.writeGenericValue(new DateTime(123456, DateTimeZone.forID("America/Los_Angeles"))); final byte[] bytes = BytesReference.toBytes(out.bytes()); StreamInput in = StreamInput.wrap(BytesReference.toBytes(out.bytes())); @@ -931,7 +931,7 @@ public void testWriteCircularReferenceException() throws IOException { BytesStreamOutput prodOut = new BytesStreamOutput() { @Override - boolean failOnTooManyNestedExceptions(Throwable throwable) { + public boolean failOnTooManyNestedExceptions(Throwable throwable) { assertThat(throwable, sameInstance(rootEx)); return true; } diff --git a/server/src/test/java/org/opensearch/rest/BytesRestResponseTests.java b/server/src/test/java/org/opensearch/rest/BytesRestResponseTests.java index 0e58e8ce719f6..a5d70886aa651 100644 --- a/server/src/test/java/org/opensearch/rest/BytesRestResponseTests.java +++ b/server/src/test/java/org/opensearch/rest/BytesRestResponseTests.java @@ -32,7 +32,7 @@ package org.opensearch.rest; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.OpenSearchStatusException; import org.opensearch.OpenSearchException; import org.opensearch.ResourceAlreadyExistsException; @@ -130,7 +130,7 @@ public void testErrorTrace() throws Exception { String text = response.content().utf8ToString(); assertThat(text, containsString("\"type\":\"unknown_exception\",\"reason\":\"an error occurred reading data\"")); assertThat(text, containsString("{\"type\":\"file_not_found_exception\"")); - assertThat(text, containsString("\"stack_trace\":\"[an error occurred reading data]")); + assertThat(text, containsString("\"stack_trace\":\"OpenSearchException[an error occurred reading data]")); } public void testGuessRootCause() throws IOException { @@ -183,7 +183,7 @@ public void testConvert() throws IOException { + "\"failed_shards\":[{\"shard\":1,\"index\":\"foo\",\"node\":\"node_1\",\"reason\":{\"type\":\"parsing_exception\"," + "\"reason\":\"foobar\",\"line\":1,\"col\":2}}]},\"status\":400}"; assertEquals(expected.trim(), text.trim()); - String stackTrace = BaseExceptionsHelper.stackTrace(ex); + String stackTrace = ExceptionsHelper.stackTrace(ex); assertTrue(stackTrace.contains("Caused by: ParsingException[foobar]")); } diff --git a/server/src/test/java/org/opensearch/search/aggregations/pipeline/DerivativeAggregatorTests.java b/server/src/test/java/org/opensearch/search/aggregations/pipeline/DerivativeAggregatorTests.java index 801f057d8888d..88628cd44c721 100644 --- a/server/src/test/java/org/opensearch/search/aggregations/pipeline/DerivativeAggregatorTests.java +++ b/server/src/test/java/org/opensearch/search/aggregations/pipeline/DerivativeAggregatorTests.java @@ -41,7 +41,7 @@ import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.store.Directory; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.action.search.SearchPhaseExecutionException; import org.opensearch.common.CheckedConsumer; import org.opensearch.index.mapper.DateFieldMapper; @@ -635,7 +635,7 @@ public void testSingleValueAggDerivative_invalidPath() throws IOException { executeTestCase(query, aggBuilder, history -> {}); fail("Expected an Exception but didn't get one"); } catch (Exception e) { - Throwable cause = BaseExceptionsHelper.unwrapCause(e); + Throwable cause = ExceptionsHelper.unwrapCause(e); if (cause == null) { throw e; } else if (cause instanceof SearchPhaseExecutionException) { diff --git a/server/src/test/java/org/opensearch/transport/TransportActionProxyTests.java b/server/src/test/java/org/opensearch/transport/TransportActionProxyTests.java index 64125863c3c5f..5190495a6253e 100644 --- a/server/src/test/java/org/opensearch/transport/TransportActionProxyTests.java +++ b/server/src/test/java/org/opensearch/transport/TransportActionProxyTests.java @@ -31,7 +31,7 @@ package org.opensearch.transport; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.OpenSearchException; import org.opensearch.Version; import org.opensearch.cluster.node.DiscoveryNode; @@ -196,7 +196,7 @@ public void handleResponse(SimpleTestResponse response) { @Override public void handleException(TransportException exp) { try { - Throwable cause = BaseExceptionsHelper.unwrapCause(exp); + Throwable cause = ExceptionsHelper.unwrapCause(exp); assertEquals("greetings from TS_C", cause.getMessage()); } finally { latch.countDown(); diff --git a/test/framework/src/main/java/org/opensearch/test/OpenSearchIntegTestCase.java b/test/framework/src/main/java/org/opensearch/test/OpenSearchIntegTestCase.java index 28ad114e4047e..284afa4a55021 100644 --- a/test/framework/src/main/java/org/opensearch/test/OpenSearchIntegTestCase.java +++ b/test/framework/src/main/java/org/opensearch/test/OpenSearchIntegTestCase.java @@ -40,7 +40,7 @@ import org.apache.lucene.search.Sort; import org.apache.lucene.search.TotalHits; import org.apache.lucene.tests.util.LuceneTestCase; -import org.opensearch.BaseExceptionsHelper; +import org.opensearch.ExceptionsHelper; import org.opensearch.OpenSearchException; import org.opensearch.action.ActionListener; import org.opensearch.action.DocWriteResponse; @@ -1651,7 +1651,7 @@ public void indexRandom(boolean forceRefresh, boolean dummyDocuments, boolean ma } final List actualErrors = new ArrayList<>(); for (Tuple tuple : errors) { - Throwable t = BaseExceptionsHelper.unwrapCause(tuple.v2()); + Throwable t = ExceptionsHelper.unwrapCause(tuple.v2()); if (t instanceof OpenSearchRejectedExecutionException) { logger.debug("Error indexing doc: " + t.getMessage() + ", reindexing."); tuple.v1().execute().actionGet(); // re-index if rejected diff --git a/test/framework/src/main/java/org/opensearch/transport/AbstractSimpleTransportTestCase.java b/test/framework/src/main/java/org/opensearch/transport/AbstractSimpleTransportTestCase.java index 2a8a9217fdf98..71f71e7b4a842 100644 --- a/test/framework/src/main/java/org/opensearch/transport/AbstractSimpleTransportTestCase.java +++ b/test/framework/src/main/java/org/opensearch/transport/AbstractSimpleTransportTestCase.java @@ -39,7 +39,6 @@ import org.apache.logging.log4j.util.Supplier; import org.apache.lucene.util.CollectionUtil; import org.apache.lucene.util.Constants; -import org.opensearch.BaseExceptionsHelper; import org.opensearch.LegacyESVersion; import org.opensearch.OpenSearchException; import org.opensearch.ExceptionsHelper; @@ -559,7 +558,7 @@ public void onRequestSent( serviceA.submitRequest(nodeB, ACTION, TransportRequest.Empty.INSTANCE, EmptyTransportResponseHandler.INSTANCE_SAME).get(); } catch (ExecutionException e) { assertThat(e.getCause(), instanceOf(OpenSearchException.class)); - assertThat(BaseExceptionsHelper.unwrapCause(e.getCause()).getMessage(), equalTo("simulated")); + assertThat(ExceptionsHelper.unwrapCause(e.getCause()).getMessage(), equalTo("simulated")); } // use assert busy as callbacks are called on a different thread @@ -578,7 +577,7 @@ public void onRequestSent( serviceB.submitRequest(nodeA, ACTION, TransportRequest.Empty.INSTANCE, EmptyTransportResponseHandler.INSTANCE_SAME).get(); } catch (ExecutionException e) { assertThat(e.getCause(), instanceOf(OpenSearchException.class)); - assertThat(BaseExceptionsHelper.unwrapCause(e.getCause()).getMessage(), equalTo("simulated")); + assertThat(ExceptionsHelper.unwrapCause(e.getCause()).getMessage(), equalTo("simulated")); } // use assert busy as callbacks are called on a different thread @@ -598,7 +597,7 @@ public void onRequestSent( serviceA.submitRequest(nodeA, ACTION, TransportRequest.Empty.INSTANCE, EmptyTransportResponseHandler.INSTANCE_SAME).get(); } catch (ExecutionException e) { assertThat(e.getCause(), instanceOf(OpenSearchException.class)); - assertThat(BaseExceptionsHelper.unwrapCause(e.getCause()).getMessage(), equalTo("simulated")); + assertThat(ExceptionsHelper.unwrapCause(e.getCause()).getMessage(), equalTo("simulated")); } // use assert busy as callbacks are called on a different thread @@ -1652,7 +1651,7 @@ public void handleResponse(StringMessageResponse response) { @Override public void handleException(TransportException exp) { - Throwable cause = BaseExceptionsHelper.unwrapCause(exp); + Throwable cause = ExceptionsHelper.unwrapCause(exp); assertThat(cause, instanceOf(ConnectTransportException.class)); assertThat(((ConnectTransportException) cause).node(), equalTo(nodeA)); } @@ -1663,7 +1662,7 @@ public void handleException(TransportException exp) { res.txGet(); fail("exception should be thrown"); } catch (Exception e) { - Throwable cause = BaseExceptionsHelper.unwrapCause(e); + Throwable cause = ExceptionsHelper.unwrapCause(e); assertThat(cause, instanceOf(ConnectTransportException.class)); assertThat(((ConnectTransportException) cause).node(), equalTo(nodeA)); }