/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Text; using Newtonsoft.Json.Linq; namespace Avro { /// /// Class for enum type schemas /// public class EnumSchema : NamedSchema { /// /// List of strings representing the enum symbols /// public IList Symbols { get; private set; } /// /// Map of enum symbols and it's corresponding ordinal number /// private readonly IDictionary symbolMap; /// /// Count of enum symbols /// public int Count { get { return Symbols.Count; } } /// /// Static function to return new instance of EnumSchema /// /// JSON object for enum schema /// list of named schema already parsed in /// enclosing namespace for the enum schema /// new instance of enum schema internal static EnumSchema NewInstance(JToken jtok, PropertyMap props, SchemaNames names, string encspace) { SchemaName name = NamedSchema.GetName(jtok, encspace); var aliases = NamedSchema.GetAliases(jtok, name.Space, name.EncSpace); JArray jsymbols = jtok["symbols"] as JArray; if (null == jsymbols) throw new SchemaParseException("Enum has no symbols: " + name); List symbols = new List(); IDictionary symbolMap = new Dictionary(); int i = 0; foreach (JValue jsymbol in jsymbols) { string s = (string)jsymbol.Value; if (symbolMap.ContainsKey(s)) throw new SchemaParseException("Duplicate symbol: " + s); symbolMap[s] = i++; symbols.Add(s); } return new EnumSchema(name, aliases, symbols, symbolMap, props, names); } /// /// Constructor for enum schema /// /// name of enum /// list of aliases for the name /// list of enum symbols /// map of enum symbols and value /// list of named schema already read private EnumSchema(SchemaName name, IList aliases, List symbols, IDictionary symbolMap, PropertyMap props, SchemaNames names) : base(Type.Enumeration, name, aliases, props, names) { if (null == name.Name) throw new SchemaParseException("name cannot be null for enum schema."); this.Symbols = symbols; this.symbolMap = symbolMap; } /// /// Writes enum schema in JSON format /// /// JSON writer /// list of named schema already written /// enclosing namespace of the enum schema protected internal override void WriteJsonFields(Newtonsoft.Json.JsonTextWriter writer, SchemaNames names, string encspace) { base.WriteJsonFields(writer, names, encspace); writer.WritePropertyName("symbols"); writer.WriteStartArray(); foreach (string s in this.Symbols) writer.WriteValue(s); writer.WriteEndArray(); } /// /// Returns the position of the given symbol within this enum. /// Throws AvroException if the symbol is not found in this enum. /// /// name of the symbol to find /// position of the given symbol in this enum schema public int Ordinal(string symbol) { int result; if (symbolMap.TryGetValue(symbol, out result)) return result; throw new AvroException("No such symbol: " + symbol); } /// /// Returns the enum symbol of the given index to the list /// /// symbol index /// symbol name public string this[int index] { get { if (index < Symbols.Count) return Symbols[index]; throw new AvroException("Enumeration out of range. Must be less than " + Symbols.Count + ", but is " + index); } } /// /// Checks if given symbol is in the list of enum symbols /// /// symbol to check /// true if symbol exist, false otherwise public bool Contains(string symbol) { return symbolMap.ContainsKey(symbol); } /// /// Returns an enumerator that enumerates the symbols in this enum schema in the order of their definition. /// /// Enumeration over the symbols of this enum schema public IEnumerator GetEnumerator() { return Symbols.GetEnumerator(); } /// /// Checks equality of two enum schema /// /// /// public override bool Equals(object obj) { if (obj == this) return true; if (obj != null && obj is EnumSchema) { EnumSchema that = obj as EnumSchema; if (SchemaName.Equals(that.SchemaName) && Count == that.Count) { for (int i = 0; i < Count; i++) if (!Symbols[i].Equals(that.Symbols[i])) return false; return areEqual(that.Props, this.Props); } } return false; } /// /// Hashcode function /// /// public override int GetHashCode() { int result = SchemaName.GetHashCode() + getHashCode(Props); foreach (string s in Symbols) result += 23 * s.GetHashCode(); return result; } /// /// Checks if this schema can read data written by the given schema. Used for decoding data. /// /// writer schema /// true if this and writer schema are compatible based on the AVRO specification, false otherwise public override bool CanRead(Schema writerSchema) { if (writerSchema.Tag != Tag) return false; EnumSchema that = writerSchema as EnumSchema; if (!that.SchemaName.Equals(SchemaName)) if (!InAliases(that.SchemaName)) return false; // we defer checking of symbols. Writer may have a symbol missing from the reader, // but if writer never used the missing symbol, then reader should still be able to read the data return true; } } }