Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 3038 was 3037, checked in by epitzer, 15 years ago

prevent exceptions during configuration (instead of catching them) (#548)

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