Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3.3-Hive/sources/HeuristicLab.Hive/HeuristicLab.Hive.Slave.Communication/3.3/WcfService.cs @ 4343

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

made disposing of cached WCF-Client object safer (by using IDisposable pattern)

File size: 15.4 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.Slave.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;
35using HeuristicLab.Hive.Slave.Communication.SlaveService;
36using HeuristicLab.Hive.Contracts.ResponseObjects;
37using HeuristicLab.Hive.Slave.Communication.Properties;
38
39namespace HeuristicLab.Hive.Slave.Communication {
40
41  /// <summary>
42  /// WcfService class is implemented as a Singleton and works as a communication Layer with the Server
43  /// </summary>
44  public class WcfService {
45    private static WcfService instance;
46    /// <summary>
47    /// Getter for the Instance of the WcfService
48    /// </summary>
49    /// <returns>the Instance of the WcfService class</returns>
50    public static WcfService Instance {
51      get {
52        if (instance == null) {
53          Logger.Debug("New WcfService Instance created");
54          instance = new WcfService();
55        }
56        return instance;
57      }
58    }
59
60    public DateTime ConnectedSince { get; private set; }
61    public NetworkEnum.WcfConnState ConnState { get; private set; }
62    public bool LoggedIn { get; set; }
63
64    private string serverIp;
65    public string ServerIp {
66      get { return serverIp; }
67      set {
68        if (serverIp != value) {
69          serverIp = value;
70          if (ServerChanged != null)
71            ServerChanged(this, new EventArgs());
72        }
73      }
74    }
75
76    public event EventHandler ConnectionRestored;
77    public event EventHandler ServerChanged;
78    public event EventHandler Connected;
79
80    SlaveServiceCache servicePool;
81
82    /// <summary>
83    /// Constructor
84    /// </summary>
85    private WcfService() {
86      ConnState = NetworkEnum.WcfConnState.Disconnected;
87      LoggedIn = false;
88    }
89
90    /// <summary>
91    /// Connects with the Server, registers the events and fires the Connected (and quiet possibly the ConnectionRestored) Event.
92    /// </summary>
93    public void Connect() {
94      servicePool = new SlaveServiceCache(ServerIp);
95      using (DisposableSlaveFacadeClient client = servicePool.GetStreamedSlaveFacade()) {
96        try {
97          Logger.Debug("Starting the Connection Process");
98          if (String.Empty.Equals(ServerIp)) {
99            Logger.Info("No Server IP set!");
100            return;
101          }
102          ConnState = NetworkEnum.WcfConnState.Connected;
103          ConnectedSince = DateTime.Now;
104
105          if (Connected != null) {
106            Connected(this, new EventArgs());
107          }
108          if (ConnState == NetworkEnum.WcfConnState.Failed) {
109            ConnectionRestored(this, new EventArgs());
110          }
111        }
112        catch (Exception ex) {
113          HandleNetworkError(ex);
114        }
115      }
116    }
117
118    ///// <summary>
119    ///// Disconnects the Slave from the Server
120    ///// </summary>
121    public void Disconnect() {
122      ConnState = NetworkEnum.WcfConnState.Disconnected;
123      LoggedIn = false;
124    }
125
126    /// <summary>
127    /// Network communication Error Handler - Every network error gets logged and the connection switches to faulted state
128    /// </summary>
129    /// <param name="e">The Exception</param>
130    private void HandleNetworkError(Exception e) {
131      ConnState = NetworkEnum.WcfConnState.Failed;
132      LoggedIn = false;
133      Logger.Error("Network exception occurred: " + e);
134    }
135
136    /// <summary>
137    /// Methods for the Server Login
138    /// </summary>
139    public void Login(SlaveDto slaveInfo) {
140      using (DisposableSlaveFacadeClient client = servicePool.GetSlaveFacade()) {
141        try {
142          if (ConnState == NetworkEnum.WcfConnState.Connected) {
143            Logger.Debug("STARTED: Login Sync");
144            Response res = client.Login(slaveInfo);
145            if (res.StatusMessage != ResponseStatus.Ok) {
146              Logger.Error("FAILED: Login Failed! " + res.StatusMessage);
147              throw new Exception(res.StatusMessage.ToString());
148            } else {
149              Logger.Info("ENDED: Login succeeded" + res.StatusMessage);
150              LoggedIn = true;
151            }
152          }
153        }
154        catch (Exception e) {
155          HandleNetworkError(e);
156        }
157      }
158    }
159
160    /// <summary>
161    /// Pull a Job from the Server
162    /// </summary>
163    #region PullJob
164    public event System.EventHandler<GetJobCompletedEventArgs> GetJobCompleted;
165    public void GetJobAsync(Guid guid) {
166      if (LoggedIn) {
167        DisposableSlaveFacadeClient client = servicePool.GetStreamedSlaveFacade();
168        Logger.Debug("STARTED: Fetching of Jobs from Server for Slave");
169        client.BeginGetStreamedJob(guid, (ar => {
170          if (ar.IsCompleted) {
171            Stream stream = null;
172            MemoryStream memStream = null;
173            try {
174              Logger.Debug("ENDED: Fetching of Jobs from Server for Slave");
175              stream = client.EndGetStreamedJob(ar);
176
177              //first deserialize the response
178              BinaryFormatter formatter = new BinaryFormatter();
179              ResponseObject<JobDto> response = (ResponseObject<JobDto>)formatter.Deserialize(stream);
180
181              //second deserialize the BLOB
182              memStream = new MemoryStream();
183
184              byte[] buffer = new byte[3024];
185              int read = 0;
186              while ((read = stream.Read(buffer, 0, buffer.Length)) > 0) {
187                memStream.Write(buffer, 0, read);
188              }
189
190              memStream.Close();
191
192              GetJobCompletedEventArgs completedEventArgs = new GetJobCompletedEventArgs(new object[] { response, memStream.GetBuffer() }, null, !ar.IsCompleted, ar.AsyncState);
193              GetJobCompleted(this, completedEventArgs);
194            }
195            catch (Exception ex) {
196              Logger.Error(ex);
197            }
198            finally {
199              if (stream != null)
200                stream.Dispose();
201
202              if (memStream != null)
203                memStream.Dispose();
204
205              servicePool.ReleaseSlaveClient(client);
206            }
207          } else
208            HandleNetworkError(new FaultException("GetJobAsync did not complete"));
209        }), null);
210      }
211    }
212
213    #endregion
214
215    /// <summary>
216    /// Send back finished Job Results
217    /// </summary>
218    #region SendJobResults
219    public event System.EventHandler<StoreFinishedJobResultCompletedEventArgs> GetFinishedJobResultCompleted;
220    public void GetFinishedJobResultAsync(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception, bool finished) {
221      if (LoggedIn) {
222        DisposableSlaveFacadeClient client = servicePool.GetStreamedSlaveFacade();
223        Logger.Debug("STARTED: Sending back the finished job results");
224        Logger.Debug("Building stream");
225        Stream stream = GetStreamedJobResult(clientId, jobId, result, percentage, exception);
226        Logger.Debug("Builded stream");
227        Logger.Debug("Making the call");
228
229        client.BeginStoreFinishedJobResultStreamed(stream, (ar => {
230          try {
231            Logger.Debug("Finished storing the job");
232            if (stream != null)
233              stream.Dispose();
234
235            if (ar.IsCompleted) {
236              var res = client.EndStoreFinishedJobResultStreamed(ar);
237              StoreFinishedJobResultCompletedEventArgs args = new StoreFinishedJobResultCompletedEventArgs(new object[] { res }, null, false, null);
238              Logger.Debug("calling the Finished Job Event");
239              GetFinishedJobResultCompleted(this, args);
240              Logger.Debug("ENDED: Sending back the finished job results");
241            } else {
242              HandleNetworkError(new FaultException("GetFinishedJobResultAsync did not complete"));
243            }
244          }
245          finally {
246            servicePool.ReleaseSlaveClient(client);
247          }
248        }), null);
249      }
250    }
251
252    #endregion
253
254    #region Processsnapshots
255    public event System.EventHandler<ProcessSnapshotCompletedEventArgs> ProcessSnapshotCompleted;
256    public void ProcessSnapshotAsync(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception, bool finished) {
257      if (LoggedIn) {
258        DisposableSlaveFacadeClient client = servicePool.GetStreamedSlaveFacade();
259
260        Stream stream = GetStreamedJobResult(clientId, jobId, result, percentage, exception);
261        client.BeginProcessSnapshotStreamed(stream, (ar => {
262          try {
263            if (stream != null)
264              stream.Dispose();
265
266            if (ar.IsCompleted) {
267              var res = client.EndStoreFinishedJobResultStreamed(ar);
268              ProcessSnapshotCompletedEventArgs args = new ProcessSnapshotCompletedEventArgs(new object[] { res }, null, false, null);
269              ProcessSnapshotCompleted(this, args);
270            } else {
271              HandleNetworkError(new FaultException("ProcessSnapshotAsync did not complete"));
272            }
273          }
274          finally {
275            servicePool.ReleaseSlaveClient(client);
276          }
277        }), null);
278      }
279    }
280
281    #endregion
282
283    /// <summary>
284    /// Methods for sending the periodically Heartbeat
285    /// </summary>
286    #region Heartbeat
287
288    public event System.EventHandler<ProcessHeartBeatCompletedEventArgs> ProcessHeartBeatCompleted;
289    public void ProcessHeartBeatSync(HeartBeatData hbd) {
290      if (LoggedIn) {
291        using (DisposableSlaveFacadeClient client = servicePool.GetStreamedSlaveFacade()) {
292          Logger.Debug("STARTING: sending heartbeat");
293          var res = client.ProcessHeartBeat(hbd);
294
295          if (res.StatusMessage == ResponseStatus.Ok) {
296            ProcessHeartBeatCompleted(this, new ProcessHeartBeatCompletedEventArgs(new object[] { res }, null, false, null));
297            Logger.Debug("ENDED: sending heartbeats");
298          } else {
299            Logger.Error("FAILED: sending heartbeats: " + res.StatusMessage.ToString());
300          }
301        }
302      }
303    }
304
305    #endregion
306
307    /// <summary>
308    /// Send back finished and Stored Job Results
309    /// </summary>
310    private Stream GetStreamedJobResult(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception) {
311      JobResult jobResult = new JobResult();
312      jobResult.SlaveId = clientId;
313      jobResult.JobId = jobId;
314      jobResult.Percentage = percentage;
315      jobResult.Exception = exception != null ? exception.Message : "";
316
317      MultiStream stream = new MultiStream();
318
319      //first send result
320      stream.AddStream(new StreamedObject<JobResult>(jobResult));
321
322      //second stream the job binary data
323      MemoryStream memStream = new MemoryStream(result, false);
324      stream.AddStream(memStream);
325
326      return stream;
327    }
328
329    public ResponseResultReceived StoreFinishedJobResultsSync(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception, bool finished) {
330      using (DisposableSlaveFacadeClient client = servicePool.GetStreamedSlaveFacade()) {
331        ResponseResultReceived res = client.StoreFinishedJobResultStreamed(GetStreamedJobResult(clientId, jobId, result, percentage, exception));
332        return res;
333      }
334    }
335
336    public Response IsJobStillNeeded(Guid jobId) {
337      try {
338        Logger.Debug("STARTING: Sync call: IsJobStillNeeded");
339        using (DisposableSlaveFacadeClient client = servicePool.GetStreamedSlaveFacade()) {
340          Response res = client.IsJobStillNeeded(jobId);
341          Logger.Debug("ENDED: Sync call: IsJobStillNeeded");
342          return res;
343        }
344      }
345      catch (Exception e) {
346        HandleNetworkError(e);
347        return null;
348      }
349    }
350
351    public ResponseResultReceived ProcessSnapshotSync(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception) {
352      try {
353        using (DisposableSlaveFacadeClient client = servicePool.GetStreamedSlaveFacade()) {
354          return client.ProcessSnapshotStreamed(GetStreamedJobResult(clientId, jobId, result, percentage, exception));
355        }
356      }
357      catch (Exception e) {
358        HandleNetworkError(e);
359        return null;
360      }
361    }
362
363    public IEnumerable<CachedHivePluginInfoDto> RequestPlugins(List<HivePluginInfoDto> requestedPlugins) {
364      try {
365        using (DisposableSlaveFacadeClient client = servicePool.GetStreamedSlaveFacade()) {
366          Logger.Debug("STARTED: Requesting Plugins for Job");
367          Logger.Debug("STARTED: Getting the stream");
368          Stream stream = client.GetStreamedPlugins(requestedPlugins.ToArray());
369          Logger.Debug("ENDED: Getting the stream");
370          BinaryFormatter formatter = new BinaryFormatter();
371          Logger.Debug("STARTED: Deserializing the stream");
372          ResponseList<CachedHivePluginInfoDto> response = (ResponseList<CachedHivePluginInfoDto>)formatter.Deserialize(stream);
373          Logger.Debug("ENDED: Deserializing the stream");
374          if (stream != null)
375            stream.Dispose();
376          return response.List;
377        }
378      }
379      catch (Exception e) {
380        HandleNetworkError(e);
381        return null;
382      }
383    }
384
385    public void Logout(Guid guid) {
386      try {
387        Logger.Debug("STARTED: Logout");
388        using (DisposableSlaveFacadeClient client = servicePool.GetStreamedSlaveFacade()) {
389          client.Logout(guid);
390        }
391        Logger.Debug("ENDED: Logout");
392      }
393      catch (Exception e) {
394        HandleNetworkError(e);
395      }
396    }
397
398    public ResponseCalendar GetCalendarSync(Guid clientId) {
399      try {
400        Logger.Debug("STARTED: Syncing Calendars");
401        using (DisposableSlaveFacadeClient client = servicePool.GetStreamedSlaveFacade()) {
402          ResponseCalendar cal = client.GetCalendar(clientId);
403          Logger.Debug("ENDED: Syncing Calendars");
404          return cal;
405        }
406      }
407      catch (Exception e) {
408        HandleNetworkError(e);
409        return null;
410      }
411    }
412
413    public Response SetCalendarStatus(Guid clientId, CalendarState state) {
414      try {
415        Logger.Debug("STARTED: Setting Calendar status to: " + state);
416        using (DisposableSlaveFacadeClient client = servicePool.GetStreamedSlaveFacade()) {
417          Response resp = client.SetCalendarStatus(clientId, state);
418          Logger.Debug("ENDED: Setting Calendar status to: " + state);
419          return resp;
420        }
421      }
422      catch (Exception e) {
423        HandleNetworkError(e);
424        return null;
425      }
426    }
427  }
428}
Note: See TracBrowser for help on using the repository browser.