Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2521_ProblemRefactoring/HeuristicLab.Persistence/3.3/Core/ConfigurationService.cs

Last change on this file was 17226, checked in by mkommend, 5 years ago

#2521: Merged trunk changes into problem refactoring branch.

File size: 10.2 KB
RevLine 
[3743]1#region License Information
2/* HeuristicLab
[17226]3 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[3743]4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
[4068]23using System.Collections.Generic;
[1454]24using System.IO;
[1644]25using System.Linq;
[1454]26using System.Reflection;
27using System.Text;
[16723]28using HEAL.Attic;
[1454]29using HeuristicLab.Persistence.Default.Xml;
30using HeuristicLab.Persistence.Interfaces;
[1469]31using HeuristicLab.Tracing;
[1454]32
33namespace HeuristicLab.Persistence.Core {
[1566]34
[3004]35  /// <summary>
36  /// Provides a persistable configuration of primitive and composite serializers for
37  /// all registered serial formats. Custom formats can be defined and will be saved
38  /// for future sessions. A default configuration can be generated through reflection.
39  ///
40  /// This class has only a single instance.
41  /// </summary>
[1454]42  public class ConfigurationService {
43
44    private static ConfigurationService instance;
[6356]45    private static object locker = new object();
[1454]46    private readonly Dictionary<IFormat, Configuration> customConfigurations;
[3004]47
48    /// <summary>
49    /// List of all available primitive serializers.
50    /// </summary>
[1823]51    public Dictionary<Type, List<IPrimitiveSerializer>> PrimitiveSerializers { get; private set; }
[3004]52
53    /// <summary>
54    /// List of all available composite serializers (discovered through reflection).
55    /// </summary>
[1823]56    public List<ICompositeSerializer> CompositeSerializers { get; private set; }
[3004]57
58    /// <summary>
59    /// List of all available formats (discovered through reflection).   
60    /// </summary>
[1564]61    public List<IFormat> Formats { get; private set; }
[1566]62
[3016]63    /// <summary>
64    /// Gets the singleton instance.
65    /// </summary>
66    /// <value>The singleton instance.</value>
[1454]67    public static ConfigurationService Instance {
68      get {
[6356]69        lock (locker) {
70          if (instance == null)
71            instance = new ConfigurationService();
72          return instance;
73        }
[1454]74      }
75    }
76
[1542]77    private ConfigurationService() {
[1823]78      PrimitiveSerializers = new Dictionary<Type, List<IPrimitiveSerializer>>();
79      CompositeSerializers = new List<ICompositeSerializer>();
[1564]80      customConfigurations = new Dictionary<IFormat, Configuration>();
81      Formats = new List<IFormat>();
[1454]82      Reset();
83      LoadSettings();
84    }
85
[3016]86    /// <summary>
87    /// Loads the settings.
88    /// </summary>
[1660]89    public void LoadSettings() {
90      LoadSettings(false);
91    }
92
[3016]93    /// <summary>
94    /// Loads the settings.
95    /// </summary>
96    /// <param name="throwOnError">if set to <c>true</c> throw on error.</param>
[1660]97    public void LoadSettings(bool throwOnError) {
[1454]98      try {
[1660]99        TryLoadSettings();
[4175]100      } catch (Exception e) {
[1660]101        if (throwOnError) {
102          throw new PersistenceException("Could not load persistence settings.", e);
103        } else {
104          Logger.Warn("Could not load settings.", e);
105        }
[1703]106      }
[1660]107    }
108
[3016]109    /// <summary>
110    /// Tries to load the settings (i.e custom configurations).
111    /// </summary>
[1660]112    protected void TryLoadSettings() {
113      if (String.IsNullOrEmpty(Properties.Settings.Default.CustomConfigurations) ||
[1542]114          String.IsNullOrEmpty(Properties.Settings.Default.CustomConfigurationsTypeCache))
[1660]115        return;
116      Deserializer deSerializer = new Deserializer(
117        XmlParser.ParseTypeCache(
118        new StringReader(
119          Properties.Settings.Default.CustomConfigurationsTypeCache)));
120      XmlParser parser = new XmlParser(
121        new StringReader(
122          Properties.Settings.Default.CustomConfigurations));
123      var newCustomConfigurations = (Dictionary<IFormat, Configuration>)
124        deSerializer.Deserialize(parser);
125      foreach (var config in newCustomConfigurations) {
126        customConfigurations[config.Key] = config.Value;
[1454]127      }
128    }
129
[3016]130    /// <summary>
131    /// Saves the settings (i.e custom configurations).
132    /// </summary>
[1623]133    protected void SaveSettings() {
[1454]134      Serializer serializer = new Serializer(
135        customConfigurations,
[1564]136        GetDefaultConfig(new XmlFormat()),
[1454]137        "CustomConfigurations");
138      XmlGenerator generator = new XmlGenerator();
139      StringBuilder configurationString = new StringBuilder();
140      foreach (ISerializationToken token in serializer) {
141        configurationString.Append(generator.Format(token));
142      }
143      StringBuilder configurationTypeCacheString = new StringBuilder();
144      foreach (string s in generator.Format(serializer.TypeCache))
145        configurationTypeCacheString.Append(s);
[1542]146      Properties.Settings.Default.CustomConfigurations =
[1454]147        configurationString.ToString();
[1542]148      Properties.Settings.Default.CustomConfigurationsTypeCache =
[1454]149        configurationTypeCacheString.ToString();
150      Properties.Settings.Default.Save();
151    }
152
[3004]153
154    /// <summary>
155    /// Rediscover available serializers and discard all custom configurations.
156    /// </summary>
[1566]157    public void Reset() {
[1454]158      customConfigurations.Clear();
[1823]159      PrimitiveSerializers.Clear();
160      CompositeSerializers.Clear();
[1454]161      Assembly defaultAssembly = Assembly.GetExecutingAssembly();
162      DiscoverFrom(defaultAssembly);
[2876]163      try {
164        foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
165          if (a != defaultAssembly)
166            DiscoverFrom(a);
[4175]167      } catch (AppDomainUnloadedException x) {
[2876]168        Logger.Warn("could not get list of assemblies, AppDomain has already been unloaded", x);
169      }
[1823]170      SortCompositeSerializers();
[1454]171    }
172
[3004]173    private class PriortiySorter : IComparer<ICompositeSerializer> {
[1823]174      public int Compare(ICompositeSerializer x, ICompositeSerializer y) {
[1539]175        return y.Priority - x.Priority;
176      }
177    }
178
[3016]179    /// <summary>
180    /// Sorts the composite serializers according to their priority.
181    /// </summary>
[1823]182    protected void SortCompositeSerializers() {
183      CompositeSerializers.Sort(new PriortiySorter());
[1539]184    }
185
[3016]186    /// <summary>
187    /// Discovers serializers from an assembly.
188    /// </summary>
189    /// <param name="a">An Assembly.</param>
[1454]190    protected void DiscoverFrom(Assembly a) {
[2876]191      try {
192        foreach (Type t in a.GetTypes()) {
[3037]193          if (t.GetInterface(typeof(IPrimitiveSerializer).FullName) != null &&
194              !t.IsAbstract && t.GetConstructor(Type.EmptyTypes) != null && !t.ContainsGenericParameters) {
195            IPrimitiveSerializer primitiveSerializer =
196              (IPrimitiveSerializer)Activator.CreateInstance(t, true);
197            if (!PrimitiveSerializers.ContainsKey(primitiveSerializer.SerialDataType))
198              PrimitiveSerializers.Add(primitiveSerializer.SerialDataType, new List<IPrimitiveSerializer>());
199            PrimitiveSerializers[primitiveSerializer.SerialDataType].Add(primitiveSerializer);
[1554]200          }
[3037]201          if (t.GetInterface(typeof(ICompositeSerializer).FullName) != null &&
202              !t.IsAbstract && t.GetConstructor(Type.EmptyTypes) != null && !t.ContainsGenericParameters) {
203            CompositeSerializers.Add((ICompositeSerializer)Activator.CreateInstance(t, true));
[1454]204          }
[3037]205          if (t.GetInterface(typeof(IFormat).FullName) != null &&
206             !t.IsAbstract && t.GetConstructor(Type.EmptyTypes) != null && !t.ContainsGenericParameters) {
207            IFormat format = (IFormat)Activator.CreateInstance(t, true);
208            Formats.Add(format);
[1566]209          }
[1564]210        }
[4175]211      } catch (ReflectionTypeLoadException e) {
[2876]212        Logger.Warn("could not analyse assembly: " + a.FullName, e);
[1454]213      }
214    }
215
[3004]216    /// <summary>
217    /// Get the default (automatically discovered) configuration for a certain format.
[3016]218    /// </summary>
219    /// <param name="format">The format.</param>
220    /// <returns>The default (auto discovered) configuration.</returns>
[1454]221    public Configuration GetDefaultConfig(IFormat format) {
[1823]222      Dictionary<Type, IPrimitiveSerializer> primitiveConfig = new Dictionary<Type, IPrimitiveSerializer>();
223      if (PrimitiveSerializers.ContainsKey(format.SerialDataType)) {
224        foreach (IPrimitiveSerializer f in PrimitiveSerializers[format.SerialDataType]) {
225          if (!primitiveConfig.ContainsKey(f.SourceType))
[4175]226            primitiveConfig.Add(f.SourceType, (IPrimitiveSerializer)Activator.CreateInstance(f.GetType()));
[1625]227        }
228      } else {
229        Logger.Warn(String.Format(
[1823]230          "No primitive serializers found for format {0} with serial data type {1}",
231          format.GetType().AssemblyQualifiedName,
232          format.SerialDataType.AssemblyQualifiedName));
[1454]233      }
[1823]234      return new Configuration(
235        format,
236        primitiveConfig.Values,
[4175]237        CompositeSerializers.Where((d) => d.Priority > 0).Select(d => (ICompositeSerializer)Activator.CreateInstance(d.GetType())));
[1454]238    }
239
[3004]240
241    /// <summary>
[3030]242    /// Get a configuration for a certain format. This returns a fresh copy of a custom configuration,
[3004]243    /// if defined, otherwise returns the default (automatically discovered) configuration.
[3016]244    /// </summary>
245    /// <param name="format">The format.</param>
246    /// <returns>A Configuration</returns>
[1454]247    public Configuration GetConfiguration(IFormat format) {
248      if (customConfigurations.ContainsKey(format))
[3030]249        return customConfigurations[format].Copy();
[1454]250      return GetDefaultConfig(format);
251    }
252
[3004]253    /// <summary>
254    /// Define a new custom configuration for a ceratin format.
[3016]255    /// </summary>
256    /// <param name="configuration">The new configuration.</param>
[1566]257    public void DefineConfiguration(Configuration configuration) {
[3030]258      customConfigurations[configuration.Format] = configuration.Copy();
[1454]259      SaveSettings();
260    }
261
262  }
[1566]263
[1454]264}
Note: See TracBrowser for help on using the repository browser.