Free cookie consent management tool by TermsFeed Policy Generator

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

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

improved HiveExperiment GUI (HL3.3 look&feel, RunCollectionView, JobItem.ToString) (#1115)

File size: 28.2 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      InitTimer();
161    }
162
163    public override IDeepCloneable Clone(Cloner cloner) {
164      LogMessage("I am beeing cloned");
165      HiveExperiment clone = (HiveExperiment)base.Clone(cloner);
166      clone.resourceIds = this.resourceIds;
167      clone.serverUrl = this.serverUrl;
168      clone.experiment = (HeuristicLab.Optimization.Experiment)cloner.Clone(experiment);
169      clone.executionState = this.executionState;
170      clone.executionTime = this.executionTime;
171      clone.pendingOptimizersByJobId = new Dictionary<Guid, IOptimizer>();
172
173      foreach (var pair in this.pendingOptimizersByJobId)
174        clone.pendingOptimizersByJobId[pair.Key] = (IOptimizer)cloner.Clone(pair.Value);
175
176      foreach (var pair in this.parentOptimizersByPendingOptimizer)
177        clone.parentOptimizersByPendingOptimizer[(IOptimizer)cloner.Clone(pair.Key)] = (IOptimizer)cloner.Clone(pair.Value);
178
179      clone.log = (ILog)cloner.Clone(log);
180      clone.stopPending = this.stopPending;
181      clone.pausePending = this.pausePending;
182      clone.jobItems = (JobItemList)cloner.Clone(jobItems);
183      clone.lastUpdateTime = this.lastUpdateTime;
184      clone.isPollingResults = this.isPollingResults;
185      return clone;
186    }
187
188    [StorableHook(HookType.AfterDeserialization)]
189    private void AfterDeserialization() {
190      InitTimer();
191      this.IsPollingResults = false;
192      this.stopResultsPollingPending = false;
193      LogMessage("I was deserialized.");
194    }
195
196    private void InitTimer() {
197      timer = new System.Timers.Timer(100);
198      timer.AutoReset = true;
199      timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
200    }
201
202    private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
203      DateTime now = DateTime.Now;
204      ExecutionTime += now - lastUpdateTime;
205      lastUpdateTime = now;
206    }
207
208    public IEnumerable<string> ResourceGroups {
209      get {
210        if (!string.IsNullOrEmpty(resourceIds)) {
211          return resourceIds.Split(';');
212        } else {
213          return new List<string>();
214        }
215      }
216    }
217    #region IExecutable Members
218
219    [Storable]
220    private Core.ExecutionState executionState;
221    public ExecutionState ExecutionState {
222      get { return executionState; }
223      private set {
224        if (executionState != value) {
225          executionState = value;
226          OnExecutionStateChanged();
227        }
228      }
229    }
230
231    [Storable]
232    private TimeSpan executionTime;
233    public TimeSpan ExecutionTime {
234      get { return executionTime; }
235      private set {
236        if (executionTime != value) {
237          executionTime = value;
238          OnExecutionTimeChanged();
239        }
240      }
241    }
242
243    public void Pause() {
244      throw new NotSupportedException();
245    }
246
247    public void Prepare() {
248      if (experiment != null) {
249        StopResultPolling();
250        pendingOptimizersByJobId.Clear();
251        parentOptimizersByPendingOptimizer.Clear();
252        jobItems.Clear();
253        experiment.Prepare();
254        this.ExecutionState = Core.ExecutionState.Prepared;
255        OnPrepared();
256      }
257    }
258
259    public void Start() {
260      OnStarted();
261      ExecutionTime = new TimeSpan();
262      lastUpdateTime = DateTime.Now;
263      this.ExecutionState = Core.ExecutionState.Started;
264      Thread t = new Thread(() => {
265        IExecutionEngineFacade executionEngineFacade = GetExecutionEngineFacade();
266
267        pendingOptimizersByJobId = new Dictionary<Guid, IOptimizer>();
268        parentOptimizersByPendingOptimizer = GetOptimizers(true);
269        IEnumerable<string> groups = ResourceGroups;
270       
271        foreach (IOptimizer optimizer in parentOptimizersByPendingOptimizer.Keys) {
272          SerializedJob serializedJob = CreateSerializedJob(optimizer);
273          ResponseObject<JobDto> response = executionEngineFacade.AddJobWithGroupStrings(serializedJob, groups);
274          pendingOptimizersByJobId.Add(response.Obj.Id, optimizer);
275
276          JobItem jobItem = new JobItem() {
277            JobDto = response.Obj,
278            LatestSnapshot = new ResponseObject<SerializedJob>() {
279              Obj = serializedJob,
280              StatusMessage = "Initial Snapshot",
281              Success = true
282            },
283            Optimizer = optimizer
284          };
285          jobItems.Add(jobItem);
286          jobItem.LogMessage("Job sent to Hive");
287
288          LogMessage("Sent job to Hive (jobId: " + response.Obj.Id + ")");
289        }
290
291        // start results polling after sending sending the jobs to the server (to avoid race conflicts at the optimizers-collection)
292        StartResultPolling();
293      });
294      t.Start();
295    }
296
297    public void Stop() {
298      this.ExecutionState = Core.ExecutionState.Stopped;
299      foreach (JobItem jobItem in jobItems) {
300        AbortJob(jobItem.JobDto.Id);
301      }
302      OnStopped();
303    }
304
305    private void CreateResultPollingThreads() {
306      foreach (JobItem jobItem in JobItems) {
307        if (!resultPollingThreads.ContainsKey(jobItem.JobDto.Id) && jobItem.JobDto.State != State.Finished) {
308          resultPollingThreads.Add(jobItem.JobDto.Id, CreateResultPollingThread(jobItem.JobDto));
309        }
310      }
311    }
312
313    public void StartResultPolling() {
314      this.stopResultsPollingPending = false;
315      this.IsPollingResults = true;
316      lock (resultPollingThreads) {
317        CreateResultPollingThreads();
318        foreach (Thread pollingThread in resultPollingThreads.Values) {
319          if (pollingThread.ThreadState != System.Threading.ThreadState.Running) {
320            pollingThread.Start();
321          }
322        }
323      }
324    }
325
326    public void StopResultPolling() {
327      this.stopResultsPollingPending = true;
328      foreach (Thread pollingThread in resultPollingThreads.Values) {
329        pollingThread.Interrupt();
330      }
331      this.stopResultsPollingPending = false;
332    }
333
334    private JobItem GetJobItemById(Guid jobId) {
335      return jobItems.Single(x => x.JobDto.Id == jobId);
336    }
337
338    /// <summary>
339    /// Returns all optimizers in the current Experiment
340    /// </summary>
341    /// <param name="flatout">if false only top level optimizers are returned, if true the optimizer-tree is flatted</param>
342    /// <returns></returns>
343    private IDictionary<IOptimizer, IOptimizer> GetOptimizers(bool flatout) {
344      if (!flatout) {
345        var optimizers = new Dictionary<IOptimizer, IOptimizer>();
346        foreach (IOptimizer opt in experiment.Optimizers) {
347          optimizers.Add(experiment, opt);
348        }
349        return optimizers;
350      } else {
351        return FlatOptimizerTree(null, experiment, "");
352      }
353    }
354
355    /// <summary>
356    /// Recursively iterates all IOptimizers in the optimizer-tree and returns them.
357    ///
358    /// [chn] this could be implemented more cleanly if Experiment and BatchRun would implement an interface like:
359    /// interface IParallelizable {
360    ///   IEnumerable&lt;IOptimizer&gt; GetOptimizers();
361    /// }
362    /// </summary>
363    /// <returns>a dictionary mapping from the parent optimizer to the child optimizer</returns>
364    private IDictionary<IOptimizer, IOptimizer> FlatOptimizerTree(IOptimizer parent, IOptimizer optimizer, string prepend) {
365      IDictionary<IOptimizer, IOptimizer> optimizers = new Dictionary<IOptimizer, IOptimizer>();
366      if (optimizer is HeuristicLab.Optimization.Experiment) {
367        HeuristicLab.Optimization.Experiment experiment = optimizer as HeuristicLab.Optimization.Experiment;
368        if (this.experiment != experiment) {
369          prepend += "Experiment/"; // don't prepend for top-level optimizers
370        }
371        foreach (IOptimizer opt in experiment.Optimizers) {
372          AddRange(optimizers, FlatOptimizerTree(experiment, opt, prepend));
373        }
374      } else if (optimizer is BatchRun) {
375        BatchRun batchRun = optimizer as BatchRun;
376        prepend += "BatchRun/";
377        for (int i = 0; i < batchRun.Repetitions; i++) {
378          IOptimizer opt = (IOptimizer)batchRun.Algorithm.Clone();
379          opt.Name += " [" + i + "]";
380          IDictionary<IOptimizer, IOptimizer> batchOptimizers = FlatOptimizerTree(batchRun, opt, prepend);
381          AddRange(optimizers, batchOptimizers);
382        }
383      } else if (optimizer is EngineAlgorithm) {
384        optimizer.Name = prepend + optimizer.Name;
385        optimizers.Add(optimizer, parent);
386      } else {
387        Logger.Warn("Optimizer of type " + optimizers.GetType().ToString() + " unknown");
388        optimizer.Name = prepend + optimizer.Name;
389        optimizers.Add(optimizer, parent);
390      }
391      return optimizers;
392    }
393
394    private void AddRange(IDictionary<IOptimizer, IOptimizer> optimizers, IDictionary<IOptimizer, IOptimizer> childs) {
395      foreach (KeyValuePair<IOptimizer, IOptimizer> kvp in childs) {
396        optimizers.Add(kvp);
397      }
398    }
399
400    private void ReplaceOptimizer(IOptimizer parentOptimizer, IOptimizer originalOptimizer, IOptimizer newOptimizer) {
401      lock (locker) {
402        if (parentOptimizer is HeuristicLab.Optimization.Experiment) {
403          HeuristicLab.Optimization.Experiment exp = (HeuristicLab.Optimization.Experiment)parentOptimizer;
404          int originalOptimizerIndex = exp.Optimizers.IndexOf(originalOptimizer);
405          exp.Optimizers[originalOptimizerIndex] = newOptimizer;
406        } else if (parentOptimizer is BatchRun) {
407          BatchRun batchRun = (BatchRun)parentOptimizer;
408          if (newOptimizer is IAlgorithm) {
409            batchRun.Runs.Add(new Run(newOptimizer.Name, (IAlgorithm)newOptimizer) );
410          } else {
411            throw new NotSupportedException("Only IAlgorithm types supported");
412          }
413        } else {
414          throw new NotSupportedException("Invalid parentOptimizer");
415        }
416      }
417    }
418
419    public void AbortJob(Guid jobId) {
420      IExecutionEngineFacade executionEngineFacade = GetExecutionEngineFacade();
421      Response response = executionEngineFacade.AbortJob(jobId);
422      GetJobItemById(jobId).LogMessage("Aborting Job: " + response.StatusMessage);
423    }
424
425    #endregion
426
427    private IExecutionEngineFacade GetExecutionEngineFacade() {
428      return ServiceLocator.CreateExecutionEngineFacade(ServerUrl);
429    }
430
431    private SerializedJob CreateSerializedJob(IOptimizer optimizer) {
432      IJob job = new OptimizerJob() {
433        Optimizer = optimizer
434      };
435
436      // serialize job
437      MemoryStream memStream = new MemoryStream();
438      XmlGenerator.Serialize(job, memStream);
439      byte[] jobByteArray = memStream.ToArray();
440      memStream.Dispose();
441
442      // find out which which plugins are needed for the given object
443      List<HivePluginInfoDto> pluginsNeeded = (
444        from p in GetDeclaringPlugins(optimizer.GetType())
445        select new HivePluginInfoDto() {
446          Name = p.Name,
447          Version = p.Version
448        }).ToList();
449
450      JobDto jobDto = new JobDto() {
451        CoresNeeded = 1, // [chn] how to determine real cores needed?
452        PluginsNeeded = pluginsNeeded,
453        State = State.Offline,
454        MemoryNeeded = 0,
455        UserId = Guid.Empty // [chn] set real userid here!
456      };
457
458      SerializedJob serializedJob = new SerializedJob() {
459        JobInfo = jobDto,
460        SerializedJobData = jobByteArray
461      };
462
463      return serializedJob;
464    }
465
466    private Thread CreateResultPollingThread(JobDto job) {
467      return new Thread(() => {
468        try {
469          GetJobItemById(job.Id).LogMessage("Starting job results polling");
470          IExecutionEngineFacade executionEngineFacade = GetExecutionEngineFacade();
471          IJob restoredObject = null;
472          IOptimizer originalOptimizer = pendingOptimizersByJobId[job.Id];
473
474          do {
475            // loop while
476            // 1. the user doesn't request an abort
477            // 2. there is a problem with server communication (success==false)
478            // 3. no result for the job is available yet (response.Obj==null)
479            // 4. the result that we get from the server is a snapshot and not the final result
480
481            if (stopPending || !this.IsPollingResults) {
482              return;
483            }
484
485            ResponseObject<JobDto> response = executionEngineFacade.GetJobById(job.Id);
486            LogMessage("Response: " + response.StatusMessage + " (jobId: " + job.Id + ")");
487            GetJobItemById(job.Id).LogMessage("Response: " + response.StatusMessage);
488
489            UpdateJobItem(response.Obj);
490
491            if (response.Obj.State == State.Abort) {
492              pendingOptimizersByJobId.Remove(job.Id);
493              parentOptimizersByPendingOptimizer.Remove(originalOptimizer);
494              GetJobItemById(job.Id).LogMessage("Job successfully aborted");
495              return;
496            }
497
498            if (response.Obj.State == State.Failed) {
499              pendingOptimizersByJobId.Remove(job.Id);
500              parentOptimizersByPendingOptimizer.Remove(originalOptimizer);
501              GetJobItemById(job.Id).LogMessage("Job failed with exception: " + response.Obj.Exception);
502              return;
503            }
504
505            if (response.Success && response.Obj != null && response.Obj.State == State.Finished) {
506              ResponseObject<SerializedJob> jobResponse = executionEngineFacade.GetLastSerializedResult(job.Id, false, false);
507              restoredObject = XmlParser.Deserialize<IJob>(new MemoryStream(jobResponse.Obj.SerializedJobData));
508              UpdateSnapshot(jobResponse);
509            } else {
510              Thread.Sleep(resultPollingIntervalMs);
511            }
512          } while (restoredObject == null || restoredObject.ExecutionState != Core.ExecutionState.Stopped);
513
514          LogMessage("Job finished (jobId: " + job.Id + ")");
515          GetJobItemById(job.Id).LogMessage("Job finished");
516          // job retrieved... replace the existing optimizers with the finished one
517         
518          IOptimizer restoredOptimizer = ((OptimizerJob)restoredObject).Optimizer;
519         
520          ReplaceOptimizer(parentOptimizersByPendingOptimizer[originalOptimizer], originalOptimizer, restoredOptimizer);
521          pendingOptimizersByJobId.Remove(job.Id);
522          parentOptimizersByPendingOptimizer.Remove(originalOptimizer);
523
524        } catch (ThreadInterruptedException exception) {
525
526        } finally {
527          GetJobItemById(job.Id).LogMessage("ResultsPolling Thread stopped");
528          lock (resultPollingThreads) {
529            resultPollingThreads.Remove(job.Id);
530            if (resultPollingThreads.Count == 0) {
531              IsPollingResults = false;
532            }
533          }
534
535          // check if finished
536          if (pendingOptimizersByJobId.Count == 0) {
537            this.ExecutionState = Core.ExecutionState.Stopped;
538            OnStopped();
539          }
540        }
541      });
542    }
543
544    private void UpdateJobItem(JobDto jobDto) {
545      JobItem jobItem = jobItems.Single(x => x.JobDto.Id == jobDto.Id);
546      jobItem.JobDto = jobDto;
547    }
548
549    private void UpdateSnapshot(ResponseObject<SerializedJob> response) {
550      JobItem jobItem = jobItems.Single(x => x.JobDto.Id == response.Obj.JobInfo.Id);
551      jobItem.LatestSnapshot = response;
552    }
553
554    private void LogMessage(string message) {
555      // HeuristicLab.Log is not Thread-Safe, so lock on every call
556      lock (locker) {
557        log.LogMessage(message);
558      }
559    }
560
561    public void RequestSnapshot(Guid jobId) {
562      IExecutionEngineFacade executionEngineFacade = GetExecutionEngineFacade();
563      ResponseObject<SerializedJob> response;
564      int retryCount = 0;
565
566      Response snapShotResponse = executionEngineFacade.RequestSnapshot(jobId);
567      if (snapShotResponse.StatusMessage == ApplicationConstants.RESPONSE_JOB_IS_NOT_BEEING_CALCULATED) {
568        // job already finished
569        Logger.Debug("HiveEngine: Abort - GetLastResult(false)");
570        response = executionEngineFacade.GetLastSerializedResult(jobId, false, false);
571        Logger.Debug("HiveEngine: Abort - Server: " + response.StatusMessage + " success: " + response.Success);
572      } else {
573        // server sent snapshot request to client
574        // poll until snapshot is ready
575        do {
576          Thread.Sleep(snapshotPollingIntervalMs);
577          Logger.Debug("HiveEngine: Abort - GetLastResult(true)");
578          response = executionEngineFacade.GetLastSerializedResult(jobId, false, true);
579          Logger.Debug("HiveEngine: Abort - Server: " + response.StatusMessage + " success: " + response.Success);
580          retryCount++;
581          // loop while
582          // 1. problem with communication with server
583          // 2. job result not yet ready
584        } while (
585          (retryCount < maxSnapshotRetries) && (
586          !response.Success ||
587          response.StatusMessage == ApplicationConstants.RESPONSE_JOB_RESULT_NOT_YET_HERE)
588          );
589      }
590      SerializedJob jobResult = response.Obj;
591      if (jobResult != null) {
592        Logger.Debug("HiveEngine: Results-polling - Got result!");
593
594        //job = XmlParser.Deserialize<Job>(new MemoryStream(jobResult.SerializedJobData));
595
596        throw new NotImplementedException("[chn] how to create a view in 3.3 and why should i do this here? shouldnt the caller of this method receive a result and decide what to do?");
597        //ControlManager.Manager.ShowControl(job.Engine.CreateView());
598      }
599    }
600
601    #region Required Plugin Search
602    /// <summary>
603    /// Returns a list of plugins in which the type itself and all members
604    /// of the type are declared. Objectgraph is searched recursively.
605    /// </summary>
606    private IEnumerable<IPluginDescription> GetDeclaringPlugins(Type type) {
607      HashSet<Type> types = new HashSet<Type>();
608      FindTypes(type, types, "HeuristicLab.");
609      return GetDeclaringPlugins(types);
610    }
611
612    /// <summary>
613    /// Returns the plugins (including dependencies) in which the given types are declared
614    /// </summary>
615    private IEnumerable<IPluginDescription> GetDeclaringPlugins(IEnumerable<Type> types) {
616      HashSet<IPluginDescription> plugins = new HashSet<IPluginDescription>();
617      foreach (Type t in types) {
618        FindDeclaringPlugins(ApplicationManager.Manager.GetDeclaringPlugin(t), plugins);
619      }
620      return plugins;
621    }
622
623    /// <summary>
624    /// Finds the dependencies of the given plugin and adds it to the plugins hashset.
625    /// Also searches the dependencies recursively.
626    /// </summary>
627    private void FindDeclaringPlugins(IPluginDescription plugin, HashSet<IPluginDescription> plugins) {
628      if (!plugins.Contains(plugin)) {
629        plugins.Add(plugin);
630        foreach (IPluginDescription dependency in plugin.Dependencies) {
631          FindDeclaringPlugins(dependency, plugins);
632        }
633      }
634    }
635
636    /// <summary>
637    /// Recursively finds all types used in type which are in a namespace which starts with namespaceStart
638    /// Be aware that search is not performed on attributes
639    /// </summary>
640    /// <param name="type">the type to be searched</param>
641    /// <param name="types">found types will be stored there, needed in order to avoid duplicates</param>
642    /// <param name="namespaceStart">only types from namespaces which start with this will be searched and added</param>
643    private void FindTypes(Type type, HashSet<Type> types, string namespaceStart) {
644      if (!types.Contains(type) && type.Namespace.StartsWith(namespaceStart)) {
645        types.Add(type);
646
647        // constructors
648        foreach (ConstructorInfo info in type.GetConstructors()) {
649          foreach (ParameterInfo paramInfo in info.GetParameters()) {
650            FindTypes(paramInfo.ParameterType, types, namespaceStart);
651          }
652        }
653
654        // interfaces
655        foreach (Type t in type.GetInterfaces()) {
656          FindTypes(t, types, namespaceStart);
657        }
658
659        // events
660        foreach (EventInfo info in type.GetEvents()) {
661          FindTypes(info.EventHandlerType, types, namespaceStart);
662          FindTypes(info.DeclaringType, types, namespaceStart);
663        }
664
665        // properties
666        foreach (PropertyInfo info in type.GetProperties()) {
667          FindTypes(info.PropertyType, types, namespaceStart);
668        }
669
670        // fields
671        foreach (FieldInfo info in type.GetFields()) {
672          FindTypes(info.FieldType, types, namespaceStart);
673        }
674
675        // methods
676        foreach (MethodInfo info in type.GetMethods()) {
677          foreach (ParameterInfo paramInfo in info.GetParameters()) {
678            FindTypes(paramInfo.ParameterType, types, namespaceStart);
679          }
680          FindTypes(info.ReturnType, types, namespaceStart);
681        }
682      }
683    }
684    #endregion
685
686    #region Eventhandler
687
688    public event EventHandler ExecutionTimeChanged;
689    private void OnExecutionTimeChanged() {
690      EventHandler handler = ExecutionTimeChanged;
691      if (handler != null) handler(this, EventArgs.Empty);
692    }
693
694    public event EventHandler ExecutionStateChanged;
695    private void OnExecutionStateChanged() {
696      LogMessage("ExecutionState changed to " + executionState.ToString());
697      EventHandler handler = ExecutionStateChanged;
698      if (handler != null) handler(this, EventArgs.Empty);
699    }
700
701    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
702
703    public event EventHandler Started;
704    private void OnStarted() {
705      LogMessage("Started");
706      timer.Start();
707      EventHandler handler = Started;
708      if (handler != null) handler(this, EventArgs.Empty);
709    }
710
711    public event EventHandler Stopped;
712    private void OnStopped() {
713      timer.Stop();
714      LogMessage("Stopped");
715      EventHandler handler = Stopped;
716      if (handler != null) handler(this, EventArgs.Empty);
717    }
718
719    public event EventHandler Paused;
720    private void OnPaused() {
721      timer.Stop();
722      LogMessage("Paused");
723      EventHandler handler = Paused;
724      if (handler != null) handler(this, EventArgs.Empty);
725    }
726
727    public event EventHandler Prepared;
728    protected virtual void OnPrepared() {
729      LogMessage("Prepared");
730      EventHandler handler = Prepared;
731      if (handler != null) handler(this, EventArgs.Empty);
732    }
733
734    public event EventHandler ResourceIdsChanged;
735    protected virtual void OnResourceIdsChanged() {
736      EventHandler handler = ResourceIdsChanged;
737      if (handler != null) handler(this, EventArgs.Empty);
738    }
739
740    public event EventHandler ExperimentChanged;
741    protected virtual void OnExperimentChanged() {
742      LogMessage("Experiment changed");
743      EventHandler handler = ExperimentChanged;
744      if (handler != null) handler(this, EventArgs.Empty);
745    }
746
747    public event EventHandler ServerUrlChanged;
748    protected virtual void OnServerUrlChanged() {
749      EventHandler handler = ServerUrlChanged;
750      if (handler != null) handler(this, EventArgs.Empty);
751    }
752
753    public event EventHandler IsResultsPollingChanged;
754    private void OnIsPollingResultsChanged() {
755      if (this.IsPollingResults) {
756        LogMessage("Results Polling Started");
757        timer.Start();
758      } else {
759        LogMessage("Results Polling Stopped");
760        timer.Stop();
761      }
762      EventHandler handler = IsResultsPollingChanged;
763      if (handler != null) handler(this, EventArgs.Empty);
764    }
765    #endregion
766  }
767}
Note: See TracBrowser for help on using the repository browser.