Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 1703 was 1703, checked in by epitzer, 16 years ago

Create folder with auxiliary classes. (#606)

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