Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Persistence/3.3/Core/ConfigurationService.cs @ 4175

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

Properly copy serializers when initializing global configuration. (#1136)

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