// Copyright (C) Stichting Deltares and State of the Netherlands 2024. All rights reserved.
//
// This file is part of Riskeer.
//
// Riskeer is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using Core.Common.Base.Properties;
using log4net;
namespace Core.Common.Base.Service
{
///
/// Abstract class that can be derived for performing activities (like calculations, data imports, data exports, etc.).
/// The regular workflow for completely performing an is: -> .
/// can be called for canceling a running .
///
///
/// By convention, only should contain UI thread related logic.
///
public abstract class Activity
{
private readonly ILog log = LogManager.GetLogger(typeof(Activity));
private string progressText;
///
/// Event for notifying progress changes.
///
public event EventHandler ProgressChanged;
///
/// Constructs a new .
///
protected Activity()
{
Description = "";
State = ActivityState.None;
}
///
/// Gets or sets the description of the .
///
public string Description { get; protected set; }
///
/// Gets or sets the of the .
///
public ActivityState State { 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();
}
}
///
/// This method resets to and then runs the .
/// The of a successfully run will become .
/// When the run fails, the will become .
///
public void Run()
{
State = ActivityState.None;
log.InfoFormat(Resources.Activity_Run_ActivityDescription_0_has_started, Description);
ChangeState(OnRun, ActivityState.Executed);
}
///
/// This method cancels a running .
/// The of a successfully canceled will become .
/// When the cancel action fails, the will become .
///
public void Cancel()
{
ChangeState(OnCancel, ActivityState.Canceled);
}
///
/// This method finishes an that successfully ran.
/// Successfully ran activities can be identified by a equal to .
/// The of a successfully finished will become .
/// When the finish action fails, the will become .
///
public void Finish()
{
if (State == ActivityState.None)
{
return;
}
ChangeState(OnFinish, State == ActivityState.Executed ? ActivityState.Finished : State); // If relevant, preserve the previous state
}
///
/// Logs the current state of the .
///
public void LogState()
{
if (State == ActivityState.Executed)
{
log.InfoFormat(Resources.Activity_Finish_ActivityDescription_0_has_succeeded, Description);
}
if (State == ActivityState.Canceled)
{
log.WarnFormat(Resources.Activity_Finish_ActivityDescription_0_has_been_canceled, Description);
}
if (State == ActivityState.Failed)
{
log.ErrorFormat(Resources.Activity_Finish_ActivityDescription_0_has_failed, Description);
}
if (State == ActivityState.Skipped)
{
log.InfoFormat(Resources.Activity_Finish_ActivityDescription_0_has_been_skipped, Description);
}
}
///
/// This template method provides the actual run logic (it is called within ).
///
///
/// The should be set to when one or more errors occur.
/// By convention, the implementation of this method should not contain UI thread related logic.
/// Implementations of this method are allowed to throw exceptions of any kind.
///
protected abstract void OnRun();
///
/// This template method provides the actual cancel logic (it is called within ).
///
///
/// By convention, the implementation of this method should not contain UI thread related logic.
/// Implementations of this method are allowed to throw exceptions of any kind.
///
protected abstract void OnCancel();
///
/// This template method provides the actual finish logic (it is called within ).
///
///
/// By convention, only the implementation of this method might contain UI thread related logic.
/// Implementations of this method are allowed to throw exceptions of any kind.
///
protected abstract void OnFinish();
private void OnProgressChanged()
{
ProgressChanged?.Invoke(this, EventArgs.Empty);
}
private void ChangeState(Action transitionAction, ActivityState stateAfter)
{
try
{
transitionAction();
if (State == ActivityState.Failed || State == ActivityState.Canceled || State == ActivityState.Skipped)
{
return;
}
}
catch (Exception)
{
State = ActivityState.Failed;
return;
}
State = stateAfter;
}
}
}