Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OptimizationNetworks/HeuristicLab.Core/3.3/Networks/MessagePort.cs @ 11682

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

#2205: Worked on cancellation

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