You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2015/11/11 10:14:59 UTC
[17/25] ignite git commit: IGNITE-1845: Adopted new binary API in
.Net.
http://git-wip-us.apache.org/repos/asf/ignite/blob/894057e5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
new file mode 100644
index 0000000..1dec7ba
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
@@ -0,0 +1,940 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Binary
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.IO;
+ using System.Runtime.Serialization;
+ using Apache.Ignite.Core.Binary;
+ using Apache.Ignite.Core.Impl.Binary.IO;
+ using Apache.Ignite.Core.Impl.Binary.Structure;
+ using Apache.Ignite.Core.Impl.Common;
+
+ /// <summary>
+ /// Binary reader implementation.
+ /// </summary>
+ internal class BinaryReader : IBinaryReader, IBinaryRawReader
+ {
+ /** Marshaller. */
+ private readonly Marshaller _marsh;
+
+ /** Type descriptors. */
+ private readonly IDictionary<long, IBinaryTypeDescriptor> _descs;
+
+ /** Parent builder. */
+ private readonly BinaryObjectBuilder _builder;
+
+ /** Handles. */
+ private BinaryReaderHandleDictionary _hnds;
+
+ /** Current position. */
+ private int _curPos;
+
+ /** Current raw flag. */
+ private bool _curRaw;
+
+ /** Detach flag. */
+ private bool _detach;
+
+ /** Binary read mode. */
+ private BinaryMode _mode;
+
+ /** Current type structure tracker. */
+ private BinaryStructureTracker _curStruct;
+
+ /** Current schema. */
+ private int[] _curSchema;
+
+ /** Current schema with positions. */
+ private Dictionary<int, int> _curSchemaMap;
+
+ /** Current header. */
+ private BinaryObjectHeader _curHdr;
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="marsh">Marshaller.</param>
+ /// <param name="descs">Descriptors.</param>
+ /// <param name="stream">Input stream.</param>
+ /// <param name="mode">The mode.</param>
+ /// <param name="builder">Builder.</param>
+ public BinaryReader
+ (Marshaller marsh,
+ IDictionary<long, IBinaryTypeDescriptor> descs,
+ IBinaryStream stream,
+ BinaryMode mode,
+ BinaryObjectBuilder builder)
+ {
+ _marsh = marsh;
+ _descs = descs;
+ _mode = mode;
+ _builder = builder;
+
+ Stream = stream;
+ }
+
+ /// <summary>
+ /// Gets the marshaller.
+ /// </summary>
+ public Marshaller Marshaller
+ {
+ get { return _marsh; }
+ }
+
+ /** <inheritdoc /> */
+ public IBinaryRawReader GetRawReader()
+ {
+ MarkRaw();
+
+ return this;
+ }
+
+ /** <inheritdoc /> */
+ public bool ReadBoolean(string fieldName)
+ {
+ return ReadField(fieldName, r => r.ReadBoolean(), BinaryUtils.TypeBool);
+ }
+
+ /** <inheritdoc /> */
+ public bool ReadBoolean()
+ {
+ return Stream.ReadBool();
+ }
+
+ /** <inheritdoc /> */
+ public bool[] ReadBooleanArray(string fieldName)
+ {
+ return ReadField(fieldName, BinaryUtils.ReadBooleanArray, BinaryUtils.TypeArrayBool);
+ }
+
+ /** <inheritdoc /> */
+ public bool[] ReadBooleanArray()
+ {
+ return Read(BinaryUtils.ReadBooleanArray, BinaryUtils.TypeArrayBool);
+ }
+
+ /** <inheritdoc /> */
+ public byte ReadByte(string fieldName)
+ {
+ return ReadField(fieldName, ReadByte, BinaryUtils.TypeByte);
+ }
+
+ /** <inheritdoc /> */
+ public byte ReadByte()
+ {
+ return Stream.ReadByte();
+ }
+
+ /** <inheritdoc /> */
+ public byte[] ReadByteArray(string fieldName)
+ {
+ return ReadField(fieldName, BinaryUtils.ReadByteArray, BinaryUtils.TypeArrayByte);
+ }
+
+ /** <inheritdoc /> */
+ public byte[] ReadByteArray()
+ {
+ return Read(BinaryUtils.ReadByteArray, BinaryUtils.TypeArrayByte);
+ }
+
+ /** <inheritdoc /> */
+ public short ReadShort(string fieldName)
+ {
+ return ReadField(fieldName, ReadShort, BinaryUtils.TypeShort);
+ }
+
+ /** <inheritdoc /> */
+ public short ReadShort()
+ {
+ return Stream.ReadShort();
+ }
+
+ /** <inheritdoc /> */
+ public short[] ReadShortArray(string fieldName)
+ {
+ return ReadField(fieldName, BinaryUtils.ReadShortArray, BinaryUtils.TypeArrayShort);
+ }
+
+ /** <inheritdoc /> */
+ public short[] ReadShortArray()
+ {
+ return Read(BinaryUtils.ReadShortArray, BinaryUtils.TypeArrayShort);
+ }
+
+ /** <inheritdoc /> */
+ public char ReadChar(string fieldName)
+ {
+ return ReadField(fieldName, ReadChar, BinaryUtils.TypeChar);
+ }
+
+ /** <inheritdoc /> */
+ public char ReadChar()
+ {
+ return Stream.ReadChar();
+ }
+
+ /** <inheritdoc /> */
+ public char[] ReadCharArray(string fieldName)
+ {
+ return ReadField(fieldName, BinaryUtils.ReadCharArray, BinaryUtils.TypeArrayChar);
+ }
+
+ /** <inheritdoc /> */
+ public char[] ReadCharArray()
+ {
+ return Read(BinaryUtils.ReadCharArray, BinaryUtils.TypeArrayChar);
+ }
+
+ /** <inheritdoc /> */
+ public int ReadInt(string fieldName)
+ {
+ return ReadField(fieldName, ReadInt, BinaryUtils.TypeInt);
+ }
+
+ /** <inheritdoc /> */
+ public int ReadInt()
+ {
+ return Stream.ReadInt();
+ }
+
+ /** <inheritdoc /> */
+ public int[] ReadIntArray(string fieldName)
+ {
+ return ReadField(fieldName, BinaryUtils.ReadIntArray, BinaryUtils.TypeArrayInt);
+ }
+
+ /** <inheritdoc /> */
+ public int[] ReadIntArray()
+ {
+ return Read(BinaryUtils.ReadIntArray, BinaryUtils.TypeArrayInt);
+ }
+
+ /** <inheritdoc /> */
+ public long ReadLong(string fieldName)
+ {
+ return ReadField(fieldName, ReadLong, BinaryUtils.TypeLong);
+ }
+
+ /** <inheritdoc /> */
+ public long ReadLong()
+ {
+ return Stream.ReadLong();
+ }
+
+ /** <inheritdoc /> */
+ public long[] ReadLongArray(string fieldName)
+ {
+ return ReadField(fieldName, BinaryUtils.ReadLongArray, BinaryUtils.TypeArrayLong);
+ }
+
+ /** <inheritdoc /> */
+ public long[] ReadLongArray()
+ {
+ return Read(BinaryUtils.ReadLongArray, BinaryUtils.TypeArrayLong);
+ }
+
+ /** <inheritdoc /> */
+ public float ReadFloat(string fieldName)
+ {
+ return ReadField(fieldName, ReadFloat, BinaryUtils.TypeFloat);
+ }
+
+ /** <inheritdoc /> */
+ public float ReadFloat()
+ {
+ return Stream.ReadFloat();
+ }
+
+ /** <inheritdoc /> */
+ public float[] ReadFloatArray(string fieldName)
+ {
+ return ReadField(fieldName, BinaryUtils.ReadFloatArray, BinaryUtils.TypeArrayFloat);
+ }
+
+ /** <inheritdoc /> */
+ public float[] ReadFloatArray()
+ {
+ return Read(BinaryUtils.ReadFloatArray, BinaryUtils.TypeArrayFloat);
+ }
+
+ /** <inheritdoc /> */
+ public double ReadDouble(string fieldName)
+ {
+ return ReadField(fieldName, ReadDouble, BinaryUtils.TypeDouble);
+ }
+
+ /** <inheritdoc /> */
+ public double ReadDouble()
+ {
+ return Stream.ReadDouble();
+ }
+
+ /** <inheritdoc /> */
+ public double[] ReadDoubleArray(string fieldName)
+ {
+ return ReadField(fieldName, BinaryUtils.ReadDoubleArray, BinaryUtils.TypeArrayDouble);
+ }
+
+ /** <inheritdoc /> */
+ public double[] ReadDoubleArray()
+ {
+ return Read(BinaryUtils.ReadDoubleArray, BinaryUtils.TypeArrayDouble);
+ }
+
+ /** <inheritdoc /> */
+ public decimal? ReadDecimal(string fieldName)
+ {
+ return ReadField(fieldName, BinaryUtils.ReadDecimal, BinaryUtils.TypeDecimal);
+ }
+
+ /** <inheritdoc /> */
+ public decimal? ReadDecimal()
+ {
+ return Read(BinaryUtils.ReadDecimal, BinaryUtils.TypeDecimal);
+ }
+
+ /** <inheritdoc /> */
+ public decimal?[] ReadDecimalArray(string fieldName)
+ {
+ return ReadField(fieldName, BinaryUtils.ReadDecimalArray, BinaryUtils.TypeArrayDecimal);
+ }
+
+ /** <inheritdoc /> */
+ public decimal?[] ReadDecimalArray()
+ {
+ return Read(BinaryUtils.ReadDecimalArray, BinaryUtils.TypeArrayDecimal);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime? ReadTimestamp(string fieldName)
+ {
+ return ReadField(fieldName, BinaryUtils.ReadTimestamp, BinaryUtils.TypeTimestamp);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime? ReadTimestamp()
+ {
+ return Read(BinaryUtils.ReadTimestamp, BinaryUtils.TypeTimestamp);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime?[] ReadTimestampArray(string fieldName)
+ {
+ return ReadField(fieldName, BinaryUtils.ReadTimestampArray, BinaryUtils.TypeArrayTimestamp);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime?[] ReadTimestampArray()
+ {
+ return Read(BinaryUtils.ReadTimestampArray, BinaryUtils.TypeArrayTimestamp);
+ }
+
+ /** <inheritdoc /> */
+ public string ReadString(string fieldName)
+ {
+ return ReadField(fieldName, BinaryUtils.ReadString, BinaryUtils.TypeString);
+ }
+
+ /** <inheritdoc /> */
+ public string ReadString()
+ {
+ return Read(BinaryUtils.ReadString, BinaryUtils.TypeString);
+ }
+
+ /** <inheritdoc /> */
+ public string[] ReadStringArray(string fieldName)
+ {
+ return ReadField(fieldName, r => BinaryUtils.ReadArray<string>(r, false), BinaryUtils.TypeArrayString);
+ }
+
+ /** <inheritdoc /> */
+ public string[] ReadStringArray()
+ {
+ return Read(r => BinaryUtils.ReadArray<string>(r, false), BinaryUtils.TypeArrayString);
+ }
+
+ /** <inheritdoc /> */
+ public Guid? ReadGuid(string fieldName)
+ {
+ return ReadField(fieldName, BinaryUtils.ReadGuid, BinaryUtils.TypeGuid);
+ }
+
+ /** <inheritdoc /> */
+ public Guid? ReadGuid()
+ {
+ return Read(BinaryUtils.ReadGuid, BinaryUtils.TypeGuid);
+ }
+
+ /** <inheritdoc /> */
+ public Guid?[] ReadGuidArray(string fieldName)
+ {
+ return ReadField(fieldName, r => BinaryUtils.ReadArray<Guid?>(r, false), BinaryUtils.TypeArrayGuid);
+ }
+
+ /** <inheritdoc /> */
+ public Guid?[] ReadGuidArray()
+ {
+ return Read(r => BinaryUtils.ReadArray<Guid?>(r, false), BinaryUtils.TypeArrayGuid);
+ }
+
+ /** <inheritdoc /> */
+ public T ReadEnum<T>(string fieldName)
+ {
+ return ReadField(fieldName, BinaryUtils.ReadEnum<T>, BinaryUtils.TypeEnum);
+ }
+
+ /** <inheritdoc /> */
+ public T ReadEnum<T>()
+ {
+ return Read(BinaryUtils.ReadEnum<T>, BinaryUtils.TypeEnum);
+ }
+
+ /** <inheritdoc /> */
+ public T[] ReadEnumArray<T>(string fieldName)
+ {
+ return ReadField(fieldName, r => BinaryUtils.ReadArray<T>(r, true), BinaryUtils.TypeArrayEnum);
+ }
+
+ /** <inheritdoc /> */
+ public T[] ReadEnumArray<T>()
+ {
+ return Read(r => BinaryUtils.ReadArray<T>(r, true), BinaryUtils.TypeArrayEnum);
+ }
+
+ /** <inheritdoc /> */
+ public T ReadObject<T>(string fieldName)
+ {
+ if (_curRaw)
+ throw new BinaryObjectException("Cannot read named fields after raw data is read.");
+
+ if (SeekField(fieldName))
+ return Deserialize<T>();
+
+ return default(T);
+ }
+
+ /** <inheritdoc /> */
+ public T ReadObject<T>()
+ {
+ return Deserialize<T>();
+ }
+
+ /** <inheritdoc /> */
+ public T[] ReadArray<T>(string fieldName)
+ {
+ return ReadField(fieldName, r => BinaryUtils.ReadArray<T>(r, true), BinaryUtils.TypeArray);
+ }
+
+ /** <inheritdoc /> */
+ public T[] ReadArray<T>()
+ {
+ return Read(r => BinaryUtils.ReadArray<T>(r, true), BinaryUtils.TypeArray);
+ }
+
+ /** <inheritdoc /> */
+ public ICollection ReadCollection(string fieldName)
+ {
+ return ReadCollection(fieldName, null, null);
+ }
+
+ /** <inheritdoc /> */
+ public ICollection ReadCollection()
+ {
+ return ReadCollection(null, null);
+ }
+
+ /** <inheritdoc /> */
+ public ICollection ReadCollection(string fieldName, CollectionFactory factory,
+ CollectionAdder adder)
+ {
+ return ReadField(fieldName, r => BinaryUtils.ReadCollection(r, factory, adder), BinaryUtils.TypeCollection);
+ }
+
+ /** <inheritdoc /> */
+ public ICollection ReadCollection(CollectionFactory factory,
+ CollectionAdder adder)
+ {
+ return Read(r => BinaryUtils.ReadCollection(r, factory, adder), BinaryUtils.TypeCollection);
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary ReadDictionary(string fieldName)
+ {
+ return ReadDictionary(fieldName, null);
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary ReadDictionary()
+ {
+ return ReadDictionary((DictionaryFactory)null);
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary ReadDictionary(string fieldName, DictionaryFactory factory)
+ {
+ return ReadField(fieldName, r => BinaryUtils.ReadDictionary(r, factory), BinaryUtils.TypeDictionary);
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary ReadDictionary(DictionaryFactory factory)
+ {
+ return Read(r => BinaryUtils.ReadDictionary(r, factory), BinaryUtils.TypeDictionary);
+ }
+
+ /// <summary>
+ /// Enable detach mode for the next object read.
+ /// </summary>
+ public void DetachNext()
+ {
+ _detach = true;
+ }
+
+ /// <summary>
+ /// Deserialize object.
+ /// </summary>
+ /// <returns>Deserialized object.</returns>
+ public T Deserialize<T>()
+ {
+ int pos = Stream.Position;
+
+ byte hdr = Stream.ReadByte();
+
+ var doDetach = _detach; // save detach flag into a var and reset so it does not go deeper
+
+ _detach = false;
+
+ switch (hdr)
+ {
+ case BinaryUtils.HdrNull:
+ if (default(T) != null)
+ throw new BinaryObjectException(string.Format("Invalid data on deserialization. " +
+ "Expected: '{0}' But was: null", typeof (T)));
+
+ return default(T);
+
+ case BinaryUtils.HdrHnd:
+ return ReadHandleObject<T>(pos);
+
+ case BinaryUtils.HdrFull:
+ return ReadFullObject<T>(pos);
+
+ case BinaryUtils.TypeBinary:
+ return ReadBinaryObject<T>(doDetach);
+ }
+
+ if (BinaryUtils.IsPredefinedType(hdr))
+ return BinarySystemHandlers.ReadSystemType<T>(hdr, this);
+
+ throw new BinaryObjectException("Invalid header on deserialization [pos=" + pos + ", hdr=" + hdr + ']');
+ }
+
+ /// <summary>
+ /// Reads the binary object.
+ /// </summary>
+ private T ReadBinaryObject<T>(bool doDetach)
+ {
+ var len = Stream.ReadInt();
+
+ var binaryBytesPos = Stream.Position;
+
+ if (_mode != BinaryMode.Deserialize)
+ return TypeCaster<T>.Cast(ReadAsBinary(binaryBytesPos, len, doDetach));
+
+ Stream.Seek(len, SeekOrigin.Current);
+
+ var offset = Stream.ReadInt();
+
+ var retPos = Stream.Position;
+
+ Stream.Seek(binaryBytesPos + offset, SeekOrigin.Begin);
+
+ _mode = BinaryMode.KeepBinary;
+
+ try
+ {
+ return Deserialize<T>();
+ }
+ finally
+ {
+ _mode = BinaryMode.Deserialize;
+
+ Stream.Seek(retPos, SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Reads the binary object in binary form.
+ /// </summary>
+ private BinaryObject ReadAsBinary(int binaryBytesPos, int dataLen, bool doDetach)
+ {
+ try
+ {
+ Stream.Seek(dataLen + binaryBytesPos, SeekOrigin.Begin);
+
+ var offs = Stream.ReadInt(); // offset inside data
+
+ var pos = binaryBytesPos + offs;
+
+ var hdr = BinaryObjectHeader.Read(Stream, pos);
+
+ if (!doDetach)
+ return new BinaryObject(_marsh, Stream.GetArray(), pos, hdr);
+
+ Stream.Seek(pos, SeekOrigin.Begin);
+
+ return new BinaryObject(_marsh, Stream.ReadByteArray(hdr.Length), 0, hdr);
+ }
+ finally
+ {
+ Stream.Seek(binaryBytesPos + dataLen + 4, SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Reads the full object.
+ /// </summary>
+ [SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "hashCode")]
+ private T ReadFullObject<T>(int pos)
+ {
+ var hdr = BinaryObjectHeader.Read(Stream, pos);
+
+ // Validate protocol version.
+ BinaryUtils.ValidateProtocolVersion(hdr.Version);
+
+ try
+ {
+ // Already read this object?
+ object hndObj;
+
+ if (_hnds != null && _hnds.TryGetValue(pos, out hndObj))
+ return (T) hndObj;
+
+ if (hdr.IsUserType && _mode == BinaryMode.ForceBinary)
+ {
+ BinaryObject portObj;
+
+ if (_detach)
+ {
+ Stream.Seek(pos, SeekOrigin.Begin);
+
+ portObj = new BinaryObject(_marsh, Stream.ReadByteArray(hdr.Length), 0, hdr);
+ }
+ else
+ portObj = new BinaryObject(_marsh, Stream.GetArray(), pos, hdr);
+
+ T obj = _builder == null ? TypeCaster<T>.Cast(portObj) : TypeCaster<T>.Cast(_builder.Child(portObj));
+
+ AddHandle(pos, obj);
+
+ return obj;
+ }
+ else
+ {
+ // Find descriptor.
+ IBinaryTypeDescriptor desc;
+
+ if (!_descs.TryGetValue(BinaryUtils.TypeKey(hdr.IsUserType, hdr.TypeId), out desc))
+ throw new BinaryObjectException("Unknown type ID: " + hdr.TypeId);
+
+ // Instantiate object.
+ if (desc.Type == null)
+ throw new BinaryObjectException("No matching type found for object [typeId=" +
+ desc.TypeId + ", typeName=" + desc.TypeName + ']');
+
+ // Preserve old frame.
+ var oldHdr = _curHdr;
+ int oldPos = _curPos;
+ var oldStruct = _curStruct;
+ bool oldRaw = _curRaw;
+ var oldSchema = _curSchema;
+ var oldSchemaMap = _curSchemaMap;
+
+ // Set new frame.
+ _curHdr = hdr;
+ _curPos = pos;
+
+ _curSchema = desc.Schema.Get(hdr.SchemaId);
+
+ if (_curSchema == null)
+ {
+ _curSchema = ReadSchema();
+
+ desc.Schema.Add(hdr.SchemaId, _curSchema);
+ }
+
+ _curStruct = new BinaryStructureTracker(desc, desc.ReaderTypeStructure);
+ _curRaw = false;
+
+ // Read object.
+ Stream.Seek(pos + BinaryObjectHeader.Size, SeekOrigin.Begin);
+
+ object obj;
+
+ var sysSerializer = desc.Serializer as IBinarySystemTypeSerializer;
+
+ if (sysSerializer != null)
+ obj = sysSerializer.ReadInstance(this);
+ else
+ {
+ try
+ {
+ obj = FormatterServices.GetUninitializedObject(desc.Type);
+
+ // Save handle.
+ AddHandle(pos, obj);
+ }
+ catch (Exception e)
+ {
+ throw new BinaryObjectException("Failed to create type instance: " +
+ desc.Type.AssemblyQualifiedName, e);
+ }
+
+ desc.Serializer.ReadBinary(obj, this);
+ }
+
+ _curStruct.UpdateReaderStructure();
+
+ // Restore old frame.
+ _curHdr = oldHdr;
+ _curPos = oldPos;
+ _curStruct = oldStruct;
+ _curRaw = oldRaw;
+ _curSchema = oldSchema;
+ _curSchemaMap = oldSchemaMap;
+
+ // Process wrappers. We could introduce a common interface, but for only 2 if-else is faster.
+ var wrappedSerializable = obj as SerializableObjectHolder;
+
+ if (wrappedSerializable != null)
+ return (T) wrappedSerializable.Item;
+
+ var wrappedDateTime = obj as DateTimeHolder;
+
+ if (wrappedDateTime != null)
+ return TypeCaster<T>.Cast(wrappedDateTime.Item);
+
+ return (T) obj;
+ }
+ }
+ finally
+ {
+ // Advance stream pointer.
+ Stream.Seek(pos + hdr.Length, SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Reads the schema.
+ /// </summary>
+ private int[] ReadSchema()
+ {
+ Stream.Seek(_curPos + _curHdr.SchemaOffset, SeekOrigin.Begin);
+
+ var count = _curHdr.SchemaFieldCount;
+
+ var offsetSize = _curHdr.SchemaFieldOffsetSize;
+
+ var res = new int[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ res[i] = Stream.ReadInt();
+ Stream.Seek(offsetSize, SeekOrigin.Current);
+ }
+
+ return res;
+ }
+ /// <summary>
+ /// Reads the handle object.
+ /// </summary>
+ private T ReadHandleObject<T>(int pos)
+ {
+ // Get handle position.
+ int hndPos = pos - Stream.ReadInt();
+
+ int retPos = Stream.Position;
+
+ try
+ {
+ object hndObj;
+
+ if (_builder == null || !_builder.TryGetCachedField(hndPos, out hndObj))
+ {
+ if (_hnds == null || !_hnds.TryGetValue(hndPos, out hndObj))
+ {
+ // No such handler, i.e. we trying to deserialize inner object before deserializing outer.
+ Stream.Seek(hndPos, SeekOrigin.Begin);
+
+ hndObj = Deserialize<T>();
+ }
+
+ // Notify builder that we deserialized object on other location.
+ if (_builder != null)
+ _builder.CacheField(hndPos, hndObj);
+ }
+
+ return (T) hndObj;
+ }
+ finally
+ {
+ // Position stream to correct place.
+ Stream.Seek(retPos, SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Adds a handle to the dictionary.
+ /// </summary>
+ /// <param name="pos">Position.</param>
+ /// <param name="obj">Object.</param>
+ private void AddHandle(int pos, object obj)
+ {
+ if (_hnds == null)
+ _hnds = new BinaryReaderHandleDictionary(pos, obj);
+ else
+ _hnds.Add(pos, obj);
+ }
+
+ /// <summary>
+ /// Underlying stream.
+ /// </summary>
+ public IBinaryStream Stream
+ {
+ get;
+ private set;
+ }
+
+ /// <summary>
+ /// Mark current output as raw.
+ /// </summary>
+ private void MarkRaw()
+ {
+ if (!_curRaw)
+ {
+ _curRaw = true;
+
+ Stream.Seek(_curPos + _curHdr.GetRawOffset(Stream, _curPos), SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Determines whether header at current position is HDR_NULL.
+ /// </summary>
+ private bool IsNotNullHeader(byte expHdr)
+ {
+ var hdr = ReadByte();
+
+ if (hdr == BinaryUtils.HdrNull)
+ return false;
+
+ if (expHdr != hdr)
+ throw new BinaryObjectException(string.Format("Invalid header on deserialization. " +
+ "Expected: {0} but was: {1}", expHdr, hdr));
+
+ return true;
+ }
+
+ /// <summary>
+ /// Seeks the field by name, reads header and returns true if field is present and header is not null.
+ /// </summary>
+ private bool SeekField(string fieldName, byte expHdr)
+ {
+ if (!SeekField(fieldName))
+ return false;
+
+ // Expected read order, no need to seek.
+ return IsNotNullHeader(expHdr);
+ }
+
+ /// <summary>
+ /// Seeks the field by name.
+ /// </summary>
+ private bool SeekField(string fieldName)
+ {
+ if (_curRaw)
+ throw new BinaryObjectException("Cannot read named fields after raw data is read.");
+
+ if (_curHdr.IsRawOnly)
+ return false;
+
+ var actionId = _curStruct.CurStructAction;
+
+ var fieldId = _curStruct.GetFieldId(fieldName);
+
+ if (_curSchema == null || actionId >= _curSchema.Length || fieldId != _curSchema[actionId])
+ {
+ _curSchema = null; // read order is different, ignore schema for future reads
+
+ _curSchemaMap = _curSchemaMap ?? _curHdr.ReadSchemaAsDictionary(Stream, _curPos);
+
+ int pos;
+
+ if (!_curSchemaMap.TryGetValue(fieldId, out pos))
+ return false;
+
+ Stream.Seek(pos, SeekOrigin.Begin);
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Seeks specified field and invokes provided func.
+ /// </summary>
+ private T ReadField<T>(string fieldName, Func<IBinaryStream, T> readFunc, byte expHdr)
+ {
+ return SeekField(fieldName, expHdr) ? readFunc(Stream) : default(T);
+ }
+
+ /// <summary>
+ /// Seeks specified field and invokes provided func.
+ /// </summary>
+ private T ReadField<T>(string fieldName, Func<BinaryReader, T> readFunc, byte expHdr)
+ {
+ return SeekField(fieldName, expHdr) ? readFunc(this) : default(T);
+ }
+
+ /// <summary>
+ /// Seeks specified field and invokes provided func.
+ /// </summary>
+ private T ReadField<T>(string fieldName, Func<T> readFunc, byte expHdr)
+ {
+ return SeekField(fieldName, expHdr) ? readFunc() : default(T);
+ }
+
+ /// <summary>
+ /// Reads header and invokes specified func if the header is not null.
+ /// </summary>
+ private T Read<T>(Func<BinaryReader, T> readFunc, byte expHdr)
+ {
+ return IsNotNullHeader(expHdr) ? readFunc(this) : default(T);
+ }
+
+ /// <summary>
+ /// Reads header and invokes specified func if the header is not null.
+ /// </summary>
+ private T Read<T>(Func<IBinaryStream, T> readFunc, byte expHdr)
+ {
+ return IsNotNullHeader(expHdr) ? readFunc(Stream) : default(T);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/894057e5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderExtensions.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderExtensions.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderExtensions.cs
new file mode 100644
index 0000000..c3dcc3a
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderExtensions.cs
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Binary
+{
+ using System.Collections.Generic;
+ using Apache.Ignite.Core.Binary;
+
+ /// <summary>
+ /// Reader extensions.
+ /// </summary>
+ internal static class BinaryReaderExtensions
+ {
+ /// <summary>
+ /// Reads untyped collection as a generic list.
+ /// </summary>
+ /// <typeparam name="T">Type of list element.</typeparam>
+ /// <param name="reader">The reader.</param>
+ /// <returns>Resulting generic list.</returns>
+ public static List<T> ReadCollectionAsList<T>(this IBinaryRawReader reader)
+ {
+ return ((List<T>) reader.ReadCollection(size => new List<T>(size),
+ (col, elem) => ((List<T>) col).Add((T) elem)));
+ }
+
+ /// <summary>
+ /// Reads untyped dictionary as generic dictionary.
+ /// </summary>
+ /// <typeparam name="TKey">The type of the key.</typeparam>
+ /// <typeparam name="TValue">The type of the value.</typeparam>
+ /// <param name="reader">The reader.</param>
+ /// <returns>Resulting dictionary.</returns>
+ public static Dictionary<TKey, TValue> ReadDictionaryAsGeneric<TKey, TValue>(this IBinaryRawReader reader)
+ {
+ return (Dictionary<TKey, TValue>) reader.ReadDictionary(size => new Dictionary<TKey, TValue>(size));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/894057e5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderHandleDictionary.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderHandleDictionary.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderHandleDictionary.cs
new file mode 100644
index 0000000..c145e7f
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderHandleDictionary.cs
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Binary
+{
+ /// <summary>
+ /// Object handle dictionary for <see cref="BinaryReader"/>.
+ /// </summary>
+ internal class BinaryReaderHandleDictionary : BinaryHandleDictionary<int, object>
+ {
+ /// <summary>
+ /// Constructor with initial key-value pair.
+ /// </summary>
+ /// <param name="key">Key.</param>
+ /// <param name="val">Value.</param>
+ public BinaryReaderHandleDictionary(int key, object val)
+ : base(key, val)
+ {
+ // No-op.
+ }
+
+ /** <inheritdoc /> */
+ protected override int EmptyKey
+ {
+ get { return -1; }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/894057e5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs
new file mode 100644
index 0000000..b229898
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs
@@ -0,0 +1,440 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Binary
+{
+ using System;
+ using System.Collections;
+ using System.Diagnostics;
+ using System.Linq.Expressions;
+ using System.Reflection;
+ using Apache.Ignite.Core.Binary;
+ using Apache.Ignite.Core.Common;
+ using Apache.Ignite.Core.Impl.Common;
+
+ /// <summary>
+ /// Write action delegate.
+ /// </summary>
+ /// <param name="obj">Target object.</param>
+ /// <param name="writer">Writer.</param>
+ internal delegate void BinaryReflectiveWriteAction(object obj, IBinaryWriter writer);
+
+ /// <summary>
+ /// Read action delegate.
+ /// </summary>
+ /// <param name="obj">Target object.</param>
+ /// <param name="reader">Reader.</param>
+ internal delegate void BinaryReflectiveReadAction(object obj, IBinaryReader reader);
+
+ /// <summary>
+ /// Routines for reflective reads and writes.
+ /// </summary>
+ internal static class BinaryReflectiveActions
+ {
+ /** Method: read enum. */
+ private static readonly MethodInfo MthdReadEnum =
+ typeof(IBinaryReader).GetMethod("ReadEnum", new[] { typeof(string) });
+
+ /** Method: read enum array. */
+ private static readonly MethodInfo MthdReadEnumArray =
+ typeof(IBinaryReader).GetMethod("ReadEnumArray", new[] { typeof(string) });
+
+ /** Method: read array. */
+ private static readonly MethodInfo MthdReadObjArray =
+ typeof(IBinaryReader).GetMethod("ReadArray", new[] { typeof(string) });
+
+ /** Method: read object. */
+ private static readonly MethodInfo MthdReadObj=
+ typeof(IBinaryReader).GetMethod("ReadObject", new[] { typeof(string) });
+
+ /** Method: write enum array. */
+ private static readonly MethodInfo MthdWriteEnumArray =
+ typeof(IBinaryWriter).GetMethod("WriteEnumArray");
+
+ /** Method: write array. */
+ private static readonly MethodInfo MthdWriteObjArray =
+ typeof(IBinaryWriter).GetMethod("WriteArray");
+
+ /** Method: read object. */
+ private static readonly MethodInfo MthdWriteObj =
+ typeof(IBinaryWriter).GetMethod("WriteObject");
+
+ /// <summary>
+ /// Lookup read/write actions for the given type.
+ /// </summary>
+ /// <param name="field">The field.</param>
+ /// <param name="writeAction">Write action.</param>
+ /// <param name="readAction">Read action.</param>
+ public static void TypeActions(FieldInfo field, out BinaryReflectiveWriteAction writeAction,
+ out BinaryReflectiveReadAction readAction)
+ {
+ var type = field.FieldType;
+
+ if (type.IsPrimitive)
+ HandlePrimitive(field, out writeAction, out readAction);
+ else if (type.IsArray)
+ HandleArray(field, out writeAction, out readAction);
+ else
+ HandleOther(field, out writeAction, out readAction);
+ }
+
+ /// <summary>
+ /// Handle primitive type.
+ /// </summary>
+ /// <param name="field">The field.</param>
+ /// <param name="writeAction">Write action.</param>
+ /// <param name="readAction">Read action.</param>
+ /// <exception cref="IgniteException">Unsupported primitive type: + type.Name</exception>
+ private static void HandlePrimitive(FieldInfo field, out BinaryReflectiveWriteAction writeAction,
+ out BinaryReflectiveReadAction readAction)
+ {
+ var type = field.FieldType;
+
+ if (type == typeof(bool))
+ {
+ writeAction = GetWriter<bool>(field, (f, w, o) => w.WriteBoolean(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadBoolean(f));
+ }
+ else if (type == typeof(sbyte))
+ {
+ writeAction = GetWriter<sbyte>(field, (f, w, o) => w.WriteByte(f, unchecked((byte) o)));
+ readAction = GetReader(field, (f, r) => unchecked ((sbyte)r.ReadByte(f)));
+ }
+ else if (type == typeof(byte))
+ {
+ writeAction = GetWriter<byte>(field, (f, w, o) => w.WriteByte(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadByte(f));
+ }
+ else if (type == typeof(short))
+ {
+ writeAction = GetWriter<short>(field, (f, w, o) => w.WriteShort(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadShort(f));
+ }
+ else if (type == typeof(ushort))
+ {
+ writeAction = GetWriter<ushort>(field, (f, w, o) => w.WriteShort(f, unchecked((short) o)));
+ readAction = GetReader(field, (f, r) => unchecked((ushort) r.ReadShort(f)));
+ }
+ else if (type == typeof(char))
+ {
+ writeAction = GetWriter<char>(field, (f, w, o) => w.WriteChar(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadChar(f));
+ }
+ else if (type == typeof(int))
+ {
+ writeAction = GetWriter<int>(field, (f, w, o) => w.WriteInt(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadInt(f));
+ }
+ else if (type == typeof(uint))
+ {
+ writeAction = GetWriter<uint>(field, (f, w, o) => w.WriteInt(f, unchecked((int) o)));
+ readAction = GetReader(field, (f, r) => unchecked((uint) r.ReadInt(f)));
+ }
+ else if (type == typeof(long))
+ {
+ writeAction = GetWriter<long>(field, (f, w, o) => w.WriteLong(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadLong(f));
+ }
+ else if (type == typeof(ulong))
+ {
+ writeAction = GetWriter<ulong>(field, (f, w, o) => w.WriteLong(f, unchecked((long) o)));
+ readAction = GetReader(field, (f, r) => unchecked((ulong) r.ReadLong(f)));
+ }
+ else if (type == typeof(float))
+ {
+ writeAction = GetWriter<float>(field, (f, w, o) => w.WriteFloat(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadFloat(f));
+ }
+ else if (type == typeof(double))
+ {
+ writeAction = GetWriter<double>(field, (f, w, o) => w.WriteDouble(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadDouble(f));
+ }
+ else
+ throw new IgniteException("Unsupported primitive type: " + type.Name);
+ }
+
+ /// <summary>
+ /// Handle array type.
+ /// </summary>
+ /// <param name="field">The field.</param>
+ /// <param name="writeAction">Write action.</param>
+ /// <param name="readAction">Read action.</param>
+ private static void HandleArray(FieldInfo field, out BinaryReflectiveWriteAction writeAction,
+ out BinaryReflectiveReadAction readAction)
+ {
+ Type elemType = field.FieldType.GetElementType();
+
+ if (elemType == typeof(bool))
+ {
+ writeAction = GetWriter<bool[]>(field, (f, w, o) => w.WriteBooleanArray(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadBooleanArray(f));
+ }
+ else if (elemType == typeof(byte))
+ {
+ writeAction = GetWriter<byte[]>(field, (f, w, o) => w.WriteByteArray(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadByteArray(f));
+ }
+ else if (elemType == typeof(sbyte))
+ {
+ writeAction = GetWriter<sbyte[]>(field, (f, w, o) => w.WriteByteArray(f, (byte[]) (Array) o));
+ readAction = GetReader(field, (f, r) => (sbyte[]) (Array) r.ReadByteArray(f));
+ }
+ else if (elemType == typeof(short))
+ {
+ writeAction = GetWriter<short[]>(field, (f, w, o) => w.WriteShortArray(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadShortArray(f));
+ }
+ else if (elemType == typeof(ushort))
+ {
+ writeAction = GetWriter<ushort[]>(field, (f, w, o) => w.WriteShortArray(f, (short[]) (Array) o));
+ readAction = GetReader(field, (f, r) => (ushort[]) (Array) r.ReadShortArray(f));
+ }
+ else if (elemType == typeof(char))
+ {
+ writeAction = GetWriter<char[]>(field, (f, w, o) => w.WriteCharArray(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadCharArray(f));
+ }
+ else if (elemType == typeof(int))
+ {
+ writeAction = GetWriter<int[]>(field, (f, w, o) => w.WriteIntArray(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadIntArray(f));
+ }
+ else if (elemType == typeof(uint))
+ {
+ writeAction = GetWriter<uint[]>(field, (f, w, o) => w.WriteIntArray(f, (int[]) (Array) o));
+ readAction = GetReader(field, (f, r) => (uint[]) (Array) r.ReadIntArray(f));
+ }
+ else if (elemType == typeof(long))
+ {
+ writeAction = GetWriter<long[]>(field, (f, w, o) => w.WriteLongArray(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadLongArray(f));
+ }
+ else if (elemType == typeof(ulong))
+ {
+ writeAction = GetWriter<ulong[]>(field, (f, w, o) => w.WriteLongArray(f, (long[]) (Array) o));
+ readAction = GetReader(field, (f, r) => (ulong[]) (Array) r.ReadLongArray(f));
+ }
+ else if (elemType == typeof(float))
+ {
+ writeAction = GetWriter<float[]>(field, (f, w, o) => w.WriteFloatArray(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadFloatArray(f));
+ }
+ else if (elemType == typeof(double))
+ {
+ writeAction = GetWriter<double[]>(field, (f, w, o) => w.WriteDoubleArray(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadDoubleArray(f));
+ }
+ else if (elemType == typeof(decimal?))
+ {
+ writeAction = GetWriter<decimal?[]>(field, (f, w, o) => w.WriteDecimalArray(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadDecimalArray(f));
+ }
+ else if (elemType == typeof(string))
+ {
+ writeAction = GetWriter<string[]>(field, (f, w, o) => w.WriteStringArray(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadStringArray(f));
+ }
+ else if (elemType == typeof(Guid?))
+ {
+ writeAction = GetWriter<Guid?[]>(field, (f, w, o) => w.WriteGuidArray(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadGuidArray(f));
+ }
+ else if (elemType.IsEnum)
+ {
+ writeAction = GetWriter(field, MthdWriteEnumArray, elemType);
+ readAction = GetReader(field, MthdReadEnumArray, elemType);
+ }
+ else
+ {
+ writeAction = GetWriter(field, MthdWriteObjArray, elemType);
+ readAction = GetReader(field, MthdReadObjArray, elemType);
+ }
+ }
+
+ /// <summary>
+ /// Handle other type.
+ /// </summary>
+ /// <param name="field">The field.</param>
+ /// <param name="writeAction">Write action.</param>
+ /// <param name="readAction">Read action.</param>
+ private static void HandleOther(FieldInfo field, out BinaryReflectiveWriteAction writeAction,
+ out BinaryReflectiveReadAction readAction)
+ {
+ var type = field.FieldType;
+
+ var genericDef = type.IsGenericType ? type.GetGenericTypeDefinition() : null;
+
+ bool nullable = genericDef == typeof(Nullable<>);
+
+ var nullableType = nullable ? type.GetGenericArguments()[0] : null;
+
+ if (type == typeof(decimal))
+ {
+ writeAction = GetWriter<decimal>(field, (f, w, o) => w.WriteDecimal(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadDecimal(f));
+ }
+ else if (type == typeof(string))
+ {
+ writeAction = GetWriter<string>(field, (f, w, o) => w.WriteString(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadString(f));
+ }
+ else if (type == typeof(Guid))
+ {
+ writeAction = GetWriter<Guid>(field, (f, w, o) => w.WriteGuid(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadObject<Guid>(f));
+ }
+ else if (nullable && nullableType == typeof(Guid))
+ {
+ writeAction = GetWriter<Guid?>(field, (f, w, o) => w.WriteGuid(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadGuid(f));
+ }
+ else if (type.IsEnum)
+ {
+ writeAction = GetWriter<object>(field, (f, w, o) => w.WriteEnum(f, o), true);
+ readAction = GetReader(field, MthdReadEnum);
+ }
+ else if (type == BinaryUtils.TypDictionary || type.GetInterface(BinaryUtils.TypDictionary.FullName) != null && !type.IsGenericType)
+ {
+ writeAction = GetWriter<IDictionary>(field, (f, w, o) => w.WriteDictionary(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadDictionary(f));
+ }
+ else if (type == BinaryUtils.TypCollection || type.GetInterface(BinaryUtils.TypCollection.FullName) != null && !type.IsGenericType)
+ {
+ writeAction = GetWriter<ICollection>(field, (f, w, o) => w.WriteCollection(f, o));
+ readAction = GetReader(field, (f, r) => r.ReadCollection(f));
+ }
+ else
+ {
+ writeAction = GetWriter(field, MthdWriteObj);
+ readAction = GetReader(field, MthdReadObj);
+ }
+ }
+
+ /// <summary>
+ /// Gets the reader with a specified write action.
+ /// </summary>
+ private static BinaryReflectiveWriteAction GetWriter<T>(FieldInfo field,
+ Expression<Action<string, IBinaryWriter, T>> write,
+ bool convertFieldValToObject = false)
+ {
+ Debug.Assert(field != null);
+ Debug.Assert(field.DeclaringType != null); // non-static
+
+ // Get field value
+ var targetParam = Expression.Parameter(typeof(object));
+ var targetParamConverted = Expression.Convert(targetParam, field.DeclaringType);
+ Expression fldExpr = Expression.Field(targetParamConverted, field);
+
+ if (convertFieldValToObject)
+ fldExpr = Expression.Convert(fldExpr, typeof (object));
+
+ // Call Writer method
+ var writerParam = Expression.Parameter(typeof(IBinaryWriter));
+ var fldNameParam = Expression.Constant(BinaryUtils.CleanFieldName(field.Name));
+ var writeExpr = Expression.Invoke(write, fldNameParam, writerParam, fldExpr);
+
+ // Compile and return
+ return Expression.Lambda<BinaryReflectiveWriteAction>(writeExpr, targetParam, writerParam).Compile();
+ }
+
+ /// <summary>
+ /// Gets the writer with a specified generic method.
+ /// </summary>
+ private static BinaryReflectiveWriteAction GetWriter(FieldInfo field, MethodInfo method,
+ params Type[] genericArgs)
+ {
+ Debug.Assert(field != null);
+ Debug.Assert(field.DeclaringType != null); // non-static
+
+ if (genericArgs.Length == 0)
+ genericArgs = new[] {field.FieldType};
+
+ // Get field value
+ var targetParam = Expression.Parameter(typeof(object));
+ var targetParamConverted = Expression.Convert(targetParam, field.DeclaringType);
+ var fldExpr = Expression.Field(targetParamConverted, field);
+
+ // Call Writer method
+ var writerParam = Expression.Parameter(typeof(IBinaryWriter));
+ var fldNameParam = Expression.Constant(BinaryUtils.CleanFieldName(field.Name));
+ var writeMethod = method.MakeGenericMethod(genericArgs);
+ var writeExpr = Expression.Call(writerParam, writeMethod, fldNameParam, fldExpr);
+
+ // Compile and return
+ return Expression.Lambda<BinaryReflectiveWriteAction>(writeExpr, targetParam, writerParam).Compile();
+ }
+
+ /// <summary>
+ /// Gets the reader with a specified read action.
+ /// </summary>
+ private static BinaryReflectiveReadAction GetReader<T>(FieldInfo field,
+ Expression<Func<string, IBinaryReader, T>> read)
+ {
+ Debug.Assert(field != null);
+ Debug.Assert(field.DeclaringType != null); // non-static
+
+ // Call Reader method
+ var readerParam = Expression.Parameter(typeof(IBinaryReader));
+ var fldNameParam = Expression.Constant(BinaryUtils.CleanFieldName(field.Name));
+ Expression readExpr = Expression.Invoke(read, fldNameParam, readerParam);
+
+ if (typeof(T) != field.FieldType)
+ readExpr = Expression.Convert(readExpr, field.FieldType);
+
+ // Assign field value
+ var targetParam = Expression.Parameter(typeof(object));
+ var targetParamConverted = Expression.Convert(targetParam, field.DeclaringType);
+ var assignExpr = Expression.Call(DelegateConverter.GetWriteFieldMethod(field), targetParamConverted,
+ readExpr);
+
+ // Compile and return
+ return Expression.Lambda<BinaryReflectiveReadAction>(assignExpr, targetParam, readerParam).Compile();
+ }
+
+ /// <summary>
+ /// Gets the reader with a specified generic method.
+ /// </summary>
+ private static BinaryReflectiveReadAction GetReader(FieldInfo field, MethodInfo method,
+ params Type[] genericArgs)
+ {
+ Debug.Assert(field != null);
+ Debug.Assert(field.DeclaringType != null); // non-static
+
+ if (genericArgs.Length == 0)
+ genericArgs = new[] {field.FieldType};
+
+ // Call Reader method
+ var readerParam = Expression.Parameter(typeof (IBinaryReader));
+ var fldNameParam = Expression.Constant(BinaryUtils.CleanFieldName(field.Name));
+ var readMethod = method.MakeGenericMethod(genericArgs);
+ Expression readExpr = Expression.Call(readerParam, readMethod, fldNameParam);
+
+ if (readMethod.ReturnType != field.FieldType)
+ readExpr = Expression.Convert(readExpr, field.FieldType);
+
+ // Assign field value
+ var targetParam = Expression.Parameter(typeof(object));
+ var targetParamConverted = Expression.Convert(targetParam, field.DeclaringType);
+ var assignExpr = Expression.Call(DelegateConverter.GetWriteFieldMethod(field), targetParamConverted,
+ readExpr);
+
+ // Compile and return
+ return Expression.Lambda<BinaryReflectiveReadAction>(assignExpr, targetParam, readerParam).Compile();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/894057e5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveSerializer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveSerializer.cs
new file mode 100644
index 0000000..0804c25
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveSerializer.cs
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Binary
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Reflection;
+ using Apache.Ignite.Core.Binary;
+
+ /// <summary>
+ /// Binary serializer which reflectively writes all fields except of ones with
+ /// <see cref="System.NonSerializedAttribute"/>.
+ /// <para />
+ /// Note that Java platform stores dates as a difference between current time
+ /// and predefined absolute UTC date. Therefore, this difference is always the
+ /// same for all time zones. .Net, in contrast, stores dates as a difference
+ /// between current time and some predefined date relative to the current time
+ /// zone. It means that this difference will be different as you change time zones.
+ /// To overcome this discrepancy Ignite always converts .Net date to UTC form
+ /// before serializing and allows user to decide whether to deserialize them
+ /// in UTC or local form using <c>ReadTimestamp(..., true/false)</c> methods in
+ /// <see cref="IBinaryReader"/> and <see cref="IBinaryRawReader"/>.
+ /// This serializer always read dates in UTC form. It means that if you have
+ /// local date in any field/property, it will be implicitly converted to UTC
+ /// form after the first serialization-deserialization cycle.
+ /// </summary>
+ internal class BinaryReflectiveSerializer : IBinarySerializer
+ {
+ /** Cached binding flags. */
+ private static readonly BindingFlags Flags = BindingFlags.Instance | BindingFlags.Public |
+ BindingFlags.NonPublic | BindingFlags.DeclaredOnly;
+
+ /** Cached type descriptors. */
+ private readonly IDictionary<Type, Descriptor> _types = new Dictionary<Type, Descriptor>();
+
+ /// <summary>
+ /// Write portalbe object.
+ /// </summary>
+ /// <param name="obj">Object.</param>
+ /// <param name="writer">Writer.</param>
+ /// <exception cref="BinaryObjectException">Type is not registered in serializer: + type.Name</exception>
+ public void WriteBinary(object obj, IBinaryWriter writer)
+ {
+ var binarizable = obj as IBinarizable;
+
+ if (binarizable != null)
+ binarizable.WriteBinary(writer);
+ else
+ GetDescriptor(obj).Write(obj, writer);
+ }
+
+ /// <summary>
+ /// Read binary object.
+ /// </summary>
+ /// <param name="obj">Instantiated empty object.</param>
+ /// <param name="reader">Reader.</param>
+ /// <exception cref="BinaryObjectException">Type is not registered in serializer: + type.Name</exception>
+ public void ReadBinary(object obj, IBinaryReader reader)
+ {
+ var binarizable = obj as IBinarizable;
+
+ if (binarizable != null)
+ binarizable.ReadBinary(reader);
+ else
+ GetDescriptor(obj).Read(obj, reader);
+ }
+
+ /// <summary>Register type.</summary>
+ /// <param name="type">Type.</param>
+ /// <param name="typeId">Type ID.</param>
+ /// <param name="converter">Name converter.</param>
+ /// <param name="idMapper">ID mapper.</param>
+ public void Register(Type type, int typeId, IBinaryNameMapper converter,
+ IBinaryIdMapper idMapper)
+ {
+ if (type.GetInterface(typeof(IBinarizable).Name) != null)
+ return;
+
+ List<FieldInfo> fields = new List<FieldInfo>();
+
+ Type curType = type;
+
+ while (curType != null)
+ {
+ foreach (FieldInfo field in curType.GetFields(Flags))
+ {
+ if (!field.IsNotSerialized)
+ fields.Add(field);
+ }
+
+ curType = curType.BaseType;
+ }
+
+ IDictionary<int, string> idMap = new Dictionary<int, string>();
+
+ foreach (FieldInfo field in fields)
+ {
+ string fieldName = BinaryUtils.CleanFieldName(field.Name);
+
+ int fieldId = BinaryUtils.FieldId(typeId, fieldName, converter, idMapper);
+
+ if (idMap.ContainsKey(fieldId))
+ {
+ throw new BinaryObjectException("Conflicting field IDs [type=" +
+ type.Name + ", field1=" + idMap[fieldId] + ", field2=" + fieldName +
+ ", fieldId=" + fieldId + ']');
+ }
+
+ idMap[fieldId] = fieldName;
+ }
+
+ fields.Sort(Compare);
+
+ Descriptor desc = new Descriptor(fields);
+
+ _types[type] = desc;
+ }
+
+ /// <summary>
+ /// Gets the descriptor for an object.
+ /// </summary>
+ private Descriptor GetDescriptor(object obj)
+ {
+ var type = obj.GetType();
+
+ Descriptor desc;
+
+ if (!_types.TryGetValue(type, out desc))
+ throw new BinaryObjectException("Type is not registered in serializer: " + type.Name);
+
+ return desc;
+ }
+
+ /// <summary>
+ /// Compare two FieldInfo instances.
+ /// </summary>
+ private static int Compare(FieldInfo info1, FieldInfo info2) {
+ string name1 = BinaryUtils.CleanFieldName(info1.Name);
+ string name2 = BinaryUtils.CleanFieldName(info2.Name);
+
+ return string.Compare(name1, name2, StringComparison.OrdinalIgnoreCase);
+ }
+
+ /// <summary>
+ /// Type descriptor.
+ /// </summary>
+ private class Descriptor
+ {
+ /** Write actions to be performed. */
+ private readonly List<BinaryReflectiveWriteAction> _wActions;
+
+ /** Read actions to be performed. */
+ private readonly List<BinaryReflectiveReadAction> _rActions;
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="fields">Fields.</param>
+ public Descriptor(List<FieldInfo> fields)
+ {
+ _wActions = new List<BinaryReflectiveWriteAction>(fields.Count);
+ _rActions = new List<BinaryReflectiveReadAction>(fields.Count);
+
+ foreach (FieldInfo field in fields)
+ {
+ BinaryReflectiveWriteAction writeAction;
+ BinaryReflectiveReadAction readAction;
+
+ BinaryReflectiveActions.TypeActions(field, out writeAction, out readAction);
+
+ _wActions.Add(writeAction);
+ _rActions.Add(readAction);
+ }
+ }
+
+ /// <summary>
+ /// Write object.
+ /// </summary>
+ /// <param name="obj">Object.</param>
+ /// <param name="writer">Writer.</param>
+ public void Write(object obj, IBinaryWriter writer)
+ {
+ int cnt = _wActions.Count;
+
+ for (int i = 0; i < cnt; i++)
+ _wActions[i](obj, writer);
+ }
+
+ /// <summary>
+ /// Read object.
+ /// </summary>
+ /// <param name="obj">Object.</param>
+ /// <param name="reader">Reader.</param>
+ public void Read(object obj, IBinaryReader reader)
+ {
+ int cnt = _rActions.Count;
+
+ for (int i = 0; i < cnt; i++ )
+ _rActions[i](obj, reader);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/894057e5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs
new file mode 100644
index 0000000..247b40d
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Binary
+{
+ using System;
+ using System.Collections.Generic;
+ using Apache.Ignite.Core.Binary;
+ using Apache.Ignite.Core.Impl.Binary.Structure;
+
+ /// <summary>
+ /// Surrogate type descriptor. Used in cases when type if identified by name and
+ /// is not provided in configuration.
+ /// </summary>
+ internal class BinarySurrogateTypeDescriptor : IBinaryTypeDescriptor
+ {
+ /** Binary configuration. */
+ private readonly BinaryConfiguration _cfg;
+
+ /** Type ID. */
+ private readonly int _id;
+
+ /** Type name. */
+ private readonly string _name;
+
+ /** Type structure. */
+ private volatile BinaryStructure _writerTypeStruct = BinaryStructure.CreateEmpty();
+
+ /** Type structure. */
+ private BinaryStructure _readerTypeStructure = BinaryStructure.CreateEmpty();
+
+ /** Type schema. */
+ private readonly BinaryObjectSchema _schema = new BinaryObjectSchema();
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="cfg">Configuration.</param>
+ /// <param name="id">Type ID.</param>
+ public BinarySurrogateTypeDescriptor(BinaryConfiguration cfg, int id)
+ {
+ _cfg = cfg;
+ _id = id;
+ }
+
+ /// <summary>
+ /// Constrcutor.
+ /// </summary>
+ /// <param name="cfg">Configuration.</param>
+ /// <param name="name">Type name.</param>
+ public BinarySurrogateTypeDescriptor(BinaryConfiguration cfg, string name)
+ {
+ _cfg = cfg;
+ _name = name;
+
+ _id = BinaryUtils.TypeId(name, cfg.DefaultNameMapper, cfg.DefaultIdMapper);
+ }
+
+ /** <inheritDoc /> */
+ public Type Type
+ {
+ get { return null; }
+ }
+
+ /** <inheritDoc /> */
+ public int TypeId
+ {
+ get { return _id; }
+ }
+
+ /** <inheritDoc /> */
+ public string TypeName
+ {
+ get { return _name; }
+ }
+
+ /** <inheritDoc /> */
+ public bool UserType
+ {
+ get { return true; }
+ }
+
+ /** <inheritDoc /> */
+ public bool KeepDeserialized
+ {
+ get { return _cfg.DefaultKeepDeserialized; }
+ }
+
+ /** <inheritDoc /> */
+ public IBinaryNameMapper NameMapper
+ {
+ get { return _cfg.DefaultNameMapper; }
+ }
+
+ /** <inheritDoc /> */
+ public IBinaryIdMapper IdMapper
+ {
+ get { return _cfg.DefaultIdMapper; }
+ }
+
+ /** <inheritDoc /> */
+ public IBinarySerializer Serializer
+ {
+ get { return _cfg.DefaultSerializer; }
+ }
+
+ /** <inheritDoc /> */
+ public string AffinityKeyFieldName
+ {
+ get { return null; }
+ }
+
+ /** <inheritDoc /> */
+ public BinaryStructure WriterTypeStructure
+ {
+ get { return _writerTypeStruct; }
+ }
+
+ public BinaryStructure ReaderTypeStructure
+ {
+ get { return _readerTypeStructure; }
+ }
+
+ /** <inheritDoc /> */
+ public void UpdateWriteStructure(BinaryStructure exp, int pathIdx, IList<BinaryStructureUpdate> updates)
+ {
+ lock (this)
+ {
+ _writerTypeStruct = _writerTypeStruct.Merge(exp, pathIdx, updates);
+ }
+ }
+
+ /** <inheritDoc /> */
+ public void UpdateReadStructure(BinaryStructure exp, int pathIdx, IList<BinaryStructureUpdate> updates)
+ {
+ lock (this)
+ {
+ _readerTypeStructure = _readerTypeStructure.Merge(exp, pathIdx, updates);
+ }
+ }
+
+ /** <inheritDoc /> */
+ public BinaryObjectSchema Schema
+ {
+ get { return _schema; }
+ }
+ }
+}