Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OptimizationNetworks/HeuristicLab.Optimization.Networks/3.3/Core.Networks/ProgrammableNetworkItem.cs @ 11565

Last change on this file since 11565 was 11565, checked in by swagner, 9 years ago

#2205: Continued working on programmable network items

  • allowed code changes only in user-defined nodes and networks
  • added manual initialization of compiled programmable network items
File size: 13.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2014 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 HeuristicLab.Common;
23using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
24using Microsoft.CSharp;
25using System;
26using System.CodeDom.Compiler;
27using System.Collections.Generic;
28using System.Drawing;
29using System.IO;
30using System.Linq;
31using System.Reflection;
32using System.Text;
33
34namespace HeuristicLab.Core.Networks {
35  [Item("ProgrammableNetworkItem", "Abstract base class for programmable items of a network.")]
36  [StorableClass]
37  public abstract class ProgrammableNetworkItem : Item, IProgrammableNetworkItem {
38    public static new Image StaticItemImage {
39      get { return HeuristicLab.Common.Resources.VSImageLibrary.Script; }
40    }
41
42    #region Item Members
43    public override string ItemName {
44      get { return CompiledNetworkItem.ItemName; }
45    }
46    public override string ItemDescription {
47      get { return CompiledNetworkItem.ItemDescription; }
48    }
49    public override Image ItemImage {
50      get { return CompiledNetworkItem.ItemImage; }
51    }
52    #endregion
53
54    #region NamedItem Members
55    [Storable]
56    private string name;
57    public string Name {
58      get { return CompiledNetworkItem.Name; }
59      set { CompiledNetworkItem.Name = value; }
60    }
61    public bool CanChangeName {
62      get { return CompiledNetworkItem.CanChangeName; }
63    }
64    [Storable]
65    private string description;
66    public string Description {
67      get { return CompiledNetworkItem.Description; }
68      set { CompiledNetworkItem.Description = value; }
69    }
70    public virtual bool CanChangeDescription {
71      get { return CompiledNetworkItem.CanChangeDescription; }
72    }
73    public event EventHandler<CancelEventArgs<string>> NameChanging;
74    private void OnNameChanging(CancelEventArgs<string> e) {
75      var handler = NameChanging;
76      if (handler != null) handler(this, e);
77    }
78    public event EventHandler NameChanged;
79    private void OnNameChanged() {
80      var handler = NameChanged;
81      if (handler != null) handler(this, EventArgs.Empty);
82    }
83    public event EventHandler DescriptionChanged;
84    private void OnDescriptionChanged() {
85      var handler = DescriptionChanged;
86      if (handler != null) handler(this, EventArgs.Empty);
87    }
88    #endregion
89
90    #region NetworkItem Members
91    public INetworkItem Parent {
92      get { return CompiledNetworkItem.Parent; }
93    }
94    public IEnumerable<INetworkItem> Children {
95      get { return CompiledNetworkItem.Children; }
96    }
97    #endregion
98
99    protected virtual string CodeTemplate {
100      get { return ReadCodeTemplate("HeuristicLab.Optimization.Networks.Core.Networks.ProgrammableNetworkItemTemplate.cs"); }
101    }
102    [Storable]
103    private string code;
104    public string Code {
105      get { return code; }
106      set {
107        if (!CanChangeCode) throw new NotSupportedException("Code cannot be changed.");
108        if (value != code) {
109          code = value;
110          OnCodeChanged();
111        }
112      }
113    }
114    private CompilerErrorCollection compileErrors;
115    public CompilerErrorCollection CompileErrors {
116      get { return compileErrors; }
117      protected set {
118        compileErrors = value;
119        OnCompileErrorsChanged();
120      }
121    }
122    public virtual bool CanChangeCode {
123      get { return false; }
124    }
125
126    private Type compiledNetworkItemType;
127    private CompiledProgrammableNetworkItem compiledNetworkItem;
128    protected CompiledProgrammableNetworkItem CompiledNetworkItem {
129      get {
130        if (compiledNetworkItem == null)
131          CompiledNetworkItem = (CompiledProgrammableNetworkItem)Activator.CreateInstance(compiledNetworkItemType, this);
132        return compiledNetworkItem;
133      }
134      private set {
135        if (compiledNetworkItem != value) {
136          if (compiledNetworkItem != null) {
137            DeregisterCompiledNetworkItemEvents();
138            compiledNetworkItem.DeregisterEvents();
139          }
140          compiledNetworkItem = value;
141          if (compiledNetworkItem != null) {
142            RegisterCompiledNetworkItemEvents();
143            compiledNetworkItem.RegisterEvents();
144          }
145          OnToStringChanged();
146          OnItemImageChanged();
147          OnNameChanged();
148          OnDescriptionChanged();
149        }
150      }
151    }
152
153    [StorableConstructor]
154    protected ProgrammableNetworkItem(bool deserializing) : base(deserializing) { }
155    protected ProgrammableNetworkItem(ProgrammableNetworkItem original, Cloner cloner)
156      : base(original, cloner) {
157      // name and description are cloned in CompiledProgrammableNetworkItem
158      code = original.code;
159      if (original.compileErrors != null)
160        compileErrors = new CompilerErrorCollection(original.compileErrors);
161      CompiledNetworkItem = cloner.Clone(original.compiledNetworkItem);
162    }
163    protected ProgrammableNetworkItem()
164      : base() {
165      name = "ProgrammableNetworkItem";
166      description = string.Empty;
167      code = CodeTemplate;
168      Compile();
169    }
170    protected ProgrammableNetworkItem(string name)
171      : base() {
172      this.name = string.IsNullOrEmpty(name) ? string.Empty : name;
173      description = string.Empty;
174      code = CodeTemplate;
175      Compile();
176    }
177    protected ProgrammableNetworkItem(string name, string description)
178      : base() {
179      this.name = string.IsNullOrEmpty(name) ? string.Empty : name;
180      this.description = string.IsNullOrEmpty(description) ? string.Empty : description;
181      code = CodeTemplate;
182      Compile();
183    }
184
185    [StorableHook(HookType.AfterDeserialization)]
186    private void AfterDeserialization() {
187      Compile();
188    }
189
190    public override string ToString() {
191      return CompiledNetworkItem.ToString();
192    }
193
194    #region Compilation
195    public virtual void Compile() {
196      var codeProvider = new CSharpCodeProvider(
197        new Dictionary<string, string> {
198          {"CompilerVersion", "v4.0"}, // support C# 4.0 syntax
199        }
200      );
201      var compilerParams = new CompilerParameters {
202        GenerateExecutable = false,
203        GenerateInMemory = true,
204        IncludeDebugInformation = true,
205        WarningLevel = 4
206      };
207      compilerParams.ReferencedAssemblies.AddRange(
208        GetAssemblies().Select(a => a.Location).ToArray()
209      );
210      var results = codeProvider.CompileAssemblyFromSource(compilerParams, code);
211      CompileErrors = results.Errors;
212      if (results.Errors.HasErrors) {
213        var sb = new StringBuilder();
214        foreach (CompilerError error in results.Errors) {
215          sb.Append(error.Line).Append(':')
216            .Append(error.Column).Append(": ")
217            .AppendLine(error.ErrorText);
218        }
219        throw new InvalidOperationException(string.Format("Compilation of \"{0}\" failed:{1}{2}",
220          Name, Environment.NewLine, sb.ToString()));
221      }
222      compiledNetworkItemType = results.CompiledAssembly.GetTypes()
223          .Single(x => typeof(CompiledProgrammableNetworkItem).IsAssignableFrom(x));
224      CompiledNetworkItem = null;
225    }
226    public virtual IEnumerable<Assembly> GetAssemblies() {
227      return AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.IsDynamic && File.Exists(a.Location));
228    }
229    #endregion
230
231    public event EventHandler CodeChanged;
232    protected virtual void OnCodeChanged() {
233      var handler = CodeChanged;
234      if (handler != null) handler(this, EventArgs.Empty);
235    }
236    public event EventHandler CompileErrorsChanged;
237    protected virtual void OnCompileErrorsChanged() {
238      var handler = CompileErrorsChanged;
239      if (handler != null) handler(this, EventArgs.Empty);
240    }
241
242    #region CompiledNetworkItem Events
243    protected virtual void RegisterCompiledNetworkItemEvents() {
244      CompiledNetworkItem.ToStringChanged += CompiledNetworkItem_ToStringChanged;
245      CompiledNetworkItem.ItemImageChanged += CompiledNetworkItem_ItemImageChanged;
246      CompiledNetworkItem.NameChanging += CompiledNetworkItem_NameChanging;
247      CompiledNetworkItem.NameChanged += CompiledNetworkItem_NameChanged;
248      CompiledNetworkItem.DescriptionChanged += CompiledNetworkItem_DescriptionChanged;
249    }
250    protected virtual void DeregisterCompiledNetworkItemEvents() {
251      CompiledNetworkItem.ToStringChanged -= CompiledNetworkItem_ToStringChanged;
252      CompiledNetworkItem.ItemImageChanged -= CompiledNetworkItem_ItemImageChanged;
253      CompiledNetworkItem.NameChanging -= CompiledNetworkItem_NameChanging;
254      CompiledNetworkItem.NameChanged -= CompiledNetworkItem_NameChanged;
255      CompiledNetworkItem.DescriptionChanged -= CompiledNetworkItem_DescriptionChanged;
256    }
257    private void CompiledNetworkItem_ToStringChanged(object sender, EventArgs e) {
258      OnToStringChanged();
259    }
260    private void CompiledNetworkItem_ItemImageChanged(object sender, EventArgs e) {
261      OnItemImageChanged();
262    }
263    private void CompiledNetworkItem_NameChanging(object sender, CancelEventArgs<string> e) {
264      OnNameChanging(e);
265    }
266    private void CompiledNetworkItem_NameChanged(object sender, EventArgs e) {
267      OnNameChanged();
268    }
269    private void CompiledNetworkItem_DescriptionChanged(object sender, EventArgs e) {
270      OnDescriptionChanged();
271    }
272    #endregion
273
274    #region CompiledProgrammableNetworkItem
275    [Item("CompiledProgrammableNetworkItem", "Abstract base class for compiled programmable items of a network.")]
276    public abstract class CompiledProgrammableNetworkItem : Item, INetworkItem {
277      public static new Image StaticItemImage {
278        get { return HeuristicLab.Common.Resources.VSImageLibrary.Script; }
279      }
280
281      #region NamedItem Members
282      public string Name {
283        get { return Context.name; }
284        set {
285          if (!CanChangeName) throw new NotSupportedException("Name cannot be changed.");
286          if (!(Context.name.Equals(value) || (value == null) && (Context.name == string.Empty))) {
287            CancelEventArgs<string> e = value == null ? new CancelEventArgs<string>(string.Empty) : new CancelEventArgs<string>(value);
288            OnNameChanging(e);
289            if (!e.Cancel) {
290              Context.name = value == null ? string.Empty : value;
291              OnNameChanged();
292            }
293          }
294        }
295      }
296      public virtual bool CanChangeName {
297        get { return true; }
298      }
299      public string Description {
300        get { return Context.description; }
301        set {
302          if (!CanChangeDescription) throw new NotSupportedException("Description cannot be changed.");
303          if (!(Context.description.Equals(value) || (value == null) && (Context.description == string.Empty))) {
304            Context.description = value == null ? string.Empty : value;
305            OnDescriptionChanged();
306          }
307        }
308      }
309      public virtual bool CanChangeDescription {
310        get { return true; }
311      }
312
313      public event EventHandler<CancelEventArgs<string>> NameChanging;
314      protected virtual void OnNameChanging(CancelEventArgs<string> e) {
315        var handler = NameChanging;
316        if (handler != null) handler(this, e);
317      }
318      public event EventHandler NameChanged;
319      protected virtual void OnNameChanged() {
320        var handler = NameChanged;
321        if (handler != null) handler(this, EventArgs.Empty);
322        OnToStringChanged();
323      }
324      public event EventHandler DescriptionChanged;
325      protected virtual void OnDescriptionChanged() {
326        var handler = DescriptionChanged;
327        if (handler != null) handler(this, EventArgs.Empty);
328      }
329      #endregion
330
331      #region NetworkItem Members
332      private INetworkItem parent;
333      public INetworkItem Parent {
334        get { return parent; }
335        protected set {
336          if (value != parent) {
337            parent = value;
338          }
339        }
340      }
341      public virtual IEnumerable<INetworkItem> Children {
342        get { return Enumerable.Empty<INetworkItem>(); }
343      }
344      #endregion
345
346      protected ProgrammableNetworkItem Context { get; private set; }
347
348      protected CompiledProgrammableNetworkItem(CompiledProgrammableNetworkItem original, Cloner cloner)
349        : base(original, cloner) {
350        Context = cloner.Clone(original.Context);
351        Context.name = original.Context.name;
352        Context.description = original.Context.description;
353      }
354      protected CompiledProgrammableNetworkItem(ProgrammableNetworkItem context)
355        : base() {
356        Context = context;
357      }
358
359      public virtual void Initialize() { }
360
361      public override string ToString() {
362        return Name;
363      }
364
365      #region Events
366      public virtual void RegisterEvents() { }
367      public virtual void DeregisterEvents() { }
368      #endregion
369    }
370    #endregion
371
372    #region Helpers
373    protected virtual string ReadCodeTemplate(string templateName) {
374      using (var stream = Assembly.GetAssembly(this.GetType()).GetManifestResourceStream(templateName))
375      using (var reader = new StreamReader(stream)) {
376        return reader.ReadToEnd();
377      }
378    }
379    #endregion
380  }
381}
Note: See TracBrowser for help on using the repository browser.