Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Persistence/3.3/Default/Xml/XmlGenerator.cs @ 3016

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

Update API docs. (#548)

File size: 10.9 KB
Line 
1using System.Collections.Generic;
2using System;
3using System.Text;
4using HeuristicLab.Persistence.Interfaces;
5using HeuristicLab.Persistence.Core;
6using System.IO;
7using ICSharpCode.SharpZipLib.Zip;
8using HeuristicLab.Tracing;
9using HeuristicLab.Persistence.Core.Tokens;
10using System.IO.Compression;
11
12namespace HeuristicLab.Persistence.Default.Xml {
13
14
15  /// <summary>
16  /// Main entry point of persistence to XML. Use the static methods to serialize
17  /// to a file or to a stream.
18  /// </summary>
19  public class XmlGenerator : GeneratorBase<string> {
20
21    private int depth;
22    private int Depth {
23      get {
24        return depth;
25      }
26      set {
27        depth = value;
28        prefix = new string(' ', depth * 2);
29      }
30    }
31
32    private string prefix;
33
34
35    /// <summary>
36    /// Initializes a new instance of the <see cref="XmlGenerator"/> class.
37    /// </summary>
38    public XmlGenerator() {
39      Depth = 0;
40    }
41
42    private enum NodeType { Start, End, Inline } ;
43
44    private static void AddXmlTagContent(StringBuilder sb, string name, Dictionary<string, object> attributes) {
45      sb.Append(name);
46      foreach (var attribute in attributes) {
47        if (attribute.Value != null && !string.IsNullOrEmpty(attribute.Value.ToString())) {
48          sb.Append(' ');
49          sb.Append(attribute.Key);
50          sb.Append("=\"");
51          sb.Append(attribute.Value);
52          sb.Append('"');
53        }
54      }
55    }
56
57    private static void AddXmlStartTag(StringBuilder sb, string name, Dictionary<string, object> attributes) {
58      sb.Append('<');
59      AddXmlTagContent(sb, name, attributes);
60      sb.Append('>');
61    }
62
63    private static void AddXmlInlineTag(StringBuilder sb, string name, Dictionary<string, object> attributes) {
64      sb.Append('<');
65      AddXmlTagContent(sb, name, attributes);
66      sb.Append("/>");
67    }
68
69    private static void AddXmlEndTag(StringBuilder sb, string name) {
70      sb.Append("</");
71      sb.Append(name);
72      sb.Append(">");
73    }
74
75    private string CreateNodeStart(string name, Dictionary<string, object> attributes) {
76      StringBuilder sb = new StringBuilder();
77      sb.Append(prefix);
78      Depth += 1;
79      AddXmlStartTag(sb, name, attributes);
80      sb.Append("\r\n");
81      return sb.ToString();
82    }
83
84    private string CreateNodeStart(string name) {
85      return CreateNodeStart(name, new Dictionary<string, object>());
86    }
87
88    private string CreateNodeEnd(string name) {
89      Depth -= 1;
90      StringBuilder sb = new StringBuilder();
91      sb.Append(prefix);
92      AddXmlEndTag(sb, name);
93      sb.Append("\r\n");
94      return sb.ToString();
95    }
96
97    private string CreateNode(string name, Dictionary<string, object> attributes) {
98      StringBuilder sb = new StringBuilder();
99      sb.Append(prefix);
100      AddXmlInlineTag(sb, name, attributes);
101      sb.Append("\r\n");
102      return sb.ToString();
103    }
104
105    private string CreateNode(string name, Dictionary<string, object> attributes, string content) {
106      StringBuilder sb = new StringBuilder();
107      sb.Append(prefix);
108      AddXmlStartTag(sb, name, attributes);
109      sb.Append(content);
110      sb.Append("</").Append(name).Append(">\r\n");
111      return sb.ToString();
112    }
113
114    protected override string Format(BeginToken beginToken) {
115      var dict = new Dictionary<string, object> {
116          {"name", beginToken.Name},
117          {"typeId", beginToken.TypeId},
118          {"id", beginToken.Id}};
119      AddTypeInfo(beginToken.TypeId, dict);
120      return CreateNodeStart(XmlStringConstants.COMPOSITE, dict);
121       
122    }
123
124    private void AddTypeInfo(int typeId, Dictionary<string, object> dict) {
125      if (lastTypeToken != null) {
126        if (typeId == lastTypeToken.Id) {
127          dict.Add("typeName", lastTypeToken.TypeName);
128          dict.Add("serializer", lastTypeToken.Serializer);
129          lastTypeToken = null;
130        } else {
131          FlushTypeToken();
132        }
133      }
134    }
135
136    protected override string Format(EndToken endToken) {
137      return CreateNodeEnd(XmlStringConstants.COMPOSITE);
138    }
139
140    protected override string Format(PrimitiveToken dataToken) {
141      var dict = new Dictionary<string, object> {
142            {"typeId", dataToken.TypeId},
143            {"name", dataToken.Name},
144            {"id", dataToken.Id}};
145      AddTypeInfo(dataToken.TypeId, dict);
146      return CreateNode(XmlStringConstants.PRIMITIVE, dict,
147        ((XmlString)dataToken.SerialData).Data);
148    }
149
150    protected override string Format(ReferenceToken refToken) {
151      return CreateNode(XmlStringConstants.REFERENCE,
152        new Dictionary<string, object> {
153          {"ref", refToken.Id},
154          {"name", refToken.Name}});
155    }
156
157    protected override string Format(NullReferenceToken nullRefToken) {
158      return CreateNode(XmlStringConstants.NULL,
159        new Dictionary<string, object>{
160          {"name", nullRefToken.Name}});
161    }
162
163    protected override string Format(MetaInfoBeginToken metaInfoBeginToken) {
164      return CreateNodeStart(XmlStringConstants.METAINFO);
165    }
166
167    protected override string Format(MetaInfoEndToken metaInfoEndToken) {
168      return CreateNodeEnd(XmlStringConstants.METAINFO);
169    }
170
171    private TypeToken lastTypeToken;
172    protected override string Format(TypeToken token) {
173      lastTypeToken = token;
174      return "";
175    }
176
177    private string FlushTypeToken() {
178      if (lastTypeToken == null)
179        return "";
180      try {
181        return CreateNode(XmlStringConstants.TYPE,
182          new Dictionary<string, object> {
183          {"id", lastTypeToken.Id},
184          {"typeName", lastTypeToken.TypeName },
185          {"serializer", lastTypeToken.Serializer }});
186      } finally {
187        lastTypeToken = null;
188      }
189    }
190
191    public IEnumerable<string> Format(List<TypeMapping> typeCache) {
192      yield return CreateNodeStart(XmlStringConstants.TYPECACHE);
193      foreach (var mapping in typeCache)
194        yield return CreateNode(
195          XmlStringConstants.TYPE,
196          mapping.GetDict());
197      yield return CreateNodeEnd(XmlStringConstants.TYPECACHE);
198    }
199
200    /// <summary>
201    /// Serialize an object into a file.
202    ///
203    /// The XML configuration is obtained from the <c>ConfigurationService</c>.
204    /// The file is actually a ZIP file.
205    /// Compression level is set to 5 and needed assemblies are not included.
206    /// </summary>   
207    public static void Serialize(object o, string filename) {
208      Serialize(o, filename, ConfigurationService.Instance.GetConfiguration(new XmlFormat()), false, 5);
209    }
210
211    /// <summary>
212    /// Serialize an object into a file.
213    ///
214    /// The XML configuration is obtained from the <c>ConfigurationService</c>.
215    /// Needed assemblies are not included.
216    /// </summary>
217    /// <param name="compression">ZIP file compression level</param>
218    public static void Serialize(object o, string filename, int compression) {
219      Serialize(o, filename, ConfigurationService.Instance.GetConfiguration(new XmlFormat()), false, compression);
220    }
221
222    public static void Serialize(object obj, string filename, Configuration config) {
223      Serialize(obj, filename, config, false, 5);
224    }
225
226    public static void Serialize(object obj, string filename, Configuration config, bool includeAssemblies, int compression) {     
227      try {
228        string tempfile = Path.GetTempFileName();
229        DateTime start = DateTime.Now;
230        using (FileStream stream = File.Create(tempfile)) {
231          Serializer serializer = new Serializer(obj, config);
232          serializer.InterleaveTypeInformation = false;
233          XmlGenerator generator = new XmlGenerator();
234          using (ZipOutputStream zipStream = new ZipOutputStream(stream)) {
235            zipStream.IsStreamOwner = false;
236            zipStream.SetLevel(compression);
237            zipStream.PutNextEntry(new ZipEntry("data.xml") { DateTime = DateTime.MinValue });
238            StreamWriter writer = new StreamWriter(zipStream);
239            foreach (ISerializationToken token in serializer) {
240              string line = generator.Format(token);
241              writer.Write(line);
242            }
243            writer.Flush();
244            zipStream.PutNextEntry(new ZipEntry("typecache.xml") { DateTime = DateTime.MinValue });
245            foreach (string line in generator.Format(serializer.TypeCache)) {
246              writer.Write(line);
247            }
248            writer.Flush();
249            if (includeAssemblies) {
250              foreach (string name in serializer.RequiredFiles) {
251                Uri uri = new Uri(name);
252                if (!uri.IsFile) {
253                  Logger.Warn("cannot read non-local files");
254                  continue;
255                }
256                zipStream.PutNextEntry(new ZipEntry(Path.GetFileName(uri.PathAndQuery)));
257                FileStream reader = File.OpenRead(uri.PathAndQuery);
258                byte[] buffer = new byte[1024 * 1024];
259                while (true) {
260                  int bytesRead = reader.Read(buffer, 0, 1024 * 1024);
261                  if (bytesRead == 0)
262                    break;
263                  zipStream.Write(buffer, 0, bytesRead);
264                }
265                writer.Flush();
266              }
267            }
268          }
269        }
270        Logger.Info(String.Format("serialization took {0} seconds with compression level {1}",
271          (DateTime.Now - start).TotalSeconds, compression));
272        File.Copy(tempfile, filename, true);
273        File.Delete(tempfile);
274      } catch (Exception) {
275        Logger.Warn("Exception caught, no data has been written.");
276        throw;
277      }
278    }
279
280    public static void Serialize(object obj, Stream stream) {
281      Serialize(obj, stream, ConfigurationService.Instance.GetConfiguration(new XmlFormat()));
282    }
283
284
285    public static void Serialize(object obj, Stream stream, Configuration config) {
286      Serialize(obj, stream, config, false);
287    }
288
289    public static void Serialize(object obj, Stream stream, Configuration config, bool includeAssemblies) {
290      Serialize(obj, stream, config, includeAssemblies, true);
291    }
292
293    public static void Serialize(object obj, Stream stream, Configuration config, bool includeAssemblies, bool interleaveTypeInfo) {     
294      try {
295        using (StreamWriter writer = new StreamWriter(new GZipStream(stream, CompressionMode.Compress))) {
296          Serializer serializer = new Serializer(obj, config);
297          serializer.InterleaveTypeInformation = true;
298          XmlGenerator generator = new XmlGenerator();
299          foreach (ISerializationToken token in serializer) {
300            string line = generator.Format(token);
301            writer.Write(line);
302          }
303          writer.Flush();
304        }
305      } catch (PersistenceException) {
306        throw;
307      } catch (Exception e) {
308        throw new PersistenceException("Unexpected exception during Serialization.", e);
309      }
310    }
311  }
312}
Note: See TracBrowser for help on using the repository browser.