Free cookie consent management tool by TermsFeed Policy Generator

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

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

add complete persistence API docs (#548)

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