Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3026_IntegrationIntoSymSpace/HeuristicLab.JsonInterface/JsonTemplateInstantiator.cs

Last change on this file was 18077, checked in by dpiringe, 2 years ago

#3026

  • added the dockerhub readme file
  • fixed a bug which caused changed values (changed by events) to be overwritten with wrong values
File size: 6.6 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using System.Text.RegularExpressions;
6using HEAL.Attic;
7using HeuristicLab.Optimization;
8using HeuristicLab.PluginInfrastructure;
9using Newtonsoft.Json.Linq;
10
11namespace HeuristicLab.JsonInterface {
12  public readonly struct InstantiatorResult {
13
14    public InstantiatorResult(IOptimizer optimizer, IEnumerable<IRunCollectionModifier> runCollectionModifiers) {
15      Optimizer = optimizer;
16      RunCollectionModifiers = runCollectionModifiers;
17    }
18
19    public IOptimizer Optimizer { get; }
20    public IEnumerable<IRunCollectionModifier> RunCollectionModifiers { get; }
21  }
22
23
24  /// <summary>
25  /// Class to instantiate an IAlgorithm object with a json interface template and config.
26  /// </summary>
27  public class JsonTemplateInstantiator {
28
29    #region Constants
30    private const string RelativePathCurrentDirectoryRegex = @"^(\.)";
31    #endregion
32
33    #region Private Properties
34    private JToken Template { get; set; }
35    private JArray Config { get; set; }
36    private IDictionary<string, IJsonItem> Objects { get; set; } = new Dictionary<string, IJsonItem>();
37    #endregion
38
39    /// <summary>
40    /// Instantiate an IAlgorithm object with a template and config.
41    /// </summary>
42    /// <param name="templateFile">Template file (json), generated with JCGenerator.</param>
43    /// <param name="configFile">Config file (json) for the template.</param>
44    /// <returns>confugrated IOptimizer object</returns>
45    public static InstantiatorResult Instantiate(string templateFile, string configFile = null) {
46      JsonTemplateInstantiator instantiator = new JsonTemplateInstantiator();
47      return instantiator.ExecuteInstantiaton(templateFile, configFile);
48    }
49
50    #region Helper
51    private InstantiatorResult ExecuteInstantiaton(string templateFile, string configFile = null) {
52
53      #region Parse Files
54      string templateFileFullPath = Path.GetFullPath(templateFile);
55      Template = JToken.Parse(File.ReadAllText(templateFile));
56      if(!string.IsNullOrEmpty(configFile))
57        Config = JArray.Parse(File.ReadAllText(Path.GetFullPath(configFile)));
58      #endregion
59
60      #region Deserialize HL File
61      // extract metadata information
62      string relativePath = Template[Constants.Metadata][Constants.HLFileLocation].ToString().Trim(); // get relative path
63      // convert to absolute path
64      if (Regex.IsMatch(relativePath, RelativePathCurrentDirectoryRegex))
65        relativePath = relativePath.Remove(0, 2); // remove first 2 chars -> indicates the current directory
66
67      string hLFileLocation = Path.Combine(Path.GetDirectoryName(templateFileFullPath), relativePath);
68      ProtoBufSerializer serializer = new ProtoBufSerializer();
69      IOptimizer optimizer = (IOptimizer)serializer.Deserialize(hLFileLocation);
70      optimizer.Prepare(true);
71      #endregion
72
73      // collect all parameterizedItems from template
74      CollectParameterizedItems(optimizer);
75     
76      if (Config != null)
77        MergeTemplateWithConfig();
78
79      // get algorithm root item
80      IJsonItem rootItem = Objects.First().Value;
81
82      // validation
83      ValidationResult validationResult = rootItem.GetValidator().Validate();
84      if (!validationResult.Success)
85        throw validationResult.GenerateException();
86
87      // inject configuration
88      JsonItemConverter.Inject(optimizer, rootItem);
89
90      return new InstantiatorResult(optimizer, CollectRunCollectionModifiers());
91    }
92
93    /// <summary>
94    /// Instantiates all defined (in template) ResultCollectionProcessors and injects the configured parameters.
95    /// </summary>
96    private IEnumerable<IRunCollectionModifier> CollectRunCollectionModifiers() {
97      IList<IRunCollectionModifier> runCollectionModifiers = new List<IRunCollectionModifier>();
98
99      if (Template is JObject o && !o.ContainsKey(Constants.RunCollectionModifiers))
100        return Enumerable.Empty<IRunCollectionModifier>();
101
102      foreach (JObject obj in Template[Constants.RunCollectionModifiers]) {
103        var guid = obj["GUID"].ToString();
104        var parameters = obj[Constants.Parameters];
105        var type = Mapper.StaticCache.GetType(new Guid(guid));
106        var rcModifier = (IRunCollectionModifier)Activator.CreateInstance(type);
107        var rcModifierItem = JsonItemConverter.Extract(rcModifier);
108
109        SetJObjects(rcModifierItem, parameters);       
110
111        JsonItemConverter.Inject(rcModifier, rcModifierItem);
112        runCollectionModifiers.Add(rcModifier);
113      }
114      return runCollectionModifiers;
115    }
116
117    private void CollectParameterizedItems(IOptimizer optimizer) {
118      IJsonItem root = JsonItemConverter.Extract(optimizer);
119      Objects.Add(root.Path, root);
120
121      foreach (var kvp in SetJObjects(root, Template[Constants.Parameters]))
122        Objects.Add(kvp);
123    }
124
125    private IDictionary<string, IJsonItem> SetJObjects(IJsonItem root, JToken parameters) {
126      var dict = new Dictionary<string, IJsonItem>();
127      foreach (JObject obj in parameters) {
128        var path = obj[nameof(IJsonItem.Path)].ToString();
129        foreach (var item in root) {
130          if (item.Path == path) {
131            item.SetJObject(obj);
132            item.Active = true;
133            dict.Add(item.Path, item);
134          }
135        }
136      }
137      return dict;
138    }
139
140    private void MergeTemplateWithConfig() {
141      foreach (JObject obj in Config) {
142        // build item from config object
143        var prop = obj.Property("Path");
144        if (prop == null)
145          throw new ArgumentException("Path property is missing.");
146        string path = prop.Value.ToString();
147        // override default value
148        if (Objects.TryGetValue(path, out IJsonItem param)) {
149          // remove fixed template parameter from config => dont allow to copy them from concrete config
150          // TODO: shift this into JsonItems?
151          obj.Property(nameof(IIntervalRestrictedJsonItem<int>.Minimum))?.Remove();
152          obj.Property(nameof(IIntervalRestrictedJsonItem<int>.Maximum))?.Remove();
153          obj.Property(nameof(IConcreteRestrictedJsonItem<string>.ConcreteRestrictedItems))?.Remove();
154          obj.Property(nameof(IMatrixJsonItem.ColumnsResizable))?.Remove();
155          obj.Property(nameof(IMatrixJsonItem.RowsResizable))?.Remove();
156          obj.Property(nameof(IArrayJsonItem.Resizable))?.Remove();
157          // merge
158          param.SetJObject(obj);
159        } else throw new InvalidDataException($"No parameter with path='{path}' defined!");
160      }
161    }
162    #endregion
163  }
164}
Note: See TracBrowser for help on using the repository browser.