/**
* 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();
}
}
}
}