// 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; } } }