blob: be4b00b9d64b721cf28c1d38833bdd19993d8958 [file] [log] [blame]
/**
* 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
{
/// <summary>
/// Base class for all named schemas: fixed, enum, record
/// </summary>
public abstract class NamedSchema : Schema
{
/// <summary>
/// Name of the schema, contains name, namespace and enclosing namespace
/// </summary>
public SchemaName SchemaName { get; private set; }
/// <summary>
/// Name of the schema
/// </summary>
public override string Name
{
get { return SchemaName.Name; }
}
/// <summary>
/// Namespace of the schema
/// </summary>
public string Namespace
{
get { return SchemaName.Namespace; }
}
/// <summary>
/// Namespace.Name of the schema
/// </summary>
public string Fullname
{
get { return SchemaName.Fullname; }
}
/// <summary>
/// List of aliases for this named schema
/// </summary>
private readonly IList<SchemaName> aliases;
/// <summary>
/// Static function to return a new instance of the named schema
/// </summary>
/// <param name="jo">JSON object of the named schema</param>
/// <param name="names">list of named schemas already read</param>
/// <param name="encspace">enclosing namespace of the named schema</param>
/// <returns></returns>
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;
}
}
/// <summary>
/// Constructor for named schema class
/// </summary>
/// <param name="type">schema type</param>
/// <param name="name">name</param>
/// <param name="names">list of named schemas already read</param>
protected NamedSchema(Type type, SchemaName name, IList<SchemaName> aliases, PropertyMap props, SchemaNames names)
: base(type, props)
{
this.SchemaName = name;
this.aliases = aliases;
if (!names.Add(name, this))
throw new AvroException("Duplicate schema name " + name.Fullname);
}
/// <summary>
/// Parses the name and namespace from the given JSON schema object then creates
/// SchemaName object including the given enclosing namespace
/// </summary>
/// <param name="jtok">JSON object to read</param>
/// <param name="encspace">enclosing namespace</param>
/// <returns>new SchemaName object</returns>
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);
}
/// <summary>
/// Parses the 'aliases' property from the given JSON token
/// </summary>
/// <param name="jtok">JSON object to read</param>
/// <param name="space">namespace of the name this alias is for</param>
/// <param name="encspace">enclosing namespace of the name this alias is for</param>
/// <returns>List of SchemaName that represents the list of alias. If no 'aliases' specified, then it returns null.</returns>
protected static IList<SchemaName> 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<SchemaName>();
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;
}
/// <summary>
/// Writes named schema in JSON format
/// </summary>
/// <param name="writer">JSON writer</param>
/// <param name="names">list of named schemas already written</param>
/// <param name="encspace">enclosing namespace of the named schema</param>
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);
}
/// <summary>
/// Writes named schema in JSON format
/// </summary>
/// <param name="writer">JSON writer</param>
/// <param name="names">list of named schemas already written</param>
/// <param name="encspace">enclosing namespace of the named schema</param>
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();
}
}
}
}