#region License Information /* HeuristicLab * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using HeuristicLab.Persistence.Auxiliary; using HeuristicLab.Persistence.Core.Tokens; using HeuristicLab.Persistence.Interfaces; namespace HeuristicLab.Persistence.Core { /// /// Core hub for deserialization. Reads the serialization token stream, /// instantiates objects and fills in values. /// public sealed class Deserializer { /// /// Helps in delivering the class instance and acts as proxy while /// the object cannot yet be instantiate. /// private class Midwife { public string Name { get; private set; } public int? Id { get; private set; } public bool MetaMode { get; set; } public object Obj { get; private set; } private List metaInfo; private List customValues; private Type type; private ICompositeSerializer compositeSerializer; public Midwife(object value) { this.Obj = value; } public Midwife(Type type, ICompositeSerializer compositeSerializer, int? id, string name) { this.type = type; this.compositeSerializer = compositeSerializer; this.Id = id; this.Name = name; MetaMode = false; metaInfo = new List(); customValues = new List(); } public void CreateInstance() { if (Obj != null) throw new PersistenceException("object already instantiated"); Obj = compositeSerializer.CreateInstance(type, metaInfo); } public void AddValue(string name, object value) { if (MetaMode) { metaInfo.Add(new Tag(name, value)); } else { customValues.Add(new Tag(name, value)); } } public void Populate() { compositeSerializer.Populate(Obj, customValues, type); } } private readonly Dictionary id2obj; private readonly Stack parentStack; private ReverseTypeCache typeCache; /// /// Instantiates a new deserializer with the given type cache, /// that contains information about the serializers to use /// for every type and their type ids. /// /// The type cache. public Deserializer(ReverseTypeCache typeCache) { this.typeCache = typeCache; id2obj = new Dictionary(); parentStack = new Stack(); } /// /// Process the token stream and deserialize an instantate a new object graph. /// /// The tokens. /// A fresh object filled with fresh data. public object Deserialize(IEnumerable tokens) { foreach (ISerializationToken token in tokens) { Type t = token.GetType(); if (t == typeof(BeginToken)) { CompositeStartHandler((BeginToken)token); } else if (t == typeof(EndToken)) { CompositeEndHandler((EndToken)token); } else if (t == typeof(PrimitiveToken)) { PrimitiveHandler((PrimitiveToken)token); } else if (t == typeof(ReferenceToken)) { ReferenceHandler((ReferenceToken)token); } else if (t == typeof(NullReferenceToken)) { NullHandler((NullReferenceToken)token); } else if (t == typeof(MetaInfoBeginToken)) { MetaInfoBegin((MetaInfoBeginToken)token); } else if (t == typeof(MetaInfoEndToken)) { MetaInfoEnd((MetaInfoEndToken)token); } else if (t == typeof(TypeToken)) { Type((TypeToken)token); } else if (t == typeof(SerializerToken)) { Serializer((SerializerToken)token); } else { throw new PersistenceException("invalid token type"); } } return parentStack.Pop().Obj; } private void InstantiateParent() { if (parentStack.Count == 0) return; Midwife m = parentStack.Peek(); if (!m.MetaMode && m.Obj == null) CreateInstance(m); } private void Type(TypeToken token) { typeCache.AddType(token.Id, TypeLoader.Load(token.TypeName)); } private void Serializer(SerializerToken token) { typeCache.AddSerializer(token.Id, TypeLoader.Load(token.Serializer)); } private void CompositeStartHandler(BeginToken token) { InstantiateParent(); Type type = typeCache.GetType(token.TypeId); try { parentStack.Push(new Midwife(type, typeCache.GetCompositeSerializer(token.TypeId), token.Id, token.Name)); } catch (Exception e) { if (e is InvalidCastException || e is KeyNotFoundException) { throw new PersistenceException(String.Format( "Invalid composite serializer configuration for type \"{0}\".", type.AssemblyQualifiedName), e); } else { throw new PersistenceException(String.Format( "Unexpected exception while trying to compose object of type \"{0}\".", type.AssemblyQualifiedName), e); } } } private void CompositeEndHandler(EndToken token) { Midwife midwife = parentStack.Pop(); if (midwife.Obj == null) CreateInstance(midwife); midwife.Populate(); SetValue(midwife.Name, midwife.Obj); } private void PrimitiveHandler(PrimitiveToken token) { try { object value = typeCache.GetPrimitiveSerializer(token.TypeId).Parse(token.SerialData); if (token.Id != null) id2obj[(int)token.Id] = value; SetValue(token.Name, value); } catch (Exception e) { if (e is InvalidCastException || e is KeyNotFoundException) { throw new PersistenceException(String.Format( "Invalid primitive serializer configuration for type \"{0}\".", typeCache.GetType(token.TypeId).AssemblyQualifiedName), e); } else { throw new PersistenceException(String.Format( "Unexpected exception while trying to parse object of type \"{0}\".", typeCache.GetType(token.TypeId).AssemblyQualifiedName), e); } } } private void ReferenceHandler(ReferenceToken token) { object referredObject = id2obj[token.Id]; SetValue(token.Name, referredObject); } private void NullHandler(NullReferenceToken token) { SetValue(token.Name, null); } private void MetaInfoBegin(MetaInfoBeginToken token) { parentStack.Peek().MetaMode = true; } private void MetaInfoEnd(MetaInfoEndToken token) { Midwife m = parentStack.Peek(); m.MetaMode = false; CreateInstance(m); } private void CreateInstance(Midwife m) { m.CreateInstance(); if (m.Id != null) id2obj.Add((int)m.Id, m.Obj); } private void SetValue(string name, object value) { if (parentStack.Count == 0) { parentStack.Push(new Midwife(value)); } else { Midwife m = parentStack.Peek(); if (m.MetaMode == false && m.Obj == null) { CreateInstance(m); } m.AddValue(name, value); } } } }