Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Client.Communication/3.3/WcfService.cs @ 4107

Last change on this file since 4107 was 4107, checked in by cneumuel, 14 years ago

migration from 3.2 to 3.3 completed. Hive Server and Client are now executable and as functional as they were in 3.2. (#1096)

File size: 16.5 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.Client.Common;
29using HeuristicLab.PluginInfrastructure;
30using System.IO;
31using System.Runtime.Serialization.Formatters.Binary;
32using HeuristicLab.Tracing;
33using HeuristicLab.Hive.Contracts;
34using HeuristicLab.Hive.Contracts.BusinessObjects;
35
36namespace HeuristicLab.Hive.Client.Communication {
37  using Service = HeuristicLab.Hive.Client.Communication.ServerService;
38  using HeuristicLab.Hive.Client.Communication.ServerService;
39
40  /// <summary>
41  /// WcfService class is implemented as a Singleton and works as a communication Layer with the Server
42  /// </summary>
43  public class WcfService {
44    private static WcfService instance;
45    /// <summary>
46    /// Getter for the Instance of the WcfService
47    /// </summary>
48    /// <returns>the Instance of the WcfService class</returns>
49    public static WcfService Instance {
50      get {
51        if (instance == null) {
52          Logger.Debug("New WcfService Instance created");
53          instance = new WcfService();
54        }
55        return instance;
56      }
57    }
58
59    public DateTime ConnectedSince { get; private set; }
60    public NetworkEnum.WcfConnState ConnState { get; private set; }
61    public string ServerIP { get; private set; }
62    public int ServerPort { get; private set; }
63
64    public event EventHandler ConnectionRestored;
65    public event EventHandler ServerChanged;
66    public event EventHandler Connected;
67
68    public ClientFacadeClient proxy = null;
69
70    /// <summary>
71    /// Constructor
72    /// </summary>
73    private WcfService() {
74      ConnState = NetworkEnum.WcfConnState.Disconnected;
75    }
76
77    /// <summary>
78    /// Connects with the Server, registers the events and fires the Connected (and quiet possibly the ConnectionRestored) Event.
79    /// </summary>
80    public void Connect() {
81      try {
82        Logger.Debug("Starting the Connection Process");
83        if (String.Empty.Equals(ServerIP) || ServerPort == 0) {
84          Logger.Info("No Server IP or Port set!");
85          return;
86        }
87
88        Logger.Debug("Creating the new connection proxy");
89        proxy = new ClientFacadeClient(
90          HeuristicLab.Hive.Contracts.WcfSettings.GetStreamedBinding(),
91          new EndpointAddress("net.tcp://" + ServerIP + ":" + ServerPort + "/HiveServer/ClientCommunicator")
92        );
93        Logger.Debug("Created the new connection proxy");
94
95        Logger.Debug("Registring new Events");
96        proxy.LoginCompleted += new EventHandler<LoginCompletedEventArgs>(proxy_LoginCompleted);
97        proxy.SendStreamedJobCompleted += new EventHandler<SendStreamedJobCompletedEventArgs>(proxy_SendStreamedJobCompleted);
98        proxy.StoreFinishedJobResultStreamedCompleted += new EventHandler<StoreFinishedJobResultStreamedCompletedEventArgs>(proxy_StoreFinishedJobResultStreamedCompleted);
99        proxy.ProcessSnapshotStreamedCompleted += new EventHandler<ProcessSnapshotStreamedCompletedEventArgs>(proxy_ProcessSnapshotStreamedCompleted);
100        proxy.ProcessHeartBeatCompleted += new EventHandler<ProcessHeartBeatCompletedEventArgs>(proxy_ProcessHeartBeatCompleted);
101        Logger.Debug("Registered new Events");
102        Logger.Debug("Opening the Connection");
103        proxy.Open();
104        Logger.Debug("Opened the Connection");
105
106        ConnState = NetworkEnum.WcfConnState.Connected;
107        ConnectedSince = DateTime.Now;
108
109        if (Connected != null) {
110          Logger.Debug("Calling the connected Event");
111          Connected(this, new EventArgs());
112          //Todo: This won't be hit. EVER       
113        }
114        if (ConnState == NetworkEnum.WcfConnState.Failed)
115          ConnectionRestored(this, new EventArgs());
116      } catch (Exception ex) {
117        HandleNetworkError(ex);
118      }
119    }
120
121
122    /// <summary>
123    /// Changes the Connectionsettings (serverIP & serverPort) and reconnects
124    /// </summary>
125    /// <param name="serverIP">current Server IP</param>
126    /// <param name="serverPort">current Server Port</param>
127    public void Connect(String serverIP, int serverPort) {
128      Logger.Debug("Called Connected with " + serverIP + ":" + serverPort);
129      String oldIp = this.ServerIP;
130      int oldPort = this.ServerPort;
131      this.ServerIP = serverIP;
132      this.ServerPort = serverPort;
133      Connect();
134      if (oldIp != serverIP || oldPort != ServerPort)
135        if (ServerChanged != null)
136          ServerChanged(this, new EventArgs());
137    }
138
139    public void SetIPAndPort(String serverIP, int serverPort) {
140      Logger.Debug("Called with " + serverIP + ":" + serverPort);
141      this.ServerIP = serverIP;
142      this.ServerPort = serverPort;
143    }
144
145    /// <summary>
146    /// Disconnects the Client from the Server
147    /// </summary>
148    public void Disconnect() {
149      ConnState = NetworkEnum.WcfConnState.Disconnected;
150    }
151
152    /// <summary>
153    /// Network communication Error Handler - Every network error gets logged and the connection switches to faulted state
154    /// </summary>
155    /// <param name="e">The Exception</param>
156    private void HandleNetworkError(Exception e) {
157      ConnState = NetworkEnum.WcfConnState.Failed;
158      Logger.Error("Network exception occurred: " + e);
159    }
160
161
162
163    /// <summary>
164    /// Methods for the Server Login
165    /// </summary>
166    #region Login
167    public event System.EventHandler<LoginCompletedEventArgs> LoginCompleted;
168    public void LoginAsync(ClientDto clientInfo) {
169      if (ConnState == NetworkEnum.WcfConnState.Connected) {
170        Logger.Debug("STARTED: Login Async");
171        proxy.LoginAsync(clientInfo);
172      }
173    }
174    private void proxy_LoginCompleted(object sender, LoginCompletedEventArgs e) {
175      if (e.Error == null) {
176        Logger.Debug("ENDED: Login Async");
177        LoginCompleted(sender, e);
178      } else
179        HandleNetworkError(e.Error.InnerException);
180    }
181
182    public void LoginSync(ClientDto clientInfo) {
183      try {
184        if (ConnState == NetworkEnum.WcfConnState.Connected) {
185          Logger.Debug("STARTED: Login Sync");
186          HeuristicLab.Hive.Contracts.Response res = proxy.Login(clientInfo);
187          if (!res.Success) {
188            Logger.Error("FAILED: Login Failed! " + res.StatusMessage);
189            throw new Exception(res.StatusMessage);
190          } else {
191            Logger.Info("ENDED: Login succeeded" + res.StatusMessage);
192            ConnState = NetworkEnum.WcfConnState.Loggedin;
193          }
194        }
195      } catch (Exception e) {
196        HandleNetworkError(e);
197      }
198    }
199
200    #endregion
201
202    /// <summary>
203    /// Pull a Job from the Server
204    /// </summary>
205    #region PullJob
206    public event System.EventHandler<SendJobCompletedEventArgs> SendJobCompleted;
207    public void SendJobAsync(Guid guid) {
208      if (ConnState == NetworkEnum.WcfConnState.Loggedin) {
209        Logger.Debug("STARTED: Fetching of Jobs from Server for Client");
210        proxy.SendStreamedJobAsync(guid);
211      }
212    }
213
214    void proxy_SendStreamedJobCompleted(object sender, SendStreamedJobCompletedEventArgs e) {
215      if (e.Error == null) {
216        Logger.Debug("ENDED: Fetching of Jobs from Server for Client");
217        Stream stream = null;
218        MemoryStream memStream = null;
219
220        try {
221          stream = (Stream)e.Result;
222
223          //first deserialize the response
224          BinaryFormatter formatter = new BinaryFormatter();
225          ResponseJob response = (ResponseJob)formatter.Deserialize(stream);
226
227          //second deserialize the BLOB
228          memStream = new MemoryStream();
229
230          byte[] buffer = new byte[3024];
231          int read = 0;
232          while ((read = stream.Read(buffer, 0, buffer.Length)) > 0) {
233            memStream.Write(buffer, 0, read);
234          }
235
236          memStream.Close();
237
238          SendJobCompletedEventArgs completedEventArgs = new SendJobCompletedEventArgs(new object[] { response, memStream.GetBuffer() }, e.Error, e.Cancelled, e.UserState);
239          SendJobCompleted(sender, completedEventArgs);
240        } catch (Exception ex) {
241          Logger.Error(ex);
242        } finally {
243          if (stream != null)
244            stream.Dispose();
245
246          if (memStream != null)
247            memStream.Dispose();
248        }
249      } else
250        HandleNetworkError(e.Error);
251    }
252
253    #endregion
254
255    /// <summary>
256    /// Send back finished Job Results
257    /// </summary>
258    #region SendJobResults
259    public event System.EventHandler<StoreFinishedJobResultCompletedEventArgs> StoreFinishedJobResultCompleted;
260    public void StoreFinishedJobResultAsync(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception, bool finished) {
261      if (ConnState == NetworkEnum.WcfConnState.Loggedin) {
262        Logger.Debug("STARTED: Sending back the finished job results");
263        Logger.Debug("Building stream");
264        Stream stream =
265          GetStreamedJobResult(clientId, jobId, result, percentage, exception);
266        Logger.Debug("Builded stream");
267        Logger.Debug("Making the call");
268        proxy.StoreFinishedJobResultStreamedAsync(stream, stream);
269      }
270    }
271    private void proxy_StoreFinishedJobResultStreamedCompleted(object sender, StoreFinishedJobResultStreamedCompletedEventArgs e) {
272      Logger.Debug("Finished storing the job");
273      Stream stream =
274        (Stream)e.UserState;
275      if (stream != null) {
276        Logger.Debug("Stream not null, disposing it");
277        stream.Dispose();
278      }
279      if (e.Error == null) {
280        StoreFinishedJobResultCompletedEventArgs args =
281          new StoreFinishedJobResultCompletedEventArgs(
282            new object[] { e.Result }, e.Error, e.Cancelled, e.UserState);
283        Logger.Debug("calling the Finished Job Event");
284        StoreFinishedJobResultCompleted(sender, args);
285        Logger.Debug("ENDED: Sending back the finished job results");
286      } else
287        HandleNetworkError(e.Error);
288    }
289
290    #endregion
291
292    #region Processsnapshots
293    public event System.EventHandler<ProcessSnapshotCompletedEventArgs> ProcessSnapshotCompleted;
294    public void ProcessSnapshotAsync(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception, bool finished) {
295      if (ConnState == NetworkEnum.WcfConnState.Loggedin) {
296        Stream stream = GetStreamedJobResult(
297            clientId, jobId, result, percentage, exception);
298
299        proxy.ProcessSnapshotStreamedAsync(stream, stream);
300      }
301    }
302    void proxy_ProcessSnapshotStreamedCompleted(object sender, ProcessSnapshotStreamedCompletedEventArgs e) {
303      Stream stream =
304        (Stream)e.UserState;
305      if (stream != null)
306        stream.Dispose();
307
308      if (e.Error == null) {
309        ProcessSnapshotCompletedEventArgs args =
310          new ProcessSnapshotCompletedEventArgs(
311            new object[] { e.Result }, e.Error, e.Cancelled, e.UserState);
312
313        ProcessSnapshotCompleted(sender, args);
314      } else
315        HandleNetworkError(e.Error);
316    }
317
318    #endregion
319
320    /// <summary>
321    /// Methods for sending the periodically Heartbeat
322    /// </summary>
323    #region Heartbeat
324
325    public event System.EventHandler<ProcessHeartBeatCompletedEventArgs> ProcessHeartBeatCompleted;
326    public void ProcessHeartBeatAsync(HeartBeatData hbd) {
327      if (ConnState == NetworkEnum.WcfConnState.Loggedin)
328        Logger.Debug("STARTING: sending heartbeat");
329      proxy.ProcessHeartBeatAsync(hbd);
330    }
331
332    private void proxy_ProcessHeartBeatCompleted(object sender, ProcessHeartBeatCompletedEventArgs e) {
333      if (e.Error == null && e.Result.Success) {
334        ProcessHeartBeatCompleted(sender, e);
335        Logger.Debug("ENDED: sending heartbeats");
336      } else {
337        try {
338          Logger.Error("Error: " + e.Result.StatusMessage);
339        } catch (Exception ex) {
340          Logger.Error("Error: ", ex);
341        }
342        HandleNetworkError(e.Error);
343      }
344    }
345
346    #endregion
347
348    /// <summary>
349    /// Send back finished and Stored Job Results
350    /// </summary>
351    private Stream GetStreamedJobResult(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception) {
352      JobResult jobResult =
353          new JobResult();
354      jobResult.ClientId = clientId;
355      jobResult.JobId = jobId;
356      jobResult.Percentage = percentage;
357      jobResult.Exception = exception;
358
359      MultiStream stream =
360              new MultiStream();
361
362      //first send result
363      stream.AddStream(
364        new StreamedObject<JobResult>(jobResult));
365
366      //second stream the job binary data
367      MemoryStream memStream =
368        new MemoryStream(result, false);
369      stream.AddStream(memStream);
370
371      return stream;
372    }
373
374    public ResponseResultReceived StoreFinishedJobResultsSync(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception, bool finished) {
375      return proxy.StoreFinishedJobResultStreamed(
376        GetStreamedJobResult(clientId, jobId, result, percentage, exception));
377    }
378
379    public Response IsJobStillNeeded(Guid jobId) {
380      try {
381        Logger.Debug("STARTING: Sync call: IsJobStillNeeded");
382        Response res = proxy.IsJobStillNeeded(jobId);
383        Logger.Debug("ENDED: Sync call: IsJobStillNeeded");
384        return res;
385      } catch (Exception e) {
386        HandleNetworkError(e);
387        return null;
388      }
389
390    }
391
392    public ResponseResultReceived ProcessSnapshotSync(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception) {
393      try {
394        return proxy.ProcessSnapshotStreamed(
395          GetStreamedJobResult(clientId, jobId, result, percentage, exception));
396      } catch (Exception e) {
397        HandleNetworkError(e);
398        return null;
399      }
400    }
401
402    public List<HeuristicLab.PluginInfrastructure.CachedHivePluginInfoDto> RequestPlugins(List<HivePluginInfoDto> requestedPlugins) {
403      try {
404        Logger.Debug("STARTED: Requesting Plugins for Job");
405        Logger.Debug("STARTED: Getting the stream");
406        Stream stream = proxy.SendStreamedPlugins(requestedPlugins.ToArray());
407        Logger.Debug("ENDED: Getting the stream");
408        BinaryFormatter formatter =
409          new BinaryFormatter();
410        Logger.Debug("STARTED: Deserializing the stream");
411        ResponsePlugin response = (ResponsePlugin)formatter.Deserialize(stream);
412        Logger.Debug("ENDED: Deserializing the stream");
413        if (stream != null)
414          stream.Dispose();
415        return response.Plugins;
416      } catch (Exception e) {
417        HandleNetworkError(e);
418        return null;
419      }
420    }
421
422    public void Logout(Guid guid) {
423      try {
424        Logger.Debug("STARTED: Logout");
425        proxy.Logout(guid);
426        Logger.Debug("ENDED: Logout");
427      } catch (Exception e) {
428        HandleNetworkError(e);
429      }
430    }
431
432    public ResponseCalendar GetCalendarSync(Guid clientId) {
433      try {
434        Logger.Debug("STARTED: Syncing Calendars");
435        ResponseCalendar cal = proxy.GetCalendar(clientId);
436        Logger.Debug("ENDED: Syncing Calendars");
437        return cal;
438      } catch (Exception e) {
439        HandleNetworkError(e);
440        return null;
441      }
442    }
443
444    public Response SetCalendarStatus(Guid clientId, CalendarState state) {
445      try {
446        Logger.Debug("STARTED: Setting Calendar status to: " + state);
447        Response resp = proxy.SetCalendarStatus(clientId, state);
448        Logger.Debug("ENDED: Setting Calendar status to: " + state);
449        return resp;
450      } catch (Exception e) {
451        HandleNetworkError(e);
452        return null;
453      }
454    }
455
456  }
457}
Note: See TracBrowser for help on using the repository browser.