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 fa36313d8..3e44fbc27 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,13 +1,43 @@ package li.strolch.execution; import li.strolch.agent.api.ComponentContainer; +import li.strolch.execution.policy.ExecutionPolicy; import li.strolch.model.Locator; +import li.strolch.model.activity.Action; +/** + * A decoupling of {@link ExecutionPolicy ExecutionPolicies} so that the execution can be performed after a certain + * period. The {@link #execute(String, ComponentContainer, Locator, long)} will complete the execution of this task + * after the given duration + * + * @author Robert von Burg + */ public interface DelayedExecutionTimer { + /** + * Completes the execution of the given {@link Action} {@link Locator} after the given duration in milliseconds + * + * @param realm + * the realm from which to retrieve the {@link Action} + * @param container + * reference to the container + * @param actionLocator + * the {@link Action}'s {@link Locator} + * @param duration + * the duration in milliseconds before calling the {@link ExecutionPolicy#toExecuted(Action)} + */ + void execute(String realm, ComponentContainer container, Locator actionLocator, long duration); + + /** + * Cancels any delayed execution for the given {@link Locator} + * + * @param actionLocator + * the {@link Action}'s {@link Locator} + */ void cancel(Locator locator); - void execute(String realm, ComponentContainer container, Locator locator, long duration); - + /** + * Destroys this timer by canceling on tasks and stopping the timer + */ void destroy(); } \ No newline at end of file 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 6f2cab8e1..1c9cea1f1 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 @@ -17,10 +17,10 @@ public class SimpleDurationExecutionTimer implements DelayedExecutionTimer { private Timer timer; - private Map simulationPolicies; + private Map simulationTasks; public SimpleDurationExecutionTimer() { - this.simulationPolicies = new HashMap<>(); + this.simulationTasks = new HashMap<>(); } @Override @@ -32,22 +32,22 @@ public class SimpleDurationExecutionTimer implements DelayedExecutionTimer { @Override public void cancel(Locator locator) { - SimulationTask task = this.simulationPolicies.remove(locator); + SimulationTask task = this.simulationTasks.remove(locator); if (task != null) { task.cancel(); } } @Override - public void execute(String realm, ComponentContainer container, Locator locator, long duration) { + public void execute(String realm, ComponentContainer container, Locator actionLocator, long duration) { if (this.timer == null) this.timer = new Timer("SimulationExecution", true); - SimulationTask task = new SimulationTask(realm, container, locator); - this.simulationPolicies.put(locator, task); + SimulationTask task = new SimulationTask(realm, container, actionLocator); + this.simulationTasks.put(actionLocator, task); this.timer.schedule(task, duration); - logger.info("Registered execution timer for " + locator); + logger.info("Registered execution timer for " + actionLocator); } private void executed(String realm, ComponentContainer container, Locator locator) { 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 4f4f0cd5c..03df98141 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 @@ -1,28 +1,101 @@ package li.strolch.execution.policy; import li.strolch.agent.api.ComponentContainer; +import li.strolch.agent.api.StrolchRealm; import li.strolch.command.UpdateActivityCommand; +import li.strolch.exception.StrolchException; import li.strolch.execution.DelayedExecutionTimer; import li.strolch.execution.ExecutionHandler; import li.strolch.model.State; import li.strolch.model.activity.Action; +import li.strolch.model.activity.Activity; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.policy.StrolchPolicy; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeContext; +import li.strolch.runtime.StrolchConstants; +import li.strolch.runtime.privilege.PrivilegedRunnable; +/** + *

+ * The {@link ExecutionPolicy} is used to execute {@link Activity Activities} and {@link Action Actions}. Execution is + * performed by calling {@link #toExecution(Action)} and the execution policy then implements some logic to change the + * state to {@link State#EXECUTION}. Here often communication with an external system is performed. + *

+ * + *

+ * Note that the public methods on this interface are always called from a instance of the concrete class, thus any + * instance fields are not kept from previous invocations + *

+ * + * @author Robert von Burg + */ public abstract class ExecutionPolicy extends StrolchPolicy { + /** + * The TX for this execution policy. The TX needs to be updated when this execution policy has a longer life time + * than the actual TX + */ + private StrolchTransaction tx; + public ExecutionPolicy(ComponentContainer container, StrolchTransaction tx) { super(container, tx); + this.tx = tx; } + /** + * Returns the TX which is defined on this class, not the one defined on {@link StrolchPolicy} + */ + @Override + protected StrolchTransaction tx() { + if (!this.tx.isOpen() && !this.tx.isCommitting()) + throw new IllegalStateException( + "The TX is in state " + this.tx.getState() + " and can not be used anymore!"); + return this.tx; + } + + /** + * Starts the execution of the given {@link Action}, i.e. sets the state to {@link State#EXECUTION} + * + * @param action + * the action to start execution for + */ public abstract void toExecution(Action action); + /** + * Completes execution of the given {@link Action}, i.e. sets the state to {@link State#EXECUTED} + * + * @param action + * the action to set to executed + */ 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} + * + * @param action + * the action to stop execution for + */ 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} + * + * @param action + * the action to set to error state + */ 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} + * + * @param action + * the action to set to warning state + */ public void toWarning(Action action) { action.setState(State.WARNING); @@ -34,7 +107,54 @@ public abstract class ExecutionPolicy extends StrolchPolicy { logger.warn("Action " + action.getLocator() + " is now in WARNING!"); } + /** + * @return the {@link DelayedExecutionTimer} to simplify the delayed execution of an {@link Action}, e.g. for + * simulated execution or simple wait tasks + */ protected DelayedExecutionTimer getDelayedExecutionTimer() { return getComponent(ExecutionHandler.class).getDelayedExecutionTimer(); } + + /** + * Returns the execution handler instance + * + * @return the {@link ExecutionHandler} instance + */ + protected ExecutionHandler getExecutionHandler() { + return getComponent(ExecutionHandler.class); + } + + /** + * 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 action + * the action to use for the opened TX + * + * @return the open {@link StrolchTransaction} + * + * @throws StrolchException + * if the {@link StrolchRealm} does not exist with the given name + */ + protected StrolchTransaction openTx(PrivilegeContext ctx) throws StrolchException { + if (this.tx.isOpen()) + throw new IllegalStateException("The current TX is still open, so can't open another one!"); + + this.tx = getContainer().getRealm(ctx.getCertificate()).openTx(ctx.getCertificate(), getClass()); + return this.tx; + } + + /** + * Performs the given {@link PrivilegedRunnable} as the system user {@link StrolchConstants#SYSTEM_USER_EXECUTION} + * + * @param runnable + * the runnable to perform + * + * @throws PrivilegeException + */ + protected void runAsAgent(PrivilegedRunnable runnable) throws PrivilegeException { + getContainer().getPrivilegeHandler().runAs(StrolchConstants.SYSTEM_USER_AGENT, runnable); + } + }