using System;
using System.Collections.Generic;
using Core.Common.Base.Properties;
using log4net;
namespace Core.Common.Base.Service
{
///
/// Abstract class that can be used for performing activies (like calculations, data imports, data exports, etc.).
/// The regular workflow for completely performing an is: -> .
/// can be called for cancelling a running .
///
public abstract class Activity
{
public event EventHandler ProgressChanged;
private readonly ILog log = LogManager.GetLogger(typeof(Activity));
private string progressText;
///
/// Constructs a new .
///
protected Activity()
{
LogMessages = new List();
}
///
/// Gets or sets the name of the .
///
public virtual string Name { get; set; }
///
/// Gets or sets the of the .
///
public ActivityStatus Status { get; protected set; }
///
/// Gets or sets the progress text of the .
/// listeners are notified when the progress text is set.
///
public string ProgressText
{
get
{
return progressText;
}
protected set
{
progressText = value;
OnProgressChanged();
}
}
///
/// Gets or sets the collection of log messages of the (which is appended while performing the ).
///
public IList LogMessages { get; private set; }
///
/// This method runs the by sequentially making calls to and .
///
public void Run()
{
Initialize();
if (Status == ActivityStatus.Failed)
{
log.ErrorFormat(Resources.Activity_Run_Initialization_of_0_has_failed, Name);
return;
}
if (Status == ActivityStatus.Cancelled)
{
log.WarnFormat(Resources.Activity_Run_Execution_of_0_has_been_canceled, Name);
return;
}
Execute();
if (Status == ActivityStatus.Failed)
{
log.ErrorFormat(Resources.Activity_Run_Execution_of_0_has_failed, Name);
}
}
///
/// This method cancels a running .
///
public void Cancel()
{
ChangeState(OnCancel, ActivityStatus.Cancelling, ActivityStatus.Cancelled);
}
///
/// This method finishes an that successfully ran.
/// Successfully ran activities can be identified by a not equal to or .
///
public void Finish()
{
if (Status != ActivityStatus.Failed && Status != ActivityStatus.Cancelled)
{
ChangeState(OnFinish, ActivityStatus.Finishing, ActivityStatus.Finished);
}
}
///
/// This method initializes an .
///
protected void Initialize()
{
ChangeState(OnInitialize, ActivityStatus.Initializing, ActivityStatus.Initialized);
}
///
/// This method executes an that successfully initialized.
/// Successfully ran activities can be identified by a not equal to or .
///
protected void Execute()
{
if (Status == ActivityStatus.Finished || Status == ActivityStatus.Cancelled || Status == ActivityStatus.Failed || Status == ActivityStatus.None)
{
throw new InvalidOperationException(string.Format(Resources.Activity_Execute_Activity_is_0_Initialize_must_be_called_before_Execute, Status));
}
if (Status != ActivityStatus.Executed && Status != ActivityStatus.Initialized)
{
throw new InvalidOperationException(string.Format(Resources.Activity_Execute_Can_t_call_Execute_for_activity_in_0_state, Status));
}
try
{
Status = ActivityStatus.Executing;
OnExecute();
if (Status == ActivityStatus.Failed ||
Status == ActivityStatus.Cancelled)
{
// keep this status
return;
}
}
catch (Exception e)
{
Status = ActivityStatus.Failed;
log.Error(e.Message);
return;
}
Status = ActivityStatus.Executed;
}
///
/// 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.
///
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();
private void OnProgressChanged()
{
if (ProgressChanged != null)
{
ProgressChanged(this, EventArgs.Empty);
}
}
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;
}
}
}