Free cookie consent management tool by TermsFeed Policy Generator

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

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

add complete persistence API docs (#548)

File size: 7.8 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    public Deserializer(
75      IEnumerable<TypeMapping> typeCache) {
76      id2obj = new Dictionary<int, object>();
77      parentStack = new Stack<Midwife>();
78      typeIds = new Dictionary<int, Type>();
79      serializerMapping = CreateSerializers(typeCache);
80    }
81
82    private Dictionary<Type, object> CreateSerializers(IEnumerable<TypeMapping> typeCache) {
83      Dictionary<Type, object> serializerInstances = new Dictionary<Type, object>();
84      try {
85        var map = new Dictionary<Type, object>();
86        foreach (var typeMapping in typeCache) {
87          Type type = TypeLoader.Load(typeMapping.TypeName);
88          typeIds.Add(typeMapping.Id, type);
89          Type serializerType = TypeLoader.Load(typeMapping.Serializer);
90          object serializer;
91          if (serializerInstances.ContainsKey(serializerType))
92            serializer = serializerInstances[serializerType];
93          else
94            serializer = Activator.CreateInstance(serializerType, true);
95          map.Add(type, serializer);
96        }
97        return map;
98      } catch (PersistenceException) {
99        throw;
100      } catch (Exception e) {
101        throw new PersistenceException(
102          "The serialization type cache could not be loaded.\r\n" +
103          "This usualy happens when you are missing an Assembly or Plugin.", e);
104      }
105    }
106
107    /// <summary>
108    /// Process the token stream and deserialize an instantate a new object graph.
109    /// </summary>   
110    public object Deserialize(IEnumerable<ISerializationToken> tokens) {
111      foreach (ISerializationToken token in tokens) {
112        Type t = token.GetType();
113        if (t == typeof(BeginToken)) {
114          CompositeStartHandler((BeginToken)token);
115        } else if (t == typeof(EndToken)) {
116          CompositeEndHandler((EndToken)token);
117        } else if (t == typeof(PrimitiveToken)) {
118          PrimitiveHandler((PrimitiveToken)token);
119        } else if (t == typeof(ReferenceToken)) {
120          ReferenceHandler((ReferenceToken)token);
121        } else if (t == typeof(NullReferenceToken)) {
122          NullHandler((NullReferenceToken)token);
123        } else if (t == typeof(MetaInfoBeginToken)) {
124          MetaInfoBegin((MetaInfoBeginToken)token);
125        } else if (t == typeof(MetaInfoEndToken)) {
126          MetaInfoEnd((MetaInfoEndToken)token);
127        } else {
128          throw new PersistenceException("invalid token type");
129        }
130      }
131      return parentStack.Pop().Obj;
132    }
133
134    private void InstantiateParent() {
135      if (parentStack.Count == 0)
136        return;
137      Midwife m = parentStack.Peek();
138      if (!m.MetaMode && m.Obj == null)
139        CreateInstance(m);
140    }
141
142    private void CompositeStartHandler(BeginToken token) {
143      InstantiateParent();
144      Type type = typeIds[(int)token.TypeId];
145      try {
146        parentStack.Push(new Midwife(type, (ICompositeSerializer)serializerMapping[type], token.Id));
147      } catch (Exception e) {
148        if (e is InvalidCastException || e is KeyNotFoundException) {
149          throw new PersistenceException(String.Format(
150            "Invalid composite serializer configuration for type \"{0}\".",
151            type.AssemblyQualifiedName), e);
152        } else {
153          throw new PersistenceException(String.Format(
154            "Unexpected exception while trying to compose object of type \"{0}\".",
155            type.AssemblyQualifiedName), e);
156        }
157      }
158    }
159
160    private void CompositeEndHandler(EndToken token) {
161      Type type = typeIds[(int)token.TypeId];
162      Midwife midwife = parentStack.Pop();
163      if (midwife.Obj == null)
164        CreateInstance(midwife);
165      midwife.Populate();
166      SetValue(token.Name, midwife.Obj);
167    }
168
169    private void PrimitiveHandler(PrimitiveToken token) {
170      Type type = typeIds[(int)token.TypeId];
171      try {
172        object value = ((IPrimitiveSerializer)serializerMapping[type]).Parse(token.SerialData);
173        if (token.Id != null)
174          id2obj[(int)token.Id] = value;
175        SetValue(token.Name, value);
176      } catch (Exception e) {
177        if (e is InvalidCastException || e is KeyNotFoundException) {
178          throw new PersistenceException(String.Format(
179            "Invalid primitive serializer configuration for type \"{0}\".",
180            type.AssemblyQualifiedName), e);
181        } else {
182          throw new PersistenceException(String.Format(
183            "Unexpected exception while trying to parse object of type \"{0}\".",
184            type.AssemblyQualifiedName), e);
185        }
186      }
187    }
188
189    private void ReferenceHandler(ReferenceToken token) {
190      object referredObject = id2obj[token.Id];
191      SetValue(token.Name, referredObject);
192    }
193
194    private void NullHandler(NullReferenceToken token) {
195      SetValue(token.Name, null);
196    }
197
198    private void MetaInfoBegin(MetaInfoBeginToken token) {
199      parentStack.Peek().MetaMode = true;
200    }
201
202    private void MetaInfoEnd(MetaInfoEndToken token) {
203      Midwife m = parentStack.Peek();
204      m.MetaMode = false;
205      CreateInstance(m);
206    }
207
208    private void CreateInstance(Midwife m) {
209      m.CreateInstance();
210      if (m.Id != null)
211        id2obj.Add((int)m.Id, m.Obj);
212    }
213
214    private void SetValue(string name, object value) {
215      if (parentStack.Count == 0) {
216        parentStack.Push(new Midwife(value));
217      } else {
218        Midwife m = parentStack.Peek();
219        if (m.MetaMode == false && m.Obj == null) {
220          CreateInstance(m);
221        }
222        m.AddValue(name, value);
223      }
224    }
225  }
226}
Note: See TracBrowser for help on using the repository browser.