source: branches/OptimizationNetworks/HeuristicLab.Optimization.Networks/3.3/Core.Networks/GenericPort.cs @ 11529

Last change on this file since 11529 was 11529, checked in by swagner, 8 years ago

#2205: Implemented review comments

  • made Node and Network abstract
  • renamed GenericNode to UserDefinedNode and sealed it
  • added sealed UserDefinedNetwork
  • made Nodes in Network not changeable by default
  • made Parameters in ParameterizedPort not changeable by default
  • removed value None in PortParameterType
  • refactored call algorithm.PrepareMessage() in AlgorithmNode
File size: 10.1 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 System;
25using System.Drawing;
26using System.Linq;
27using System.Threading;
28using System.Threading.Tasks;
29
30namespace HeuristicLab.Core.Networks {
31  [Item("GenericPort", "A generic port of an optimization network node.")]
32  [StorableClass]
33  public class GenericPort : ParameterizedPort, IGenericPort, IConnectedPort {
34    public override Image ItemImage {
35      get {
36        if (PortConnectionValid) return base.ItemImage;
37        else return HeuristicLab.Common.Resources.VSImageLibrary.Error;
38      }
39    }
40
41    new public PortParameterCollection Parameters {
42      get { return base.Parameters; }
43    }
44
45    [Storable]
46    protected IConnectedPort connectedPort;
47    public IConnectedPort ConnectedPort {
48      get { return connectedPort; }
49      set {
50        if (connectedPort != value) {
51          DeregisterConnectedPortEvents();
52          connectedPort = value;
53          RegisterConnectedPortEvents();
54          OnConnectedPortChanged();
55          OnInterfaceChanged();
56        }
57      }
58    }
59    [Storable]
60    protected bool portConnectionValid;
61    public bool PortConnectionValid {
62      get { return portConnectionValid; }
63      protected set {
64        if (value != portConnectionValid) {
65          portConnectionValid = value;
66          OnPortConnectionValidChanged();
67          OnItemImageChanged();
68        }
69      }
70    }
71    [Storable]
72    protected bool logMessages;
73    public bool LogMessages {
74      get { return logMessages; }
75      set {
76        if (value != logMessages) {
77          logMessages = value;
78          OnLogMessagesChanged();
79        }
80      }
81    }
82    [Storable]
83    protected MessageCollection messages;
84    public MessageCollection Messages {
85      get { return messages; }
86    }
87
88    [StorableConstructor]
89    protected GenericPort(bool deserializing) : base(deserializing) { }
90    protected GenericPort(GenericPort original, Cloner cloner)
91      : base(original, cloner) {
92      connectedPort = cloner.Clone(original.connectedPort);
93      portConnectionValid = original.portConnectionValid;
94      logMessages = original.logMessages;
95      messages = cloner.Clone(original.messages);
96      RegisterConnectedPortEvents();
97    }
98    public GenericPort()
99      : base("GenericPort") {
100      portConnectionValid = true;
101      logMessages = false;
102      messages = new MessageCollection();
103    }
104    public GenericPort(string name)
105      : base(name) {
106      portConnectionValid = true;
107      logMessages = false;
108      messages = new MessageCollection();
109    }
110    public GenericPort(string name, string description)
111      : base(name, description) {
112      portConnectionValid = true;
113      logMessages = false;
114      messages = new MessageCollection();
115    }
116
117    [StorableHook(HookType.AfterDeserialization)]
118    private void AfterDeserialization() {
119      RegisterConnectedPortEvents();
120    }
121
122    public override IDeepCloneable Clone(Cloner cloner) {
123      return new GenericPort(this, cloner);
124    }
125
126    public bool CanConnectToPort(IPort port) {
127      if (port == null) return true;
128
129      var cp = port as IConnectedPort;
130      if (cp == null) return false;
131
132      // check connected port input parameters
133      foreach (var input in cp.Parameters.Where(p => p.Type.HasFlag(PortParameterType.Input))) {
134        IPortParameter param;
135        Parameters.TryGetValue(input.Name, out param);
136        if ((param == null) && (input.DefaultValue == null)) return false;
137        if (!param.Type.HasFlag(PortParameterType.Output)) return false;
138        if (!input.DataType.IsAssignableFrom(param.DataType)) return false;
139      }
140      // check local port input parameters
141      foreach (var input in Parameters.Where(p => p.Type.HasFlag(PortParameterType.Input))) {
142        IPortParameter param;
143        cp.Parameters.TryGetValue(input.Name, out param);
144        if ((param == null) && (input.DefaultValue == null)) return false;
145        if (!param.Type.HasFlag(PortParameterType.Output)) return false;
146        if (!input.DataType.IsAssignableFrom(param.DataType)) return false;
147      }
148      return true;
149    }
150    public void CloneConnectedPortParameters() {
151      Parameters.Clear();
152      foreach (var p in connectedPort.Parameters) {
153        var param = (IPortParameter)p.Clone();
154        if (!(param.Type.HasFlag(PortParameterType.Input) && param.Type.HasFlag(PortParameterType.Output))) {
155          param.Type = ~param.Type;  // bitwise negation: input -> output, output -> input
156        }
157        Parameters.Add(param);
158      }
159    }
160
161    public IMessage PrepareMessage() {
162      if (!PortConnectionValid) throw new InvalidOperationException("Port connection is not valid");
163      var message = new Message();
164
165      // collect output parameters from local port
166      message.Values.AddRange(
167        Parameters
168          .Where(p => p.Type.HasFlag(PortParameterType.Output))
169          .Select(p => p.CreateMessageValue())
170      );
171
172      // collect remaining input parameters from connected port
173      if (ConnectedPort != null) {
174        message.Values.AddRange(
175          ConnectedPort.Parameters
176            .Where(p => p.Type.HasFlag(PortParameterType.Input) && !message.Values.ContainsKey(p.Name))
177            .Select(p => p.CreateMessageValue())
178        );
179      }
180
181      // collect output parameters from connected port
182      if (ConnectedPort != null) {
183        message.Values.AddRange(
184          ConnectedPort.Parameters
185            .Where(p => p.Type.HasFlag(PortParameterType.Output) && !message.Values.ContainsKey(p.Name))
186            .Select(p => p.CreateMessageValue())
187        );
188      }
189
190      // collect remaining input parameters from local port
191      message.Values.AddRange(
192        Parameters
193          .Where(p => p.Type.HasFlag(PortParameterType.Input) && !message.Values.ContainsKey(p.Name))
194          .Select(p => p.CreateMessageValue())
195      );
196
197      return message;
198    }
199    public void SendMessage(IMessage message) {
200      SendMessage(message, CancellationToken.None);
201    }
202    public void SendMessage(IMessage message, CancellationToken token) {
203      if (!PortConnectionValid) throw new InvalidOperationException("Port connection is not valid");
204      if (LogMessages) Messages.Add(message);
205      if (ConnectedPort != null) ConnectedPort.ReceiveMessage(message, token);
206      OnMessageSent(message, token);
207    }
208    public async Task SendMessageAsync(IMessage message) {
209      await SendMessageAsync(message, CancellationToken.None);
210    }
211    public async Task SendMessageAsync(IMessage message, CancellationToken token) {
212      await Task.Run(() => { SendMessage(message, token); }, token);
213    }
214    public event EventHandler<EventArgs<IMessage, CancellationToken>> MessageSent;
215    protected virtual void OnMessageSent(IMessage message, CancellationToken token) {
216      var handler = MessageSent;
217      if (handler != null) handler(this, new EventArgs<IMessage, CancellationToken>(message, token));
218    }
219
220    public void ReceiveMessage(IMessage message, CancellationToken token) {
221      if (!PortConnectionValid) throw new InvalidOperationException("Port connection is not valid");
222      if (LogMessages) Messages.Add(message);
223      OnMessageReceived(message, token);
224    }
225    public event EventHandler<EventArgs<IMessage, CancellationToken>> MessageReceived;
226    protected virtual void OnMessageReceived(IMessage message, CancellationToken token) {
227      var handler = MessageReceived;
228      if (handler != null) handler(this, new EventArgs<IMessage, CancellationToken>(message, token));
229    }
230
231    public event EventHandler ConnectedPortChanged;
232    protected virtual void OnConnectedPortChanged() {
233      var handler = ConnectedPortChanged;
234      if (handler != null) handler(this, EventArgs.Empty);
235    }
236    public event EventHandler PortConnectionValidChanged;
237    protected virtual void OnPortConnectionValidChanged() {
238      var handler = PortConnectionValidChanged;
239      if (handler != null) handler(this, EventArgs.Empty);
240    }
241    public event EventHandler LogMessagesChanged;
242    protected virtual void OnLogMessagesChanged() {
243      var handler = LogMessagesChanged;
244      if (handler != null) handler(this, EventArgs.Empty);
245    }
246
247    protected override void OnInterfaceChanged() {
248      PortConnectionValid = CanConnectToPort(connectedPort);
249      base.OnInterfaceChanged();
250    }
251
252    #region ConnectedPort Events
253    protected virtual void RegisterConnectedPortEvents() {
254      if (connectedPort != null) {
255        connectedPort.InterfaceChanged += ConnectedPort_InterfaceChanged;
256        connectedPort.MessageSent += ConnectedPort_MessageSent;
257      }
258    }
259    protected virtual void DeregisterConnectedPortEvents() {
260      if (connectedPort != null) {
261        connectedPort.InterfaceChanged -= ConnectedPort_InterfaceChanged;
262        connectedPort.MessageSent -= ConnectedPort_MessageSent;
263      }
264    }
265    protected virtual void ConnectedPort_InterfaceChanged(object sender, EventArgs e) {
266      OnInterfaceChanged();
267    }
268    protected virtual void ConnectedPort_MessageSent(object sender, EventArgs<IMessage, CancellationToken> e) {
269      ReceiveMessage(e.Value, e.Value2);
270    }
271    #endregion
272  }
273}
Note: See TracBrowser for help on using the repository browser.