#region License Information /* HeuristicLab * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Hive; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.Analysis.SolutionCaching.RunCollectionModifiers { [Item("RunCollectionModifierTask", "An item that runs RunCollectionModifiers on RunCollections with Hive support.")] [StorableClass] public class RunCollectionModifierTask : ParameterizedNamedItem, ITask { public virtual bool IsParallelizable { get { return false; } } public virtual bool ComputeInParallel { get { return false; } set { throw new NotSupportedException("Parallelization is not supported for RunCollectionModifierTasks."); } } [Storable] protected ExecutionState executionState; public ExecutionState ExecutionState { get { return executionState; } set { if (value != executionState) { executionState = value; OnExecutionStateChanged(); } } } [Storable] protected TimeSpan executionTime; public TimeSpan ExecutionTime { get { return executionTime; } set { if (value != executionTime) { executionTime = value; OnExecutionTimeChanged(); } } } public ValueParameter> RunCollectionModifiersParameter { get { return (ValueParameter>)Parameters["RunCollectionModifiers"]; } } public ItemList RunCollectionModifiers { get { return RunCollectionModifiersParameter.Value; } } [Storable] protected RunCollection runCollection; public RunCollection RunCollection { get { return runCollection; } } [Storable] protected Stack executionStack; protected Stack ExecutionStack { get { return executionStack; } } [Storable] protected ILog log; public ILog Log { get { return log; } } protected CancellationTokenSource cancellationTokenSource; protected bool stopPending; #region Constructors and Cloning public RunCollectionModifierTask() { Parameters.Add(new ValueParameter>("RunCollectionModifiers", "List of RunCollectionModifiers that are executed. ", new ItemList())); executionStack = new Stack(); runCollection = new RunCollection(); log = new Log(); } [StorableConstructor] protected RunCollectionModifierTask(bool deserializing) : base(deserializing) { } protected RunCollectionModifierTask(RunCollectionModifierTask original, Cloner cloner) : base(original, cloner) { executionTime = original.executionTime; executionState = original.executionState; runCollection = (RunCollection)original.runCollection.Clone(cloner); executionStack = new Stack(); foreach (var runCollectionModifier in original.executionStack) { executionStack.Push(runCollectionModifier); } log = (ILog)original.log.Clone(cloner); } public override IDeepCloneable Clone(Cloner cloner) { return new RunCollectionModifierTask(this, cloner); } #endregion public void Pause() { cancellationTokenSource.Cancel(); } public void Prepare() { executionStack.Clear(); foreach (var runCollectionModifier in RunCollectionModifiers) { executionStack.Push(runCollectionModifier); } executionState = ExecutionState.Prepared; } public void Start() { cancellationTokenSource = new CancellationTokenSource(); Task task = Task.Factory.StartNew(RunModifiers, cancellationTokenSource.Token, cancellationTokenSource.Token); task.ContinueWith(t => { try { t.Wait(); } catch (AggregateException ex) { try { ex.Flatten().Handle(x => x is OperationCanceledException); } catch (AggregateException remaining) { if (remaining.InnerExceptions.Count == 1) OnTaskFailed(remaining.InnerExceptions[0]); else OnTaskFailed(remaining); } } cancellationTokenSource.Dispose(); cancellationTokenSource = null; if (stopPending) executionStack.Clear(); if (executionStack.Count == 0) OnTaskStopped(); else OnTaskPaused(); }); } public void Stop() { if (ExecutionState == ExecutionState.Paused) { executionStack.Clear(); OnTaskStopped(); } else { stopPending = true; cancellationTokenSource.Cancel(); } } public virtual void AddRunCollectionModifiers(IRunCollectionModifier modifier) { RunCollectionModifiers.Add(modifier); } protected virtual void RunModifiers(object state) { CancellationToken ct = (CancellationToken)state; OnTaskStarted(); IRunCollectionModifier next; while (executionStack.Count > 0) { next = executionStack.Pop(); try { ct.ThrowIfCancellationRequested(); next.Modify(runCollection.ToList()); } catch (Exception ex) { executionStack.Push(next); if (ex is OperationCanceledException) throw ex; else throw new Exception("IRunCollectionModifier " + next + "threw an exception.", ex); } } } #region Events public event EventHandler TaskStarted; protected virtual void OnTaskStarted() { executionState = ExecutionState.Started; EventHandler handler = TaskStarted; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler TaskStopped; protected virtual void OnTaskStopped() { executionState = ExecutionState.Stopped; EventHandler handler = TaskStopped; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler TaskPaused; protected virtual void OnTaskPaused() { executionState = ExecutionState.Paused; EventHandler handler = TaskPaused; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler TaskFailed; protected virtual void OnTaskFailed(Exception e) { var eventArgs = new EventArgs(e); Log.LogException(e); EventHandler handler = TaskFailed; if (handler != null) handler(this, eventArgs); } public event EventHandler ExecutionTimeChanged; protected virtual void OnExecutionTimeChanged() { EventHandler handler = ExecutionTimeChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler ExecutionStateChanged; protected virtual void OnExecutionStateChanged() { EventHandler handler = ExecutionStateChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler ComputeInParallelChanged; //not needed #endregion } }