Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 3578 was 3578, checked in by kgrading, 14 years ago

Removed References to HiveLogging and updated the default logging mechanism (#991)

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