Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2839_HiveProjectManagement/HeuristicLab.Persistence/3.3/Core/ConfigurationService.cs

Last change on this file was 16057, checked in by jkarder, 6 years ago

#2839:

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