From 0ce29fb2a1bf99d6371923b53bae22cb6c73ce9c Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Tue, 11 Oct 2022 15:53:50 +0200 Subject: [PATCH] [New] Extending execution policies for warning task --- .../execution/DelayedExecutionTimer.java | 26 ++++- .../SimpleDurationExecutionTimer.java | 21 +++- .../execution/policy/ExecutionPolicy.java | 97 ++++++++++++------- .../execution/policy/SimpleExecution.java | 36 +++++++ 4 files changed, 142 insertions(+), 38 deletions(-) diff --git a/li.strolch.service/src/main/java/li/strolch/execution/DelayedExecutionTimer.java b/li.strolch.service/src/main/java/li/strolch/execution/DelayedExecutionTimer.java index 5eee429e8..da029ac2c 100644 --- a/li.strolch.service/src/main/java/li/strolch/execution/DelayedExecutionTimer.java +++ b/li.strolch.service/src/main/java/li/strolch/execution/DelayedExecutionTimer.java @@ -1,9 +1,13 @@ package li.strolch.execution; +import java.time.Duration; +import java.util.concurrent.ScheduledFuture; + import li.strolch.agent.api.ComponentContainer; import li.strolch.execution.policy.ExecutionPolicy; import li.strolch.model.Locator; import li.strolch.model.activity.Action; +import li.strolch.utils.time.PeriodDuration; /** * A decoupling of {@link ExecutionPolicy ExecutionPolicies} so that the execution can be performed after a certain @@ -14,6 +18,26 @@ import li.strolch.model.activity.Action; */ public interface DelayedExecutionTimer { + /** + * Delays the execution of the given {@link Runnable} by the given {@link PeriodDuration} + * + * @param duration + * the duration before calling the {@link Runnable} + * @param runnable + * the action to call after the given delay + */ + ScheduledFuture delay(PeriodDuration duration, Runnable runnable); + + /** + * Delays the execution of the given {@link Runnable} by the given {@link Duration} + * + * @param duration + * the duration before calling the {@link Runnable} + * @param runnable + * the action to call after the given delay + */ + ScheduledFuture delay(Duration duration, Runnable runnable); + /** * Delays the execution of the given {@link Runnable} by the given milliseconds * @@ -22,7 +46,7 @@ public interface DelayedExecutionTimer { * @param runnable * the action to call after the given delay */ - void delay(long duration, Runnable runnable); + ScheduledFuture delay(long duration, Runnable runnable); /** * Completes the execution of the given {@link Action} {@link Locator} after the given duration in milliseconds diff --git a/li.strolch.service/src/main/java/li/strolch/execution/SimpleDurationExecutionTimer.java b/li.strolch.service/src/main/java/li/strolch/execution/SimpleDurationExecutionTimer.java index 7b203cd0e..9f3e9f83f 100644 --- a/li.strolch.service/src/main/java/li/strolch/execution/SimpleDurationExecutionTimer.java +++ b/li.strolch.service/src/main/java/li/strolch/execution/SimpleDurationExecutionTimer.java @@ -2,6 +2,7 @@ package li.strolch.execution; import static li.strolch.runtime.StrolchConstants.SYSTEM_USER_AGENT; +import java.time.Duration; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -17,6 +18,7 @@ import li.strolch.model.Locator; import li.strolch.model.log.LogMessage; import li.strolch.model.log.LogMessageState; import li.strolch.model.log.LogSeverity; +import li.strolch.utils.time.PeriodDuration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,8 +51,18 @@ public class SimpleDurationExecutionTimer implements DelayedExecutionTimer { } @Override - public void delay(long duration, Runnable runnable) { - getExecutor().schedule(runnable, duration, TimeUnit.MILLISECONDS); + public ScheduledFuture delay(PeriodDuration duration, Runnable runnable) { + return delay(duration.toMillis(), runnable); + } + + @Override + public ScheduledFuture delay(Duration duration, Runnable runnable) { + return delay(duration.toMillis(), runnable); + } + + @Override + public ScheduledFuture delay(long duration, Runnable runnable) { + return getExecutor().schedule(runnable, duration, TimeUnit.MILLISECONDS); } @Override @@ -93,8 +105,9 @@ public class SimpleDurationExecutionTimer implements DelayedExecutionTimer { logger.error("Failed to set " + locator + " to executed due to " + e.getMessage(), e); if (this.agent.getContainer().hasComponent(OperationsLog.class)) { - this.agent.getContainer().getComponent(OperationsLog.class).addMessage( - new LogMessage(realm, SYSTEM_USER_AGENT, locator, LogSeverity.Exception, + this.agent.getContainer() + .getComponent(OperationsLog.class) + .addMessage(new LogMessage(realm, SYSTEM_USER_AGENT, locator, LogSeverity.Exception, LogMessageState.Information, ResourceBundle.getBundle("strolch-service"), "execution.handler.failed.executed").withException(e).value("reason", e)); } diff --git a/li.strolch.service/src/main/java/li/strolch/execution/policy/ExecutionPolicy.java b/li.strolch.service/src/main/java/li/strolch/execution/policy/ExecutionPolicy.java index fe0ae7bfe..949eade7c 100644 --- a/li.strolch.service/src/main/java/li/strolch/execution/policy/ExecutionPolicy.java +++ b/li.strolch.service/src/main/java/li/strolch/execution/policy/ExecutionPolicy.java @@ -16,6 +16,7 @@ import li.strolch.execution.Controller; import li.strolch.execution.DelayedExecutionTimer; import li.strolch.execution.ExecutionHandler; import li.strolch.model.Locator; +import li.strolch.model.Resource; import li.strolch.model.State; import li.strolch.model.activity.Action; import li.strolch.model.activity.Activity; @@ -50,6 +51,7 @@ public abstract class ExecutionPolicy extends StrolchPolicy { protected String realm; protected String actionType; + protected Locator resourceLoc; protected Locator actionLoc; /** @@ -65,7 +67,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy { } /** - *

Set the {@link Controller} for this execution policy. Usually called by the controller itself, when instantiating this instance

+ *

Set the {@link Controller} for this execution policy. Usually called by the controller itself, when + * instantiating this instance

* *

Note: This is used as execution policies can have a longer lifecycle than its transaction.

* @@ -89,6 +92,22 @@ public abstract class ExecutionPolicy extends StrolchPolicy { return this.controller; } + /** + * Returns the type of the {@link Resource} for this action. Can only be called after {@link #initialize(Action)} + * was called. + */ + protected String getResourceType() { + return this.resourceLoc.get(1); + } + + /** + * Returns the id of the {@link Resource} for this action. Can only be called after {@link #initialize(Action)} was + * called. + */ + protected String getResourceId() { + return this.resourceLoc.get(2); + } + /** * Returns the {@link ExecutionHandler} * @@ -144,8 +163,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy { } /** - * Performs any initialization of this {@link ExecutionPolicy} for the given action, this method stores the {@link - * Locator} of the action and its type + * Performs any initialization of this {@link ExecutionPolicy} for the given action, this method stores the + * {@link Locator} of the action and its type * * @param action * the action for which to initialize @@ -153,6 +172,7 @@ public abstract class ExecutionPolicy extends StrolchPolicy { public void initialize(Action action) { this.actionType = action.getType(); this.actionLoc = action.getLocator(); + this.resourceLoc = action.getResourceLocator(); } /** @@ -172,8 +192,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy { public abstract void toExecuted(Action action); /** - * Stops the execution of this {@link Action} without completing its execution, i.e. sets the state to {@link - * State#STOPPED} + * Stops the execution of this {@link Action} without completing its execution, i.e. sets the state to + * {@link State#STOPPED} * * @param action * the action to stop execution for @@ -181,8 +201,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy { public abstract void toStopped(Action action); /** - * Sets this {@link Action} which should be in execution to an error state, i.e. sets the state to {@link - * State#ERROR} + * Sets this {@link Action} which should be in execution to an error state, i.e. sets the state to + * {@link State#ERROR} * * @param action * the action to set to error state @@ -190,8 +210,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy { public abstract void toError(Action action); /** - * Sets this {@link Action} which should be in execution to a warning state, i.e. sets the state to {@link - * State#WARNING} + * Sets this {@link Action} which should be in execution to a warning state, i.e. sets the state to + * {@link State#WARNING} * * @param action * the action to set to warning state @@ -219,7 +239,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy { } /** - * Updates the state of the given {@link Action} to the given {@link State} and updates the {@link Activity} for persisting on the TX + * Updates the state of the given {@link Action} to the given {@link State} and updates the {@link Activity} for + * persisting on the TX * * @param action * the action to change @@ -241,6 +262,16 @@ public abstract class ExecutionPolicy extends StrolchPolicy { logger.info(msg); } + /** + * Finds the duration of the given {@link Action} by searching the activity hierarchy using + * {@link Action#findParameter(String, String, boolean)} using #BAG_OBJECTIVES and #PARAM_DURATION. + * + * @return the {@link DurationParameter} + */ + protected DurationParameter findActionDuration(Action action) { + return action.findParameter(BAG_OBJECTIVES, PARAM_DURATION, true); + } + /** * Delays the given {@link Runnable} by the given {@link Duration} * @@ -255,15 +286,16 @@ public abstract class ExecutionPolicy extends StrolchPolicy { } /** - * Async method to delay setting the given {@link Action} to executed by the duration defined by the {@link DurationParameter} found by calling {@link Action#findParameter(String, String, boolean)} + * Async method to delay setting the given {@link Action} to executed by the duration defined by the + * {@link DurationParameter} found by calling {@link Action#findParameter(String, String, boolean)} */ protected void delayToExecuted(Action action) { - DurationParameter durationP = action.findParameter(BAG_OBJECTIVES, PARAM_DURATION, true); - delayToExecutedBy(durationP); + delayToExecutedBy(findActionDuration(action)); } /** - * Async method to delay setting the {@link Action} to executed by the duration defined by the given {@link DurationParameter} + * Async method to delay setting the {@link Action} to executed by the duration defined by the given + * {@link DurationParameter} */ protected void delayToExecutedBy(DurationParameter durationP) { long duration = durationP.getValue().toMillis(); @@ -278,8 +310,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy { } /** - * Async method to delay setting the {@link Action} to executed by the given duration, - * but randomly changing the duration in milliseconds by the given min and max factors + * Async method to delay setting the {@link Action} to executed by the given duration, but randomly changing the + * duration in milliseconds by the given min and max factors */ protected void delayToExecutedByRandom(Duration duration, double minFactor, double maxFactor) { long durationMs = duration.toMillis(); @@ -287,19 +319,17 @@ public abstract class ExecutionPolicy extends StrolchPolicy { } /** - * Async method to delay setting the given {@link Action} to executed by the duration defined - * by the {@link DurationParameter} found by calling {@link Action#findParameter(String, String, boolean)}, - * but randomly changing the duration in milliseconds by the given min and max factors + * Async method to delay setting the given {@link Action} to executed by the duration defined by the + * {@link DurationParameter} found by calling {@link Action#findParameter(String, String, boolean)}, but randomly + * changing the duration in milliseconds by the given min and max factors */ protected void delayToExecutedByRandom(Action action, double minFactor, double maxFactor) { - DurationParameter durationP = action.findParameter(BAG_OBJECTIVES, PARAM_DURATION, true); - delayToExecutedByRandom(durationP, minFactor, maxFactor); + delayToExecutedByRandom(findActionDuration(action), minFactor, maxFactor); } /** - * Async method to delay setting the {@link Action} to executed - * by the duration defined by the given {@link DurationParameter}, - * but randomly changing the duration in milliseconds by the given min and max factors + * Async method to delay setting the {@link Action} to executed by the duration defined by the given + * {@link DurationParameter}, but randomly changing the duration in milliseconds by the given min and max factors */ protected void delayToExecutedByRandom(DurationParameter durationP, double minFactor, double maxFactor) { long duration = durationP.getValue().toMillis(); @@ -307,16 +337,16 @@ public abstract class ExecutionPolicy extends StrolchPolicy { } /** - * Async method to delay setting the {@link Action} to executed by the given duration, - * but randomly changing the duration in milliseconds by the given min and max factors + * Async method to delay setting the {@link Action} to executed by the given duration, but randomly changing the + * duration in milliseconds by the given min and max factors */ protected void delayToExecutedByRandom(long duration, double minFactor, double maxFactor, TimeUnit delayUnit) { delayToExecutedByRandom((long) (duration * minFactor), (long) (duration * maxFactor), delayUnit); } /** - * Async method to delay setting the {@link Action} to executed by randomly choosing a value - * by calling {@link ThreadLocalRandom#nextLong(long, long)} passing min and max as origin and bound respectively + * Async method to delay setting the {@link Action} to executed by randomly choosing a value by calling + * {@link ThreadLocalRandom#nextLong(long, long)} passing min and max as origin and bound respectively */ protected void delayToExecutedByRandom(long min, long max, TimeUnit delayUnit) { long delay = ThreadLocalRandom.current().nextLong(min, max + 1); @@ -345,13 +375,14 @@ public abstract class ExecutionPolicy extends StrolchPolicy { * @return the {@link DelayedExecutionTimer} to simplify the delayed execution of an {@link Action}, e.g. for * simulated execution or simple wait tasks */ - private DelayedExecutionTimer getDelayedExecutionTimer() { + protected DelayedExecutionTimer getDelayedExecutionTimer() { return getComponent(ExecutionHandler.class).getDelayedExecutionTimer(); } /** - * Opens a {@link StrolchTransaction} where the realm retrieved using {@link ComponentContainer#getRealm(Certificate)}. - * This transaction should be used in a try-with-resource clause so it is properly closed. + * Opens a {@link StrolchTransaction} where the realm retrieved using + * {@link ComponentContainer#getRealm(Certificate)}. This transaction should be used in a try-with-resource clause + * so it is properly closed. * * @param ctx * the privilege context @@ -387,8 +418,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy { } /** - * Performs the given {@link PrivilegedRunnableWithResult} as the system user {@link - * StrolchConstants#SYSTEM_USER_AGENT} + * Performs the given {@link PrivilegedRunnableWithResult} as the system user + * {@link StrolchConstants#SYSTEM_USER_AGENT} * * @param runnable * the runnable to perform diff --git a/li.strolch.service/src/main/java/li/strolch/execution/policy/SimpleExecution.java b/li.strolch.service/src/main/java/li/strolch/execution/policy/SimpleExecution.java index 00c22765e..95583cd2a 100644 --- a/li.strolch.service/src/main/java/li/strolch/execution/policy/SimpleExecution.java +++ b/li.strolch.service/src/main/java/li/strolch/execution/policy/SimpleExecution.java @@ -1,7 +1,9 @@ package li.strolch.execution.policy; +import java.util.concurrent.ScheduledFuture; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.Supplier; import li.strolch.exception.StrolchException; import li.strolch.execution.ExecutionHandler; @@ -9,10 +11,12 @@ import li.strolch.handler.operationslog.OperationsLog; import li.strolch.model.State; import li.strolch.model.activity.Action; import li.strolch.model.log.LogMessage; +import li.strolch.model.parameter.DurationParameter; import li.strolch.model.timevalue.impl.FloatValue; import li.strolch.model.timevalue.impl.ValueChange; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.privilege.model.PrivilegeContext; +import li.strolch.utils.time.PeriodDuration; /** *

@@ -23,10 +27,36 @@ import li.strolch.privilege.model.PrivilegeContext; */ public class SimpleExecution extends ExecutionPolicy { + private ScheduledFuture warningTask; + public SimpleExecution(StrolchTransaction tx) { super(tx); } + protected void startWarningTask(Action action, Supplier handler) { + DurationParameter durationP = findActionDuration(action); + startWarningTask(durationP.getValue(), action, handler); + } + + protected void startWarningTask(PeriodDuration duration, Action action, Supplier handler) { + if (this.warningTask != null) { + logger.warn("There is already a warning task registered, for action " + action.getLocator() + + ". Cancelling and creating a new task..."); + this.warningTask.cancel(true); + this.warningTask = null; + } + + DurationParameter durationP = findActionDuration(action); + this.warningTask = getDelayedExecutionTimer().delay(durationP.getValue(), () -> toWarning(handler.get())); + } + + protected void cancelWarningTask() { + if (this.warningTask != null) { + this.warningTask.cancel(true); + this.warningTask = null; + } + } + @Override public void toExecution(Action action) { setActionState(action, State.EXECUTION); @@ -42,6 +72,7 @@ public class SimpleExecution extends ExecutionPolicy { @Override public void toExecuted(Action action) { + cancelWarningTask(); stop(); setActionState(action, State.EXECUTED); @@ -52,6 +83,7 @@ public class SimpleExecution extends ExecutionPolicy { @Override public void toStopped(Action action) { + cancelWarningTask(); stop(); setActionState(action, State.STOPPED); @@ -62,6 +94,7 @@ public class SimpleExecution extends ExecutionPolicy { @Override public void toError(Action action) { + cancelWarningTask(); stop(); setActionState(action, State.ERROR); @@ -78,12 +111,14 @@ public class SimpleExecution extends ExecutionPolicy { } protected void toExecuted() throws Exception { + cancelWarningTask(); stop(); getController().toExecuted(this.actionLoc); getComponent(ExecutionHandler.class).triggerExecution(this.realm); } protected void toError(LogMessage message) { + cancelWarningTask(); stop(); logger.error("Action " + message.getLocator() + " failed because of: " + message.formatMessage()); addMessage(message); @@ -91,6 +126,7 @@ public class SimpleExecution extends ExecutionPolicy { } protected void toWarning(LogMessage message) { + cancelWarningTask(); stop(); addMessage(message); getController().asyncToWarning(message.getLocator());