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, 15 years ago

Update API docs. (#548)

File size: 10.9 KB
RevLine 
[1454]1using System.Collections.Generic;
2using System;
3using System.Text;
4using HeuristicLab.Persistence.Interfaces;
5using HeuristicLab.Persistence.Core;
6using System.IO;
[1466]7using ICSharpCode.SharpZipLib.Zip;
[1476]8using HeuristicLab.Tracing;
[1556]9using HeuristicLab.Persistence.Core.Tokens;
[3005]10using System.IO.Compression;
[1454]11
[1615]12namespace HeuristicLab.Persistence.Default.Xml {
[1454]13
[3004]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>
[1564]19  public class XmlGenerator : GeneratorBase<string> {
[1566]20
[1454]21    private int depth;
[1570]22    private int Depth {
23      get {
24        return depth;
25      }
26      set {
27        depth = value;
28        prefix = new string(' ', depth * 2);
29      }
30    }
[1454]31
[1570]32    private string prefix;
33
34
[3016]35    /// <summary>
36    /// Initializes a new instance of the <see cref="XmlGenerator"/> class.
37    /// </summary>
[1454]38    public XmlGenerator() {
[1570]39      Depth = 0;
[1454]40    }
41
42    private enum NodeType { Start, End, Inline } ;
43
[1570]44    private static void AddXmlTagContent(StringBuilder sb, string name, Dictionary<string, object> attributes) {
[1566]45      sb.Append(name);
[1454]46      foreach (var attribute in attributes) {
47        if (attribute.Value != null && !string.IsNullOrEmpty(attribute.Value.ToString())) {
[1570]48          sb.Append(' ');
[1454]49          sb.Append(attribute.Key);
50          sb.Append("=\"");
51          sb.Append(attribute.Value);
52          sb.Append('"');
53        }
54      }
[1570]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);
[1454]72      sb.Append(">");
[1570]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");
[1566]81      return sb.ToString();
[1454]82    }
83
[1570]84    private string CreateNodeStart(string name) {
85      return CreateNodeStart(name, new Dictionary<string, object>());
[1454]86    }
87
[1570]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
[1566]114    protected override string Format(BeginToken beginToken) {
[3005]115      var dict = new Dictionary<string, object> {
[1570]116          {"name", beginToken.Name},
117          {"typeId", beginToken.TypeId},
[3005]118          {"id", beginToken.Id}};
119      AddTypeInfo(beginToken.TypeId, dict);
120      return CreateNodeStart(XmlStringConstants.COMPOSITE, dict);
121       
[1454]122    }
123
[3005]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
[1566]136    protected override string Format(EndToken endToken) {
[1612]137      return CreateNodeEnd(XmlStringConstants.COMPOSITE);
[1454]138    }
139
[1566]140    protected override string Format(PrimitiveToken dataToken) {
[3005]141      var dict = new Dictionary<string, object> {
[1454]142            {"typeId", dataToken.TypeId},
143            {"name", dataToken.Name},
[3005]144            {"id", dataToken.Id}};
145      AddTypeInfo(dataToken.TypeId, dict);
146      return CreateNode(XmlStringConstants.PRIMITIVE, dict,
[1570]147        ((XmlString)dataToken.SerialData).Data);
[1454]148    }
149
[1566]150    protected override string Format(ReferenceToken refToken) {
[1612]151      return CreateNode(XmlStringConstants.REFERENCE,
[1570]152        new Dictionary<string, object> {
153          {"ref", refToken.Id},
154          {"name", refToken.Name}});
[1454]155    }
156
[1566]157    protected override string Format(NullReferenceToken nullRefToken) {
[1612]158      return CreateNode(XmlStringConstants.NULL,
[1570]159        new Dictionary<string, object>{
160          {"name", nullRefToken.Name}});
[1454]161    }
162
[1553]163    protected override string Format(MetaInfoBeginToken metaInfoBeginToken) {
[1612]164      return CreateNodeStart(XmlStringConstants.METAINFO);
[1553]165    }
166
167    protected override string Format(MetaInfoEndToken metaInfoEndToken) {
[1612]168      return CreateNodeEnd(XmlStringConstants.METAINFO);
[1553]169    }
170
[3005]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
[1454]191    public IEnumerable<string> Format(List<TypeMapping> typeCache) {
[1612]192      yield return CreateNodeStart(XmlStringConstants.TYPECACHE);
[1454]193      foreach (var mapping in typeCache)
[1570]194        yield return CreateNode(
[1612]195          XmlStringConstants.TYPE,
[1570]196          mapping.GetDict());
[1612]197      yield return CreateNodeEnd(XmlStringConstants.TYPECACHE);
[1454]198    }
199
[3004]200    /// <summary>
201    /// Serialize an object into a file.
202    ///
[3016]203    /// The XML configuration is obtained from the <c>ConfigurationService</c>.
[3004]204    /// The file is actually a ZIP file.
205    /// Compression level is set to 5 and needed assemblies are not included.
206    /// </summary>   
[1566]207    public static void Serialize(object o, string filename) {
[3004]208      Serialize(o, filename, ConfigurationService.Instance.GetConfiguration(new XmlFormat()), false, 5);
[1454]209    }
210
[3004]211    /// <summary>
212    /// Serialize an object into a file.
213    ///
[3016]214    /// The XML configuration is obtained from the <c>ConfigurationService</c>.
[3004]215    /// Needed assemblies are not included.
216    /// </summary>
217    /// <param name="compression">ZIP file compression level</param>
[1892]218    public static void Serialize(object o, string filename, int compression) {
219      Serialize(o, filename, ConfigurationService.Instance.GetConfiguration(new XmlFormat()), false, compression);
220    }
221
[1466]222    public static void Serialize(object obj, string filename, Configuration config) {
[1892]223      Serialize(obj, filename, config, false, 5);
[1797]224    }
225
[1892]226    public static void Serialize(object obj, string filename, Configuration config, bool includeAssemblies, int compression) {     
[1625]227      try {
[1892]228        string tempfile = Path.GetTempFileName();
229        DateTime start = DateTime.Now;
[2037]230        using (FileStream stream = File.Create(tempfile)) {
[3005]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          }
[2037]269        }
[1892]270        Logger.Info(String.Format("serialization took {0} seconds with compression level {1}",
271          (DateTime.Now - start).TotalSeconds, compression));
[1733]272        File.Copy(tempfile, filename, true);
273        File.Delete(tempfile);
[1823]274      } catch (Exception) {
[1733]275        Logger.Warn("Exception caught, no data has been written.");
276        throw;
277      }
278    }
279
[3005]280    public static void Serialize(object obj, Stream stream) {
281      Serialize(obj, stream, ConfigurationService.Instance.GetConfiguration(new XmlFormat()));
282    }
[1797]283
[3005]284
[1733]285    public static void Serialize(object obj, Stream stream, Configuration config) {
[1797]286      Serialize(obj, stream, config, false);
287    }
[3005]288
[1892]289    public static void Serialize(object obj, Stream stream, Configuration config, bool includeAssemblies) {
[3005]290      Serialize(obj, stream, config, includeAssemblies, true);
[1892]291    }
[1797]292
[3005]293    public static void Serialize(object obj, Stream stream, Configuration config, bool includeAssemblies, bool interleaveTypeInfo) {     
[1733]294      try {
[3005]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();
[1704]299          foreach (ISerializationToken token in serializer) {
300            string line = generator.Format(token);
301            writer.Write(line);
302          }
303          writer.Flush();
[1625]304        }
[1823]305      } catch (PersistenceException) {
[1625]306        throw;
307      } catch (Exception e) {
308        throw new PersistenceException("Unexpected exception during Serialization.", e);
[3005]309      }
[1454]310    }
311  }
312}
Note: See TracBrowser for help on using the repository browser.