source: branches/OptimizationNetworks/HeuristicLab.Optimization.Networks/3.3/Ports/GenericPort.cs @ 11501

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

#2205: Worked on optimization networks

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