Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OptimizationNetworks/HeuristicLab.Networks/3.3/Programmable/ProgrammableNetworkItem.cs @ 11577

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

#2205: Restructured solution and projects and switched all projects to .NET 4.5

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