/** * 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 { /// /// Base class for all named schemas: fixed, enum, record /// public abstract class NamedSchema : Schema { /// /// Name of the schema, contains name, namespace and enclosing namespace /// public SchemaName SchemaName { get; private set; } /// /// Name of the schema /// public override string Name { get { return SchemaName.Name; } } /// /// Namespace of the schema /// public string Namespace { get { return SchemaName.Namespace; } } /// /// Namespace.Name of the schema /// public string Fullname { get { return SchemaName.Fullname; } } /// /// List of aliases for this named schema /// private readonly IList aliases; /// /// Static function to return a new instance of the named schema /// /// JSON object of the named schema /// list of named schemas already read /// enclosing namespace of the named schema /// internal static NamedSchema NewInstance(JObject jo, PropertyMap props, SchemaNames names, string encspace) { string type = JsonHelper.GetRequiredString(jo, "type"); switch (type) { case "fixed": return FixedSchema.NewInstance(jo, props, names, encspace); case "enum": return EnumSchema.NewInstance(jo, props, names, encspace); case "record": return RecordSchema.NewInstance(Type.Record, jo, props, names, encspace); case "error": return RecordSchema.NewInstance(Type.Error, jo, props, names, encspace); default: NamedSchema result; if (names.TryGetValue(type, null, encspace, out result)) return result; return null; } } /// /// Constructor for named schema class /// /// schema type /// name /// list of named schemas already read protected NamedSchema(Type type, SchemaName name, IList aliases, PropertyMap props, SchemaNames names) : base(type, props) { this.SchemaName = name; this.aliases = aliases; if (null != name.Name) // Added this check for anonymous records inside Message if (!names.Add(name, this)) throw new AvroException("Duplicate schema name " + name.Fullname); } /// /// Parses the name and namespace from the given JSON schema object then creates /// SchemaName object including the given enclosing namespace /// /// JSON object to read /// enclosing namespace /// new SchemaName object protected static SchemaName GetName(JToken jtok, string encspace) { String n = JsonHelper.GetOptionalString(jtok, "name"); // Changed this to optional string for anonymous records in messages String ns = JsonHelper.GetOptionalString(jtok, "namespace"); return new SchemaName(n, ns, encspace); } /// /// Parses the 'aliases' property from the given JSON token /// /// JSON object to read /// namespace of the name this alias is for /// enclosing namespace of the name this alias is for /// List of SchemaName that represents the list of alias. If no 'aliases' specified, then it returns null. protected static IList GetAliases(JToken jtok, string space, string encspace) { JToken jaliases = jtok["aliases"]; if (null == jaliases) return null; if (jaliases.Type != JTokenType.Array) throw new SchemaParseException("Aliases must be of format JSON array of strings"); var aliases = new List(); foreach (JToken jalias in jaliases) { if (jalias.Type != JTokenType.String) throw new SchemaParseException("Aliases must be of format JSON array of strings"); aliases.Add(new SchemaName((string)jalias, space, encspace)); } return aliases; } protected bool InAliases(SchemaName name) { if (null != aliases) { foreach (SchemaName alias in aliases) if (name.Equals(alias)) return true; } return false; } /// /// Writes named schema in JSON format /// /// JSON writer /// list of named schemas already written /// enclosing namespace of the named schema protected internal override void WriteJson(Newtonsoft.Json.JsonTextWriter writer, SchemaNames names, string encspace) { if (!names.Add(this)) { // schema is already in the list, write name only SchemaName schemaName = this.SchemaName; string name; if (schemaName.Namespace != encspace) name = schemaName.Namespace + "." + schemaName.Name; // we need to add the qualifying namespace of the target schema if it's not the same as current namespace else name = schemaName.Name; writer.WriteValue(name); } else // schema is not in the list, write full schema definition base.WriteJson(writer, names, encspace); } /// /// Writes named schema in JSON format /// /// JSON writer /// list of named schemas already written /// enclosing namespace of the named schema protected internal override void WriteJsonFields(Newtonsoft.Json.JsonTextWriter writer, SchemaNames names, string encspace) { this.SchemaName.WriteJson(writer, names, encspace); if (null != aliases) { writer.WritePropertyName("aliases"); writer.WriteStartArray(); foreach (SchemaName name in aliases) { string fullname = (null != name.Space) ? name.Space + "." + name.Name : name.Name; writer.WriteValue(fullname); } writer.WriteEndArray(); } } } }