Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Hive.Experiment/3.3/HiveExperiment.cs @ 4145

Last change on this file since 4145 was 4145, checked in by cneumuel, 12 years ago

worked on "request snapshot" feature (#1115)

File size: 30.5 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 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.Linq;
24using HeuristicLab.Common;
25using HeuristicLab.Core;
26using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
27using HeuristicLab.Optimization;
28using System.Drawing;
29using HeuristicLab.Collections;
30using System.Collections.Generic;
31using HeuristicLab.Hive.Contracts.BusinessObjects;
32using System.IO;
33using HeuristicLab.Persistence.Default.Xml;
34using HeuristicLab.PluginInfrastructure;
35using System.Reflection;
36using HeuristicLab.Hive.Contracts.Interfaces;
37using HeuristicLab.Hive.Contracts;
38using System.Threading;
39using HeuristicLab.Tracing;
40using HeuristicLab.Hive.JobBase;
41using System.Diagnostics;
42using System.Collections;
43
44namespace HeuristicLab.Hive.Experiment {
45  /// <summary>
46  /// An experiment which contains multiple batch runs of algorithms.
47  /// </summary>
48  [Item(itemName, itemDescription)]
49  [Creatable("Testing & Analysis")]
50  [StorableClass]
51  public class HiveExperiment : NamedItem, IExecutable {
52    private const string itemName = "Hive Experiment";
53    private const string itemDescription = "A runner for a single experiment, which's algorithms are executed in the Hive.";
54    private const int resultPollingIntervalMs = 15000;
55    private const int snapshotPollingIntervalMs = 1000;
56    private const int maxSnapshotRetries = 20;
57    private object locker = new object();
58
59    private System.Timers.Timer timer;
60    private bool pausePending, stopPending;
61
62    [Storable]
63    private DateTime lastUpdateTime;
64
65    private bool isPollingResults;
66    public bool IsPollingResults {
67      get { return isPollingResults; }
68      private set {
69        if (isPollingResults != value) {
70          isPollingResults = value;
71          OnIsPollingResultsChanged();
72        }
73      }
74    }
75
76    private bool stopResultsPollingPending = false;
77
78    private IDictionary<Guid, Thread> resultPollingThreads;
79
80    /// <summary>
81    /// Mapping from JobId to an optimizer.
82    /// Stores all pending optimizers. If an optimizer is finished it is removed from this collection
83    /// </summary>
84    [Storable]
85    private IDictionary<Guid, IOptimizer> pendingOptimizersByJobId = new Dictionary<Guid, IOptimizer>();
86
87    /// <summary>
88    /// Stores a mapping from the child-optimizer to the parent optimizer.
89    /// Needed to replace a finished optimizer in the optimizer-tree.
90    /// Only pending optmizers are stored.
91    /// </summary>
92    [Storable]
93    private IDictionary<IOptimizer, IOptimizer> parentOptimizersByPendingOptimizer = new Dictionary<IOptimizer, IOptimizer>();
94
95    [Storable]
96    private JobItemList jobItems;
97    public JobItemList JobItems {
98      get { return jobItems; }
99    }
100
101
102    [Storable]
103    private string serverUrl;
104    public string ServerUrl {
105      get { return serverUrl; }
106      set {
107        if (serverUrl != value) {
108          serverUrl = value;
109          OnServerUrlChanged();
110        }
111      }
112    }
113
114    [Storable]
115    private string resourceIds;
116    public string ResourceIds {
117      get { return resourceIds; }
118      set {
119        if (resourceIds != value) {
120          resourceIds = value;
121          OnResourceIdsChanged();
122        }
123      }
124    }
125
126    [Storable]
127    private HeuristicLab.Optimization.Experiment experiment;
128    public HeuristicLab.Optimization.Experiment Experiment {
129      get { return experiment; }
130      set {
131        if (experiment != value) {
132          experiment = value;
133          OnExperimentChanged();
134        }
135      }
136    }
137
138    [Storable]
139    private ILog log;
140    public ILog Log {
141      get { return log; }
142    }
143
144    [StorableConstructor]
145    public HiveExperiment(bool deserializing)
146      : base(deserializing) {
147      this.resultPollingThreads = new Dictionary<Guid, Thread>();
148      jobItems = new JobItemList();
149    }
150
151    public HiveExperiment()
152      : base(itemName, itemDescription) {
153      this.ServerUrl = HeuristicLab.Hive.Experiment.Properties.Settings.Default.HiveServerUrl;
154      this.ResourceIds = HeuristicLab.Hive.Experiment.Properties.Settings.Default.ResourceIds;
155      this.log = new Log();
156      pausePending = stopPending = false;
157      jobItems = new JobItemList();
158      isPollingResults = false;
159      resultPollingThreads = new Dictionary<Guid, Thread>();
160      RegisterEvents();
161      InitTimer();
162    }
163
164    public override IDeepCloneable Clone(Cloner cloner) {
165      LogMessage("I am beeing cloned");
166      HiveExperiment clone = (HiveExperiment)base.Clone(cloner);
167      clone.resourceIds = this.resourceIds;
168      clone.serverUrl = this.serverUrl;
169      clone.experiment = (HeuristicLab.Optimization.Experiment)cloner.Clone(experiment);
170      clone.executionState = this.executionState;
171      clone.executionTime = this.executionTime;
172      clone.pendingOptimizersByJobId = new Dictionary<Guid, IOptimizer>();
173
174      foreach (var pair in this.pendingOptimizersByJobId)
175        clone.pendingOptimizersByJobId[pair.Key] = (IOptimizer)cloner.Clone(pair.Value);
176
177      foreach (var pair in this.parentOptimizersByPendingOptimizer)
178        clone.parentOptimizersByPendingOptimizer[(IOptimizer)cloner.Clone(pair.Key)] = (IOptimizer)cloner.Clone(pair.Value);
179
180      clone.log = (ILog)cloner.Clone(log);
181      clone.stopPending = this.stopPending;
182      clone.pausePending = this.pausePending;
183      clone.jobItems = (JobItemList)cloner.Clone(jobItems);
184      clone.lastUpdateTime = this.lastUpdateTime;
185      clone.isPollingResults = this.isPollingResults;
186      return clone;
187    }
188
189    [StorableHook(HookType.AfterDeserialization)]
190    private void AfterDeserialization() {
191      InitTimer();
192      this.IsPollingResults = false;
193      this.stopResultsPollingPending = false;
194      RegisterEvents();
195      LogMessage("I was deserialized.");
196    }
197   
198    private void InitTimer() {
199      timer = new System.Timers.Timer(100);
200      timer.AutoReset = true;
201      timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
202    }
203
204    private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
205      DateTime now = DateTime.Now;
206      ExecutionTime += now - lastUpdateTime;
207      lastUpdateTime = now;
208    }
209
210    public IEnumerable<string> ResourceGroups {
211      get {
212        if (!string.IsNullOrEmpty(resourceIds)) {
213          return resourceIds.Split(';');
214        } else {
215          return new List<string>();
216        }
217      }
218    }
219    #region IExecutable Members
220
221    [Storable]
222    private Core.ExecutionState executionState;
223    public ExecutionState ExecutionState {
224      get { return executionState; }
225      private set {
226        if (executionState != value) {
227          executionState = value;
228          OnExecutionStateChanged();
229        }
230      }
231    }
232
233    [Storable]
234    private TimeSpan executionTime;
235    public TimeSpan ExecutionTime {
236      get { return executionTime; }
237      private set {
238        if (executionTime != value) {
239          executionTime = value;
240          OnExecutionTimeChanged();
241        }
242      }
243    }
244
245    public void Pause() {
246      throw new NotSupportedException();
247    }
248
249    public void Prepare() {
250      if (experiment != null) {
251        StopResultPolling();
252        pendingOptimizersByJobId.Clear();
253        parentOptimizersByPendingOptimizer.Clear();
254        jobItems.Clear();
255        experiment.Prepare();
256        this.ExecutionState = Core.ExecutionState.Prepared;
257        OnPrepared();
258      }
259    }
260
261    public void Start() {
262      OnStarted();
263      ExecutionTime = new TimeSpan();
264      lastUpdateTime = DateTime.Now;
265      this.ExecutionState = Core.ExecutionState.Started;
266      Thread t = new Thread(() => {
267        IExecutionEngineFacade executionEngineFacade = GetExecutionEngineFacade();
268
269        pendingOptimizersByJobId = new Dictionary<Guid, IOptimizer>();
270        parentOptimizersByPendingOptimizer = GetOptimizers(true);
271        IEnumerable<string> groups = ResourceGroups;
272       
273        foreach (IOptimizer optimizer in parentOptimizersByPendingOptimizer.Keys) {
274          SerializedJob serializedJob = CreateSerializedJob(optimizer);
275          ResponseObject<JobDto> response = executionEngineFacade.AddJobWithGroupStrings(serializedJob, groups);
276          pendingOptimizersByJobId.Add(response.Obj.Id, optimizer);
277
278          JobItem jobItem = new JobItem() {
279            JobDto = response.Obj,
280            LatestSnapshot = new ResponseObject<SerializedJob>() {
281              Obj = serializedJob,
282              StatusMessage = "Initial Snapshot",
283              Success = true
284            },
285            Optimizer = optimizer
286          };
287          jobItems.Add(jobItem);
288          jobItem.LogMessage("Job sent to Hive");
289
290          LogMessage("Sent job to Hive (jobId: " + response.Obj.Id + ")");
291        }
292
293        // start results polling after sending sending the jobs to the server (to avoid race conflicts at the optimizers-collection)
294        StartResultPolling();
295      });
296      t.Start();
297    }
298
299    public void Stop() {
300      this.ExecutionState = Core.ExecutionState.Stopped;
301      foreach (JobItem jobItem in jobItems) {
302        AbortJob(jobItem.JobDto.Id);
303      }
304      OnStopped();
305    }
306
307    private void CreateResultPollingThreads() {
308      foreach (JobItem jobItem in JobItems) {
309        if (!resultPollingThreads.ContainsKey(jobItem.JobDto.Id) && jobItem.JobDto.State != State.Finished) {
310          resultPollingThreads.Add(jobItem.JobDto.Id, CreateResultPollingThread(jobItem.JobDto));
311        }
312      }
313    }
314
315    public void StartResultPolling() {
316      this.stopResultsPollingPending = false;
317      this.IsPollingResults = true;
318      lock (resultPollingThreads) {
319        CreateResultPollingThreads();
320        foreach (Thread pollingThread in resultPollingThreads.Values) {
321          if (pollingThread.ThreadState != System.Threading.ThreadState.Running) {
322            pollingThread.Start();
323          }
324        }
325      }
326    }
327
328    public void StopResultPolling() {
329      this.stopResultsPollingPending = true;
330      foreach (Thread pollingThread in resultPollingThreads.Values) {
331        pollingThread.Interrupt();
332      }
333      this.stopResultsPollingPending = false;
334    }
335
336    private JobItem GetJobItemById(Guid jobId) {
337      return jobItems.Single(x => x.JobDto.Id == jobId);
338    }
339
340    /// <summary>
341    /// Returns all optimizers in the current Experiment
342    /// </summary>
343    /// <param name="flatout">if false only top level optimizers are returned, if true the optimizer-tree is flatted</param>
344    /// <returns></returns>
345    private IDictionary<IOptimizer, IOptimizer> GetOptimizers(bool flatout) {
346      if (!flatout) {
347        var optimizers = new Dictionary<IOptimizer, IOptimizer>();
348        foreach (IOptimizer opt in experiment.Optimizers) {
349          optimizers.Add(experiment, opt);
350        }
351        return optimizers;
352      } else {
353        return FlatOptimizerTree(null, experiment, "");
354      }
355    }
356
357    /// <summary>
358    /// Recursively iterates all IOptimizers in the optimizer-tree and returns them.
359    ///
360    /// [chn] this could be implemented more cleanly if Experiment and BatchRun would implement an interface like:
361    /// interface IParallelizable {
362    ///   IEnumerable&lt;IOptimizer&gt; GetOptimizers();
363    /// }
364    /// </summary>
365    /// <returns>a dictionary mapping from the parent optimizer to the child optimizer</returns>
366    private IDictionary<IOptimizer, IOptimizer> FlatOptimizerTree(IOptimizer parent, IOptimizer optimizer, string prepend) {
367      IDictionary<IOptimizer, IOptimizer> optimizers = new Dictionary<IOptimizer, IOptimizer>();
368      if (optimizer is HeuristicLab.Optimization.Experiment) {
369        HeuristicLab.Optimization.Experiment experiment = optimizer as HeuristicLab.Optimization.Experiment;
370        if (this.experiment != experiment) {
371          prepend += "Experiment/"; // don't prepend for top-level optimizers
372        }
373        foreach (IOptimizer opt in experiment.Optimizers) {
374          AddRange(optimizers, FlatOptimizerTree(experiment, opt, prepend));
375        }
376      } else if (optimizer is BatchRun) {
377        BatchRun batchRun = optimizer as BatchRun;
378        prepend += "BatchRun/";
379        for (int i = 0; i < batchRun.Repetitions; i++) {
380          IOptimizer opt = (IOptimizer)batchRun.Algorithm.Clone();
381          opt.Name += " [" + i + "]";
382          IDictionary<IOptimizer, IOptimizer> batchOptimizers = FlatOptimizerTree(batchRun, opt, prepend);
383          AddRange(optimizers, batchOptimizers);
384        }
385      } else if (optimizer is EngineAlgorithm) {
386        optimizer.Name = prepend + optimizer.Name;
387        optimizers.Add(optimizer, parent);
388      } else {
389        Logger.Warn("Optimizer of type " + optimizers.GetType().ToString() + " unknown");
390        optimizer.Name = prepend + optimizer.Name;
391        optimizers.Add(optimizer, parent);
392      }
393      return optimizers;
394    }
395
396    private void AddRange(IDictionary<IOptimizer, IOptimizer> optimizers, IDictionary<IOptimizer, IOptimizer> childs) {
397      foreach (KeyValuePair<IOptimizer, IOptimizer> kvp in childs) {
398        optimizers.Add(kvp);
399      }
400    }
401
402    private void ReplaceOptimizer(IOptimizer parentOptimizer, IOptimizer originalOptimizer, IOptimizer newOptimizer) {
403      lock (locker) {
404        if (parentOptimizer is HeuristicLab.Optimization.Experiment) {
405          HeuristicLab.Optimization.Experiment exp = (HeuristicLab.Optimization.Experiment)parentOptimizer;
406          int originalOptimizerIndex = exp.Optimizers.IndexOf(originalOptimizer);
407          exp.Optimizers[originalOptimizerIndex] = newOptimizer;
408        } else if (parentOptimizer is BatchRun) {
409          BatchRun batchRun = (BatchRun)parentOptimizer;
410          if (newOptimizer is IAlgorithm) {
411            batchRun.Runs.Add(new Run(newOptimizer.Name, (IAlgorithm)newOptimizer) );
412          } else {
413            throw new NotSupportedException("Only IAlgorithm types supported");
414          }
415        } else {
416          throw new NotSupportedException("Invalid parentOptimizer");
417        }
418      }
419    }
420
421    public void AbortJob(Guid jobId) {
422      IExecutionEngineFacade executionEngineFacade = GetExecutionEngineFacade();
423      Response response = executionEngineFacade.AbortJob(jobId);
424      GetJobItemById(jobId).LogMessage("Aborting Job: " + response.StatusMessage);
425    }
426
427    #endregion
428
429    private IExecutionEngineFacade GetExecutionEngineFacade() {
430      return ServiceLocator.CreateExecutionEngineFacade(ServerUrl);
431    }
432
433    private SerializedJob CreateSerializedJob(IOptimizer optimizer) {
434      IJob job = new OptimizerJob() {
435        Optimizer = optimizer
436      };
437
438      // serialize job
439      MemoryStream memStream = new MemoryStream();
440      XmlGenerator.Serialize(job, memStream);
441      byte[] jobByteArray = memStream.ToArray();
442      memStream.Dispose();
443
444      // find out which which plugins are needed for the given object
445      List<HivePluginInfoDto> pluginsNeeded = (
446        from p in GetDeclaringPlugins(optimizer.GetType())
447        select new HivePluginInfoDto() {
448          Name = p.Name,
449          Version = p.Version
450        }).ToList();
451
452      JobDto jobDto = new JobDto() {
453        CoresNeeded = 1, // [chn] how to determine real cores needed?
454        PluginsNeeded = pluginsNeeded,
455        State = State.Offline,
456        MemoryNeeded = 0,
457        UserId = Guid.Empty // [chn] set real userid here!
458      };
459
460      SerializedJob serializedJob = new SerializedJob() {
461        JobInfo = jobDto,
462        SerializedJobData = jobByteArray
463      };
464
465      return serializedJob;
466    }
467
468    private Thread CreateResultPollingThread(JobDto job) {
469      return new Thread(() => {
470        try {
471          GetJobItemById(job.Id).LogMessage("Starting job results polling");
472          IExecutionEngineFacade executionEngineFacade = GetExecutionEngineFacade();
473          IJob restoredObject = null;
474          IOptimizer originalOptimizer = pendingOptimizersByJobId[job.Id];
475
476          do {
477            // loop while
478            // 1. the user doesn't request an abort
479            // 2. there is a problem with server communication (success==false)
480            // 3. no result for the job is available yet (response.Obj==null)
481            // 4. the result that we get from the server is a snapshot and not the final result
482
483            if (stopPending || !this.IsPollingResults) {
484              return;
485            }
486
487            ResponseObject<JobDto> response = executionEngineFacade.GetJobById(job.Id);
488            LogMessage("Response: " + response.StatusMessage + " (jobId: " + job.Id + ")");
489            GetJobItemById(job.Id).LogMessage("Response: " + response.StatusMessage);
490
491            UpdateJobItem(response.Obj);
492
493            if (response.Obj.State == State.Abort) {
494              pendingOptimizersByJobId.Remove(job.Id);
495              parentOptimizersByPendingOptimizer.Remove(originalOptimizer);
496              GetJobItemById(job.Id).LogMessage("Job successfully aborted");
497              return;
498            }
499
500            if (response.Obj.State == State.Failed) {
501              pendingOptimizersByJobId.Remove(job.Id);
502              parentOptimizersByPendingOptimizer.Remove(originalOptimizer);
503              GetJobItemById(job.Id).LogMessage("Job failed with exception: " + response.Obj.Exception);
504              return;
505            }
506
507            if (response.Success && response.Obj != null && response.Obj.State == State.Finished) {
508              ResponseObject<SerializedJob> jobResponse = executionEngineFacade.GetLastSerializedResult(job.Id, false, false);
509              restoredObject = XmlParser.Deserialize<IJob>(new MemoryStream(jobResponse.Obj.SerializedJobData));
510              UpdateSnapshot(jobResponse);
511            } else {
512              Thread.Sleep(resultPollingIntervalMs);
513            }
514          } while (restoredObject == null || restoredObject.ExecutionState != Core.ExecutionState.Stopped);
515
516          LogMessage("Job finished (jobId: " + job.Id + ")");
517          GetJobItemById(job.Id).LogMessage("Job finished");
518          // job retrieved... replace the existing optimizers with the finished one
519         
520          IOptimizer restoredOptimizer = ((OptimizerJob)restoredObject).Optimizer;
521         
522          ReplaceOptimizer(parentOptimizersByPendingOptimizer[originalOptimizer], originalOptimizer, restoredOptimizer);
523          pendingOptimizersByJobId.Remove(job.Id);
524          parentOptimizersByPendingOptimizer.Remove(originalOptimizer);
525
526        } catch (ThreadInterruptedException exception) {
527
528        } finally {
529          GetJobItemById(job.Id).LogMessage("ResultsPolling Thread stopped");
530          lock (resultPollingThreads) {
531            resultPollingThreads.Remove(job.Id);
532            if (resultPollingThreads.Count == 0) {
533              IsPollingResults = false;
534            }
535          }
536
537          // check if finished
538          if (pendingOptimizersByJobId.Count == 0) {
539            this.ExecutionState = Core.ExecutionState.Stopped;
540            OnStopped();
541          }
542        }
543      });
544    }
545
546    private void UpdateJobItem(JobDto jobDto) {
547      JobItem jobItem = jobItems.Single(x => x.JobDto.Id == jobDto.Id);
548      jobItem.JobDto = jobDto;
549    }
550
551    private void UpdateSnapshot(ResponseObject<SerializedJob> response) {
552      JobItem jobItem = jobItems.Single(x => x.JobDto.Id == response.Obj.JobInfo.Id);
553      jobItem.LatestSnapshot = response;
554    }
555
556    private void LogMessage(string message) {
557      // HeuristicLab.Log is not Thread-Safe, so lock on every call
558      lock (locker) {
559        log.LogMessage(message);
560      }
561    }
562
563    void JobItem_SnapshotRequestedStateChanged(object sender, EventArgs e) {
564      JobItem jobItem = (JobItem)sender;
565      if (jobItem.SnapshotRequestedState == SnapshotRequestedState.Requested) {
566        RequestSnapshot(jobItem.JobDto.Id);
567      }
568    }
569
570    public void RequestSnapshot(Guid jobId) {
571      IExecutionEngineFacade executionEngineFacade = GetExecutionEngineFacade();
572      ResponseObject<SerializedJob> response;
573      int retryCount = 0;
574
575      Response snapShotResponse = executionEngineFacade.RequestSnapshot(jobId);
576      if (snapShotResponse.StatusMessage == ApplicationConstants.RESPONSE_JOB_IS_NOT_BEEING_CALCULATED) {
577        // job already finished
578        Logger.Debug("HiveEngine: Abort - GetLastResult(false)");
579        response = executionEngineFacade.GetLastSerializedResult(jobId, false, false);
580        Logger.Debug("HiveEngine: Abort - Server: " + response.StatusMessage + " success: " + response.Success);
581      } else {
582        // server sent snapshot request to client
583        // poll until snapshot is ready
584        do {
585          Thread.Sleep(snapshotPollingIntervalMs);
586          Logger.Debug("HiveEngine: Abort - GetLastResult(true)");
587          response = executionEngineFacade.GetLastSerializedResult(jobId, false, true);
588          Logger.Debug("HiveEngine: Abort - Server: " + response.StatusMessage + " success: " + response.Success);
589          retryCount++;
590          // loop while
591          // 1. problem with communication with server
592          // 2. job result not yet ready
593        } while (
594          (retryCount < maxSnapshotRetries) && (
595          !response.Success ||
596          response.StatusMessage == ApplicationConstants.RESPONSE_JOB_RESULT_NOT_YET_HERE)
597          );
598      }
599      if (response.Success) {
600        GetJobItemById(jobId).LogMessage("Snapshot polling successfull for job " + jobId);
601        GetJobItemById(jobId).LatestSnapshot = response;
602      } else {
603        GetJobItemById(jobId).LogMessage("Error: Polling of Snapshot failed for job " + jobId + ": " + response.StatusMessage);
604      }
605    }
606
607    #region Required Plugin Search
608    /// <summary>
609    /// Returns a list of plugins in which the type itself and all members
610    /// of the type are declared. Objectgraph is searched recursively.
611    /// </summary>
612    private IEnumerable<IPluginDescription> GetDeclaringPlugins(Type type) {
613      HashSet<Type> types = new HashSet<Type>();
614      FindTypes(type, types, "HeuristicLab.");
615      return GetDeclaringPlugins(types);
616    }
617
618    /// <summary>
619    /// Returns the plugins (including dependencies) in which the given types are declared
620    /// </summary>
621    private IEnumerable<IPluginDescription> GetDeclaringPlugins(IEnumerable<Type> types) {
622      HashSet<IPluginDescription> plugins = new HashSet<IPluginDescription>();
623      foreach (Type t in types) {
624        FindDeclaringPlugins(ApplicationManager.Manager.GetDeclaringPlugin(t), plugins);
625      }
626      return plugins;
627    }
628
629    /// <summary>
630    /// Finds the dependencies of the given plugin and adds it to the plugins hashset.
631    /// Also searches the dependencies recursively.
632    /// </summary>
633    private void FindDeclaringPlugins(IPluginDescription plugin, HashSet<IPluginDescription> plugins) {
634      if (!plugins.Contains(plugin)) {
635        plugins.Add(plugin);
636        foreach (IPluginDescription dependency in plugin.Dependencies) {
637          FindDeclaringPlugins(dependency, plugins);
638        }
639      }
640    }
641
642    /// <summary>
643    /// Recursively finds all types used in type which are in a namespace which starts with namespaceStart
644    /// Be aware that search is not performed on attributes
645    /// </summary>
646    /// <param name="type">the type to be searched</param>
647    /// <param name="types">found types will be stored there, needed in order to avoid duplicates</param>
648    /// <param name="namespaceStart">only types from namespaces which start with this will be searched and added</param>
649    private void FindTypes(Type type, HashSet<Type> types, string namespaceStart) {
650      if (!types.Contains(type) && type.Namespace.StartsWith(namespaceStart)) {
651        types.Add(type);
652
653        // constructors
654        foreach (ConstructorInfo info in type.GetConstructors()) {
655          foreach (ParameterInfo paramInfo in info.GetParameters()) {
656            FindTypes(paramInfo.ParameterType, types, namespaceStart);
657          }
658        }
659
660        // interfaces
661        foreach (Type t in type.GetInterfaces()) {
662          FindTypes(t, types, namespaceStart);
663        }
664
665        // events
666        foreach (EventInfo info in type.GetEvents()) {
667          FindTypes(info.EventHandlerType, types, namespaceStart);
668          FindTypes(info.DeclaringType, types, namespaceStart);
669        }
670
671        // properties
672        foreach (PropertyInfo info in type.GetProperties()) {
673          FindTypes(info.PropertyType, types, namespaceStart);
674        }
675
676        // fields
677        foreach (FieldInfo info in type.GetFields()) {
678          FindTypes(info.FieldType, types, namespaceStart);
679        }
680
681        // methods
682        foreach (MethodInfo info in type.GetMethods()) {
683          foreach (ParameterInfo paramInfo in info.GetParameters()) {
684            FindTypes(paramInfo.ParameterType, types, namespaceStart);
685          }
686          FindTypes(info.ReturnType, types, namespaceStart);
687        }
688      }
689    }
690    #endregion
691
692    #region Eventhandler
693
694    public event EventHandler ExecutionTimeChanged;
695    private void OnExecutionTimeChanged() {
696      EventHandler handler = ExecutionTimeChanged;
697      if (handler != null) handler(this, EventArgs.Empty);
698    }
699
700    public event EventHandler ExecutionStateChanged;
701    private void OnExecutionStateChanged() {
702      LogMessage("ExecutionState changed to " + executionState.ToString());
703      EventHandler handler = ExecutionStateChanged;
704      if (handler != null) handler(this, EventArgs.Empty);
705    }
706
707    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
708
709    public event EventHandler Started;
710    private void OnStarted() {
711      LogMessage("Started");
712      timer.Start();
713      EventHandler handler = Started;
714      if (handler != null) handler(this, EventArgs.Empty);
715    }
716
717    public event EventHandler Stopped;
718    private void OnStopped() {
719      timer.Stop();
720      LogMessage("Stopped");
721      EventHandler handler = Stopped;
722      if (handler != null) handler(this, EventArgs.Empty);
723    }
724
725    public event EventHandler Paused;
726    private void OnPaused() {
727      timer.Stop();
728      LogMessage("Paused");
729      EventHandler handler = Paused;
730      if (handler != null) handler(this, EventArgs.Empty);
731    }
732
733    public event EventHandler Prepared;
734    protected virtual void OnPrepared() {
735      LogMessage("Prepared");
736      EventHandler handler = Prepared;
737      if (handler != null) handler(this, EventArgs.Empty);
738    }
739
740    public event EventHandler ResourceIdsChanged;
741    protected virtual void OnResourceIdsChanged() {
742      EventHandler handler = ResourceIdsChanged;
743      if (handler != null) handler(this, EventArgs.Empty);
744    }
745
746    public event EventHandler ExperimentChanged;
747    protected virtual void OnExperimentChanged() {
748      LogMessage("Experiment changed");
749      EventHandler handler = ExperimentChanged;
750      if (handler != null) handler(this, EventArgs.Empty);
751    }
752
753    public event EventHandler ServerUrlChanged;
754    protected virtual void OnServerUrlChanged() {
755      EventHandler handler = ServerUrlChanged;
756      if (handler != null) handler(this, EventArgs.Empty);
757    }
758
759    public event EventHandler IsResultsPollingChanged;
760    private void OnIsPollingResultsChanged() {
761      if (this.IsPollingResults) {
762        LogMessage("Results Polling Started");
763        timer.Start();
764      } else {
765        LogMessage("Results Polling Stopped");
766        timer.Stop();
767      }
768      EventHandler handler = IsResultsPollingChanged;
769      if (handler != null) handler(this, EventArgs.Empty);
770    }
771
772    private void RegisterEvents() {
773      jobItems.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<JobItem>>(jobItems_CollectionReset);
774      jobItems.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<JobItem>>(jobItems_ItemsAdded);
775      jobItems.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<JobItem>>(jobItems_ItemsRemoved);
776      jobItems.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<JobItem>>(jobItems_ItemsReplaced);
777    }
778
779    private void DeregisterEvents() {
780      jobItems.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<JobItem>>(jobItems_CollectionReset);
781      jobItems.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<JobItem>>(jobItems_ItemsAdded);
782      jobItems.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<JobItem>>(jobItems_ItemsRemoved);
783      jobItems.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<JobItem>>(jobItems_ItemsReplaced);
784    }
785
786
787    void jobItems_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<JobItem>> e) {
788      UpdateSnapshotRequestedEvents(e);
789    }
790
791    private void UpdateSnapshotRequestedEvents(CollectionItemsChangedEventArgs<IndexedItem<JobItem>> e) {
792      foreach (var item in e.OldItems) {
793        item.Value.SnapshotRequestedStateChanged -= new EventHandler(JobItem_SnapshotRequestedStateChanged);
794      }
795      foreach (var item in e.Items) {
796        item.Value.SnapshotRequestedStateChanged += new EventHandler(JobItem_SnapshotRequestedStateChanged);
797      }
798    }
799
800    void jobItems_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<JobItem>> e) {
801      UpdateSnapshotRequestedEvents(e);
802    }
803
804    void jobItems_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<JobItem>> e) {
805      UpdateSnapshotRequestedEvents(e);
806    }
807
808    void jobItems_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<JobItem>> e) {
809      foreach (var item in e.OldItems) {
810        item.Value.SnapshotRequestedStateChanged -= new EventHandler(JobItem_SnapshotRequestedStateChanged);
811      }
812    }
813    #endregion
814  }
815}
Note: See TracBrowser for help on using the repository browser.