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 @ 4368

Last change on this file since 4368 was 4368, checked in by cneumuel, 14 years ago
  • created HiveClient which shows an overview over all submitted HiveExperiments
  • its possible to download all submitted HiveExperiments including results
  • Experiments are now sent as a whole to the Hive and the Hive-Slaves take care of creating child-jobs (if necessary). The parent job is then paused and will be reactivated when all child-jobs are finished
  • WcfService-Clients are now consistently managed by WcfServicePool which allows to use IDisposable-Pattern and always keeps exactly one proxy-object until all callers disposed them.
  • created ProgressView which is able to lock a View and display progress of an action. It also allows to simulate progress if no progress-information is available so that users don't get too nervous while waiting.
File size: 18.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.IO;
25using System.Runtime.Serialization.Formatters.Binary;
26using System.ServiceModel;
27using HeuristicLab.Hive.Contracts;
28using HeuristicLab.Hive.Contracts.BusinessObjects;
29using HeuristicLab.Hive.Contracts.ResponseObjects;
30using HeuristicLab.Hive.Slave.Common;
31using HeuristicLab.Hive.Slave.Communication.SlaveFacade;
32using HeuristicLab.PluginInfrastructure;
33using HeuristicLab.Tracing;
34
35namespace HeuristicLab.Hive.Slave.Communication {
36
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          Logger.Debug("New WcfService Instance created");
50          instance = new WcfService();
51        }
52        return instance;
53      }
54    }
55
56    public DateTime ConnectedSince { get; private set; }
57    public NetworkEnum.WcfConnState ConnState { get; private set; }
58    public bool LoggedIn { get; set; }
59
60    private string serverIp;
61    public string ServerIp {
62      get { return serverIp; }
63      set {
64        if (serverIp != value) {
65          serverIp = value;
66          if (ServerChanged != null)
67            ServerChanged(this, new EventArgs());
68        }
69      }
70    }
71
72    public event EventHandler ConnectionRestored;
73    public event EventHandler ServerChanged;
74    public event EventHandler Connected;
75
76    /// <summary>
77    /// Constructor
78    /// </summary>
79    private WcfService() {
80      ConnState = NetworkEnum.WcfConnState.Disconnected;
81      LoggedIn = false;
82    }
83
84    /// <summary>
85    /// Connects with the Server, registers the events and fires the Connected (and quiet possibly the ConnectionRestored) Event.
86    /// </summary>
87    public void Connect() {
88      ServiceLocator.Instance.HostAddress = ServerIp;
89      ServiceLocator.Instance.SlaveFacadePool.ExceptionOccured += new EventHandler<HeuristicLab.Common.EventArgs<Exception>>(ClientFacadePool_ExceptionOccured);
90      ServiceLocator.Instance.StreamedSlaveFacadePool.ExceptionOccured += new EventHandler<HeuristicLab.Common.EventArgs<Exception>>(ClientFacadePool_ExceptionOccured);
91      using (Disposable<SlaveFacade.ISlaveFacade> service = ServiceLocator.Instance.StreamedSlaveFacadePool.GetService()) {
92        try {
93          Logger.Debug("Starting the Connection Process");
94          if (String.Empty.Equals(ServerIp)) {
95            Logger.Info("No Server IP set!");
96            return;
97          }
98          ConnState = NetworkEnum.WcfConnState.Connected;
99          ConnectedSince = DateTime.Now;
100
101          if (Connected != null) {
102            Connected(this, new EventArgs());
103          }
104          if (ConnState == NetworkEnum.WcfConnState.Failed) {
105            ConnectionRestored(this, new EventArgs());
106          }
107        }
108        catch (Exception ex) {
109          HandleNetworkError(ex);
110        }
111      }
112    }
113
114    void ClientFacadePool_ExceptionOccured(object sender, HeuristicLab.Common.EventArgs<Exception> e) {
115      Logger.Error("An exception occured in the WCF-Communication: " + e.Value.ToString());
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 (Disposable<SlaveFacade.ISlaveFacade> service = ServiceLocator.Instance.SlaveFacadePool.GetService()) {
141        try {
142          if (ConnState == NetworkEnum.WcfConnState.Connected) {
143            Logger.Debug("STARTED: Login Sync");
144            Response res = service.Obj.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        Disposable<SlaveFacade.ISlaveFacade> service = ServiceLocator.Instance.StreamedSlaveFacadePool.GetService();
168        Logger.Debug("STARTED: Fetching of Jobs from Server for Slave");
169        service.Obj.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 = service.Obj.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              service.Dispose();
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        Disposable<SlaveFacade.ISlaveFacade> service = ServiceLocator.Instance.StreamedSlaveFacadePool.GetService();
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        service.Obj.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 = service.Obj.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            service.Dispose();
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        Disposable<SlaveFacade.ISlaveFacade> service = ServiceLocator.Instance.StreamedSlaveFacadePool.GetService();
259
260        Stream stream = GetStreamedJobResult(clientId, jobId, result, percentage, exception);
261        service.Obj.BeginProcessSnapshotStreamed(stream, (ar => {
262          try {
263            if (stream != null)
264              stream.Dispose();
265
266            if (ar.IsCompleted) {
267              var res = service.Obj.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            service.Dispose();
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 (Disposable<SlaveFacade.ISlaveFacade> service = ServiceLocator.Instance.StreamedSlaveFacadePool.GetService()) {
292          Logger.Debug("STARTING: sending heartbeat");
293          var res = service.Obj.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 if (res.StatusMessage == ResponseStatus.ProcessHeartBeat_UserNotLoggedIn) {
299            LoggedIn = false;
300          } else {
301            Logger.Error("FAILED: sending heartbeats: " + res.StatusMessage.ToString());
302          }
303        }
304      }
305    }
306
307    #endregion
308
309    /// <summary>
310    /// Send back finished and Stored Job Results
311    /// </summary>
312    private Stream GetStreamedJobResult(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception) {
313      JobResult jobResult = new JobResult();
314      jobResult.SlaveId = clientId;
315      jobResult.Id = jobId;
316      jobResult.Percentage = percentage;
317      jobResult.Exception = exception != null ? exception.Message : "";
318
319      MultiStream stream = new MultiStream();
320
321      //first send result
322      stream.AddStream(new StreamedObject<JobResult>(jobResult));
323
324      //second stream the job binary data
325      MemoryStream memStream = new MemoryStream(result, false);
326      stream.AddStream(memStream);
327
328      return stream;
329    }
330
331    public ResponseResultReceived StoreFinishedJobResultsSync(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception, bool finished) {
332      using (Disposable<SlaveFacade.ISlaveFacade> service = ServiceLocator.Instance.StreamedSlaveFacadePool.GetService()) {
333        ResponseResultReceived res = service.Obj.StoreFinishedJobResultStreamed(GetStreamedJobResult(clientId, jobId, result, percentage, exception));
334        return res;
335      }
336    }
337
338    public Response IsJobStillNeeded(Guid jobId) {
339      try {
340        Logger.Debug("STARTING: Sync call: IsJobStillNeeded");
341        using (Disposable<SlaveFacade.ISlaveFacade> service = ServiceLocator.Instance.StreamedSlaveFacadePool.GetService()) {
342          Response res = service.Obj.IsJobStillNeeded(jobId);
343          Logger.Debug("ENDED: Sync call: IsJobStillNeeded");
344          return res;
345        }
346      }
347      catch (Exception e) {
348        HandleNetworkError(e);
349        return null;
350      }
351    }
352
353    public ResponseResultReceived ProcessSnapshotSync(Guid clientId, Guid jobId, byte[] result, double percentage, Exception exception) {
354      try {
355        using (Disposable<SlaveFacade.ISlaveFacade> service = ServiceLocator.Instance.StreamedSlaveFacadePool.GetService()) {
356          return service.Obj.ProcessSnapshotStreamed(GetStreamedJobResult(clientId, jobId, result, percentage, exception));
357        }
358      }
359      catch (Exception e) {
360        HandleNetworkError(e);
361        return null;
362      }
363    }
364
365    public IEnumerable<CachedHivePluginInfoDto> RequestPlugins(List<HivePluginInfoDto> requestedPlugins) {
366      try {
367        using (Disposable<SlaveFacade.ISlaveFacade> service = ServiceLocator.Instance.StreamedSlaveFacadePool.GetService()) {
368          Logger.Debug("STARTED: Requesting Plugins for Job");
369          Logger.Debug("STARTED: Getting the stream");
370          Stream stream = service.Obj.GetStreamedPlugins(requestedPlugins.ToArray());
371          Logger.Debug("ENDED: Getting the stream");
372          BinaryFormatter formatter = new BinaryFormatter();
373          Logger.Debug("STARTED: Deserializing the stream");
374          ResponseList<CachedHivePluginInfoDto> response = (ResponseList<CachedHivePluginInfoDto>)formatter.Deserialize(stream);
375          Logger.Debug("ENDED: Deserializing the stream");
376          if (stream != null)
377            stream.Dispose();
378          return response.List;
379        }
380      }
381      catch (Exception e) {
382        HandleNetworkError(e);
383        return null;
384      }
385    }
386
387    public void Logout(Guid guid) {
388      try {
389        Logger.Debug("STARTED: Logout");
390        using (Disposable<SlaveFacade.ISlaveFacade> service = ServiceLocator.Instance.StreamedSlaveFacadePool.GetService()) {
391          service.Obj.Logout(guid);
392        }
393        Logger.Debug("ENDED: Logout");
394      }
395      catch (Exception e) {
396        HandleNetworkError(e);
397      }
398    }
399
400    public ResponseCalendar GetCalendarSync(Guid clientId) {
401      try {
402        Logger.Debug("STARTED: Syncing Calendars");
403        using (Disposable<SlaveFacade.ISlaveFacade> service = ServiceLocator.Instance.StreamedSlaveFacadePool.GetService()) {
404          ResponseCalendar cal = service.Obj.GetCalendar(clientId);
405          Logger.Debug("ENDED: Syncing Calendars");
406          return cal;
407        }
408      }
409      catch (Exception e) {
410        HandleNetworkError(e);
411        return null;
412      }
413    }
414
415    public Response SetCalendarStatus(Guid clientId, CalendarState state) {
416      try {
417        Logger.Debug("STARTED: Setting Calendar status to: " + state);
418        using (Disposable<SlaveFacade.ISlaveFacade> service = ServiceLocator.Instance.StreamedSlaveFacadePool.GetService()) {
419          Response resp = service.Obj.SetCalendarStatus(clientId, state);
420          Logger.Debug("ENDED: Setting Calendar status to: " + state);
421          return resp;
422        }
423      }
424      catch (Exception e) {
425        HandleNetworkError(e);
426        return null;
427      }
428    }
429
430    public ResponseObject<JobDto> AddChildJob(Guid parentJobId, SerializedJob serializedJob) {
431      try {
432        Logger.Debug("STARTED: Add Child Job for parent: " + parentJobId);
433        using (Disposable<SlaveFacade.ISlaveFacade> service = ServiceLocator.Instance.StreamedSlaveFacadePool.GetService()) {
434          ResponseObject<JobDto> response = service.Obj.AddChildJob(parentJobId, serializedJob);
435          Logger.Debug("ENDED: Add Child Job for parent: " + parentJobId);
436          return response;
437        }
438      }
439      catch (Exception e) {
440        HandleNetworkError(e);
441        return null;
442      }
443    }
444
445    public ResponseObject<JobDto> PauseJob(SerializedJob serializedJob) {
446      try {
447        Logger.Debug("STARTED: Pausing job: " + serializedJob.JobInfo.Id);
448        using (Disposable<SlaveFacade.ISlaveFacade> service = ServiceLocator.Instance.StreamedSlaveFacadePool.GetService()) {
449          ResponseObject<JobDto> response = service.Obj.PauseJob(serializedJob);
450          Logger.Debug("ENDED: Pausing job: " + serializedJob.JobInfo.Id);
451          return response;
452        }
453      }
454      catch (Exception e) {
455        HandleNetworkError(e);
456        return null;
457      }
458    }
459
460    public ResponseObject<SerializedJobList> GetChildJobs(Guid parentJob) {
461      try {
462        Logger.Debug("STARTED: GetChildJobs job: " + parentJob);
463        using (Disposable<SlaveFacade.ISlaveFacade> service = ServiceLocator.Instance.StreamedSlaveFacadePool.GetService()) {
464          SerializedJobList serializedJobs = new SerializedJobList();
465          JobResult[] results = service.Obj.GetChildJobResults(new Guid?(parentJob), false, false);
466          foreach (JobResult result in results) {
467            serializedJobs.Add(service.Obj.GetLastSerializedResult(result.Id));
468          }
469
470          Logger.Debug("ENDED: GetChildJobs job: " + parentJob);
471          return new ResponseObject<SerializedJobList>() {
472            Obj = serializedJobs
473          };
474        }
475      }
476      catch (Exception e) {
477        HandleNetworkError(e);
478        return null;
479      }
480    }
481  }
482}
Note: See TracBrowser for help on using the repository browser.