Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Persistence/3.3/Core/DeSerializer.cs @ 3016

Last change on this file since 3016 was 3016, checked in by epitzer, 14 years ago

Update API docs. (#548)

File size: 8.3 KB
Line 
1using System.Collections.Generic;
2using System;
3using HeuristicLab.Persistence.Interfaces;
4using HeuristicLab.Persistence.Core.Tokens;
5using HeuristicLab.Persistence.Auxiliary;
6using HeuristicLab.Tracing;
7using System.Reflection;
8
9namespace HeuristicLab.Persistence.Core {
10
11  /// <summary>
12  /// Core hub for deserialization. Reads the serialization token stream,
13  /// instantiates objects and fills in values.
14  /// </summary>
15  public class Deserializer {
16
17    /// <summary>
18    /// Helps in delivering the class instance and acts as proxy while
19    /// the object cannot yet be instantiate.
20    /// </summary>
21    private class Midwife {
22
23      public int? Id { get; private set; }
24      public bool MetaMode { get; set; }
25      public object Obj { get; private set; }
26
27      private List<Tag> metaInfo;
28      private List<Tag> customValues;
29      private Type type;
30      private ICompositeSerializer compositeSerializer;
31
32      public Midwife(object value) {
33        this.Obj = value;
34      }
35
36      public Midwife(Type type, ICompositeSerializer compositeSerializer, int? id) {
37        this.type = type;
38        this.compositeSerializer = compositeSerializer;
39        this.Id = id;
40        MetaMode = false;
41        metaInfo = new List<Tag>();
42        customValues = new List<Tag>();
43      }
44
45      public void CreateInstance() {
46        if (Obj != null)
47          throw new PersistenceException("object already instantiated");
48        Obj = compositeSerializer.CreateInstance(type, metaInfo);
49      }
50
51      public void AddValue(string name, object value) {
52        if (MetaMode) {
53          metaInfo.Add(new Tag(name, value));
54        } else {
55          customValues.Add(new Tag(name, value));
56        }
57      }
58
59      public void Populate() {
60        compositeSerializer.Populate(Obj, customValues, type);
61      }
62    }
63   
64    private readonly Dictionary<int, object> id2obj;
65    private readonly Dictionary<Type, object> serializerMapping;
66    private readonly Stack<Midwife> parentStack;
67    private readonly Dictionary<int, Type> typeIds;
68
69    /// <summary>
70    /// Instantiates a new deserializer with the given type cache,
71    /// that contains information about the serializers to use
72    /// for every type and their type ids.
73    /// </summary>
74    /// <param name="typeCache">The type cache.</param>
75    public Deserializer(
76      IEnumerable<TypeMapping> typeCache) {
77      id2obj = new Dictionary<int, object>();
78      parentStack = new Stack<Midwife>();
79      typeIds = new Dictionary<int, Type>();
80      serializerMapping = new Dictionary<Type, object>();
81      foreach (var typeMapping in typeCache) {
82        AddTypeInfo(typeMapping);
83      }
84    }
85
86    private Dictionary<Type, object> serializerInstances = new Dictionary<Type, object>();
87
88    /// <summary>
89    /// Adds additionaly type information.
90    /// </summary>
91    /// <param name="typeMapping">The new type mapping.</param>
92    public void AddTypeInfo(TypeMapping typeMapping) {
93      if (typeIds.ContainsKey(typeMapping.Id))
94        return;
95      try {
96        Type type = TypeLoader.Load(typeMapping.TypeName);
97        typeIds.Add(typeMapping.Id, type);
98        Type serializerType = TypeLoader.Load(typeMapping.Serializer);
99        object serializer;
100        if (serializerInstances.ContainsKey(serializerType))
101          serializer = serializerInstances[serializerType];
102        else
103          serializer = Activator.CreateInstance(serializerType, true);
104        serializerMapping.Add(type, serializer);
105      } catch (PersistenceException) {
106        throw;
107      } catch (Exception e) {
108        throw new PersistenceException(string.Format(
109          "Could not add type info for {0} ({1})",
110          typeMapping.TypeName, typeMapping.Serializer), e);
111      }
112    }
113
114    /// <summary>
115    /// Process the token stream and deserialize an instantate a new object graph.
116    /// </summary>
117    /// <param name="tokens">The tokens.</param>
118    /// <returns>A fresh object filled with fresh data.</returns>
119    public object Deserialize(IEnumerable<ISerializationToken> tokens) {
120      foreach (ISerializationToken token in tokens) {
121        Type t = token.GetType();
122        if (t == typeof(BeginToken)) {
123          CompositeStartHandler((BeginToken)token);
124        } else if (t == typeof(EndToken)) {
125          CompositeEndHandler((EndToken)token);
126        } else if (t == typeof(PrimitiveToken)) {
127          PrimitiveHandler((PrimitiveToken)token);
128        } else if (t == typeof(ReferenceToken)) {
129          ReferenceHandler((ReferenceToken)token);
130        } else if (t == typeof(NullReferenceToken)) {
131          NullHandler((NullReferenceToken)token);
132        } else if (t == typeof(MetaInfoBeginToken)) {
133          MetaInfoBegin((MetaInfoBeginToken)token);
134        } else if (t == typeof(MetaInfoEndToken)) {
135          MetaInfoEnd((MetaInfoEndToken)token);
136        } else if (t == typeof(TypeToken)) {
137          Type((TypeToken)token);
138        } else {
139          throw new PersistenceException("invalid token type");
140        }
141      }
142      return parentStack.Pop().Obj;
143    }
144
145    private void InstantiateParent() {
146      if (parentStack.Count == 0)
147        return;
148      Midwife m = parentStack.Peek();
149      if (!m.MetaMode && m.Obj == null)
150        CreateInstance(m);
151    }
152
153    private void Type(TypeToken token) {
154      AddTypeInfo(new TypeMapping(token.Id, token.TypeName, token.Serializer));
155    }
156
157    private void CompositeStartHandler(BeginToken token) {
158      InstantiateParent();
159      Type type = typeIds[(int)token.TypeId];
160      try {
161        parentStack.Push(new Midwife(type, (ICompositeSerializer)serializerMapping[type], token.Id));
162      } catch (Exception e) {
163        if (e is InvalidCastException || e is KeyNotFoundException) {
164          throw new PersistenceException(String.Format(
165            "Invalid composite serializer configuration for type \"{0}\".",
166            type.AssemblyQualifiedName), e);
167        } else {
168          throw new PersistenceException(String.Format(
169            "Unexpected exception while trying to compose object of type \"{0}\".",
170            type.AssemblyQualifiedName), e);
171        }
172      }
173    }
174
175    private void CompositeEndHandler(EndToken token) {
176      Type type = typeIds[(int)token.TypeId];
177      Midwife midwife = parentStack.Pop();
178      if (midwife.Obj == null)
179        CreateInstance(midwife);
180      midwife.Populate();
181      SetValue(token.Name, midwife.Obj);
182    }
183
184    private void PrimitiveHandler(PrimitiveToken token) {
185      Type type = typeIds[(int)token.TypeId];
186      try {
187        object value = ((IPrimitiveSerializer)serializerMapping[type]).Parse(token.SerialData);
188        if (token.Id != null)
189          id2obj[(int)token.Id] = value;
190        SetValue(token.Name, value);
191      } catch (Exception e) {
192        if (e is InvalidCastException || e is KeyNotFoundException) {
193          throw new PersistenceException(String.Format(
194            "Invalid primitive serializer configuration for type \"{0}\".",
195            type.AssemblyQualifiedName), e);
196        } else {
197          throw new PersistenceException(String.Format(
198            "Unexpected exception while trying to parse object of type \"{0}\".",
199            type.AssemblyQualifiedName), e);
200        }
201      }
202    }
203
204    private void ReferenceHandler(ReferenceToken token) {
205      object referredObject = id2obj[token.Id];
206      SetValue(token.Name, referredObject);
207    }
208
209    private void NullHandler(NullReferenceToken token) {
210      SetValue(token.Name, null);
211    }
212
213    private void MetaInfoBegin(MetaInfoBeginToken token) {
214      parentStack.Peek().MetaMode = true;
215    }
216
217    private void MetaInfoEnd(MetaInfoEndToken token) {
218      Midwife m = parentStack.Peek();
219      m.MetaMode = false;
220      CreateInstance(m);
221    }
222
223    private void CreateInstance(Midwife m) {
224      m.CreateInstance();
225      if (m.Id != null)
226        id2obj.Add((int)m.Id, m.Obj);
227    }
228
229    private void SetValue(string name, object value) {
230      if (parentStack.Count == 0) {
231        parentStack.Push(new Midwife(value));
232      } else {
233        Midwife m = parentStack.Peek();
234        if (m.MetaMode == false && m.Obj == null) {
235          CreateInstance(m);
236        }
237        m.AddValue(name, value);
238      }
239    }
240  }
241}
Note: See TracBrowser for help on using the repository browser.