You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by cu...@apache.org on 2011/03/31 23:16:49 UTC
svn commit: r1087439 [4/6] - in /avro/trunk: ./ lang/csharp/
lang/csharp/lib/ lang/csharp/lib/main/ lang/csharp/lib/test/
lang/csharp/src/ lang/csharp/src/apache/ lang/csharp/src/apache/codegen/
lang/csharp/src/apache/codegen/Properties/ lang/csharp/sr...
Added: avro/trunk/lang/csharp/src/apache/main/Schema/NamedSchema.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Schema/NamedSchema.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Schema/NamedSchema.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Schema/NamedSchema.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,223 @@
+/**
+ * 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>
+ /// Returns the SchemaName object of the named schema
+ /// </summary>
+ /// <returns></returns>
+ public SchemaName GetName()
+ {
+ return schemaName;
+ }
+ */
+
+ /// <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;
+ try
+ {
+ names.Add(name, this);
+ }
+ catch (Exception ex)
+ {
+ throw new AvroException("Could not add " + name.Fullname + ". " + ex.Message);
+ }
+ }
+
+ /// <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();
+ }
+ }
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Schema/PrimitiveSchema.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Schema/PrimitiveSchema.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Schema/PrimitiveSchema.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Schema/PrimitiveSchema.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,130 @@
+/**
+ * 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;
+
+namespace Avro
+{
+ /// <summary>
+ /// Class for schemas of primitive types
+ /// </summary>
+ public sealed class PrimitiveSchema : UnnamedSchema
+ {
+ /// <summary>
+ /// Constructor for primitive schema
+ /// </summary>
+ /// <param name="type"></param>
+ private PrimitiveSchema(Type type, PropertyMap props) : base(type, props)
+ {
+ }
+
+ /// <summary>
+ /// Static function to return new instance of primitive schema
+ /// </summary>
+ /// <param name="type">primitive type</param>
+ /// <returns></returns>
+ public static PrimitiveSchema NewInstance(string type, PropertyMap props = null)
+ {
+ const string q = "\"";
+ if (type.StartsWith(q) && type.EndsWith(q)) type = type.Substring(1, type.Length - 2);
+ switch (type)
+ {
+ case "null":
+ return new PrimitiveSchema(Schema.Type.Null, props);
+ case "boolean":
+ return new PrimitiveSchema(Schema.Type.Boolean, props);
+ case "int":
+ return new PrimitiveSchema(Schema.Type.Int, props);
+ case "long":
+ return new PrimitiveSchema(Schema.Type.Long, props);
+ case "float":
+ return new PrimitiveSchema(Schema.Type.Float, props);
+ case "double":
+ return new PrimitiveSchema(Schema.Type.Double, props);
+ case "bytes":
+ return new PrimitiveSchema(Schema.Type.Bytes, props);
+ case "string":
+ return new PrimitiveSchema(Schema.Type.String, props);
+ default:
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Writes primitive schema in JSON format
+ /// </summary>
+ /// <param name="w"></param>
+ /// <param name="names"></param>
+ /// <param name="encspace"></param>
+ protected internal override void WriteJson(JsonTextWriter w, SchemaNames names, string encspace)
+ {
+ w.WriteValue(Name);
+ }
+
+ /// <summary>
+ /// Checks if this schema can read data written by the given schema. Used for decoding data.
+ /// </summary>
+ /// <param name="writerSchema">writer schema</param>
+ /// <returns>true if this and writer schema are compatible based on the AVRO specification, false otherwise</returns>
+ public override bool CanRead(Schema writerSchema)
+ {
+ if (writerSchema is UnionSchema || Tag == writerSchema.Tag) return true;
+ Type t = writerSchema.Tag;
+ switch (Tag)
+ {
+ case Type.Double:
+ return t == Type.Int || t == Type.Long || t == Type.Float;
+ case Type.Float:
+ return t == Type.Int || t == Type.Long;
+ case Type.Long:
+ return t == Type.Int;
+ default:
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Function to compare equality of two primitive schemas
+ /// </summary>
+ /// <param name="obj">other primitive schema</param>
+ /// <returns>true two schemas are equal, false otherwise</returns>
+ public override bool Equals(object obj)
+ {
+ if (this == obj) return true;
+
+ if (obj != null && obj is PrimitiveSchema)
+ {
+ var that = obj as PrimitiveSchema;
+ if (this.Tag == that.Tag)
+ return areEqual(that.Props, this.Props);
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Hashcode function
+ /// </summary>
+ /// <returns></returns>
+ public override int GetHashCode()
+ {
+ return 13 * Tag.GetHashCode() + getHashCode(Props);
+ }
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Schema/Property.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Schema/Property.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Schema/Property.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Schema/Property.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,124 @@
+/**
+ * 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.Linq;
+using System.Text;
+using Newtonsoft.Json.Linq;
+using Newtonsoft.Json;
+
+namespace Avro
+{
+ public class PropertyMap : Dictionary<string, string>
+ {
+ /// <summary>
+ /// Set of reserved schema property names, any other properties not defined in this set are custom properties and can be added to this map
+ /// </summary>
+ private static readonly HashSet<string> ReservedProps = new HashSet<string>() { "type", "name", "namespace", "fields", "items", "size", "symbols", "values", "aliases", "order", "doc", "default" };
+
+ /// <summary>
+ /// Parses the custom properties from the given JSON object and stores them
+ /// into the schema's list of custom properties
+ /// </summary>
+ /// <param name="jtok">JSON object to prase</param>
+ public void Parse(JToken jtok)
+ {
+ JObject jo = jtok as JObject;
+ foreach (JProperty prop in jo.Properties())
+ {
+ if (ReservedProps.Contains(prop.Name))
+ continue;
+ if (!ContainsKey(prop.Name))
+ Add(prop.Name, prop.Value.ToString());
+ }
+ }
+
+ /// <summary>
+ /// Adds a custom property to the schema
+ /// </summary>
+ /// <param name="key">custom property name</param>
+ /// <param name="value">custom property value</param>
+ public void Set(string key, string value)
+ {
+ if (ReservedProps.Contains(key))
+ throw new AvroException("Can't set reserved property: " + key);
+
+ string oldValue;
+ if (TryGetValue(key, out oldValue))
+ {
+ if (!oldValue.Equals(value)) throw new AvroException("Property cannot be overwritten: " + key);
+ }
+ else
+ Add(key, value);
+ }
+
+ /// <summary>
+ /// Writes the schema's custom properties in JSON format
+ /// </summary>
+ /// <param name="writer">JSON writer</param>
+ public void WriteJson(JsonTextWriter writer)
+ {
+ foreach (KeyValuePair<string, string> kp in this)
+ {
+ if (ReservedProps.Contains(kp.Key)) continue;
+
+ writer.WritePropertyName(kp.Key);
+ writer.WriteRawValue(kp.Value);
+ }
+ }
+
+ /// <summary>
+ /// Function to compare equality of two PropertyMaps
+ /// </summary>
+ /// <param name="obj">other PropertyMap</param>
+ /// <returns>true if contents of the two maps are the same, false otherwise</returns>
+ public override bool Equals(object obj)
+ {
+ if (this == obj) return true;
+
+ if (obj != null && obj is PropertyMap)
+ {
+ var that = obj as PropertyMap;
+ if (this.Count != that.Count)
+ return false;
+ foreach (KeyValuePair<string, string> pair in this)
+ {
+ if (!that.ContainsKey(pair.Key))
+ return false;
+ if (!pair.Value.Equals(that[pair.Key]))
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Hashcode function
+ /// </summary>
+ /// <returns></returns>
+ public override int GetHashCode()
+ {
+ int hash = this.Count;
+ int index = 1;
+ foreach (KeyValuePair<string, string> pair in this)
+ hash += (pair.Key.GetHashCode() + pair.Value.GetHashCode()) * index++;
+ return hash;
+ }
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Schema/RecordSchema.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Schema/RecordSchema.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Schema/RecordSchema.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Schema/RecordSchema.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,338 @@
+/**
+ * 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;
+using Newtonsoft.Json;
+
+namespace Avro
+{
+ internal delegate T Function<T>();
+
+ /// <summary>
+ /// Class for record schemas
+ /// </summary>
+ public class RecordSchema : NamedSchema
+ {
+ /// <summary>
+ /// List of fields in the record
+ /// </summary>
+ public List<Field> Fields { get; private set; }
+
+ /// <summary>
+ /// Number of fields in the record
+ /// </summary>
+ public int Count { get { return Fields.Count; } }
+
+ /// <summary>
+ /// Map of field name and Field object for faster field lookups
+ /// </summary>
+ private readonly IDictionary<string, Field> fieldLookup;
+
+ private readonly IDictionary<string, Field> fieldAliasLookup;
+ private bool request;
+
+ /// <summary>
+ /// Static function to return new instance of the record schema
+ /// </summary>
+ /// <param name="type">type of record schema, either record or error</param>
+ /// <param name="jtok">JSON object for the record schema</param>
+ /// <param name="names">list of named schema already read</param>
+ /// <param name="encspace">enclosing namespace of the records schema</param>
+ /// <returns>new RecordSchema object</returns>
+ internal static RecordSchema NewInstance(Type type, JToken jtok, PropertyMap props, SchemaNames names, string encspace)
+ {
+ bool request = false;
+ JToken jfields = jtok["fields"]; // normal record
+ if (null == jfields)
+ {
+ jfields = jtok["request"]; // anonymous record from messages
+ if (null != jfields) request = true;
+ }
+ if (null == jfields)
+ throw new SchemaParseException("'fields' cannot be null for record");
+ if (jfields.Type != JTokenType.Array)
+ throw new SchemaParseException("'fields' not an array for record");
+
+ var name = GetName(jtok, encspace);
+ var aliases = NamedSchema.GetAliases(jtok, name.Space, name.EncSpace);
+ var fields = new List<Field>();
+ var fieldMap = new Dictionary<string, Field>();
+ var fieldAliasMap = new Dictionary<string, Field>();
+ var result = new RecordSchema(type, name, aliases, props, fields, request, fieldMap, fieldAliasMap, names);
+
+ int fieldPos = 0;
+ foreach (JObject jfield in jfields)
+ {
+ string fieldName = JsonHelper.GetRequiredString(jfield, "name");
+ Field field = createField(jfield, fieldPos++, names, name.Namespace); // add record namespace for field look up
+ fields.Add(field);
+ addToFieldMap(fieldMap, fieldName, field);
+ addToFieldMap(fieldAliasMap, fieldName, field);
+
+ if (null != field.aliases) // add aliases to field lookup map so reader function will find it when writer field name appears only as an alias on the reader field
+ foreach (string alias in field.aliases)
+ addToFieldMap(fieldAliasMap, alias, field);
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Constructor for the record schema
+ /// </summary>
+ /// <param name="type">type of record schema, either record or error</param>
+ /// <param name="name">name of the record schema</param>
+ /// <param name="aliases">list of aliases for the record name</param>
+ /// <param name="fields">list of fields for the record</param>
+ /// <param name="request">true if this is an anonymous record with 'request' instead of 'fields'</param>
+ /// <param name="fieldMap">map of field names and field objects</param>
+ /// <param name="names">list of named schema already read</param>
+ private RecordSchema(Type type, SchemaName name, IList<SchemaName> aliases, PropertyMap props,
+ List<Field> fields, bool request, IDictionary<string, Field> fieldMap,
+ IDictionary<string, Field> fieldAliasMap, SchemaNames names)
+ : base(type, name, aliases, props, names)
+ {
+ this.Fields = fields;
+ this.request = request;
+ this.fieldLookup = fieldMap;
+ this.fieldAliasLookup = fieldAliasMap;
+ }
+
+ /// <summary>
+ /// Creates a new field for the record
+ /// </summary>
+ /// <param name="jfield">JSON object for the field</param>
+ /// <param name="pos">position number of the field</param>
+ /// <param name="names">list of named schemas already read</param>
+ /// <param name="encspace">enclosing namespace of the records schema</param>
+ /// <returns>new Field object</returns>
+ private static Field createField(JToken jfield, int pos, SchemaNames names, string encspace)
+ {
+ var name = JsonHelper.GetRequiredString(jfield, "name");
+ var doc = JsonHelper.GetOptionalString(jfield, "doc");
+
+ var jorder = JsonHelper.GetOptionalString(jfield, "order");
+ Field.SortOrder sortorder = Field.SortOrder.ignore;
+ if (null != jorder)
+ sortorder = (Field.SortOrder) Enum.Parse(typeof(Field.SortOrder), jorder);
+
+ var aliases = Field.GetAliases(jfield);
+ var props = Schema.GetProperties(jfield);
+ var defaultValue = jfield["default"];
+
+ JToken jtype = jfield["type"];
+ if (null == jtype)
+ throw new SchemaParseException("'type' was not found for field: " + name);
+ var schema = Schema.ParseJson(jtype, names, encspace);
+
+ return new Field(schema, name, aliases, pos, doc, defaultValue, sortorder, props);
+ }
+
+ private static void addToFieldMap(Dictionary<string, Field> map, string name, Field field)
+ {
+ if (map.ContainsKey(name))
+ throw new SchemaParseException("field or alias " + name + " is a duplicate name");
+ map.Add(name, field);
+ }
+
+ /// <summary>
+ /// Returns the field with the given name.
+ /// </summary>
+ /// <param name="name">field name</param>
+ /// <returns>Field object</returns>
+ public Field this[string name]
+ {
+ get
+ {
+ if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
+ Field field;
+ return (fieldLookup.TryGetValue(name, out field)) ? field : null;
+ }
+ }
+
+ /// <summary>
+ /// Returns true if and only if the record contains a field by the given name.
+ /// </summary>
+ /// <param name="fieldName">The name of the field</param>
+ /// <returns>true if the field exists, false otherwise</returns>
+ public bool Contains(string fieldName)
+ {
+ return fieldLookup.ContainsKey(fieldName);
+ }
+
+ public bool TryGetField(string fieldName, out Field field)
+ {
+ return fieldLookup.TryGetValue(fieldName, out field);
+ }
+ public bool TryGetFieldAlias(string fieldName, out Field field)
+ {
+ return fieldAliasLookup.TryGetValue(fieldName, out field);
+ }
+
+ /// <summary>
+ /// Returns an enumerator which enumerates over the fields of this record schema
+ /// </summary>
+ /// <returns>Enumerator over the field in the order of their definition</returns>
+ public IEnumerator<Field> GetEnumerator()
+ {
+ return Fields.GetEnumerator();
+ }
+
+ /// <summary>
+ /// Writes the records 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 record schema</param>
+ protected internal override void WriteJsonFields(Newtonsoft.Json.JsonTextWriter writer, SchemaNames names, string encspace)
+ {
+ base.WriteJsonFields(writer, names, encspace);
+
+ // we allow reading for empty fields, so writing of records with empty fields are allowed as well
+ if (request)
+ writer.WritePropertyName("request");
+ else
+ writer.WritePropertyName("fields");
+ writer.WriteStartArray();
+
+ if (null != this.Fields && this.Fields.Count > 0)
+ {
+ foreach (Field field in this)
+ field.writeJson(writer, names, this.Namespace); // use the namespace of the record for the fields
+ }
+ writer.WriteEndArray();
+ }
+
+ /// <summary>
+ /// Compares equality of two record schemas
+ /// </summary>
+ /// <param name="obj">record schema to compare against this schema</param>
+ /// <returns>true if the two schemas are equal, false otherwise</returns>
+ public override bool Equals(object obj)
+ {
+ if (obj == this) return true;
+ if (obj != null && obj is RecordSchema)
+ {
+ RecordSchema that = obj as RecordSchema;
+ return protect(() => true, () =>
+ {
+ if (this.SchemaName.Equals(that.SchemaName) && this.Count == that.Count)
+ {
+ for (int i = 0; i < Fields.Count; i++) if (!Fields[i].Equals(that.Fields[i])) return false;
+ return areEqual(that.Props, this.Props);
+ }
+ return false;
+ }, that);
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Hash code function
+ /// </summary>
+ /// <returns></returns>
+ public override int GetHashCode()
+ {
+ return protect(() =>
+ {
+ int result = SchemaName.GetHashCode();
+ foreach (Field f in Fields) result += 29 * f.GetHashCode();
+ result += getHashCode(Props);
+ return result;
+ }, () => 0, this);
+ }
+
+ /// <summary>
+ /// Checks if this schema can read data written by the given schema. Used for decoding data.
+ /// </summary>
+ /// <param name="writerSchema">writer schema</param>
+ /// <returns>true if this and writer schema are compatible based on the AVRO specification, false otherwise</returns>
+ public override bool CanRead(Schema writerSchema)
+ {
+ if (writerSchema.Tag != Type.Record) return false;
+ RecordSchema that = writerSchema as RecordSchema;
+ return protect(() => true, () =>
+ {
+ if (!that.SchemaName.Equals(SchemaName))
+ if (!InAliases(that.SchemaName))
+ return false;
+
+ foreach (Field f in this)
+ {
+ Field f2 = that[f.Name];
+ if (null == f2) // reader field not in writer field, check aliases of reader field if any match with a writer field
+ if (null != f.aliases)
+ foreach (string alias in f.aliases)
+ {
+ f2 = that[alias];
+ if (null != f2) break;
+ }
+
+ if (f2 == null && f.DefaultValue != null)
+ continue; // Writer field missing, reader has default.
+
+ if (f2 != null && f.Schema.CanRead(f2.Schema)) continue; // Both fields exist and are compatible.
+ return false;
+ }
+ return true;
+ }, that);
+ }
+
+ private class RecordSchemaPair
+ {
+ public readonly RecordSchema first;
+ public readonly RecordSchema second;
+
+ public RecordSchemaPair(RecordSchema first, RecordSchema second)
+ {
+ this.first = first;
+ this.second = second;
+ }
+ }
+
+ [ThreadStatic]
+ private static List<RecordSchemaPair> seen;
+
+ /**
+ * We want to protect against infinite recursion when the schema is recursive. We look into a thread local
+ * to see if we have been into this if so, we execute the bypass function otherwise we execute the main function.
+ * Before executing the main function, we ensure that we create a marker so that if we come back here recursively
+ * we can detect it.
+ *
+ * The infinite loop happens in ToString(), Equals() and GetHashCode() methods.
+ * Though it does not happen for CanRead() because of the current implemenation of UnionSchema's can read,
+ * it could potenitally happen.
+ * We do a linear seach for the marker as we don't expect the list to be very long.
+ */
+ private T protect<T>(Function<T> bypass, Function<T> main, RecordSchema that)
+ {
+ if (seen == null)
+ seen = new List<RecordSchemaPair>();
+
+ else if (seen.Find((RecordSchemaPair rs) => rs.first == this && rs.second == that) != null)
+ return bypass();
+
+ RecordSchemaPair p = new RecordSchemaPair(this, that);
+ seen.Add(p);
+ try { return main(); }
+ finally { seen.Remove(p); }
+ }
+
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Schema/Schema.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Schema/Schema.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Schema/Schema.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Schema/Schema.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,306 @@
+/**
+ * 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;
+using Newtonsoft.Json;
+
+namespace Avro
+{
+ /// <summary>
+ /// Base class for all schema types
+ /// </summary>
+ public abstract class Schema
+ {
+ /// <summary>
+ /// Enum for schema types
+ /// </summary>
+ public enum Type
+ {
+ Null,
+ Boolean,
+ Int,
+ Long,
+ Float,
+ Double,
+ Bytes,
+ String,
+ Record,
+ Enumeration,
+ Array,
+ Map,
+ Union,
+ Fixed,
+ Error
+ }
+
+ /// <summary>
+ /// Schema type property
+ /// </summary>
+ public Type Tag { get; private set; }
+
+ /// <summary>
+ /// Additional JSON attributes apart from those defined in the AVRO spec
+ /// </summary>
+ internal PropertyMap Props { get; private set; }
+
+ /// <summary>
+ /// Constructor for schema class
+ /// </summary>
+ /// <param name="type"></param>
+ protected Schema(Type type, PropertyMap props)
+ {
+ this.Tag = type;
+ this.Props = props;
+ }
+
+ /// <summary>
+ /// The name of this schema. If this is a named schema such as an enum, it returns the fully qualified
+ /// name for the schema. For other schemas, it returns the type of the schema.
+ /// </summary>
+ public abstract string Name { get; }
+
+ /// <summary>
+ /// Static class to return new instance of schema object
+ /// </summary>
+ /// <param name="jtok">JSON object</param>
+ /// <param name="names">list of named schemas already read</param>
+ /// <param name="encspace">enclosing namespace of the schema</param>
+ /// <returns>new Schema object</returns>
+ internal static Schema ParseJson(JToken jtok, SchemaNames names, string encspace)
+ {
+ if (null == jtok) throw new ArgumentNullException("j", "j cannot be null.");
+
+ if (jtok.Type == JTokenType.String) // primitive schema with no 'type' property or primitive or named type of a record field
+ {
+ string value = (string)jtok;
+
+ PrimitiveSchema ps = PrimitiveSchema.NewInstance(value);
+ if (null != ps) return ps;
+
+ NamedSchema schema = null;
+ if (names.TryGetValue(value, null, encspace, out schema)) return schema;
+
+ throw new SchemaParseException("Undefined name: " + value);
+ }
+
+ if (jtok is JArray) // union schema with no 'type' property or union type for a record field
+ return UnionSchema.NewInstance(jtok as JArray, null, names, encspace);
+
+ if (jtok is JObject) // JSON object with open/close parenthesis, it must have a 'type' property
+ {
+ JObject jo = jtok as JObject;
+
+ JToken jtype = jo["type"];
+ if (null == jtype)
+ throw new SchemaParseException("Property type is required");
+
+ var props = Schema.GetProperties(jtok);
+
+ if (jtype.Type == JTokenType.String)
+ {
+ string type = (string)jtype;
+
+ if (type.Equals("array"))
+ return ArraySchema.NewInstance(jtok, props, names, encspace);
+ if (type.Equals("map"))
+ return MapSchema.NewInstance(jtok, props, names, encspace);
+
+ Schema schema = PrimitiveSchema.NewInstance((string)type, props);
+ if (null != schema) return schema;
+
+ return NamedSchema.NewInstance(jo, props, names, encspace);
+ }
+ else if (jtype.Type == JTokenType.Array)
+ return UnionSchema.NewInstance(jtype as JArray, props, names, encspace);
+ }
+ throw new AvroTypeException("Invalid JSON for schema: " + jtok);
+ }
+
+ /// <summary>
+ /// Parses a given JSON string to create a new schema object
+ /// </summary>
+ /// <param name="json">JSON string</param>
+ /// <returns>new Schema object</returns>
+ public static Schema Parse(string json)
+ {
+ if (string.IsNullOrEmpty(json)) throw new ArgumentNullException("json", "json cannot be null.");
+ return Parse(json.Trim(), new SchemaNames(), null); // standalone schema, so no enclosing namespace
+ }
+
+ /// <summary>
+ /// Parses a JSON string to create a new schema object
+ /// </summary>
+ /// <param name="json">JSON string</param>
+ /// <param name="names">list of named schemas already read</param>
+ /// <param name="encspace">enclosing namespace of the schema</param>
+ /// <returns>new Schema object</returns>
+ internal static Schema Parse(string json, SchemaNames names, string encspace)
+ {
+ Schema sc = PrimitiveSchema.NewInstance(json);
+ if (null != sc) return sc;
+
+ try
+ {
+ bool IsArray = json.StartsWith("[") && json.EndsWith("]");
+ JContainer j = IsArray ? (JContainer)JArray.Parse(json) : (JContainer)JObject.Parse(json);
+
+ return ParseJson(j, names, encspace);
+ }
+ catch (Newtonsoft.Json.JsonSerializationException ex)
+ {
+ throw new SchemaParseException("Could not parse. " + ex.Message + Environment.NewLine + json);
+ }
+ }
+
+ /// <summary>
+ /// Static function to parse custom properties (not defined in the Avro spec) from the given JSON object
+ /// </summary>
+ /// <param name="jtok">JSON object to parse</param>
+ /// <returns>Property map if custom properties were found, null if no custom properties found</returns>
+ internal static PropertyMap GetProperties(JToken jtok)
+ {
+ var props = new PropertyMap();
+ props.Parse(jtok);
+ if (props.Count > 0)
+ return props;
+ else
+ return null;
+ }
+
+ /// <summary>
+ /// Returns the canonical JSON representation of this schema.
+ /// </summary>
+ /// <returns>The canonical JSON representation of this schema.</returns>
+ public override string ToString()
+ {
+ System.IO.StringWriter sw = new System.IO.StringWriter();
+ Newtonsoft.Json.JsonTextWriter writer = new Newtonsoft.Json.JsonTextWriter(sw);
+
+ if (this is PrimitiveSchema || this is UnionSchema)
+ {
+ writer.WriteStartObject();
+ writer.WritePropertyName("type");
+ }
+
+ WriteJson(writer, new SchemaNames(), null); // stand alone schema, so no enclosing name space
+
+ if (this is PrimitiveSchema || this is UnionSchema)
+ writer.WriteEndObject();
+
+ return sw.ToString();
+ }
+
+ /// <summary>
+ /// Writes opening { and 'type' property
+ /// </summary>
+ /// <param name="writer">JSON writer</param>
+ private void writeStartObject(JsonTextWriter writer)
+ {
+ writer.WriteStartObject();
+ writer.WritePropertyName("type");
+ writer.WriteValue(getTypeString(this.Tag));
+ }
+
+ /// <summary>
+ /// Returns symbol name for the given schema type
+ /// </summary>
+ /// <param name="type">schema type</param>
+ /// <returns>symbol name</returns>
+ protected static string getTypeString(Type type)
+ {
+ if (type != Type.Enumeration) return type.ToString().ToLower();
+ return "enum";
+ }
+
+ /// <summary>
+ /// Default implementation for writing schema properties 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 schema</param>
+ protected internal virtual void WriteJsonFields(JsonTextWriter writer, SchemaNames names, string encspace)
+ {
+ }
+
+ /// <summary>
+ /// Writes schema object 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 schema</param>
+ protected internal virtual void WriteJson(JsonTextWriter writer, SchemaNames names, string encspace)
+ {
+ writeStartObject(writer);
+ WriteJsonFields(writer, names, encspace);
+ if (null != this.Props) Props.WriteJson(writer);
+ writer.WriteEndObject();
+ }
+
+ /// <summary>
+ /// Returns the schema's custom property value given the property name
+ /// </summary>
+ /// <param name="key">custom property name</param>
+ /// <returns>custom property value</returns>
+ public string GetProperty(string key)
+ {
+ if (null == this.Props) return null;
+ string v;
+ return (this.Props.TryGetValue(key, out v)) ? v : null;
+ }
+
+ /// <summary>
+ /// Hash code function
+ /// </summary>
+ /// <returns></returns>
+ public override int GetHashCode()
+ {
+ return Tag.GetHashCode() + getHashCode(Props);
+ }
+
+ /// <summary>
+ /// Returns true if and only if data written using writerSchema can be read using the current schema
+ /// according to the Avro resolution rules.
+ /// </summary>
+ /// <param name="writerSchema">The writer's schema to match against.</param>
+ /// <returns>True if and only if the current schema matches the writer's.</returns>
+ public virtual bool CanRead(Schema writerSchema) { return Tag == writerSchema.Tag; }
+
+ /// <summary>
+ /// Compares two objects, null is equal to null
+ /// </summary>
+ /// <param name="o1">first object</param>
+ /// <param name="o2">second object</param>
+ /// <returns>true if two objects are equal, false otherwise</returns>
+ protected static bool areEqual(object o1, object o2)
+ {
+ return o1 == null ? o2 == null : o1.Equals(o2);
+ }
+
+ /// <summary>
+ /// Hash code helper function
+ /// </summary>
+ /// <param name="obj"></param>
+ /// <returns></returns>
+ protected static int getHashCode(object obj)
+ {
+ return obj == null ? 0 : obj.GetHashCode();
+ }
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Schema/SchemaName.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Schema/SchemaName.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Schema/SchemaName.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Schema/SchemaName.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,222 @@
+/**
+ * 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;
+
+namespace Avro
+{
+ /// <summary>
+ /// Class to store schema name, namespace and enclosing namespace
+ /// </summary>
+ public class SchemaName
+ {
+ /// <summary>
+ /// Name of the schema
+ /// </summary>
+ public String Name { get; private set; }
+
+ /// <summary>
+ /// Namespace specified within the schema
+ /// </summary>
+ public String Space { get; private set; }
+
+ /// <summary>
+ /// Namespace from the most tightly enclosing schema
+ /// </summary>
+ public String EncSpace { get; private set; }
+
+ /// <summary>
+ /// Namespace.Name of the schema
+ /// </summary>
+ public String Fullname { get { return string.IsNullOrEmpty(Namespace) ? this.Name : Namespace + "." + this.Name; } }
+
+ /// <summary>
+ /// Namespace of the schema
+ /// </summary>
+ public String Namespace { get { return string.IsNullOrEmpty(this.Space) ? this.EncSpace : this.Space; } }
+
+ /// <summary>
+ /// Constructor for SchemaName
+ /// </summary>
+ /// <param name="name">name of the schema</param>
+ /// <param name="space">namespace of the schema</param>
+ /// <param name="encspace">enclosing namespace of the schema</param>
+ public SchemaName(String name, String space, String encspace)
+ {
+ if (name == null)
+ { // anonymous
+ this.Name = this.Space = null;
+ this.EncSpace = encspace; // need to save enclosing namespace for anonymous types, so named types within the anonymous type can be resolved
+ }
+ else if (!name.Contains("."))
+ { // unqualified name
+ this.Space = space; // use default space
+ this.Name = name;
+ this.EncSpace = encspace;
+ }
+ else
+ {
+ string[] parts = name.Split('.');
+ this.Space = string.Join(".", parts, 0, parts.Length - 1);
+ this.Name = parts[parts.Length - 1];
+ this.EncSpace = encspace;
+ }
+ }
+
+ /// <summary>
+ /// Returns the full name of the schema
+ /// </summary>
+ /// <returns></returns>
+ public override string ToString()
+ {
+ return Fullname;
+ }
+
+ /// <summary>
+ /// Writes the schema name 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 schema</param>
+ internal void WriteJson(Newtonsoft.Json.JsonTextWriter writer, SchemaNames names, string encspace)
+ {
+ if (null != this.Name) // write only if not anonymous
+ {
+ JsonHelper.writeIfNotNullOrEmpty(writer, "name", this.Name);
+ if (!String.IsNullOrEmpty(this.Space))
+ JsonHelper.writeIfNotNullOrEmpty(writer, "namespace", this.Space);
+ else if (!String.IsNullOrEmpty(this.EncSpace)) // need to put enclosing name space for code generated classes
+ JsonHelper.writeIfNotNullOrEmpty(writer, "namespace", this.EncSpace);
+ }
+ }
+
+ /// <summary>
+ /// Compares two schema names
+ /// </summary>
+ /// <param name="obj">SchameName object to compare against this object</param>
+ /// <returns>true or false</returns>
+ public override bool Equals(Object obj)
+ {
+ if (obj == this) return true;
+ if (obj != null && obj is SchemaName)
+ {
+ SchemaName that = (SchemaName)obj;
+ return areEqual(that.Name, Name) && areEqual(that.Namespace, Namespace);
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Compares two objects
+ /// </summary>
+ /// <param name="obj1">first object</param>
+ /// <param name="obj2">second object</param>
+ /// <returns>true or false</returns>
+ private static bool areEqual(object obj1, object obj2)
+ {
+ return obj1 == null ? obj2 == null : obj1.Equals(obj2);
+ }
+
+ public override int GetHashCode()
+ {
+ return string.IsNullOrEmpty(Fullname) ? 0 : 29 * Fullname.GetHashCode();
+ }
+ }
+
+ /// <summary>
+ /// A class that contains a list of named schemas. This is used when reading or writing a schema/protocol.
+ /// This prevents reading and writing of duplicate schema definitions within a protocol or schema file
+ /// </summary>
+ public class SchemaNames
+ {
+ /// <summary>
+ /// Map of schema name and named schema objects
+ /// </summary>
+ public IDictionary<SchemaName, NamedSchema> Names { get; private set; }
+
+ /// <summary>
+ /// Constructor
+ /// </summary>
+ public SchemaNames()
+ {
+ Names = new Dictionary<SchemaName, NamedSchema>();
+ }
+
+ /// <summary>
+ /// Checks if given name is in the map
+ /// </summary>
+ /// <param name="name">schema name</param>
+ /// <returns>true or false</returns>
+ public bool Contains(SchemaName name)
+ {
+ if (Names.ContainsKey(name))
+ return true;
+ return false;
+ }
+
+ /// <summary>
+ /// Adds a schema name to the map if it doesn't exist yet
+ /// </summary>
+ /// <param name="name">schema name</param>
+ /// <param name="schema">schema object</param>
+ /// <returns>true if schema was added to the list, false if schema is already in the list</returns>
+ public bool Add(SchemaName name, NamedSchema schema)
+ {
+ if (Names.ContainsKey(name))
+ return false;
+
+ Names.Add(name, schema);
+ return true;
+ }
+
+ /// <summary>
+ /// Adds a named schema to the list
+ /// </summary>
+ /// <param name="schema">schema object</param>
+ /// <returns>true if schema was added to the list, false if schema is already in the list</returns>
+ public bool Add(NamedSchema schema)
+ {
+ SchemaName name = schema.SchemaName;
+ return Add(name, schema);
+ }
+
+ /// <summary>
+ /// Tries to get the value for the given name fields
+ /// </summary>
+ /// <param name="name">name of the schema</param>
+ /// <param name="space">namespace of the schema</param>
+ /// <param name="encspace">enclosing namespace of the schema</param>
+ /// <param name="schema">schema object found</param>
+ /// <returns>true if name is found in the map, false otherwise</returns>
+ public bool TryGetValue(string name, string space, string encspace, out NamedSchema schema)
+ {
+ SchemaName schemaname = new SchemaName(name, space, encspace);
+ return Names.TryGetValue(schemaname, out schema);
+ }
+
+ /// <summary>
+ /// Returns the enumerator for the map
+ /// </summary>
+ /// <returns></returns>
+ public IEnumerator<KeyValuePair<SchemaName, NamedSchema>> GetEnumerator()
+ {
+ return Names.GetEnumerator();
+ }
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Schema/SchemaParseException.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Schema/SchemaParseException.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Schema/SchemaParseException.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Schema/SchemaParseException.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,31 @@
+/**
+ * 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;
+
+namespace Avro
+{
+ public class SchemaParseException:AvroException
+ {
+ public SchemaParseException(string s)
+ : base(s)
+ {
+ }
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Schema/UnionSchema.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Schema/UnionSchema.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Schema/UnionSchema.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Schema/UnionSchema.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,164 @@
+/**
+ * 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;
+using Newtonsoft.Json;
+
+namespace Avro
+{
+ /// <summary>
+ /// Class for union schemas
+ /// </summary>
+ public class UnionSchema : UnnamedSchema
+ {
+ /// <summary>
+ /// List of schemas in the union
+ /// </summary>
+ public IList<Schema> Schemas { get; private set; }
+
+ /// <summary>
+ /// Count of schemas in the union
+ /// </summary>
+ public int Count { get { return Schemas.Count; } }
+
+ /// <summary>
+ /// Static function to return instance of the union schema
+ /// </summary>
+ /// <param name="jarr">JSON object for the union schema</param>
+ /// <param name="names">list of named schemas already read</param>
+ /// <param name="encspace">enclosing namespace of the schema</param>
+ /// <returns>new UnionSchema object</returns>
+ internal static UnionSchema NewInstance(JArray jarr, PropertyMap props, SchemaNames names, string encspace)
+ {
+ List<Schema> schemas = new List<Schema>();
+ IDictionary<string, string> uniqueSchemas = new Dictionary<string, string>();
+
+ foreach (JToken jvalue in jarr)
+ {
+ Schema unionType = Schema.ParseJson(jvalue, names, encspace);
+ if (null == unionType)
+ throw new SchemaParseException("Invalid JSON in union" + jvalue.ToString());
+
+ string name = unionType.Name;
+ if (uniqueSchemas.ContainsKey(name))
+ throw new SchemaParseException("Duplicate type in union: " + name);
+
+ uniqueSchemas.Add(name, name);
+ schemas.Add(unionType);
+ }
+
+ return new UnionSchema(schemas, props);
+ }
+
+ /// <summary>
+ /// Contructor for union schema
+ /// </summary>
+ /// <param name="schemas"></param>
+ private UnionSchema(List<Schema> schemas, PropertyMap props) : base(Type.Union, props)
+ {
+ if (schemas.Count == 0)
+ throw new ArgumentNullException("schemas");
+ this.Schemas = schemas;
+ }
+
+ /// <summary>
+ /// Returns the schema at the given branch.
+ /// </summary>
+ /// <param name="index">Index to the branch, starting with 0.</param>
+ /// <returns>The branch corresponding to the given index.</returns>
+ public Schema this[int index]
+ {
+ get
+ {
+ return Schemas[index];
+ }
+ }
+
+ /// <summary>
+ /// Writes union 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 schema</param>
+ protected internal override void WriteJson(Newtonsoft.Json.JsonTextWriter writer, SchemaNames names, string encspace)
+ {
+ writer.WriteStartArray();
+ foreach (Schema schema in this.Schemas)
+ schema.WriteJson(writer, names, encspace);
+ writer.WriteEndArray();
+ }
+
+ /// <summary>
+ /// Returns the index of a branch that can read the data written by the given schema s.
+ /// </summary>
+ /// <param name="s">The schema to match the branches against.</param>
+ /// <returns>The index of the matching branch. If non matches a -1 is returned.</returns>
+ public int MatchingBranch(Schema s)
+ {
+ if (s is UnionSchema) throw new AvroException("Cannot find a match against union schema");
+ // Try exact match.
+ //for (int i = 0; i < Count; i++) if (Schemas[i].Equals(s)) return i; // removed this for performance's sake
+ for (int i = 0; i < Count; i++) if (Schemas[i].CanRead(s)) return i;
+ return -1;
+ }
+
+ /// <summary>
+ /// Checks if this schema can read data written by the given schema. Used for decoding data.
+ /// </summary>
+ /// <param name="writerSchema">writer schema</param>
+ /// <returns>true if this and writer schema are compatible based on the AVRO specification, false otherwise</returns>
+ public override bool CanRead(Schema writerSchema)
+ {
+ return writerSchema.Tag == Schema.Type.Union || MatchingBranch(writerSchema) >= 0;
+ }
+
+ /// <summary>
+ /// Compares two union schema objects
+ /// </summary>
+ /// <param name="obj">union schema object to compare against this schema</param>
+ /// <returns>true if objects are equal, false otherwise</returns>
+ public override bool Equals(object obj)
+ {
+ if (obj == this) return true;
+ if (obj != null && obj is UnionSchema)
+ {
+ UnionSchema that = obj as UnionSchema;
+ if (that.Count == Count)
+ {
+ for (int i = 0; i < Count; i++) if (!that[i].Equals(this[i])) return false;
+ return areEqual(that.Props, this.Props);
+ }
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Hash code function
+ /// </summary>
+ /// <returns></returns>
+ public override int GetHashCode()
+ {
+ int result = 53;
+ foreach (Schema schema in Schemas) result += 89 * schema.GetHashCode();
+ result += getHashCode(Props);
+ return result;
+ }
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Schema/UnnamedSchema.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Schema/UnnamedSchema.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Schema/UnnamedSchema.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Schema/UnnamedSchema.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,39 @@
+/**
+ * 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.Linq;
+using System.Text;
+
+namespace Avro
+{
+ /// <summary>
+ /// Base class for all unnamed schemas
+ /// </summary>
+ public abstract class UnnamedSchema : Schema
+ {
+ protected UnnamedSchema(Type type, PropertyMap props) : base(type, props)
+ {
+ }
+
+ public override string Name
+ {
+ get { return Tag.ToString().ToLower(); }
+ }
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Specific/ObjectCreator.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Specific/ObjectCreator.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Specific/ObjectCreator.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Specific/ObjectCreator.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,165 @@
+/**
+ * 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 System.Reflection;
+using System.Reflection.Emit;
+
+namespace Avro.Specific
+{
+
+ public sealed class ObjectCreator
+ {
+ private static readonly ObjectCreator instance = new ObjectCreator();
+ public static ObjectCreator Instance { get { return instance; } }
+
+ /// <summary>
+ /// Static generic dictionary type used for creating new dictionary instances
+ /// </summary>
+ private Type GenericMapType = typeof(Dictionary<,>);
+
+ /// <summary>
+ /// Static generic list type used for creating new array instances
+ /// </summary>
+ private Type GenericListType = typeof(List<>);
+
+ private readonly Assembly execAssembly;
+ private readonly Assembly entryAssembly;
+ private readonly bool diffAssembly;
+ private readonly Type[] margs;
+ private readonly Type[] largs;
+
+ private delegate object CtorDelegate();
+ private Type ctorType = typeof(CtorDelegate);
+ Dictionary<NameCtorKey, CtorDelegate> ctors;
+
+ private ObjectCreator()
+ {
+ execAssembly = System.Reflection.Assembly.GetExecutingAssembly();
+ entryAssembly = System.Reflection.Assembly.GetEntryAssembly();
+ if (entryAssembly != null && execAssembly != entryAssembly) // entryAssembly returns null when running from NUnit
+ diffAssembly = true;
+
+ GenericMapType = typeof(Dictionary<,>);
+ GenericListType = typeof(List<>);
+ margs = new Type[2] { typeof(string), null };
+ largs = new Type[1] { null };
+
+ ctors = new Dictionary<NameCtorKey, CtorDelegate>();
+ }
+
+ public struct NameCtorKey : IEquatable<NameCtorKey>
+ {
+ public string name { get; private set; }
+ public Schema.Type type { get; private set; }
+ public NameCtorKey(string value1, Schema.Type value2)
+ : this()
+ {
+ name = value1;
+ type = value2;
+ }
+ public bool Equals(NameCtorKey other)
+ {
+ return Equals(other.name, name) && other.type == type;
+ }
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj))
+ return false;
+ if (obj.GetType() != typeof(NameCtorKey))
+ return false;
+ return Equals((NameCtorKey)obj);
+ }
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ return ((name != null ? name.GetHashCode() : 0) * 397) ^ type.GetHashCode();
+ }
+ }
+ public static bool operator ==(NameCtorKey left, NameCtorKey right)
+ {
+ return left.Equals(right);
+ }
+ public static bool operator !=(NameCtorKey left, NameCtorKey right)
+ {
+ return !left.Equals(right);
+ }
+ }
+
+ /// <summary>
+ /// Creates new instance of the given type
+ /// </summary>
+ /// <param name="name">fully qualified name of the type</param>
+ /// <param name="schemaType">type of schema</param>
+ /// <returns>new object of the given type</returns>
+ public object New(string name, Schema.Type schemaType)
+ {
+ NameCtorKey key = new NameCtorKey(name, schemaType);
+ CtorDelegate ctor;
+ if (!ctors.TryGetValue(key, out ctor))
+ {
+ Type type;
+ if (diffAssembly)
+ {
+ // entry assembly different from current assembly, try entry assembly first
+ type = entryAssembly.GetType(name);
+ if (type == null) // now try current assembly and mscorlib
+ type = Type.GetType(name);
+ }
+ else
+ type = Type.GetType(name);
+
+ if (type == null) // type is still not found, need to loop through all loaded assemblies
+ {
+ Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
+ foreach (Assembly assembly in assemblies)
+ {
+ type = assembly.GetType(name);
+ if (type != null)
+ break;
+ }
+ }
+ if (type == null)
+ throw new AvroException("Unable to find type " + name + " in all loaded assemblies");
+
+ if (schemaType == Schema.Type.Map)
+ {
+ margs[1] = type;
+ type = GenericMapType.MakeGenericType(margs);
+ }
+ else if (schemaType == Schema.Type.Array)
+ {
+ largs[0] = type;
+ type = GenericListType.MakeGenericType(largs);
+ }
+
+ DynamicMethod dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" + name, typeof(object), null, type, true);
+ ILGenerator ilGen = dynMethod.GetILGenerator();
+ ilGen.Emit(OpCodes.Nop);
+ ilGen.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes));
+ ilGen.Emit(OpCodes.Ret);
+
+ ctor = (CtorDelegate)dynMethod.CreateDelegate(ctorType);
+ ctors.Add(key, ctor);
+ }
+ return ctor();
+ }
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Specific/SpecificFixed.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Specific/SpecificFixed.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Specific/SpecificFixed.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Specific/SpecificFixed.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,34 @@
+/**
+ * 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.Linq;
+using System.Text;
+using Avro.Generic;
+
+namespace Avro.Specific
+{
+ /// <summary>
+ /// Base class for all generated classes
+ /// </summary>
+ public abstract class SpecificFixed : GenericFixed
+ {
+ public SpecificFixed(uint size) : base(size) { }
+ public abstract new Schema Schema { get; }
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Specific/SpecificReader.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Specific/SpecificReader.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Specific/SpecificReader.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Specific/SpecificReader.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,272 @@
+/**
+ * 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.Linq;
+using System.Reflection;
+using System.IO;
+using Avro;
+using Avro.IO;
+using Avro.Generic;
+
+namespace Avro.Specific
+{
+ /// <summary>
+ /// Reader wrapper class for reading data and storing into specific classes
+ /// </summary>
+ /// <typeparam name="T">Specific class type</typeparam>
+ public class SpecificReader<T> : DatumReader<T>
+ {
+ /// <summary>
+ /// Reader class for reading data and storing into specific classes
+ /// </summary>
+ private readonly SpecificDefaultReader reader;
+
+ /// <summary>
+ /// Constructs a generic reader for the given schemas using the DefaultReader. If the
+ /// reader's and writer's schemas are different this class performs the resolution.
+ /// </summary>
+ /// <param name="writerSchema">The schema used while generating the data</param>
+ /// <param name="readerSchema">The schema desired by the reader</param>
+ public SpecificReader(Schema writerSchema, Schema readerSchema)
+ {
+ reader = new SpecificDefaultReader(writerSchema, readerSchema);
+ }
+
+ /// <summary>
+ /// Schema for the writer class
+ /// </summary>
+ public Schema WriterSchema { get { return reader.WriterSchema; } }
+
+ /// <summary>
+ /// Schema for the reader class
+ /// </summary>
+ public Schema ReaderSchema { get { return reader.ReaderSchema; } }
+
+ /// <summary>
+ /// Generic read function
+ /// </summary>
+ /// <param name="reuse">object to store data read</param>
+ /// <param name="dec">decorder to use for reading data</param>
+ /// <returns></returns>
+ public T Read(T reuse, Decoder dec)
+ {
+ return reader.Read(reuse, dec);
+ }
+ }
+
+ /// <summary>
+ /// Reader class for reading data and storing into specific classes
+ /// </summary>
+ public class SpecificDefaultReader : DefaultReader
+ {
+ /// <summary>
+ /// Static dictionary of type names and its corresponding assembly type.
+ /// This is used to prevent multiple reflection for the same type name.
+ /// </summary>
+ private static IDictionary<string, Type> TypeName = new Dictionary<string, Type>();
+
+ /// <summary>
+ /// Constructor
+ /// </summary>
+ /// <param name="writerSchema">schema of the object that wrote the data</param>
+ /// <param name="readerSchema">schema of the object that will store the data</param>
+ public SpecificDefaultReader(Schema writerSchema, Schema readerSchema) : base(writerSchema,readerSchema)
+ {
+ }
+
+ /// <summary>
+ /// Deserializes a record from the stream.
+ /// </summary>
+ /// <param name="reuse">If not null, a record object that could be reused for returning the result</param>
+ /// <param name="writerSchema">The writer's RecordSchema</param>
+ /// <param name="readerSchema">The reader's schema, must be RecordSchema too.</param>
+ /// <param name="dec">The decoder for deserialization</param>
+ /// <returns>The record object just read</returns>
+ protected override object ReadRecord(object reuse, RecordSchema writerSchema, Schema readerSchema, Decoder dec)
+ {
+ RecordSchema rs = (RecordSchema)readerSchema;
+
+ SpecificRecord rec = (reuse != null ? reuse : ObjectCreator.Instance.New(rs.Fullname, Schema.Type.Record)) as SpecificRecord;
+ object obj;
+ foreach (Field wf in writerSchema)
+ {
+ try
+ {
+ Field rf;
+ if (rs.TryGetField(wf.Name, out rf))
+ {
+ obj = rec.Get(rf.Pos);
+ rec.Put(rf.Pos, Read(obj, wf.Schema, rf.Schema, dec));
+ }
+ else
+ Skip(wf.Schema, dec);
+ }
+ catch (Exception ex)
+ {
+ throw new AvroException(ex.Message + " in field " + wf.Name);
+ }
+ }
+
+ var defaultStream = new MemoryStream();
+ var defaultEncoder = new BinaryEncoder(defaultStream);
+ var defaultDecoder = new BinaryDecoder(defaultStream);
+ foreach (Field rf in rs)
+ {
+ if (writerSchema.Contains(rf.Name)) continue;
+
+ defaultStream.Position = 0; // reset for writing
+ Resolver.EncodeDefaultValue(defaultEncoder, rf.Schema, rf.DefaultValue);
+ defaultStream.Flush();
+ defaultStream.Position = 0; // reset for reading
+
+ obj = rec.Get(rf.Pos);
+ rec.Put(rf.Pos, Read(obj, rf.Schema, rf.Schema, defaultDecoder));
+ }
+
+ return rec;
+ }
+
+ /// <summary>
+ /// Deserializes a fixed object and returns the object. The default implementation uses CreateFixed()
+ /// and GetFixedBuffer() and returns what CreateFixed() returned.
+ /// </summary>
+ /// <param name="reuse">If appropriate, uses this object instead of creating a new one.</param>
+ /// <param name="writerSchema">The FixedSchema the writer used during serialization.</param>
+ /// <param name="readerSchema">The schema that the readr uses. Must be a FixedSchema with the same
+ /// size as the writerSchema.</param>
+ /// <param name="d">The decoder for deserialization.</param>
+ /// <returns>The deserilized object.</returns>
+ protected override object ReadFixed(object reuse, FixedSchema writerSchema, Schema readerSchema, Decoder d)
+ {
+ FixedSchema rs = readerSchema as FixedSchema;
+ if (rs.Size != writerSchema.Size)
+ {
+ throw new AvroException("Size mismatch between reader and writer fixed schemas. Writer: " + writerSchema +
+ ", reader: " + readerSchema);
+ }
+
+ SpecificFixed fixedrec = (reuse != null ? reuse : ObjectCreator.Instance.New(rs.Fullname, Schema.Type.Fixed)) as SpecificFixed;
+ d.ReadFixed(fixedrec.Value);
+ return fixedrec;
+ }
+
+ /// <summary>
+ /// Reads an enum from the given decoder
+ /// </summary>
+ /// <param name="reuse">object to store data read</param>
+ /// <param name="writerSchema">schema of the object that wrote the data</param>
+ /// <param name="readerSchema">schema of the object that will store the data</param>
+ /// <param name="dec">decoder object that contains the data to be read</param>
+ /// <returns>enum value</returns>
+ protected override object ReadEnum(object reuse, EnumSchema writerSchema, Schema readerSchema, Decoder dec)
+ {
+ return dec.ReadEnum();
+ }
+
+ /// <summary>
+ /// Reads an array from the given decoder
+ /// </summary>
+ /// <param name="reuse">object to store data read</param>
+ /// <param name="writerSchema">schema of the object that wrote the data</param>
+ /// <param name="readerSchema">schema of the object that will store the data</param>
+ /// <param name="dec">decoder object that contains the data to be read</param>
+ /// <returns>array</returns>
+ protected override object ReadArray(object reuse, ArraySchema writerSchema, Schema readerSchema, Decoder dec)
+ {
+ ArraySchema rs = readerSchema as ArraySchema;
+ System.Collections.IList array;
+ if (reuse != null)
+ {
+ array = reuse as System.Collections.IList;
+ if (array == null)
+ throw new AvroException("array object does not implement non-generic IList");
+
+ array.Clear();
+ }
+ else
+ array = ObjectCreator.Instance.New(getTargetType(readerSchema), Schema.Type.Array) as System.Collections.IList;
+
+ int i = 0;
+ for (int n = (int)dec.ReadArrayStart(); n != 0; n = (int)dec.ReadArrayNext())
+ {
+ for (int j = 0; j < n; j++, i++)
+ array.Add(Read(null, writerSchema.ItemSchema, rs.ItemSchema, dec));
+ }
+ return array;
+ }
+
+ /// <summary>
+ /// Deserialized an avro map. The default implemenation creats a new map using CreateMap() and then
+ /// adds elements to the map using AddMapEntry().
+ /// </summary>
+ /// <param name="reuse">If appropriate, use this instead of creating a new map object.</param>
+ /// <param name="writerSchema">The schema the writer used to write the map.</param>
+ /// <param name="readerSchema">The schema the reader is using.</param>
+ /// <param name="d">The decoder for serialization.</param>
+ /// <returns>The deserialized map object.</returns>
+ protected override object ReadMap(object reuse, MapSchema writerSchema, Schema readerSchema, Decoder d)
+ {
+ MapSchema rs = readerSchema as MapSchema;
+ System.Collections.IDictionary map;
+ if (reuse != null)
+ {
+ map = reuse as System.Collections.IDictionary;
+ if (map == null)
+ throw new AvroException("map object does not implement non-generic IList");
+
+ map.Clear();
+ }
+ else
+ map = ObjectCreator.Instance.New(getTargetType(readerSchema), Schema.Type.Map) as System.Collections.IDictionary;
+
+ for (int n = (int)d.ReadMapStart(); n != 0; n = (int)d.ReadMapNext())
+ {
+ for (int j = 0; j < n; j++)
+ {
+ string k = d.ReadString();
+ map[k] = Read(null, writerSchema.ValueSchema, rs.ValueSchema, d); // always create new map item
+ }
+ }
+ return map;
+ }
+
+ /// <summary>
+ /// Gets the target type name in the given schema
+ /// </summary>
+ /// <param name="schema">schema containing the type to be determined</param>
+ /// <param name="nullible">used for union schema</param>
+ /// <returns></returns>
+ private string getTargetType(Schema schema)
+ {
+ bool nEnum = false;
+ string type = Avro.CodeGen.getType(schema, false, ref nEnum);
+ if (schema.Tag == Schema.Type.Array)
+ {
+ type = type.Remove(0, 6); // remove IList<
+ type = type.Remove(type.Length - 1); // remove >
+ }
+ else if (schema.Tag == Schema.Type.Map)
+ {
+ type = type.Remove(0, 19); // remove IDictionary<string,
+ type = type.Remove(type.Length - 1); // remove >
+ }
+ return type;
+ }
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Specific/SpecificRecord.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Specific/SpecificRecord.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Specific/SpecificRecord.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Specific/SpecificRecord.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,34 @@
+/**
+ * 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.Linq;
+using System.Text;
+
+namespace Avro.Specific
+{
+ /// <summary>
+ /// Base class for generated classes
+ /// </summary>
+ public abstract class SpecificRecord
+ {
+ public abstract Schema Schema { get; }
+ public abstract object Get(int fieldPos);
+ public abstract void Put(int fieldPos, object fieldValue);
+ }
+}