Free cookie consent management tool by TermsFeed Policy Generator

source: branches/SimulationCore/HeuristicLab.Persistence/3.3/Core/ConfigurationService.cs @ 7196

Last change on this file since 7196 was 6356, checked in by epitzer, 13 years ago

Added additional locks to improve concurrent persistence (#1544)

File size: 10.2 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 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;
23using System.Collections.Generic;
24using System.IO;
25using System.Linq;
26using System.Reflection;
27using System.Text;
28using HeuristicLab.Persistence.Default.Xml;
29using HeuristicLab.Persistence.Interfaces;
30using HeuristicLab.Tracing;
31
32namespace HeuristicLab.Persistence.Core {
33
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>
41  public class ConfigurationService {
42
43    private static ConfigurationService instance;
44    private static object locker = new object();
45    private readonly Dictionary<IFormat, Configuration> customConfigurations;
46
47    /// <summary>
48    /// List of all available primitive serializers.
49    /// </summary>
50    public Dictionary<Type, List<IPrimitiveSerializer>> PrimitiveSerializers { get; private set; }
51
52    /// <summary>
53    /// List of all available composite serializers (discovered through reflection).
54    /// </summary>
55    public List<ICompositeSerializer> CompositeSerializers { get; private set; }
56
57    /// <summary>
58    /// List of all available formats (discovered through reflection).   
59    /// </summary>
60    public List<IFormat> Formats { get; private set; }
61
62    /// <summary>
63    /// Gets the singleton instance.
64    /// </summary>
65    /// <value>The singleton instance.</value>
66    public static ConfigurationService Instance {
67      get {
68        lock (locker) {
69          if (instance == null)
70            instance = new ConfigurationService();
71          return instance;
72        }
73      }
74    }
75
76    private ConfigurationService() {
77      PrimitiveSerializers = new Dictionary<Type, List<IPrimitiveSerializer>>();
78      CompositeSerializers = new List<ICompositeSerializer>();
79      customConfigurations = new Dictionary<IFormat, Configuration>();
80      Formats = new List<IFormat>();
81      Reset();
82      LoadSettings();
83    }
84
85    /// <summary>
86    /// Loads the settings.
87    /// </summary>
88    public void LoadSettings() {
89      LoadSettings(false);
90    }
91
92    /// <summary>
93    /// Loads the settings.
94    /// </summary>
95    /// <param name="throwOnError">if set to <c>true</c> throw on error.</param>
96    public void LoadSettings(bool throwOnError) {
97      try {
98        TryLoadSettings();
99      } catch (Exception e) {
100        if (throwOnError) {
101          throw new PersistenceException("Could not load persistence settings.", e);
102        } else {
103          Logger.Warn("Could not load settings.", e);
104        }
105      }
106    }
107
108    /// <summary>
109    /// Tries to load the settings (i.e custom configurations).
110    /// </summary>
111    protected void TryLoadSettings() {
112      if (String.IsNullOrEmpty(Properties.Settings.Default.CustomConfigurations) ||
113          String.IsNullOrEmpty(Properties.Settings.Default.CustomConfigurationsTypeCache))
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;
126      }
127    }
128
129    /// <summary>
130    /// Saves the settings (i.e custom configurations).
131    /// </summary>
132    protected void SaveSettings() {
133      Serializer serializer = new Serializer(
134        customConfigurations,
135        GetDefaultConfig(new XmlFormat()),
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);
145      Properties.Settings.Default.CustomConfigurations =
146        configurationString.ToString();
147      Properties.Settings.Default.CustomConfigurationsTypeCache =
148        configurationTypeCacheString.ToString();
149      Properties.Settings.Default.Save();
150    }
151
152
153    /// <summary>
154    /// Rediscover available serializers and discard all custom configurations.
155    /// </summary>
156    public void Reset() {
157      customConfigurations.Clear();
158      PrimitiveSerializers.Clear();
159      CompositeSerializers.Clear();
160      Assembly defaultAssembly = Assembly.GetExecutingAssembly();
161      DiscoverFrom(defaultAssembly);
162      try {
163        foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
164          if (a != defaultAssembly)
165            DiscoverFrom(a);
166      } catch (AppDomainUnloadedException x) {
167        Logger.Warn("could not get list of assemblies, AppDomain has already been unloaded", x);
168      }
169      SortCompositeSerializers();
170    }
171
172    private class PriortiySorter : IComparer<ICompositeSerializer> {
173      public int Compare(ICompositeSerializer x, ICompositeSerializer y) {
174        return y.Priority - x.Priority;
175      }
176    }
177
178    /// <summary>
179    /// Sorts the composite serializers according to their priority.
180    /// </summary>
181    protected void SortCompositeSerializers() {
182      CompositeSerializers.Sort(new PriortiySorter());
183    }
184
185    /// <summary>
186    /// Discovers serializers from an assembly.
187    /// </summary>
188    /// <param name="a">An Assembly.</param>
189    protected void DiscoverFrom(Assembly a) {
190      try {
191        foreach (Type t in a.GetTypes()) {
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);
199          }
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));
203          }
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);
208          }
209        }
210      } catch (ReflectionTypeLoadException e) {
211        Logger.Warn("could not analyse assembly: " + a.FullName, e);
212      }
213    }
214
215    /// <summary>
216    /// Get the default (automatically discovered) configuration for a certain format.
217    /// </summary>
218    /// <param name="format">The format.</param>
219    /// <returns>The default (auto discovered) configuration.</returns>
220    public Configuration GetDefaultConfig(IFormat format) {
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))
225            primitiveConfig.Add(f.SourceType, (IPrimitiveSerializer)Activator.CreateInstance(f.GetType()));
226        }
227      } else {
228        Logger.Warn(String.Format(
229          "No primitive serializers found for format {0} with serial data type {1}",
230          format.GetType().AssemblyQualifiedName,
231          format.SerialDataType.AssemblyQualifiedName));
232      }
233      return new Configuration(
234        format,
235        primitiveConfig.Values,
236        CompositeSerializers.Where((d) => d.Priority > 0).Select(d => (ICompositeSerializer)Activator.CreateInstance(d.GetType())));
237    }
238
239
240    /// <summary>
241    /// Get a configuration for a certain format. This returns a fresh copy of a custom configuration,
242    /// if defined, otherwise returns the default (automatically discovered) configuration.
243    /// </summary>
244    /// <param name="format">The format.</param>
245    /// <returns>A Configuration</returns>
246    public Configuration GetConfiguration(IFormat format) {
247      if (customConfigurations.ContainsKey(format))
248        return customConfigurations[format].Copy();
249      return GetDefaultConfig(format);
250    }
251
252    /// <summary>
253    /// Define a new custom configuration for a ceratin format.
254    /// </summary>
255    /// <param name="configuration">The new configuration.</param>
256    public void DefineConfiguration(Configuration configuration) {
257      customConfigurations[configuration.Format] = configuration.Copy();
258      SaveSettings();
259    }
260
261  }
262
263}
Note: See TracBrowser for help on using the repository browser.