Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Hive.Client.Communication/3.2/WcfService.cs @ 2063

Last change on this file since 2063 was 2063, checked in by kgrading, 15 years ago

added "time for shutdown" behavior: Snapshots of jobs get sent back to the server and then killed. When all jobs are killed, the client switches to disconnect state (#669)

File size: 13.2 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 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 System;
23using System.Collections.Generic;
24using System.Linq;
25using System.Text;
26using System.ServiceModel;
27using HeuristicLab.Hive.Contracts.Interfaces;
28using HeuristicLab.Hive.Contracts;
29using HeuristicLab.Hive.Contracts.BusinessObjects;
30using HeuristicLab.Hive.Client.Common;
31using HeuristicLab.Hive.Client.Communication.ServerService;
32using HeuristicLab.PluginInfrastructure;
33using System.IO;
34using System.Runtime.Serialization.Formatters.Binary;
35
36namespace HeuristicLab.Hive.Client.Communication {
37  /// <summary>
38  /// WcfService class is implemented as a Singleton and works as a communication Layer with the Server
39  /// </summary>
40  public class WcfService {
41    private static WcfService instance;
42    /// <summary>
43    /// Getter for the Instance of the WcfService
44    /// </summary>
45    /// <returns>the Instance of the WcfService class</returns>
46    public static WcfService Instance {
47      get {
48        if (instance == null) {
49          instance = new WcfService();
50        }
51        return instance;
52      }
53    }
54
55    public DateTime ConnectedSince { get; private set; }   
56    public NetworkEnum.WcfConnState ConnState { get; private set; }
57    public string ServerIP { get; private set; }
58    public int ServerPort { get; private set; }
59
60    public event EventHandler ConnectionRestored;   
61    public event EventHandler ServerChanged;
62    public event EventHandler Connected;   
63
64    public ClientFacadeClient proxy = null;
65
66    /// <summary>
67    /// Constructor
68    /// </summary>
69    private WcfService() {
70      ConnState = NetworkEnum.WcfConnState.Disconnected;
71    }
72
73    /// <summary>
74    /// Connects with the Server, registers the events and fires the Connected (and quiet possibly the ConnectionRestored) Event.
75    /// </summary>
76    public void Connect() {
77      try {
78        if (String.Empty.Equals(ServerIP) || ServerPort == 0) {
79          Logging.Instance.Info(this.ToString(), "No Server IP or Port set!");
80          return;
81        }
82        proxy = new ClientFacadeClient(
83          WcfSettings.GetStreamedBinding(),
84          new EndpointAddress("net.tcp://" + ServerIP + ":" + ServerPort + "/HiveServer/ClientCommunicator")
85        );
86
87        proxy.LoginCompleted += new EventHandler<LoginCompletedEventArgs>(proxy_LoginCompleted);
88        proxy.SendStreamedJobCompleted += new EventHandler<SendStreamedJobCompletedEventArgs>(proxy_SendStreamedJobCompleted);
89        proxy.StoreFinishedJobResultStreamedCompleted += new EventHandler<StoreFinishedJobResultStreamedCompletedEventArgs>(proxy_StoreFinishedJobResultStreamedCompleted);
90        proxy.ProcessSnapshotStreamedCompleted += new EventHandler<ProcessSnapshotStreamedCompletedEventArgs>(proxy_ProcessSnapshotStreamedCompleted);
91        proxy.ProcessHeartBeatCompleted += new EventHandler<ProcessHeartBeatCompletedEventArgs>(proxy_ProcessHeartBeatCompleted);
92        proxy.Open();
93
94        ConnState = NetworkEnum.WcfConnState.Connected;
95        ConnectedSince = DateTime.Now;
96       
97        if (Connected != null)
98          Connected(this, new EventArgs());                               
99        //Todo: This won't be hit. EVER       
100        if (ConnState == NetworkEnum.WcfConnState.Failed)
101          ConnectionRestored(this, new EventArgs());       
102      }
103      catch (Exception ex) {     
104        HandleNetworkError(ex);
105      }
106    }
107
108
109    /// <summary>
110    /// Changes the Connectionsettings (serverIP & serverPort) and reconnects
111    /// </summary>
112    /// <param name="serverIP">current Server IP</param>
113    /// <param name="serverPort">current Server Port</param>
114    public void Connect(String serverIP, int serverPort) {
115      String oldIp = this.ServerIP;
116      int oldPort = this.ServerPort;
117      this.ServerIP = serverIP;
118      this.ServerPort = serverPort;     
119      Connect();
120      if (oldIp != serverIP || oldPort != ServerPort)
121        if(ServerChanged != null)
122          ServerChanged(this, new EventArgs());
123    }
124
125    public void SetIPAndPort(String serverIP, int serverPort) {
126      this.ServerIP = serverIP;
127      this.ServerPort = serverPort;
128    }
129   
130    /// <summary>
131    /// Disconnects the Client from the Server
132    /// </summary>
133    public void Disconnect() {
134      ConnState = NetworkEnum.WcfConnState.Disconnected;
135    }
136
137    /// <summary>
138    /// Network communication Error Handler - Every network error gets logged and the connection switches to faulted state
139    /// </summary>
140    /// <param name="e">The Exception</param>
141    private void HandleNetworkError(Exception e) {
142      ConnState = NetworkEnum.WcfConnState.Failed;
143      Logging.Instance.Error(this.ToString(), "exception: ", e);
144    }
145
146   
147
148    /// <summary>
149    /// Methods for the Server Login
150    /// </summary>
151    #region Login
152    public event System.EventHandler<LoginCompletedEventArgs> LoginCompleted;
153    public void LoginAsync(ClientInfo clientInfo) {
154      if (ConnState == NetworkEnum.WcfConnState.Connected)
155        proxy.LoginAsync(clientInfo);
156    }
157    private void proxy_LoginCompleted(object sender, LoginCompletedEventArgs e) {
158      if (e.Error == null)
159        LoginCompleted(sender, e);
160      else
161        HandleNetworkError(e.Error.InnerException);
162    }
163
164    public void LoginSync(ClientInfo clientInfo) {
165      try {
166        if (ConnState == NetworkEnum.WcfConnState.Connected) {
167          Response res = proxy.Login(clientInfo);
168          if (!res.Success) {
169            Logging.Instance.Error(this.ToString(), "Login Failed! " + res.StatusMessage);
170            HandleNetworkError(new Exception(res.StatusMessage));
171          } else {
172            ConnState = NetworkEnum.WcfConnState.Loggedin;
173            Logging.Instance.Info(this.ToString(), res.StatusMessage);
174          }
175        }
176      }
177      catch (Exception e) {
178        HandleNetworkError(e);
179      }
180    }
181
182    #endregion
183
184    /// <summary>
185    /// Pull a Job from the Server
186    /// </summary>
187    #region PullJob
188    public event System.EventHandler<SendJobCompletedEventArgs> SendJobCompleted;
189    public void SendJobAsync(Guid guid) {
190      if (ConnState == NetworkEnum.WcfConnState.Loggedin)       
191        proxy.SendStreamedJobAsync(guid);
192    }
193
194    void proxy_SendStreamedJobCompleted(object sender, SendStreamedJobCompletedEventArgs e) {
195      if (e.Error == null) {
196        Stream stream =
197          (Stream)e.Result;
198               
199        BinaryFormatter formatter =
200          new BinaryFormatter();
201        ResponseJob response = (ResponseJob)formatter.Deserialize(stream);
202
203        SendJobCompletedEventArgs completedEventArgs =
204          new SendJobCompletedEventArgs(new object[] { response }, e.Error, e.Cancelled, e.UserState);
205        SendJobCompleted(sender, completedEventArgs);
206      } else
207        HandleNetworkError(e.Error);
208    }
209
210    #endregion
211
212    /// <summary>
213    /// Send back finished Job Results
214    /// </summary>
215    #region SendJobResults
216    public event System.EventHandler<StoreFinishedJobResultCompletedEventArgs> StoreFinishedJobResultCompleted;
217    public void StoreFinishedJobResultAsync(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception, bool finished) {
218      if (ConnState == NetworkEnum.WcfConnState.Loggedin)
219        proxy.StoreFinishedJobResultStreamedAsync(
220          GetStreamedJobResult(clientId, jobId, result, percentage, exception));
221    }
222    private void proxy_StoreFinishedJobResultStreamedCompleted(object sender, StoreFinishedJobResultStreamedCompletedEventArgs e) {
223      if (e.Error == null) {
224        StoreFinishedJobResultCompletedEventArgs args =
225          new StoreFinishedJobResultCompletedEventArgs(
226            new object[] { e.Result }, e.Error, e.Cancelled, e.UserState);
227        StoreFinishedJobResultCompleted(sender, args);
228      } else
229        HandleNetworkError(e.Error);
230    }
231
232    #endregion
233
234    #region Processsnapshots
235    public event System.EventHandler<ProcessSnapshotCompletedEventArgs> ProcessSnapshotCompleted;
236    public void ProcessSnapshotAsync(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception, bool finished) {
237      if(ConnState == NetworkEnum.WcfConnState.Loggedin)
238        proxy.ProcessSnapshotStreamedAsync(
239          GetStreamedJobResult(
240            clientId, jobId, result, percentage, exception));
241    }
242    void proxy_ProcessSnapshotStreamedCompleted(object sender, ProcessSnapshotStreamedCompletedEventArgs e) {
243      if (e.Error == null) {
244        ProcessSnapshotCompletedEventArgs args =
245          new ProcessSnapshotCompletedEventArgs(
246            new object[] { e.Result }, e.Error, e.Cancelled, e.UserState);
247
248        ProcessSnapshotCompleted(sender, args);
249      } else
250        HandleNetworkError(e.Error);
251    }   
252   
253    #endregion
254
255    /// <summary>
256    /// Methods for sending the periodically Heartbeat
257    /// </summary>
258    #region Heartbeat
259
260    public event System.EventHandler<ProcessHeartBeatCompletedEventArgs> SendHeartBeatCompleted;
261    public void SendHeartBeatAsync(HeartBeatData hbd) {
262      if (ConnState == NetworkEnum.WcfConnState.Loggedin)
263        proxy.ProcessHeartBeatAsync(hbd);
264    }
265
266    private void proxy_ProcessHeartBeatCompleted(object sender, ProcessHeartBeatCompletedEventArgs e) {
267      if (e.Error == null && e.Result.Success == true)
268        SendHeartBeatCompleted(sender, e);
269      else {
270        Logging.Instance.Error(this.ToString(), "Error: " + e.Result.StatusMessage);
271        HandleNetworkError(e.Error);
272      }
273    }
274
275    #endregion 
276
277    /// <summary>
278    /// Send back finished and Stored Job Results
279    /// </summary>
280    /*#region SendJobResults
281    public event System.EventHandler<StoreFinishedJobResultCompletedEventArgs> ProcessStoredJobResultCompleted;
282    public void ProcessStoredJobResultAsync(Guid clientId, long jobId, byte[] result, double percentage, Exception exception, bool finished) {
283      if (ConnState == NetworkEnum.WcfConnState.Loggedin)
284        //TODO: some sort of algo for the stored jobs
285        proxy.ProcessJobResultAsync(clientId, jobId, result, percentage, exception, finished);
286    } 
287    #endregion  */
288
289    private Stream GetStreamedJobResult(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception) {
290      JobResult jobResult =
291          new JobResult();
292      jobResult.ClientId = clientId;
293      jobResult.JobId = jobId;
294      jobResult.Result = result;
295      jobResult.Percentage = percentage;
296      jobResult.Exception = exception;
297
298      MemoryStream stream =
299        new MemoryStream();
300
301      BinaryFormatter formatter =
302        new BinaryFormatter();
303
304      formatter.Serialize(stream, jobResult);
305      stream.Seek(0, SeekOrigin.Begin);
306
307      return stream;
308    }
309
310    public ResponseResultReceived SendStoredJobResultsSync(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception, bool finished) {     
311      return proxy.StoreFinishedJobResultStreamed(
312        GetStreamedJobResult(clientId, jobId, result, percentage, exception));
313    }
314
315    public Response IsJobStillNeeded(Guid jobId) {
316      try {
317        return proxy.IsJobStillNeeded(jobId);
318      }
319      catch (Exception e) {
320        HandleNetworkError(e);
321        return null;
322      }
323     
324    }
325
326    public ResponseResultReceived ProcessSnapshotSync(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception) {
327      try {
328        Logging.Instance.Info(this.ToString(), "Snapshot for Job " + jobId + " submitted");
329        return proxy.ProcessSnapshotStreamed(
330          GetStreamedJobResult(clientId, jobId, result, percentage, exception));
331      }
332      catch (Exception e) {
333        HandleNetworkError(e);
334        return null;
335      }
336    }
337
338    public List<CachedHivePluginInfo> RequestPlugins(List<HivePluginInfo> requestedPlugins) {
339      try {
340        Stream stream = proxy.SendStreamedPlugins(requestedPlugins.ToArray());
341
342        BinaryFormatter formatter =
343          new BinaryFormatter();
344        ResponsePlugin response = (ResponsePlugin)formatter.Deserialize(stream);
345        return response.Plugins;       
346      }
347      catch (Exception e) {
348        HandleNetworkError(e);
349        return null;
350      }
351    }
352
353    public void Logout(Guid guid) {
354      try {
355        proxy.Logout(guid);
356      }
357      catch (Exception e) {
358        HandleNetworkError(e);
359      }
360    }
361  }
362}
Note: See TracBrowser for help on using the repository browser.