Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceSpeedUp/HeuristicLab.Persistence/3.3/Default/Xml/XmlParser.cs @ 6737

Last change on this file since 6737 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: 11.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;
24using System.Collections.Generic;
25using System.IO;
26using System.IO.Compression;
27using System.Xml;
28using HeuristicLab.Persistence.Auxiliary;
29using HeuristicLab.Persistence.Core;
30using HeuristicLab.Persistence.Core.Tokens;
31using HeuristicLab.Persistence.Interfaces;
32using ICSharpCode.SharpZipLib.Zip;
33
34namespace HeuristicLab.Persistence.Default.Xml {
35
36  /// <summary>
37  /// Main entry point of persistence loading from XML. Use the static
38  /// methods to load from a file or stream.
39  /// </summary>
40  public class XmlParser : IEnumerable<ISerializationToken> {
41
42    private readonly XmlTextReader reader;
43    private delegate IEnumerator<ISerializationToken> Handler();
44    private readonly Dictionary<string, Handler> handlers;
45
46    /// <summary>
47    /// Initializes a new instance of the <see cref="XmlParser"/> class.
48    /// </summary>
49    /// <param name="input">The input.</param>
50    public XmlParser(TextReader input) {
51      reader = new XmlTextReader(input);
52      reader.WhitespaceHandling = WhitespaceHandling.All;
53      reader.Normalization = false;
54      handlers = new Dictionary<string, Handler> {
55                     {XmlStringConstants.PRIMITIVE, ParsePrimitive},
56                     {XmlStringConstants.COMPOSITE, ParseComposite},
57                     {XmlStringConstants.REFERENCE, ParseReference},
58                     {XmlStringConstants.NULL, ParseNull},
59                     {XmlStringConstants.METAINFO, ParseMetaInfo},
60                     {XmlStringConstants.TYPE, ParseTypeInfo},
61                     {XmlStringConstants.SERIALIZER, ParseSerializer},
62                   };
63    }
64
65    /// <summary>
66    /// Returns an enumerator that iterates through the serialization tokens.
67    /// </summary>
68    /// <returns>
69    /// An that can be used to iterate through the collection of serialization tokens.
70    /// </returns>
71    public IEnumerator<ISerializationToken> GetEnumerator() {
72      while (reader.Read()) {
73        if (!reader.IsStartElement()) {
74          break;
75        }
76        IEnumerator<ISerializationToken> iterator;
77        try {
78          iterator = handlers[reader.Name].Invoke();
79        } catch (KeyNotFoundException) {
80          throw new PersistenceException(String.Format(
81            "Invalid XML tag \"{0}\" in persistence file.",
82            reader.Name));
83        }
84        while (iterator.MoveNext()) {
85          yield return iterator.Current;
86        }
87      }
88    }
89
90    /// <summary>
91    /// Returns an enumerator that iterates through the serialization tokens.
92    /// </summary>
93    /// <returns>
94    /// An that can be used to iterate through the collection of serialization tokens.
95    /// </returns>
96    IEnumerator IEnumerable.GetEnumerator() {
97      return GetEnumerator();
98    }
99
100    private IEnumerator<ISerializationToken> ParsePrimitive() {
101      int? id = null;
102      string idString = reader.GetAttribute("id");
103      if (idString != null)
104        id = int.Parse(idString);
105      string name = reader.GetAttribute("name");
106      int typeId = int.Parse(reader.GetAttribute("typeId"));
107      string typeName = reader.GetAttribute("typeName");
108      string serializer = reader.GetAttribute("serializer");
109      if (typeName != null)
110        yield return new TypeToken(typeId, typeName);
111      if (serializer != null)
112        yield return new SerializerToken(typeId, serializer);
113      XmlReader inner = reader.ReadSubtree();
114      inner.Read();
115      string xml = inner.ReadInnerXml();
116      inner.Close();
117      yield return new PrimitiveToken(name, typeId, id, new XmlString(xml));
118    }
119
120    private IEnumerator<ISerializationToken> ParseComposite() {
121      string name = reader.GetAttribute("name");
122      string idString = reader.GetAttribute("id");
123      int? id = null;
124      if (idString != null)
125        id = int.Parse(idString);
126      int typeId = int.Parse(reader.GetAttribute("typeId"));
127      string typeName = reader.GetAttribute("typeName");
128      string serializer = reader.GetAttribute("serializer");
129      if (typeName != null)
130        yield return new TypeToken(typeId, typeName);
131      if (serializer != null)
132        yield return new SerializerToken(typeId, serializer);
133      yield return new BeginToken(name, typeId, id);
134      IEnumerator<ISerializationToken> iterator = GetEnumerator();
135      while (iterator.MoveNext())
136        yield return iterator.Current;
137      yield return new EndToken();
138    }
139
140    private IEnumerator<ISerializationToken> ParseReference() {
141      yield return new ReferenceToken(
142        reader.GetAttribute("name"),
143        int.Parse(reader.GetAttribute("ref")));
144    }
145
146    private IEnumerator<ISerializationToken> ParseNull() {
147      yield return new NullReferenceToken(reader.GetAttribute("name"));
148    }
149
150    private IEnumerator<ISerializationToken> ParseMetaInfo() {
151      yield return new MetaInfoBeginToken();
152      IEnumerator<ISerializationToken> iterator = GetEnumerator();
153      while (iterator.MoveNext())
154        yield return iterator.Current;
155      yield return new MetaInfoEndToken();
156    }
157
158    private IEnumerator<ISerializationToken> ParseTypeInfo() {
159      int id = int.Parse(reader.GetAttribute("id"));
160      string typeName = reader.GetAttribute("typeName");
161      yield return new TypeToken(id, typeName);
162      string serializer = reader.GetAttribute("serializer");
163      if (serializer != null)
164        yield return new SerializerToken(id, serializer);
165    }
166
167    private IEnumerator<ISerializationToken> ParseSerializer() {
168      int id = int.Parse(reader.GetAttribute("id"));
169      string serializer = reader.GetAttribute("serializer");
170      yield return new SerializerToken(id, serializer);
171    }
172
173    /// <summary>
174    /// Parses the type cache.
175    /// </summary>
176    /// <param name="reader">The reader.</param>
177    /// <returns>A list of type mapping entries.</returns>
178    public static ReverseTypeCache ParseTypeCache(TextReader reader) {
179      ReverseTypeCache typeCache = new ReverseTypeCache();
180      try {
181        XmlReader xmlReader = XmlReader.Create(reader);
182        while (xmlReader.Read()) {
183          if (xmlReader.Name == XmlStringConstants.TYPE) {
184            int id = int.Parse(xmlReader.GetAttribute("id"));
185            typeCache.AddType(id, TypeLoader.Load(xmlReader.GetAttribute("typeName")));
186            string serializer = xmlReader.GetAttribute("serializer");
187            if (serializer != null)
188              typeCache.AddSerializer(id, TypeLoader.Load(serializer));
189          } else if (xmlReader.Name == XmlStringConstants.SERIALIZER) {
190            typeCache.AddSerializer(
191              int.Parse(xmlReader.GetAttribute("id")),
192              TypeLoader.Load(xmlReader.GetAttribute("serializer")));
193          }
194        }
195        return typeCache;
196      } catch (PersistenceException) {
197        throw;
198      } catch (Exception e) {
199        throw new PersistenceException("Unexpected exception during type cache parsing.", e);
200      }
201    }
202
203    /// <summary>
204    /// Deserializes an object from the specified filename.
205    /// </summary>
206    /// <param name="filename">The filename.</param>
207    /// <returns>A fresh object instance</returns>
208    public static object Deserialize(string filename) {
209      TimeSpan start = System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime;
210      try {
211        using (ZipFile file = new ZipFile(filename)) {
212          return Deserialize(file);
213        }
214      } finally {
215        TimeSpan end = System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime;
216        Tracing.Logger.Info(string.Format(
217          "deserialization of {0} took {1} seconds",
218          filename, (end - start).TotalSeconds));
219      }
220    }
221
222    /// <summary>
223    /// Deserializes the specified filename.
224    /// </summary>
225    /// <typeparam name="T">object type expected from the serialized file</typeparam>
226    /// <param name="filename">The filename.</param>
227    /// <returns>A fresh object of type T</returns>
228    public static T Deserialize<T>(string filename) {
229      return (T)Deserialize(filename);
230    }
231
232
233    /// <summary>
234    /// Deserializes an object from the specified stream.
235    /// </summary>
236    /// <param name="stream">The stream.</param>
237    /// <returns>A fresh object instance.</returns>
238    public static object Deserialize(Stream stream) {
239      try {
240        using (StreamReader reader = new StreamReader(new GZipStream(stream, CompressionMode.Decompress))) {
241          XmlParser parser = new XmlParser(reader);
242          Deserializer deserializer = new Deserializer(new ReverseTypeCache());
243          return deserializer.Deserialize(new AsyncBuffer<ISerializationToken>(parser));
244        }
245      } catch (PersistenceException) {
246        throw;
247      } catch (Exception x) {
248        throw new PersistenceException("Unexpected exception during deserialization", x);
249      }
250    }
251
252    /// <summary>
253    /// Deserializes an object from the specified stream.
254    /// </summary>
255    /// <typeparam name="T">object type expected from the serialized stream</typeparam>
256    /// <param name="stream">The stream.</param>
257    /// <returns>A fresh object instance.</returns>
258    public static T Deserialize<T>(Stream stream) {
259      return (T)Deserialize(stream);
260    }
261
262    private static object Deserialize(ZipFile zipFile) {
263      try {
264        ZipEntry typecache = zipFile.GetEntry("typecache.xml");
265        if (typecache == null)
266          throw new PersistenceException("file does not contain typecache.xml");
267        Deserializer deSerializer = new Deserializer(ParseTypeCache(new StreamReader(zipFile.GetInputStream(typecache))));
268        ZipEntry data = zipFile.GetEntry("data.xml");
269        if (data == null)
270          throw new PersistenceException("file does not contain data.xml");
271        XmlParser parser = new XmlParser(
272          new StreamReader(zipFile.GetInputStream(data)));
273        object result = deSerializer.Deserialize(new AsyncBuffer<ISerializationToken>(parser));
274        zipFile.Close();
275        return result;
276      } catch (PersistenceException) {
277        throw;
278      } catch (Exception e) {
279        throw new PersistenceException("Unexpected exception during deserialization", e);
280      }
281    }
282  }
283}
Note: See TracBrowser for help on using the repository browser.