Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2205: Continued working on programmable network items

File size: 13.7 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
103    [Storable]
104    private string code;
105    public string Code {
106      get { return code; }
107      set {
108        if (value != code) {
109          code = value;
110          OnCodeChanged();
111        }
112      }
113    }
114
115    private CompilerErrorCollection compileErrors;
116    public CompilerErrorCollection CompileErrors {
117      get { return compileErrors; }
118      protected set {
119        compileErrors = value;
120        OnCompileErrorsChanged();
121      }
122    }
123
124    private Type compiledNetworkItemType;
125    private CompiledProgrammableNetworkItem compiledNetworkItem;
126    protected CompiledProgrammableNetworkItem CompiledNetworkItem {
127      get {
128        if (compiledNetworkItem == null)
129          CompiledNetworkItem = (CompiledProgrammableNetworkItem)Activator.CreateInstance(compiledNetworkItemType, this);
130        return compiledNetworkItem;
131      }
132      private set {
133        if (compiledNetworkItem != value) {
134          if (compiledNetworkItem != null) {
135            DeregisterCompiledNetworkItemEvents();
136            compiledNetworkItem.DeregisterEvents();
137          }
138          compiledNetworkItem = value;
139          if (compiledNetworkItem != null) {
140            RegisterCompiledNetworkItemEvents();
141            compiledNetworkItem.RegisterEvents();
142          }
143          OnToStringChanged();
144          OnItemImageChanged();
145          OnNameChanged();
146          OnDescriptionChanged();
147        }
148      }
149    }
150
151    [StorableConstructor]
152    protected ProgrammableNetworkItem(bool deserializing) : base(deserializing) { }
153    protected ProgrammableNetworkItem(ProgrammableNetworkItem original, Cloner cloner)
154      : base(original, cloner) {
155      // name and description are cloned in CompiledProgrammableNetworkItem
156      code = original.code;
157      if (original.compileErrors != null)
158        compileErrors = new CompilerErrorCollection(original.compileErrors);
159      CompiledNetworkItem = cloner.Clone(original.compiledNetworkItem);
160    }
161    protected ProgrammableNetworkItem()
162      : base() {
163      name = "ProgrammableNetworkItem";
164      description = string.Empty;
165      code = CodeTemplate;
166      Compile();
167    }
168    protected ProgrammableNetworkItem(string name)
169      : base() {
170      this.name = string.IsNullOrEmpty(name) ? string.Empty : name;
171      description = string.Empty;
172      code = CodeTemplate;
173      Compile();
174    }
175    protected ProgrammableNetworkItem(string name, string description)
176      : base() {
177      this.name = string.IsNullOrEmpty(name) ? string.Empty : name;
178      this.description = string.IsNullOrEmpty(description) ? string.Empty : description;
179      code = CodeTemplate;
180      Compile();
181    }
182
183    [StorableHook(HookType.AfterDeserialization)]
184    private void AfterDeserialization() {
185      Compile();
186    }
187
188    public override string ToString() {
189      return CompiledNetworkItem.ToString();
190    }
191
192    #region Compilation
193    public virtual void Compile() {
194      var codeProvider = new CSharpCodeProvider(
195        new Dictionary<string, string> {
196          {"CompilerVersion", "v4.0"}, // support C# 4.0 syntax
197        }
198      );
199      var compilerParams = new CompilerParameters {
200        GenerateExecutable = false,
201        GenerateInMemory = true,
202        IncludeDebugInformation = true,
203        WarningLevel = 4
204      };
205      compilerParams.ReferencedAssemblies.AddRange(
206        GetAssemblies().Select(a => a.Location).ToArray()
207      );
208      var results = codeProvider.CompileAssemblyFromSource(compilerParams, code);
209      CompileErrors = results.Errors;
210      if (results.Errors.HasErrors) {
211        var sb = new StringBuilder();
212        foreach (CompilerError error in results.Errors) {
213          sb.Append(error.Line).Append(':')
214            .Append(error.Column).Append(": ")
215            .AppendLine(error.ErrorText);
216        }
217        throw new InvalidOperationException(string.Format("Compilation of \"{0}\" failed:{1}{2}",
218          Name, Environment.NewLine, sb.ToString()));
219      }
220      compiledNetworkItemType = results.CompiledAssembly.GetTypes()
221          .Single(x => typeof(CompiledProgrammableNetworkItem).IsAssignableFrom(x));
222      CompiledNetworkItem = null;
223    }
224    public virtual IEnumerable<Assembly> GetAssemblies() {
225      return AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.IsDynamic && File.Exists(a.Location));
226    }
227    #endregion
228
229    public event EventHandler CodeChanged;
230    protected virtual void OnCodeChanged() {
231      var handler = CodeChanged;
232      if (handler != null) handler(this, EventArgs.Empty);
233    }
234    public event EventHandler CompileErrorsChanged;
235    protected virtual void OnCompileErrorsChanged() {
236      var handler = CompileErrorsChanged;
237      if (handler != null) handler(this, EventArgs.Empty);
238    }
239
240    #region CompiledNetworkItem Events
241    protected virtual void RegisterCompiledNetworkItemEvents() {
242      CompiledNetworkItem.ToStringChanged += CompiledNetworkItem_ToStringChanged;
243      CompiledNetworkItem.ItemImageChanged += CompiledNetworkItem_ItemImageChanged;
244      CompiledNetworkItem.NameChanging += CompiledNetworkItem_NameChanging;
245      CompiledNetworkItem.NameChanged += CompiledNetworkItem_NameChanged;
246      CompiledNetworkItem.DescriptionChanged += CompiledNetworkItem_DescriptionChanged;
247    }
248    protected virtual void DeregisterCompiledNetworkItemEvents() {
249      CompiledNetworkItem.ToStringChanged -= CompiledNetworkItem_ToStringChanged;
250      CompiledNetworkItem.ItemImageChanged -= CompiledNetworkItem_ItemImageChanged;
251      CompiledNetworkItem.NameChanging -= CompiledNetworkItem_NameChanging;
252      CompiledNetworkItem.NameChanged -= CompiledNetworkItem_NameChanged;
253      CompiledNetworkItem.DescriptionChanged -= CompiledNetworkItem_DescriptionChanged;
254    }
255    private void CompiledNetworkItem_ToStringChanged(object sender, EventArgs e) {
256      OnToStringChanged();
257    }
258    private void CompiledNetworkItem_ItemImageChanged(object sender, EventArgs e) {
259      OnItemImageChanged();
260    }
261    private void CompiledNetworkItem_NameChanging(object sender, CancelEventArgs<string> e) {
262      OnNameChanging(e);
263    }
264    private void CompiledNetworkItem_NameChanged(object sender, EventArgs e) {
265      OnNameChanged();
266    }
267    private void CompiledNetworkItem_DescriptionChanged(object sender, EventArgs e) {
268      OnDescriptionChanged();
269    }
270    #endregion
271
272    #region CompiledProgrammableNetworkItem
273    [Item("CompiledProgrammableNetworkItem", "Abstract base class for compiled programmable items of a network.")]
274    public abstract class CompiledProgrammableNetworkItem : Item, INetworkItem {
275      public static new Image StaticItemImage {
276        get { return HeuristicLab.Common.Resources.VSImageLibrary.Script; }
277      }
278
279      #region NamedItem Members
280      public string Name {
281        get { return Context.name; }
282        set {
283          if (!CanChangeName) throw new NotSupportedException("Name cannot be changed.");
284          if (!(Context.name.Equals(value) || (value == null) && (Context.name == string.Empty))) {
285            CancelEventArgs<string> e = value == null ? new CancelEventArgs<string>(string.Empty) : new CancelEventArgs<string>(value);
286            OnNameChanging(e);
287            if (!e.Cancel) {
288              Context.name = value == null ? string.Empty : value;
289              OnNameChanged();
290            }
291          }
292        }
293      }
294      public virtual bool CanChangeName {
295        get { return true; }
296      }
297      public string Description {
298        get { return Context.description; }
299        set {
300          if (!CanChangeDescription) throw new NotSupportedException("Description cannot be changed.");
301          if (!(Context.description.Equals(value) || (value == null) && (Context.description == string.Empty))) {
302            Context.description = value == null ? string.Empty : value;
303            OnDescriptionChanged();
304          }
305        }
306      }
307      public virtual bool CanChangeDescription {
308        get { return true; }
309      }
310
311      public event EventHandler<CancelEventArgs<string>> NameChanging;
312      protected virtual void OnNameChanging(CancelEventArgs<string> e) {
313        var handler = NameChanging;
314        if (handler != null) handler(this, e);
315      }
316      public event EventHandler NameChanged;
317      protected virtual void OnNameChanged() {
318        var handler = NameChanged;
319        if (handler != null) handler(this, EventArgs.Empty);
320        OnToStringChanged();
321      }
322      public event EventHandler DescriptionChanged;
323      protected virtual void OnDescriptionChanged() {
324        var handler = DescriptionChanged;
325        if (handler != null) handler(this, EventArgs.Empty);
326      }
327      #endregion
328
329      #region NetworkItem Members
330      private INetworkItem parent;
331      public INetworkItem Parent {
332        get { return parent; }
333        protected set {
334          if (value != parent) {
335            parent = value;
336          }
337        }
338      }
339      public virtual IEnumerable<INetworkItem> Children {
340        get { return Enumerable.Empty<INetworkItem>(); }
341      }
342      #endregion
343
344      protected ProgrammableNetworkItem Context { get; private set; }
345
346      protected CompiledProgrammableNetworkItem(CompiledProgrammableNetworkItem original, Cloner cloner)
347        : base(original, cloner) {
348        Context = cloner.Clone(original.Context);
349        Context.name = original.Context.name;
350        Context.description = original.Context.description;
351      }
352      protected CompiledProgrammableNetworkItem(ProgrammableNetworkItem context)
353        : base() {
354        Context = context;
355      }
356
357      public virtual void Initialize() { }
358
359      public override string ToString() {
360        return Name;
361      }
362
363      #region Events
364      public virtual void RegisterEvents() { }
365      public virtual void DeregisterEvents() { }
366      #endregion
367    }
368    #endregion
369
370    #region Helpers
371    protected virtual string ReadCodeTemplate(string templateName) {
372      using (var stream = Assembly.GetAssembly(this.GetType()).GetManifestResourceStream(templateName))
373      using (var reader = new StreamReader(stream)) {
374        return reader.ReadToEnd();
375      }
376    }
377    #endregion
378  }
379}
Note: See TracBrowser for help on using the repository browser.