Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceSpeedUp/HeuristicLab.Persistence/3.3/Core/DeSerializer.cs @ 16574

Last change on this file since 16574 was 6737, checked in by epitzer, 13 years ago

#1530 Split type and serializer tokens and include special handling for CachedTypeSerializer (this should also fix #1527)

File size: 8.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using HeuristicLab.Persistence.Auxiliary;
25using HeuristicLab.Persistence.Core.Tokens;
26using HeuristicLab.Persistence.Interfaces;
27
28namespace HeuristicLab.Persistence.Core {
29
30  /// <summary>
31  /// Core hub for deserialization. Reads the serialization token stream,
32  /// instantiates objects and fills in values.
33  /// </summary>
34  public sealed class Deserializer {
35
36    /// <summary>
37    /// Helps in delivering the class instance and acts as proxy while
38    /// the object cannot yet be instantiate.
39    /// </summary>
40    private class Midwife {
41
42      public string Name { get; private set; }
43      public int? Id { get; private set; }
44      public bool MetaMode { get; set; }
45      public object Obj { get; private set; }
46
47      private List<Tag> metaInfo;
48      private List<Tag> customValues;
49      private Type type;
50      private ICompositeSerializer compositeSerializer;
51
52      public Midwife(object value) {
53        this.Obj = value;
54      }
55
56      public Midwife(Type type, ICompositeSerializer compositeSerializer, int? id, string name) {
57        this.type = type;
58        this.compositeSerializer = compositeSerializer;
59        this.Id = id;
60        this.Name = name;
61        MetaMode = false;
62        metaInfo = new List<Tag>();
63        customValues = new List<Tag>();
64      }
65
66      public void CreateInstance() {
67        if (Obj != null)
68          throw new PersistenceException("object already instantiated");
69        Obj = compositeSerializer.CreateInstance(type, metaInfo);
70      }
71
72      public void AddValue(string name, object value) {
73        if (MetaMode) {
74          metaInfo.Add(new Tag(name, value));
75        } else {
76          customValues.Add(new Tag(name, value));
77        }
78      }
79
80      public void Populate() {
81        compositeSerializer.Populate(Obj, customValues, type);
82      }
83    }
84
85    private readonly Dictionary<int, object> id2obj;
86    private readonly Stack<Midwife> parentStack;
87    private ReverseTypeCache typeCache;
88
89    /// <summary>
90    /// Instantiates a new deserializer with the given type cache,
91    /// that contains information about the serializers to use
92    /// for every type and their type ids.
93    /// </summary>
94    /// <param name="typeCache">The type cache.</param>
95    public Deserializer(ReverseTypeCache typeCache) {
96      this.typeCache = typeCache;
97      id2obj = new Dictionary<int, object>();
98      parentStack = new Stack<Midwife>();
99    }
100
101    /// <summary>
102    /// Process the token stream and deserialize an instantate a new object graph.
103    /// </summary>
104    /// <param name="tokens">The tokens.</param>
105    /// <returns>A fresh object filled with fresh data.</returns>
106    public object Deserialize(IEnumerable<ISerializationToken> tokens) {
107      foreach (ISerializationToken token in tokens) {
108        Type t = token.GetType();
109        if (t == typeof(BeginToken)) {
110          CompositeStartHandler((BeginToken)token);
111        } else if (t == typeof(EndToken)) {
112          CompositeEndHandler((EndToken)token);
113        } else if (t == typeof(PrimitiveToken)) {
114          PrimitiveHandler((PrimitiveToken)token);
115        } else if (t == typeof(ReferenceToken)) {
116          ReferenceHandler((ReferenceToken)token);
117        } else if (t == typeof(NullReferenceToken)) {
118          NullHandler((NullReferenceToken)token);
119        } else if (t == typeof(MetaInfoBeginToken)) {
120          MetaInfoBegin((MetaInfoBeginToken)token);
121        } else if (t == typeof(MetaInfoEndToken)) {
122          MetaInfoEnd((MetaInfoEndToken)token);
123        } else if (t == typeof(TypeToken)) {
124          Type((TypeToken)token);
125        } else if (t == typeof(SerializerToken)) {
126          Serializer((SerializerToken)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 Type(TypeToken token) {
143      typeCache.AddType(token.Id, TypeLoader.Load(token.TypeName));
144    }
145
146    private void Serializer(SerializerToken token) {
147      typeCache.AddSerializer(token.Id, TypeLoader.Load(token.Serializer));
148    }
149
150    private void CompositeStartHandler(BeginToken token) {
151      InstantiateParent();
152      Type type = typeCache.GetType(token.TypeId);
153      try {
154        parentStack.Push(new Midwife(type, typeCache.GetCompositeSerializer(token.TypeId), token.Id, token.Name));
155      } catch (Exception e) {
156        if (e is InvalidCastException || e is KeyNotFoundException) {
157          throw new PersistenceException(String.Format(
158            "Invalid composite serializer configuration for type \"{0}\".",
159            type.AssemblyQualifiedName), e);
160        } else {
161          throw new PersistenceException(String.Format(
162            "Unexpected exception while trying to compose object of type \"{0}\".",
163            type.AssemblyQualifiedName), e);
164        }
165      }
166    }
167
168    private void CompositeEndHandler(EndToken token) {
169      Midwife midwife = parentStack.Pop();
170      if (midwife.Obj == null)
171        CreateInstance(midwife);
172      midwife.Populate();
173      SetValue(midwife.Name, midwife.Obj);
174    }
175
176    private void PrimitiveHandler(PrimitiveToken token) {
177      try {
178        object value = typeCache.GetPrimitiveSerializer(token.TypeId).Parse(token.SerialData);
179        if (token.Id != null)
180          id2obj[(int)token.Id] = value;
181        SetValue(token.Name, value);
182      } catch (Exception e) {
183        if (e is InvalidCastException || e is KeyNotFoundException) {
184          throw new PersistenceException(String.Format(
185            "Invalid primitive serializer configuration for type \"{0}\".",
186            typeCache.GetType(token.TypeId).AssemblyQualifiedName), e);
187        } else {
188          throw new PersistenceException(String.Format(
189            "Unexpected exception while trying to parse object of type \"{0}\".",
190            typeCache.GetType(token.TypeId).AssemblyQualifiedName), e);
191        }
192      }
193    }
194
195    private void ReferenceHandler(ReferenceToken token) {
196      object referredObject = id2obj[token.Id];
197      SetValue(token.Name, referredObject);
198    }
199
200    private void NullHandler(NullReferenceToken token) {
201      SetValue(token.Name, null);
202    }
203
204    private void MetaInfoBegin(MetaInfoBeginToken token) {
205      parentStack.Peek().MetaMode = true;
206    }
207
208    private void MetaInfoEnd(MetaInfoEndToken token) {
209      Midwife m = parentStack.Peek();
210      m.MetaMode = false;
211      CreateInstance(m);
212    }
213
214    private void CreateInstance(Midwife m) {
215      m.CreateInstance();
216      if (m.Id != null)
217        id2obj.Add((int)m.Id, m.Obj);
218    }
219
220    private void SetValue(string name, object value) {
221      if (parentStack.Count == 0) {
222        parentStack.Push(new Midwife(value));
223      } else {
224        Midwife m = parentStack.Peek();
225        if (m.MetaMode == false && m.Obj == null) {
226          CreateInstance(m);
227        }
228        m.AddValue(name, value);
229      }
230    }
231  }
232}
Note: See TracBrowser for help on using the repository browser.