/* 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. */ /* * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. * * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch B.V. 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. */ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Runtime.Serialization; using OpenSearch.Net.Extensions; using OpenSearch.Net.Utf8Json; using OpenSearch.Net.Utf8Json.Internal; namespace OpenSearch.Net { [JsonFormatter(typeof(ErrorCauseFormatter))] [DataContract] public class ErrorCause { private static readonly IReadOnlyCollection DefaultCollection = new ReadOnlyCollection(new string[0]); private static readonly IReadOnlyDictionary DefaultDictionary = new ReadOnlyDictionary(new Dictionary()); private static readonly IReadOnlyCollection DefaultFailedShards = new ReadOnlyCollection(new ShardFailure[0]); /// /// Additional properties related to the error cause. Contains properties that /// are not explicitly mapped on /// public IReadOnlyDictionary AdditionalProperties { get; internal set; } = DefaultDictionary; public long? BytesLimit { get; internal set; } public long? BytesWanted { get; internal set; } public ErrorCause CausedBy { get; internal set; } public int? Column { get; internal set; } public IReadOnlyCollection FailedShards { get; internal set; } = DefaultFailedShards; public bool? Grouped { get; internal set; } public string Index { get; internal set; } public string IndexUUID { get; internal set; } public string Language { get; internal set; } public int? Line { get; internal set; } public string Phase { get; internal set; } public string Reason { get; internal set; } public IReadOnlyCollection ResourceId { get; internal set; } = DefaultCollection; public string ResourceType { get; internal set; } public string Script { get; internal set; } public IReadOnlyCollection ScriptStack { get; internal set; } = DefaultCollection; public int? Shard { get; internal set; } public string StackTrace { get; internal set; } public string Type { get; internal set; } public override string ToString() => CausedBy == null ? $"Type: {Type} Reason: \"{Reason}\"" : $"Type: {Type} Reason: \"{Reason}\" CausedBy: \"{CausedBy}\""; } internal static class ErrorCauseFormatterStatics { public static readonly AutomataDictionary Fields = new AutomataDictionary { { "bytes_limit", 0 }, { "bytes_wanted", 1 }, { "caused_by", 2 }, { "col", 3 }, { "failed_shards", 4 }, { "grouped", 5 }, { "index", 6 }, { "index_uuid", 7 }, { "lang", 8 }, { "line", 9 }, { "phase", 10 }, { "reason", 11 }, { "resource.id", 12 }, { "resource.type", 13 }, { "script", 14 }, { "script_stack", 15 }, { "shard", 16 }, { "stack_trace", 17 }, { "type", 18 } }; public static readonly NullableStringIntFormatter ShardFormatter = new NullableStringIntFormatter(); public static readonly InterfaceReadOnlyCollectionSingleOrEnumerableFormatter SingleOrEnumerableFormatter = new InterfaceReadOnlyCollectionSingleOrEnumerableFormatter(); public static readonly ErrorCauseFormatter ErrorCausePropertyFormatter = new ErrorCauseFormatter(); } internal class ErrorCauseFormatter : IJsonFormatter where TErrorCause : ErrorCause, new() { protected virtual bool Deserialize(ref JsonReader reader, ref ArraySegment property, TErrorCause value, IJsonFormatterResolver formatterResolver) => false; protected virtual void Serialize(ref JsonWriter writer, ref int count, TErrorCause value, IJsonFormatterResolver formatterResolver) {} public TErrorCause Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { var token = reader.GetCurrentJsonToken(); switch (token) { case JsonToken.String: return new TErrorCause { Reason = reader.ReadString() }; case JsonToken.BeginObject: var count = 0; var errorCause = new TErrorCause(); var additionalProperties = new Dictionary(); errorCause.AdditionalProperties = additionalProperties; var formatter = formatterResolver.GetFormatter(); while (reader.ReadIsInObject(ref count)) { var property = reader.ReadPropertyNameSegmentRaw(); if (ErrorCauseFormatterStatics.Fields.TryGetValue(property, out var value)) { switch (value) { case 0: errorCause.BytesLimit = reader.ReadInt64(); break; case 1: errorCause.BytesWanted = reader.ReadInt64(); break; case 2: errorCause.CausedBy = ErrorCauseFormatterStatics.ErrorCausePropertyFormatter.Deserialize(ref reader, formatterResolver); break; case 3: errorCause.Column = reader.ReadInt32(); break; case 4: errorCause.FailedShards = formatterResolver.GetFormatter>() .Deserialize(ref reader, formatterResolver); break; case 5: errorCause.Grouped = reader.ReadBoolean(); break; case 6: errorCause.Index = reader.ReadString(); break; case 7: errorCause.IndexUUID = reader.ReadString(); break; case 8: errorCause.Language = reader.ReadString(); break; case 9: errorCause.Line = reader.ReadInt32(); break; case 10: errorCause.Phase = reader.ReadString(); break; case 11: errorCause.Reason = reader.ReadString(); break; case 12: errorCause.ResourceId = ErrorCauseFormatterStatics.SingleOrEnumerableFormatter.Deserialize(ref reader, formatterResolver); break; case 13: errorCause.ResourceType = reader.ReadString(); break; case 14: errorCause.Script = reader.ReadString(); break; case 15: errorCause.ScriptStack = ErrorCauseFormatterStatics.SingleOrEnumerableFormatter.Deserialize(ref reader, formatterResolver); break; case 16: errorCause.Shard = ErrorCauseFormatterStatics.ShardFormatter.Deserialize(ref reader, formatterResolver); break; case 17: errorCause.StackTrace = reader.ReadString(); break; case 18: errorCause.Type = reader.ReadString(); break; } } else { if (!Deserialize(ref reader, ref property, errorCause, formatterResolver)) additionalProperties.Add(property.Utf8String(), formatter.Deserialize(ref reader, formatterResolver)); } } return errorCause; default: reader.ReadNextBlock(); return null; } } public void Serialize(ref JsonWriter writer, TErrorCause value, IJsonFormatterResolver formatterResolver) { if (value == null) { writer.WriteNull(); return; } writer.WriteBeginObject(); var count = 0; if (value.BytesLimit.HasValue) { writer.WritePropertyName("bytes_limit"); writer.WriteInt64(value.BytesLimit.Value); count++; } if (value.BytesWanted.HasValue) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("bytes_wanted"); writer.WriteInt64(value.BytesWanted.Value); count++; } if (value.CausedBy != null) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("caused_by"); ErrorCauseFormatterStatics.ErrorCausePropertyFormatter.Serialize(ref writer, value.CausedBy, formatterResolver); count++; } if (value.Column.HasValue) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("col"); writer.WriteInt32(value.Column.Value); count++; } if (value.FailedShards.Any()) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("failed_shards"); formatterResolver.GetFormatter>() .Serialize(ref writer, value.FailedShards, formatterResolver); count++; } if (value.Grouped.HasValue) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("grouped"); writer.WriteBoolean(value.Grouped.Value); count++; } if (value.Index != null) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("index"); writer.WriteString(value.Index); count++; } if (value.IndexUUID != null) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("index_uuid"); writer.WriteString(value.IndexUUID); count++; } if (value.Language != null) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("lang"); writer.WriteString(value.Language); count++; } if (value.Line.HasValue) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("line"); writer.WriteInt32(value.Line.Value); count++; } if (value.Phase != null) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("phase"); writer.WriteString(value.Phase); count++; } if (value.Reason != null) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("reason"); writer.WriteString(value.Reason); count++; } if (value.ResourceId.Any()) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("resource.id"); ErrorCauseFormatterStatics.SingleOrEnumerableFormatter.Serialize(ref writer, value.ResourceId, formatterResolver); count++; } if (value.ResourceType != null) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("resource.type"); writer.WriteString(value.ResourceType); count++; } if (value.Script != null) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("script"); writer.WriteString(value.Script); count++; } if (value.ScriptStack.Any()) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("script_stack"); ErrorCauseFormatterStatics.SingleOrEnumerableFormatter.Serialize(ref writer, value.ScriptStack, formatterResolver); count++; } if (value.Shard.HasValue) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("shard"); writer.WriteInt32(value.Shard.Value); count++; } if (value.StackTrace != null) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("stack_trace"); writer.WriteString(value.StackTrace); count++; } if (value.Type != null) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName("type"); writer.WriteString(value.Type); count++; } Serialize(ref writer, ref count, value, formatterResolver); if (value.AdditionalProperties.Any()) { var formatter = formatterResolver.GetFormatter(); foreach (var additionalProperty in value.AdditionalProperties) { if (count > 0) writer.WriteValueSeparator(); writer.WritePropertyName(additionalProperty.Key); formatter.Serialize(ref writer, additionalProperty.Value, formatterResolver); count++; } } writer.WriteEndObject(); } } internal class ErrorCauseFormatter : ErrorCauseFormatter {} }