#region License Information /* HeuristicLab * Copyright (C) 2002-2015 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.Threading; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.Scripting { [Item("Executable Script", "An executable script.")] [StorableClass("7D7C1BAB-6E99-49C2-AE2E-23265E128A00")] public abstract class ExecutableScript : Script { private Thread scriptThread; private DateTime lastUpdateTime; [Storable] private TimeSpan executionTime; public TimeSpan ExecutionTime { get { return executionTime; } protected set { executionTime = value; OnExecutionTimeChanged(); } } public bool Running { get; protected set; } #region Construction & Cloning [StorableConstructor] protected ExecutableScript(bool deserializing) : base(deserializing) { } protected ExecutableScript(ExecutableScript original, Cloner cloner) : base(original, cloner) { executionTime = original.executionTime; } protected ExecutableScript() : base() { executionTime = TimeSpan.Zero; } protected ExecutableScript(string code) : base(code) { executionTime = TimeSpan.Zero; } #endregion #region Execution protected abstract void ExecuteCode(); public virtual void Execute() { if (Running) throw new InvalidOperationException("Script is already running"); ExecutionTime = TimeSpan.Zero; Exception ex = null; var timer = new System.Timers.Timer(250) { AutoReset = true }; timer.Elapsed += timer_Elapsed; try { Running = true; OnScriptExecutionStarted(); lastUpdateTime = DateTime.UtcNow; timer.Start(); ExecuteCode(); } catch (Exception e) { ex = e; } finally { timer.Elapsed -= timer_Elapsed; timer.Stop(); timer.Dispose(); ExecutionTime += DateTime.UtcNow - lastUpdateTime; Running = false; OnScriptExecutionFinished(ex); } } public virtual void ExecuteAsync() { scriptThread = new Thread(() => { try { Execute(); } finally { scriptThread = null; } }); scriptThread.SetApartmentState(ApartmentState.STA); scriptThread.Start(); } public virtual void Kill() { if (!Running) return; scriptThread.Abort(); } #endregion private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { var timer = (System.Timers.Timer)sender; timer.Enabled = false; DateTime now = DateTime.UtcNow; ExecutionTime += now - lastUpdateTime; lastUpdateTime = now; timer.Enabled = true; } public event EventHandler ScriptExecutionStarted; protected virtual void OnScriptExecutionStarted() { var handler = ScriptExecutionStarted; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler> ScriptExecutionFinished; protected virtual void OnScriptExecutionFinished(Exception e) { var handler = ScriptExecutionFinished; if (handler != null) handler(this, new EventArgs(e)); } public event EventHandler ExecutionTimeChanged; protected virtual void OnExecutionTimeChanged() { var handler = ExecutionTimeChanged; if (handler != null) handler(this, EventArgs.Empty); } } }