#region License Information /* HeuristicLab * Copyright (C) 2002-2019 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.IO; using System.Linq; using System.Reflection; using System.Text; using HEAL.Attic; using HeuristicLab.Persistence.Default.Xml; using HeuristicLab.Persistence.Interfaces; using HeuristicLab.Tracing; namespace HeuristicLab.Persistence.Core { /// /// Provides a persistable configuration of primitive and composite serializers for /// all registered serial formats. Custom formats can be defined and will be saved /// for future sessions. A default configuration can be generated through reflection. /// /// This class has only a single instance. /// public class ConfigurationService { private static ConfigurationService instance; private static object locker = new object(); private readonly Dictionary customConfigurations; /// /// List of all available primitive serializers. /// public Dictionary> PrimitiveSerializers { get; private set; } /// /// List of all available composite serializers (discovered through reflection). /// public List CompositeSerializers { get; private set; } /// /// List of all available formats (discovered through reflection). /// public List Formats { get; private set; } /// /// Gets the singleton instance. /// /// The singleton instance. public static ConfigurationService Instance { get { lock (locker) { if (instance == null) instance = new ConfigurationService(); return instance; } } } private ConfigurationService() { PrimitiveSerializers = new Dictionary>(); CompositeSerializers = new List(); customConfigurations = new Dictionary(); Formats = new List(); Reset(); LoadSettings(); } /// /// Loads the settings. /// public void LoadSettings() { LoadSettings(false); } /// /// Loads the settings. /// /// if set to true throw on error. public void LoadSettings(bool throwOnError) { try { TryLoadSettings(); } catch (Exception e) { if (throwOnError) { throw new PersistenceException("Could not load persistence settings.", e); } else { Logger.Warn("Could not load settings.", e); } } } /// /// Tries to load the settings (i.e custom configurations). /// protected void TryLoadSettings() { if (String.IsNullOrEmpty(Properties.Settings.Default.CustomConfigurations) || String.IsNullOrEmpty(Properties.Settings.Default.CustomConfigurationsTypeCache)) return; Deserializer deSerializer = new Deserializer( XmlParser.ParseTypeCache( new StringReader( Properties.Settings.Default.CustomConfigurationsTypeCache))); XmlParser parser = new XmlParser( new StringReader( Properties.Settings.Default.CustomConfigurations)); var newCustomConfigurations = (Dictionary) deSerializer.Deserialize(parser); foreach (var config in newCustomConfigurations) { customConfigurations[config.Key] = config.Value; } } /// /// Saves the settings (i.e custom configurations). /// protected void SaveSettings() { Serializer serializer = new Serializer( customConfigurations, GetDefaultConfig(new XmlFormat()), "CustomConfigurations"); XmlGenerator generator = new XmlGenerator(); StringBuilder configurationString = new StringBuilder(); foreach (ISerializationToken token in serializer) { configurationString.Append(generator.Format(token)); } StringBuilder configurationTypeCacheString = new StringBuilder(); foreach (string s in generator.Format(serializer.TypeCache)) configurationTypeCacheString.Append(s); Properties.Settings.Default.CustomConfigurations = configurationString.ToString(); Properties.Settings.Default.CustomConfigurationsTypeCache = configurationTypeCacheString.ToString(); Properties.Settings.Default.Save(); } /// /// Rediscover available serializers and discard all custom configurations. /// public void Reset() { customConfigurations.Clear(); PrimitiveSerializers.Clear(); CompositeSerializers.Clear(); Assembly defaultAssembly = Assembly.GetExecutingAssembly(); DiscoverFrom(defaultAssembly); try { foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) if (a != defaultAssembly) DiscoverFrom(a); } catch (AppDomainUnloadedException x) { Logger.Warn("could not get list of assemblies, AppDomain has already been unloaded", x); } SortCompositeSerializers(); } private class PriortiySorter : IComparer { public int Compare(ICompositeSerializer x, ICompositeSerializer y) { return y.Priority - x.Priority; } } /// /// Sorts the composite serializers according to their priority. /// protected void SortCompositeSerializers() { CompositeSerializers.Sort(new PriortiySorter()); } /// /// Discovers serializers from an assembly. /// /// An Assembly. protected void DiscoverFrom(Assembly a) { try { foreach (Type t in a.GetTypes()) { if (t.GetInterface(typeof(IPrimitiveSerializer).FullName) != null && !t.IsAbstract && t.GetConstructor(Type.EmptyTypes) != null && !t.ContainsGenericParameters) { IPrimitiveSerializer primitiveSerializer = (IPrimitiveSerializer)Activator.CreateInstance(t, true); if (!PrimitiveSerializers.ContainsKey(primitiveSerializer.SerialDataType)) PrimitiveSerializers.Add(primitiveSerializer.SerialDataType, new List()); PrimitiveSerializers[primitiveSerializer.SerialDataType].Add(primitiveSerializer); } if (t.GetInterface(typeof(ICompositeSerializer).FullName) != null && !t.IsAbstract && t.GetConstructor(Type.EmptyTypes) != null && !t.ContainsGenericParameters) { CompositeSerializers.Add((ICompositeSerializer)Activator.CreateInstance(t, true)); } if (t.GetInterface(typeof(IFormat).FullName) != null && !t.IsAbstract && t.GetConstructor(Type.EmptyTypes) != null && !t.ContainsGenericParameters) { IFormat format = (IFormat)Activator.CreateInstance(t, true); Formats.Add(format); } } } catch (ReflectionTypeLoadException e) { Logger.Warn("could not analyse assembly: " + a.FullName, e); } } /// /// Get the default (automatically discovered) configuration for a certain format. /// /// The format. /// The default (auto discovered) configuration. public Configuration GetDefaultConfig(IFormat format) { Dictionary primitiveConfig = new Dictionary(); if (PrimitiveSerializers.ContainsKey(format.SerialDataType)) { foreach (IPrimitiveSerializer f in PrimitiveSerializers[format.SerialDataType]) { if (!primitiveConfig.ContainsKey(f.SourceType)) primitiveConfig.Add(f.SourceType, (IPrimitiveSerializer)Activator.CreateInstance(f.GetType())); } } else { Logger.Warn(String.Format( "No primitive serializers found for format {0} with serial data type {1}", format.GetType().AssemblyQualifiedName, format.SerialDataType.AssemblyQualifiedName)); } return new Configuration( format, primitiveConfig.Values, CompositeSerializers.Where((d) => d.Priority > 0).Select(d => (ICompositeSerializer)Activator.CreateInstance(d.GetType()))); } /// /// Get a configuration for a certain format. This returns a fresh copy of a custom configuration, /// if defined, otherwise returns the default (automatically discovered) configuration. /// /// The format. /// A Configuration public Configuration GetConfiguration(IFormat format) { if (customConfigurations.ContainsKey(format)) return customConfigurations[format].Copy(); return GetDefaultConfig(format); } /// /// Define a new custom configuration for a ceratin format. /// /// The new configuration. public void DefineConfiguration(Configuration configuration) { customConfigurations[configuration.Format] = configuration.Copy(); SaveSettings(); } } }