Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 1780 was 1780, checked in by epitzer, 15 years ago

Store full version information with serialized data, only fall back to version invariant format if loading fails with full version. Also check, that loaded version is newer than requested version if possible. (#613)

File size: 7.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  public class TypeLoader {
12
13    public static Type Load(string typeNameString) {
14      Type type;
15      try {
16        type = Type.GetType(typeNameString, true);
17      } catch (Exception) {
18        Logger.Warn(String.Format(
19          "Cannot load type \"{0}\", falling back to loading with partial name", typeNameString));
20        try {
21          TypeName typeName = TypeNameParser.Parse(typeNameString);
22          Assembly a = Assembly.LoadWithPartialName(typeName.AssemblyName);
23          type = a.GetType(typeName.ToString(false, false), true);
24        } catch (Exception) {
25          throw new PersistenceException(String.Format(
26            "Could not load type \"{0}\"",
27            typeNameString));
28        }
29        try {
30          if (
31            TypeNameParser.Parse(type.AssemblyQualifiedName).IsOlderThan(
32            TypeNameParser.Parse(typeNameString)))
33            throw new PersistenceException(String.Format(
34              "Serialized type is newer than available type: serialized: {0}, loaded: {1}",
35              typeNameString,
36              type.AssemblyQualifiedName));
37        } catch (PersistenceException) {
38          throw;
39        } catch (Exception e) {
40          Logger.Warn(String.Format(
41            "Could not perform version check requested type was {0} while loaded type is {1}:",
42            typeNameString,
43            type.AssemblyQualifiedName),
44            e);
45        }
46      }
47      return type;
48    }
49
50  }
51
52  public class Deserializer {
53
54    class Midwife {
55
56      public int? Id { get; private set; }
57      public bool MetaMode { get; set; }
58      public object Obj { get; private set; }
59
60      private List<Tag> metaInfo;
61      private List<Tag> customValues;
62      private Type type;
63      private IDecomposer decomposer;
64
65      public Midwife(object value) {
66        this.Obj = value;
67      }
68
69      public Midwife(Type type, IDecomposer decomposer, int? id) {
70        this.type = type;
71        this.decomposer = decomposer;
72        this.Id = id;
73        MetaMode = false;
74        metaInfo = new List<Tag>();
75        customValues = new List<Tag>();
76      }
77
78      public void CreateInstance() {
79        if (Obj != null)
80          throw new PersistenceException("object already instantiated");
81        Obj = decomposer.CreateInstance(type, metaInfo);
82      }
83
84      public void AddValue(string name, object value) {
85        if (MetaMode) {
86          metaInfo.Add(new Tag(name, value));
87        } else {
88          customValues.Add(new Tag(name, value));
89        }
90      }
91
92      public void Populate() {
93        decomposer.Populate(Obj, customValues, type);
94      }
95    }
96
97    private readonly Dictionary<int, object> id2obj;
98    private readonly Dictionary<Type, object> serializerMapping;
99    private readonly Stack<Midwife> parentStack;
100    private readonly Dictionary<int, Type> typeIds;
101
102    public Deserializer(
103      IEnumerable<TypeMapping> typeCache) {
104      id2obj = new Dictionary<int, object>();
105      parentStack = new Stack<Midwife>();
106      typeIds = new Dictionary<int, Type>();
107      serializerMapping = CreateSerializers(typeCache);
108    }
109
110    private Dictionary<Type, object> CreateSerializers(IEnumerable<TypeMapping> typeCache) {
111      try {
112        var map = new Dictionary<Type, object>();
113        foreach (var typeMapping in typeCache) {
114          Type type = TypeLoader.Load(typeMapping.TypeName);
115          typeIds.Add(typeMapping.Id, type);
116          Type serializerType = TypeLoader.Load(typeMapping.Serializer);
117          map.Add(type, Activator.CreateInstance(serializerType, true));
118        }
119        return map;
120      } catch (PersistenceException) {
121        throw;
122      } catch (Exception e) {
123        throw new PersistenceException(
124          "The serialization type cache could not be loaded.\r\n" +
125          "This usualy happens when you are missing an Assembly/Plugin.", e);
126      }
127    }
128
129
130    public object Deserialize(IEnumerable<ISerializationToken> tokens) {
131      foreach (ISerializationToken token in tokens) {
132        Type t = token.GetType();
133        if (t == typeof(BeginToken)) {
134          CompositeStartHandler((BeginToken)token);
135        } else if (t == typeof(EndToken)) {
136          CompositeEndHandler((EndToken)token);
137        } else if (t == typeof(PrimitiveToken)) {
138          PrimitiveHandler((PrimitiveToken)token);
139        } else if (t == typeof(ReferenceToken)) {
140          ReferenceHandler((ReferenceToken)token);
141        } else if (t == typeof(NullReferenceToken)) {
142          NullHandler((NullReferenceToken)token);
143        } else if (t == typeof(MetaInfoBeginToken)) {
144          MetaInfoBegin((MetaInfoBeginToken)token);
145        } else if (t == typeof(MetaInfoEndToken)) {
146          MetaInfoEnd((MetaInfoEndToken)token);
147        } else {
148          throw new PersistenceException("invalid token type");
149        }
150      }
151      return parentStack.Pop().Obj;
152    }
153
154    private void CompositeStartHandler(BeginToken token) {
155      Type type = typeIds[(int)token.TypeId];
156      IDecomposer decomposer = null;
157      if (serializerMapping.ContainsKey(type))
158        decomposer = serializerMapping[type] as IDecomposer;
159      if (decomposer == null)
160        throw new PersistenceException(String.Format(
161          "No suitable method for deserialization of type \"{0}\" found.",
162          type.VersionInvariantName()));
163      parentStack.Push(new Midwife(type, decomposer, token.Id));
164    }
165
166    private void CompositeEndHandler(EndToken token) {
167      Type type = typeIds[(int)token.TypeId];
168      Midwife midwife = parentStack.Pop();
169      if (midwife.Obj == null)
170        CreateInstance(midwife);
171      midwife.Populate();
172      SetValue(token.Name, midwife.Obj);
173    }
174
175    private void PrimitiveHandler(PrimitiveToken token) {
176      Type type = typeIds[(int)token.TypeId];
177      object value = ((IFormatter)serializerMapping[type]).Parse(token.SerialData);
178      if (token.Id != null)
179        id2obj[(int)token.Id] = value;
180      SetValue(token.Name, value);
181    }
182
183    private void ReferenceHandler(ReferenceToken token) {
184      object referredObject = id2obj[token.Id];
185      SetValue(token.Name, referredObject);
186    }
187
188    private void NullHandler(NullReferenceToken token) {
189      SetValue(token.Name, null);
190    }
191
192    private void MetaInfoBegin(MetaInfoBeginToken token) {
193      parentStack.Peek().MetaMode = true;
194    }
195
196    private void MetaInfoEnd(MetaInfoEndToken token) {
197      Midwife m = parentStack.Peek();
198      m.MetaMode = false;
199      CreateInstance(m);
200    }
201
202    private void CreateInstance(Midwife m) {
203      m.CreateInstance();
204      if (m.Id != null)
205        id2obj.Add((int)m.Id, m.Obj);
206    }
207
208    private void SetValue(string name, object value) {
209      if (parentStack.Count == 0) {
210        parentStack.Push(new Midwife(value));
211      } else {
212        Midwife m = parentStack.Peek();
213        if (m.MetaMode == false && m.Obj == null)
214          CreateInstance(m);
215        m.AddValue(name, value);
216      }
217    }
218  }
219}
Note: See TracBrowser for help on using the repository browser.