source: trunk/sources/HeuristicLab.Clients.Hive/3.3/RefreshableJob.cs @ 9390

Last change on this file since 9390 was 9390, checked in by ascheibe, 7 years ago

#1890 fixed a bug in RefreshAutomatically where the event for receiving the results was deregistered to early

File size: 23.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2012 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.ComponentModel;
25using System.Drawing;
26using System.Linq;
27using HeuristicLab.Collections;
28using HeuristicLab.Common;
29using HeuristicLab.Core;
30using HeuristicLab.MainForm;
31
32namespace HeuristicLab.Clients.Hive {
33  public class RefreshableJob : IHiveItem, IDeepCloneable, IContent, IComparable<RefreshableJob>, IDisposable {
34    private JobResultPoller jobResultPoller;
35    private ConcurrentTaskDownloader<ItemTask> jobDownloader;
36    private object locker = new object();
37    private object downloadFinishedLocker = new object();
38    object jobResultReceivedLocker = new object();
39
40    public bool IsProgressing { get; set; }
41
42    private Job job;
43    public Job Job {
44      get { return job; }
45      set {
46        if (value != job) {
47          if (value == null)
48            throw new ArgumentNullException();
49
50          if (job != null) DeregisterJobEvents();
51          job = value;
52          if (job != null) {
53            RegisterJobEvents();
54            job_PropertyChanged(job, new PropertyChangedEventArgs("Id"));
55          }
56          OnJobChanged();
57          OnToStringChanged(this, EventArgs.Empty);
58          job_ItemImageChanged(this, EventArgs.Empty);
59        }
60      }
61    }
62
63    private ItemCollection<HiveTask> hiveTasks;
64    public ItemCollection<HiveTask> HiveTasks {
65      get { return hiveTasks; }
66      set {
67        if (hiveTasks != value) {
68          if (hiveTasks != null) DeregisterHiveTasksEvents();
69          hiveTasks = value;
70          if (hiveTasks != null) RegisterHiveTasksEvents();
71          OnHiveTasksChanged();
72        }
73      }
74    }
75
76    private ExecutionState executionState;
77    public ExecutionState ExecutionState {
78      get { return executionState; }
79      internal set {
80        if (executionState != value) {
81          executionState = value;
82          OnExecutionStateChanged();
83        }
84      }
85    }
86
87    private TimeSpan executionTime;
88    public TimeSpan ExecutionTime {
89      get { return executionTime; }
90      internal set {
91        if (executionTime != value) {
92          executionTime = value;
93          OnExecutionTimeChanged();
94        }
95      }
96    }
97
98    private bool refreshAutomatically;
99    public bool RefreshAutomatically {
100      get { return refreshAutomatically; }
101      set {
102        lock (locker) {
103          if (refreshAutomatically != value) {
104            refreshAutomatically = value;
105            OnRefreshAutomaticallyChanged();
106          }
107          if (RefreshAutomatically) {
108            if (this.HiveTasks != null && this.HiveTasks.Count > 0 && (jobResultPoller == null || !jobResultPoller.IsPolling)) {
109              StartResultPolling();
110            }
111          } else {
112            PauseResultPolling();
113          }
114        }
115      }
116    }
117
118    // indicates if download button is enabled
119    private bool isDownloadable = true;
120    public bool IsDownloadable {
121      get { return isDownloadable; }
122      set {
123        if (value != isDownloadable) {
124          isDownloadable = value;
125          OnIsDownloadableChanged();
126        }
127      }
128    }
129
130    // if true, all control buttons should be enabled. otherwise disabled
131    private bool isControllable = true;
132    public bool IsControllable {
133      get { return isControllable; }
134      private set {
135        if (value != isControllable) {
136          isControllable = value;
137          OnIsControllableChanged();
138          if (this.hiveTasks != null) {
139            foreach (var hiveJob in this.hiveTasks) {
140              hiveJob.IsControllable = value;
141            }
142          }
143        }
144      }
145    }
146
147    // indicates if a user is allowed to share this experiment
148    private bool isSharable = true;
149    public bool IsSharable {
150      get { return isSharable; }
151      private set {
152        if (value != isSharable) {
153          isSharable = value;
154          OnIsSharableChanged();
155        }
156      }
157    }
158
159    // may execute jobs with privileged permissions on slaves
160    public bool IsAllowedPrivileged {
161      get { return Job.IsPrivileged; }
162      set {
163        if (value != Job.IsPrivileged) {
164          Job.IsPrivileged = value;
165          OnIsAllowedPrivilegedChanged();
166        }
167      }
168    }
169
170    private Progress progress;
171    public Progress Progress {
172      get { return progress; }
173      set {
174        this.progress = value;
175        OnIsProgressingChanged();
176      }
177    }
178
179
180    private ThreadSafeLog log;
181    public ILog Log {
182      get { return log; }
183    }
184
185    public StateLogListList StateLogList {
186      get { return new StateLogListList(this.GetAllHiveTasks().Select(x => x.StateLog)); }
187    }
188
189    #region Constructors and Cloning
190    public RefreshableJob() {
191      this.refreshAutomatically = false;
192      this.Job = new Job();
193      this.log = new ThreadSafeLog();
194      this.jobDownloader = new ConcurrentTaskDownloader<ItemTask>(Settings.Default.MaxParallelDownloads, Settings.Default.MaxParallelDownloads);
195      this.jobDownloader.ExceptionOccured += new EventHandler<EventArgs<Exception>>(jobDownloader_ExceptionOccured);
196      this.HiveTasks = new ItemCollection<HiveTask>();
197    }
198    public RefreshableJob(Job hiveExperiment) {
199      this.refreshAutomatically = true;
200      this.Job = hiveExperiment;
201      this.log = new ThreadSafeLog();
202      this.jobDownloader = new ConcurrentTaskDownloader<ItemTask>(Settings.Default.MaxParallelDownloads, Settings.Default.MaxParallelDownloads);
203      this.jobDownloader.ExceptionOccured += new EventHandler<EventArgs<Exception>>(jobDownloader_ExceptionOccured);
204      this.HiveTasks = new ItemCollection<HiveTask>();
205    }
206    protected RefreshableJob(RefreshableJob original, Cloner cloner) {
207      cloner.RegisterClonedObject(original, this);
208      this.Job = cloner.Clone(original.Job);
209      this.IsControllable = original.IsControllable;
210      this.log = cloner.Clone(original.log);
211      this.RefreshAutomatically = false; // do not start results polling automatically
212      this.jobDownloader = new ConcurrentTaskDownloader<ItemTask>(Settings.Default.MaxParallelDownloads, Settings.Default.MaxParallelDownloads);
213      this.jobDownloader.ExceptionOccured += new EventHandler<EventArgs<Exception>>(jobDownloader_ExceptionOccured);
214      this.HiveTasks = cloner.Clone(original.HiveTasks);
215      this.ExecutionTime = original.ExecutionTime;
216      this.ExecutionState = original.ExecutionState;
217    }
218    public IDeepCloneable Clone(Cloner cloner) {
219      return new RefreshableJob(this, cloner);
220    }
221    public object Clone() {
222      return this.Clone(new Cloner());
223    }
224    #endregion
225
226    #region JobResultPoller Events
227    public void StartResultPolling() {
228      if (jobResultPoller == null) {
229        jobResultPoller = new JobResultPoller(job.Id, Settings.Default.ResultPollingInterval);
230        RegisterResultPollingEvents();
231        jobResultPoller.AutoResumeOnException = false;
232      }
233
234      if (!jobResultPoller.IsPolling) {
235        jobResultPoller.Start();
236      }
237    }
238
239    public void StopResultPolling() {
240      if (jobResultPoller != null && jobResultPoller.IsPolling) {
241        refreshAutomatically = false;
242        jobResultPoller.Stop();
243        DeregisterResultPollingEvents();
244        jobResultPoller = null;
245      }
246    }
247
248    public void PauseResultPolling() {
249      if (jobResultPoller != null && jobResultPoller.IsPolling) {
250        jobResultPoller.Stop();
251      }
252    }
253
254    private void RegisterResultPollingEvents() {
255      jobResultPoller.ExceptionOccured += new EventHandler<EventArgs<Exception>>(jobResultPoller_ExceptionOccured);
256      jobResultPoller.JobResultsReceived += new EventHandler<EventArgs<IEnumerable<LightweightTask>>>(jobResultPoller_JobResultReceived);
257      jobResultPoller.IsPollingChanged += new EventHandler(jobResultPoller_IsPollingChanged);
258    }
259    private void DeregisterResultPollingEvents() {
260      jobResultPoller.ExceptionOccured -= new EventHandler<EventArgs<Exception>>(jobResultPoller_ExceptionOccured);
261      jobResultPoller.JobResultsReceived -= new EventHandler<EventArgs<IEnumerable<LightweightTask>>>(jobResultPoller_JobResultReceived);
262      jobResultPoller.IsPollingChanged -= new EventHandler(jobResultPoller_IsPollingChanged);
263    }
264    private void jobResultPoller_IsPollingChanged(object sender, EventArgs e) {
265      if (this.refreshAutomatically != jobResultPoller.IsPolling) {
266        this.refreshAutomatically = jobResultPoller.IsPolling;
267        OnRefreshAutomaticallyChanged();
268      }
269    }
270
271    private void jobResultPoller_JobResultReceived(object sender, EventArgs<IEnumerable<LightweightTask>> e) {
272      lock (jobResultReceivedLocker) {
273        foreach (LightweightTask lightweightTask in e.Value) {
274          HiveTask hiveTask = GetHiveTaskById(lightweightTask.Id);
275          if (hiveTask != null) {
276            // lastJobDataUpdate equals DateTime.MinValue right after it was uploaded. When the first results are polled, this value is updated
277            if (hiveTask.Task.State == TaskState.Offline && lightweightTask.State == TaskState.Waiting) {
278              hiveTask.Task.LastTaskDataUpdate = lightweightTask.LastTaskDataUpdate;
279            }
280
281            hiveTask.UpdateFromLightweightJob(lightweightTask);
282
283            if (!hiveTask.IsFinishedTaskDownloaded && !hiveTask.IsDownloading && hiveTask.Task.LastTaskDataUpdate < lightweightTask.LastTaskDataUpdate && (lightweightTask.State == TaskState.Finished || lightweightTask.State == TaskState.Aborted || lightweightTask.State == TaskState.Failed || lightweightTask.State == TaskState.Paused)) {
284              log.LogMessage(string.Format("Downloading task {0}", lightweightTask.Id));
285              hiveTask.IsDownloading = true;
286              jobDownloader.DownloadTaskData(hiveTask.Task, (localJob, itemJob) => {
287                lock (downloadFinishedLocker) {
288                  log.LogMessage(string.Format("Finished downloading task {0}", localJob.Id));
289                  HiveTask localHiveTask = GetHiveTaskById(localJob.Id);
290
291                  if (itemJob == null) {
292                    // something bad happened to this task. bad task, BAAAD task!
293                    localHiveTask.IsDownloading = false;
294                  } else {
295                    // if the task is paused, download but don't integrate into parent optimizer (to avoid Prepare)
296                    if (localJob.State == TaskState.Paused) {
297                      localHiveTask.ItemTask = itemJob;
298                    } else {
299                      if (localJob.ParentTaskId.HasValue) {
300                        HiveTask parentHiveTask = GetHiveTaskById(localJob.ParentTaskId.Value);
301                        parentHiveTask.IntegrateChild(itemJob, localJob.Id);
302                      } else {
303                        localHiveTask.ItemTask = itemJob;
304                      }
305                    }
306                    localHiveTask.IsDownloading = false;
307                    localHiveTask.Task.LastTaskDataUpdate = lightweightTask.LastTaskDataUpdate;
308                  }
309                }
310              });
311            }
312          }
313        }
314        GC.Collect(); // force GC, because .NET is too lazy here (deserialization takes a lot of memory)
315        if (AllJobsFinished()) {
316          this.ExecutionState = Core.ExecutionState.Stopped;
317          StopResultPolling();
318        }
319        UpdateTotalExecutionTime();
320        UpdateStatistics();
321        OnStateLogListChanged();
322        OnTaskReceived();
323      }
324    }
325
326    public HiveTask GetHiveTaskById(Guid jobId) {
327      foreach (HiveTask t in this.HiveTasks) {
328        var hj = t.GetHiveTaskByTaskId(jobId);
329        if (hj != null)
330          return hj;
331      }
332      return null;
333    }
334
335    private void UpdateStatistics() {
336      var jobs = this.GetAllHiveTasks();
337      job.JobCount = jobs.Count();
338      job.CalculatingCount = jobs.Count(j => j.Task.State == TaskState.Calculating);
339      job.FinishedCount = jobs.Count(j => j.Task.State == TaskState.Finished);
340      OnJobStatisticsChanged();
341    }
342
343    public bool AllJobsFinished() {
344      return this.GetAllHiveTasks().All(j => (j.Task.State == TaskState.Finished
345                                                   || j.Task.State == TaskState.Aborted
346                                                   || j.Task.State == TaskState.Failed)
347                                                   && !j.IsDownloading);
348    }
349
350    private void jobResultPoller_ExceptionOccured(object sender, EventArgs<Exception> e) {
351      OnExceptionOccured(sender, e.Value);
352    }
353    private void jobDownloader_ExceptionOccured(object sender, EventArgs<Exception> e) {
354      OnExceptionOccured(sender, e.Value);
355    }
356    public void UpdateTotalExecutionTime() {
357      this.ExecutionTime = TimeSpan.FromMilliseconds(this.GetAllHiveTasks().Sum(x => x.Task.ExecutionTime.TotalMilliseconds));
358    }
359    #endregion
360
361    #region Job Events
362    private void RegisterJobEvents() {
363      job.ToStringChanged += new EventHandler(OnToStringChanged);
364      job.PropertyChanged += new PropertyChangedEventHandler(job_PropertyChanged);
365      job.ItemImageChanged += new EventHandler(job_ItemImageChanged);
366      job.ModifiedChanged += new EventHandler(job_ModifiedChanged);
367    }
368
369    private void DeregisterJobEvents() {
370      job.ToStringChanged -= new EventHandler(OnToStringChanged);
371      job.PropertyChanged -= new PropertyChangedEventHandler(job_PropertyChanged);
372      job.ItemImageChanged -= new EventHandler(job_ItemImageChanged);
373      job.ModifiedChanged -= new EventHandler(job_ModifiedChanged);
374    }
375    #endregion
376
377    #region Event Handler
378    public event EventHandler RefreshAutomaticallyChanged;
379    private void OnRefreshAutomaticallyChanged() {
380      var handler = RefreshAutomaticallyChanged;
381      if (handler != null) handler(this, EventArgs.Empty);
382    }
383
384    public event EventHandler JobChanged;
385    private void OnJobChanged() {
386      var handler = JobChanged;
387      if (handler != null) handler(this, EventArgs.Empty);
388    }
389
390    public event EventHandler ModifiedChanged;
391    private void job_ModifiedChanged(object sender, EventArgs e) {
392      var handler = ModifiedChanged;
393      if (handler != null) handler(sender, e);
394    }
395
396    public event EventHandler ItemImageChanged;
397    private void job_ItemImageChanged(object sender, EventArgs e) {
398      var handler = ItemImageChanged;
399      if (handler != null) handler(this, e);
400    }
401
402    public event PropertyChangedEventHandler PropertyChanged;
403    private void job_PropertyChanged(object sender, PropertyChangedEventArgs e) {
404      this.IsSharable = job.Permission == Permission.Full;
405      this.IsControllable = job.Permission == Permission.Full;
406
407      var handler = PropertyChanged;
408      if (handler != null) handler(sender, e);
409    }
410
411    public event EventHandler ToStringChanged;
412    private void OnToStringChanged(object sender, EventArgs e) {
413      var handler = ToStringChanged;
414      if (handler != null) handler(this, e);
415    }
416
417    public event EventHandler IsDownloadableChanged;
418    private void OnIsDownloadableChanged() {
419      var handler = IsDownloadableChanged;
420      if (handler != null) handler(this, EventArgs.Empty);
421    }
422
423    public event EventHandler IsControllableChanged;
424    private void OnIsControllableChanged() {
425      var handler = IsControllableChanged;
426      if (handler != null) handler(this, EventArgs.Empty);
427    }
428
429    public event EventHandler IsSharableChanged;
430    private void OnIsSharableChanged() {
431      var handler = IsSharableChanged;
432      if (handler != null) handler(this, EventArgs.Empty);
433    }
434
435    public event EventHandler IsAllowedPrivilegedChanged;
436    private void OnIsAllowedPrivilegedChanged() {
437      var handler = IsAllowedPrivilegedChanged;
438      if (handler != null) handler(this, EventArgs.Empty);
439    }
440
441    public event EventHandler JobStatisticsChanged;
442    private void OnJobStatisticsChanged() {
443      var handler = JobStatisticsChanged;
444      if (handler != null) handler(this, EventArgs.Empty);
445    }
446
447    public event EventHandler<EventArgs<Exception>> ExceptionOccured;
448    private void OnExceptionOccured(object sender, Exception exception) {
449      log.LogException(exception);
450      var handler = ExceptionOccured;
451      if (handler != null) handler(sender, new EventArgs<Exception>(exception));
452    }
453
454    public event EventHandler StateLogListChanged;
455    private void OnStateLogListChanged() {
456      var handler = StateLogListChanged;
457      if (handler != null) handler(this, EventArgs.Empty);
458    }
459
460    public event EventHandler ExecutionTimeChanged;
461    protected virtual void OnExecutionTimeChanged() {
462      var handler = ExecutionTimeChanged;
463      if (handler != null) handler(this, EventArgs.Empty);
464    }
465
466    public event EventHandler ExecutionStateChanged;
467    protected virtual void OnExecutionStateChanged() {
468      var handler = ExecutionStateChanged;
469      if (handler != null) handler(this, EventArgs.Empty);
470    }
471    public event EventHandler TaskReceived;
472    protected virtual void OnTaskReceived() {
473      var handler = TaskReceived;
474      if (handler != null) handler(this, EventArgs.Empty);
475    }
476    public event EventHandler IsProgressingChanged;
477    private void OnIsProgressingChanged() {
478      var handler = IsProgressingChanged;
479      if (handler != null) handler(this, EventArgs.Empty);
480    }
481    #endregion
482
483    #region HiveTasks Events
484    private void RegisterHiveTasksEvents() {
485      this.hiveTasks.ItemsAdded += new CollectionItemsChangedEventHandler<HiveTask>(hivetasks_ItemsAdded);
486      this.hiveTasks.ItemsRemoved += new CollectionItemsChangedEventHandler<HiveTask>(hiveTasks_ItemsRemoved);
487      this.hiveTasks.CollectionReset += new CollectionItemsChangedEventHandler<HiveTask>(hiveTasks_CollectionReset);
488    }
489
490    private void DeregisterHiveTasksEvents() {
491      this.hiveTasks.ItemsAdded -= new CollectionItemsChangedEventHandler<HiveTask>(hivetasks_ItemsAdded);
492      this.hiveTasks.ItemsRemoved -= new CollectionItemsChangedEventHandler<HiveTask>(hiveTasks_ItemsRemoved);
493      this.hiveTasks.CollectionReset -= new CollectionItemsChangedEventHandler<HiveTask>(hiveTasks_CollectionReset);
494    }
495
496    private void hiveTasks_CollectionReset(object sender, CollectionItemsChangedEventArgs<HiveTask> e) {
497      foreach (var item in e.Items) {
498        item.StateLogChanged -= new EventHandler(item_StateLogChanged);
499      }
500      OnHiveTasksReset(e);
501    }
502
503    private void hiveTasks_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<HiveTask> e) {
504      foreach (var item in e.Items) {
505        item.StateLogChanged -= new EventHandler(item_StateLogChanged);
506      }
507      OnHiveTasksRemoved(e);
508    }
509
510    private void hivetasks_ItemsAdded(object sender, CollectionItemsChangedEventArgs<HiveTask> e) {
511      foreach (var item in e.Items) {
512        item.StateLogChanged += new EventHandler(item_StateLogChanged);
513        item.IsControllable = this.IsControllable;
514      }
515      OnHiveTasksAdded(e);
516    }
517
518    private void item_StateLogChanged(object sender, EventArgs e) {
519      OnStateLogListChanged();
520    }
521    #endregion
522
523    public event EventHandler HiveTasksChanged;
524    protected virtual void OnHiveTasksChanged() {
525      if (this.HiveTasks != null && this.HiveTasks.Count > 0 && this.GetAllHiveTasks().All(x => x.Task.Id != Guid.Empty)) {
526        if (IsFinished()) {
527          this.ExecutionState = Core.ExecutionState.Stopped;
528          this.RefreshAutomatically = false;
529          StopResultPolling();
530        } else {
531          this.RefreshAutomatically = true;
532        }
533      }
534
535      var handler = HiveTasksChanged;
536      if (handler != null) handler(this, EventArgs.Empty);
537    }
538
539    public event EventHandler Loaded;
540    public virtual void OnLoaded() {
541      this.UpdateTotalExecutionTime();
542      this.OnStateLogListChanged();
543
544      if (this.ExecutionState != ExecutionState.Stopped) {
545        this.RefreshAutomatically = true;
546      }
547
548      var handler = Loaded;
549      if (handler != null) handler(this, EventArgs.Empty);
550    }
551
552    public event EventHandler<CollectionItemsChangedEventArgs<HiveTask>> HiveTasksAdded;
553    private void OnHiveTasksAdded(CollectionItemsChangedEventArgs<HiveTask> e) {
554      var handler = HiveTasksAdded;
555      if (handler != null) handler(this, e);
556    }
557
558    public event EventHandler<CollectionItemsChangedEventArgs<HiveTask>> HiveTasksRemoved;
559    private void OnHiveTasksRemoved(CollectionItemsChangedEventArgs<HiveTask> e) {
560      var handler = HiveTasksRemoved;
561      if (handler != null) handler(this, e);
562    }
563
564    public event EventHandler<CollectionItemsChangedEventArgs<HiveTask>> HiveTasksReset;
565    private void OnHiveTasksReset(CollectionItemsChangedEventArgs<HiveTask> e) {
566      var handler = HiveTasksReset;
567      if (handler != null) handler(this, e);
568    }
569
570    public Guid Id {
571      get {
572        if (job == null) return Guid.Empty;
573        return job.Id;
574      }
575      set { job.Id = value; }
576    }
577    public bool Modified {
578      get { return job.Modified; }
579    }
580    public void Store() {
581      job.Store();
582    }
583    public string ItemDescription {
584      get { return job.ItemDescription; }
585    }
586    public Image ItemImage {
587      get { return job.ItemImage; }
588    }
589    public string ItemName {
590      get { return job.ItemName; }
591    }
592    public Version ItemVersion {
593      get { return job.ItemVersion; }
594    }
595
596    public override string ToString() {
597      return string.Format("{0} {1}", Job.DateCreated.ToString("MM.dd.yyyy HH:mm"), Job.ToString());
598    }
599
600    public bool IsFinished() {
601      return HiveTasks != null
602        && HiveTasks.All(x => x.Task.DateFinished.HasValue && x.Task.DateCreated.HasValue);
603    }
604
605    public IEnumerable<HiveTask> GetAllHiveTasks() {
606      if (hiveTasks == null) return Enumerable.Empty<HiveTask>();
607
608      var tasks = new List<HiveTask>();
609      foreach (HiveTask task in HiveTasks) {
610        tasks.AddRange(task.GetAllHiveTasks());
611      }
612      return tasks;
613    }
614
615    public int CompareTo(RefreshableJob other) {
616      return this.ToString().CompareTo(other.ToString());
617    }
618
619    public void Unload() {
620      // stop result polling
621      if (refreshAutomatically)
622        RefreshAutomatically = false;
623      DisposeTasks();
624      hiveTasks = new ItemCollection<HiveTask>();
625    }
626
627    #region IDisposable Members
628    public void Dispose() {
629      if (jobDownloader != null) {
630        jobDownloader.ExceptionOccured -= new EventHandler<EventArgs<Exception>>(jobDownloader_ExceptionOccured);
631        jobDownloader.Dispose();
632        jobDownloader = null;
633      }
634      if (jobResultPoller != null) {
635        DeregisterResultPollingEvents();
636        jobResultPoller = null;
637      }
638      if (hiveTasks != null) {
639        DisposeTasks();
640      }
641      if (job != null) {
642        DeregisterJobEvents();
643        job = null;
644      }
645    }
646
647    private void DisposeTasks() {
648      DeregisterHiveTasksEvents();
649      foreach (var task in hiveTasks) {
650        task.Dispose();
651      }
652      hiveTasks.Clear(); // this should remove the item_StateLogChanged event handlers
653      hiveTasks = null;
654    }
655    #endregion
656  }
657}
Note: See TracBrowser for help on using the repository browser.