using System; using System.Collections.Generic; using DelftTools.Utils.Collections.Generic; using log4net; namespace DelftTools.Shell.Core.Workflow { public abstract class Activity : IActivity { public virtual event EventHandler StatusChanged; public event EventHandler ProgressChanged; private static readonly ILog log = LogManager.GetLogger(typeof(Activity)); private string progressText; private ActivityStatus status; protected Activity() { DependsOn = new EventedList(); } public virtual string Name { get; set; } public virtual IEventedList DependsOn { get; set; } public virtual ActivityStatus Status { get { return status; } protected set { if (value == status) { return; } var oldStatus = status; status = value; if (StatusChanged != null) { StatusChanged(this, new ActivityStatusChangedEventArgs(oldStatus, status)); } } } public virtual string ProgressText { get { return progressText; } } public virtual IEnumerable GetDirectChildren() { throw new NotImplementedException(); } public virtual void Initialize() { ChangeState(OnInitialize, ActivityStatus.Initializing, ActivityStatus.Initialized); } public virtual void Execute() { if (Status == ActivityStatus.Finished || Status == ActivityStatus.Cancelled || Status == ActivityStatus.Failed || Status == ActivityStatus.None) { throw new InvalidOperationException(string.Format("Activity is {0}, Initialize() must be called before Execute()", Status)); } if (Status != ActivityStatus.Executed && Status != ActivityStatus.Initialized) { throw new InvalidOperationException(string.Format("Can't call Execute() for activity in {0} state.", Status)); } try { Status = ActivityStatus.Executing; OnExecute(); OnProgressChanged(); if (Status == ActivityStatus.Failed || Status == ActivityStatus.Done || Status == ActivityStatus.Cancelled) { // keep this status return; } } catch (Exception e) { Status = ActivityStatus.Failed; log.Error(e.Message); return; } Status = ActivityStatus.Executed; } public virtual void Cancel() { ChangeState(OnCancel, ActivityStatus.Cancelling, ActivityStatus.Cancelled); } public virtual void Cleanup() { if (Status != ActivityStatus.Cancelled || Status != ActivityStatus.Failed) { ChangeState(OnCleanUp, ActivityStatus.Cleaning, ActivityStatus.Cleaned); } else { ChangeState(OnCleanUp, status, status); } } public virtual void Finish() { ChangeState(OnFinish, ActivityStatus.Finishing, ActivityStatus.Finished); } public virtual object DeepClone() { throw new NotImplementedException(); } protected virtual void OnProgressChanged() { if (ProgressChanged != null) { ProgressChanged(this, EventArgs.Empty); } } protected void SetProgressText(string progressText) { this.progressText = progressText; if (ProgressChanged != null) { ProgressChanged(this, null); } } /// /// Initializes internal state to prepare for execution. After calling this method, /// will be set to if /// no error has occurred. /// /// Set to /// when an error has occurred while performing the initialization. protected abstract void OnInitialize(); /// /// Executes one step. This method will be called multiple times to allow for multiple /// execution steps. After calling this method, will be set to /// if no error has occurred. /// /// /// Set to /// when an error has occurred while executing. /// Set to /// when execution has finished without errors. /// protected abstract void OnExecute(); /// /// Activity has finished successfully. After calling this method, /// will be set to if no error has occurred. /// protected abstract void OnFinish(); /// /// Cancels current run. will change to /// after this method has been called. /// protected abstract void OnCancel(); /// /// Performs clean-up of all internal resources. /// protected abstract void OnCleanUp(); private void ChangeState(Action transitionAction, ActivityStatus statusBefore, ActivityStatus statusAfter) { try { Status = statusBefore; transitionAction(); if (Status == ActivityStatus.Failed) { return; } } catch (Exception e) { Status = ActivityStatus.Failed; log.Error(e.Message); return; } Status = statusAfter; } } }