#region License Information /* HeuristicLab * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Text; using System.Xml; using System.IO; using System.IO.Compression; using HeuristicLab.PluginInfrastructure; namespace HeuristicLab.Core { /// /// Static class for serializing and deserializing objects. /// public static class PersistenceManager { /// /// Creates an to persist an object with xml declaration. /// /// The created . public static XmlDocument CreateXmlDocument() { XmlDocument document = new XmlDocument(); document.AppendChild(document.CreateXmlDeclaration("1.0", null, null)); return document; } /// /// Saves the specified in the specified /// if it has not already been serialized. /// /// The tag name of the saved instance is its type name.
/// The guid is saved as an with tag name GUID.
/// The object that should be saved. /// The where to save the data. /// The dictionary of all already persisted objects. (Needed to avoid cycles.) /// The saved . public static XmlNode Persist(IStorable instance, XmlDocument document, IDictionary persistedObjects) { string name = instance.GetType().Name; name = name.Replace('`', '_'); return Persist(name, instance, document, persistedObjects); } /// /// Saves the specified in the specified /// if it has not already been serialized. /// /// The (tag)name of the . /// The object that should be saved. /// The where to save the data. /// The dictionary of all already persisted objects. (Needed to avoid cycles.) /// The saved . public static XmlNode Persist(string name, IStorable instance, XmlDocument document, IDictionary persistedObjects) { if(persistedObjects.ContainsKey(instance.Guid)) { XmlNode node = document.CreateNode(XmlNodeType.Element, name, null); XmlAttribute guidAttribute = document.CreateAttribute("GUID"); guidAttribute.Value = instance.Guid.ToString(); node.Attributes.Append(guidAttribute); return node; } else { persistedObjects.Add(instance.Guid, instance); XmlNode node = instance.GetXmlNode(name, document, persistedObjects); return node; } } /// /// Loads a persisted object from the specified . /// /// The guid is saved as an attribute with tag name GUID. The type of the /// persisted object is saved as attribute with tag name Type.
/// Calls instance.Populate.
/// The where the object is saved. /// A dictionary of all already restored objects. /// (Needed to avoid cycles.) /// The loaded object. public static IStorable Restore(XmlNode node, IDictionary restoredObjects) { Guid guid = new Guid(node.Attributes["GUID"].Value); if(restoredObjects.ContainsKey(guid)) { return restoredObjects[guid]; } else { Type type = Type.GetType(node.Attributes["Type"].Value, true); IStorable instance = (IStorable)Activator.CreateInstance(type); restoredObjects.Add(guid, instance); instance.Populate(node, restoredObjects); return instance; } } /// /// Saves the specified in the specified file through creating an /// . /// /// The object that should be saved. /// The name of the file where the should be saved. public static void Save(IStorable instance, string filename) { string tempfile = Path.GetTempFileName(); using (FileStream stream = File.Create(tempfile)) { Save(instance, stream); stream.Close(); } File.Copy(tempfile, filename, true); File.Delete(tempfile); } /// /// Saves the specified in the specified /// through creating an . /// /// The object that should be saved. /// The (file) stream where the object should be saved. public static void Save(IStorable instance, Stream stream) { XmlDocument document = PersistenceManager.CreateXmlDocument(); Dictionary dictionary = new Dictionary(); XmlNode rootNode = document.CreateElement("Root"); document.AppendChild(rootNode); rootNode.AppendChild(Persist(instance, document, dictionary)); document.Save(stream); } /// /// Loads an object from a file with the specified . /// /// The object must be saved as an .
/// Calls .
/// The filename of the file where the data is saved. /// The loaded object. public static IStorable Load(string filename) { using(FileStream stream = File.OpenRead(filename)) { IStorable storable = Load(stream); stream.Close(); return storable; } } /// /// Loads an object from the specified . /// /// The object must be saved as an .
/// Calls .
/// The stream from where to load the data. /// The loaded object. public static IStorable Load(Stream stream) { XmlDocument doc = new XmlDocument(); doc.Load(stream); XmlNode rootNode = doc.ChildNodes[1]; if(rootNode.Name == "Root") { XmlNode bodyNode; if (rootNode.ChildNodes.Count == 2) bodyNode = rootNode.ChildNodes[1]; else bodyNode = rootNode.ChildNodes[0]; // load documents that have a list of necessary plugins at the top return PersistenceManager.Restore(bodyNode, new Dictionary()); } else { // compatibility to load documents without list of necessary plugins return PersistenceManager.Restore(rootNode, new Dictionary()); } } /// /// Loads an object from a zip file. /// /// The zip file from where to load as byte array. /// The loaded object. public static IStorable RestoreFromGZip(byte[] serializedStorable) { GZipStream stream = new GZipStream(new MemoryStream(serializedStorable), CompressionMode.Decompress); return Load(stream); } /// /// Saves the specified in a zip file. /// /// Calls . /// The object to save. /// The zip stream as byte array. public static byte[] SaveToGZip(IStorable storable) { MemoryStream memStream = new MemoryStream(); GZipStream stream = new GZipStream(memStream, CompressionMode.Compress, true); Save(storable, stream); stream.Close(); return memStream.ToArray(); } /// /// Builds a meaningful string for the given with the namespace information, /// all its arguments, the assembly name... /// /// The type for which a string should be created. /// A string value of this type containing different additional information. public static string BuildTypeString(Type type) { string assembly = type.Assembly.FullName; assembly = assembly.Substring(0, assembly.IndexOf(", ")); StringBuilder builder = new StringBuilder(); builder.Append(type.Namespace); builder.Append("."); builder.Append(type.Name); Type[] args = type.GetGenericArguments(); if(args.Length > 0) { builder.Append("[["); builder.Append(BuildTypeString(args[0])); builder.Append("]"); for(int i = 1; i < args.Length; i++) { builder.Append(",["); builder.Append(BuildTypeString(args[i])); builder.Append("]"); } builder.Append("]"); } builder.Append(", "); builder.Append(assembly); return builder.ToString(); } } }