#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
}
}