Free cookie consent management tool by TermsFeed Policy Generator

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

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

replace repeated calls through reflection with generated code for a twofold speedup (#548)

File size: 9.2 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          }
178          if (t.GetInterface(typeof(ICompositeSerializer).FullName) != null &&
179              !t.IsAbstract && t.GetConstructor(Type.EmptyTypes) != null && !t.ContainsGenericParameters) {
180            CompositeSerializers.Add((ICompositeSerializer)Activator.CreateInstance(t, true));
181          }
182          if (t.GetInterface(typeof(IFormat).FullName) != null &&
183             !t.IsAbstract && t.GetConstructor(Type.EmptyTypes) != null && !t.ContainsGenericParameters) {
184            IFormat format = (IFormat)Activator.CreateInstance(t, true);
185            Formats.Add(format);
186          }
187        }
188      } catch (ReflectionTypeLoadException e) {
189        Logger.Warn("could not analyse assembly: " + a.FullName, e);
190      }
191    }
192
193    /// <summary>
194    /// Get the default (automatically discovered) configuration for a certain format.
195    /// </summary>
196    /// <param name="format">The format.</param>
197    /// <returns>The default (auto discovered) configuration.</returns>
198    public Configuration GetDefaultConfig(IFormat format) {
199      Dictionary<Type, IPrimitiveSerializer> primitiveConfig = new Dictionary<Type, IPrimitiveSerializer>();
200      if (PrimitiveSerializers.ContainsKey(format.SerialDataType)) {
201        foreach (IPrimitiveSerializer f in PrimitiveSerializers[format.SerialDataType]) {
202          if (!primitiveConfig.ContainsKey(f.SourceType))
203            primitiveConfig.Add(f.SourceType, f);
204        }
205      } else {
206        Logger.Warn(String.Format(
207          "No primitive serializers found for format {0} with serial data type {1}",
208          format.GetType().AssemblyQualifiedName,
209          format.SerialDataType.AssemblyQualifiedName));
210      }
211      return new Configuration(
212        format,
213        primitiveConfig.Values,
214        CompositeSerializers.Where((d) => d.Priority > 0));
215    }
216
217
218    /// <summary>
219    /// Get a configuration for a certain format. This returns a fresh copy of a custom configuration,
220    /// if defined, otherwise returns the default (automatically discovered) configuration.
221    /// </summary>
222    /// <param name="format">The format.</param>
223    /// <returns>A Configuration</returns>
224    public Configuration GetConfiguration(IFormat format) {
225      if (customConfigurations.ContainsKey(format))
226        return customConfigurations[format].Copy();
227      return GetDefaultConfig(format);
228    }
229
230    /// <summary>
231    /// Define a new custom configuration for a ceratin format.
232    /// </summary>
233    /// <param name="configuration">The new configuration.</param>
234    public void DefineConfiguration(Configuration configuration) {
235      customConfigurations[configuration.Format] = configuration.Copy();
236      SaveSettings();
237    }
238
239  }
240
241}
Note: See TracBrowser for help on using the repository browser.