[New] Extended ExecutionHandler to be paused, persisted over reboots
This commit is contained in:
parent
d09fb9fa4b
commit
67d77bafea
|
@ -64,6 +64,7 @@ public class StrolchModelConstants {
|
||||||
public static final String BAG_PARAMETERS = "parameters";
|
public static final String BAG_PARAMETERS = "parameters";
|
||||||
public static final String TYPE_PARAMETERS = "Parameters";
|
public static final String TYPE_PARAMETERS = "Parameters";
|
||||||
public static final String TYPE_ENUMERATION = "Enumeration";
|
public static final String TYPE_ENUMERATION = "Enumeration";
|
||||||
|
public static final String TYPE_CONFIGURATION = "Configuration";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ID of the admin role which has access to all resources
|
* ID of the admin role which has access to all resources
|
||||||
|
|
|
@ -1,29 +1,31 @@
|
||||||
package li.strolch.rest.endpoint;
|
package li.strolch.rest.endpoint;
|
||||||
|
|
||||||
|
import static li.strolch.execution.ExecutionHandler.PARAM_STATE;
|
||||||
|
import static li.strolch.rest.StrolchRestfulConstants.STROLCH_CERTIFICATE;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.ws.rs.*;
|
import javax.ws.rs.*;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonArray;
|
||||||
import li.strolch.execution.ExecutionHandler;
|
import li.strolch.execution.ExecutionHandler;
|
||||||
|
import li.strolch.execution.ExecutionHandlerState;
|
||||||
import li.strolch.execution.service.*;
|
import li.strolch.execution.service.*;
|
||||||
import li.strolch.model.Locator;
|
import li.strolch.model.Locator;
|
||||||
import li.strolch.model.State;
|
|
||||||
import li.strolch.model.activity.Activity;
|
import li.strolch.model.activity.Activity;
|
||||||
import li.strolch.model.json.StrolchElementToJsonVisitor;
|
import li.strolch.model.json.StrolchElementToJsonVisitor;
|
||||||
import li.strolch.persistence.api.StrolchTransaction;
|
import li.strolch.persistence.api.StrolchTransaction;
|
||||||
import li.strolch.privilege.model.Certificate;
|
import li.strolch.privilege.model.Certificate;
|
||||||
import li.strolch.rest.RestfulStrolchComponent;
|
import li.strolch.rest.RestfulStrolchComponent;
|
||||||
import li.strolch.rest.StrolchRestfulConstants;
|
|
||||||
import li.strolch.rest.helper.ResponseUtil;
|
import li.strolch.rest.helper.ResponseUtil;
|
||||||
import li.strolch.service.LocatorArgument;
|
import li.strolch.service.LocatorArgument;
|
||||||
|
import li.strolch.service.StringMapArgument;
|
||||||
import li.strolch.service.api.ServiceArgument;
|
import li.strolch.service.api.ServiceArgument;
|
||||||
|
import li.strolch.service.api.ServiceHandler;
|
||||||
import li.strolch.service.api.ServiceResult;
|
import li.strolch.service.api.ServiceResult;
|
||||||
|
|
||||||
@Path("strolch/control")
|
@Path("strolch/control")
|
||||||
|
@ -42,26 +44,27 @@ public class ControlResource {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public Response getActivities(@Context HttpServletRequest request, @QueryParam("realm") String realm) {
|
public Response getActivities(@Context HttpServletRequest request, @QueryParam("realm") String realm) {
|
||||||
|
|
||||||
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
|
Certificate cert = (Certificate) request.getAttribute(STROLCH_CERTIFICATE);
|
||||||
|
|
||||||
StrolchElementToJsonVisitor visitor = new StrolchElementToJsonVisitor().withVersion().withLocator();
|
StrolchElementToJsonVisitor visitor = new StrolchElementToJsonVisitor().withVersion().withLocator();
|
||||||
|
|
||||||
List<JsonElement> activities;
|
|
||||||
try (StrolchTransaction tx = openTx(cert, realm)) {
|
try (StrolchTransaction tx = openTx(cert, realm)) {
|
||||||
activities = tx.getContainer().getComponent(ExecutionHandler.class).getActiveActivitiesLocator(realm)
|
ExecutionHandler executionHandler = tx.getContainer().getComponent(ExecutionHandler.class);
|
||||||
.stream().map(locator -> tx.getActivityBy(locator.get(1), locator.get(2))).filter(Objects::nonNull)
|
JsonArray activitiesJ = executionHandler.getActiveActivitiesLocator(realm).stream()
|
||||||
|
.map(locator -> tx.getActivityBy(locator.get(1), locator.get(2))).filter(Objects::nonNull)
|
||||||
.sorted(Comparator.comparing(Activity::getId)).map(activity -> activity.accept(visitor))
|
.sorted(Comparator.comparing(Activity::getId)).map(activity -> activity.accept(visitor))
|
||||||
.collect(Collectors.toList());
|
.collect(JsonArray::new, JsonArray::add, JsonArray::addAll);
|
||||||
}
|
|
||||||
|
|
||||||
return ResponseUtil.toResponse(activities);
|
ExecutionHandlerState state = executionHandler.getState(tx.getRealmName());
|
||||||
|
return ResponseUtil.toResponse(PARAM_STATE, state.name(), activitiesJ);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("all")
|
@Path("all")
|
||||||
public Response clearAllActivities(@Context HttpServletRequest request, @QueryParam("realm") String realm) {
|
public Response clearAllActivities(@Context HttpServletRequest request, @QueryParam("realm") String realm) {
|
||||||
|
|
||||||
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
|
Certificate cert = (Certificate) request.getAttribute(STROLCH_CERTIFICATE);
|
||||||
|
|
||||||
RestfulStrolchComponent instance = RestfulStrolchComponent.getInstance();
|
RestfulStrolchComponent instance = RestfulStrolchComponent.getInstance();
|
||||||
|
|
||||||
|
@ -79,7 +82,7 @@ public class ControlResource {
|
||||||
public Response executeActivity(@Context HttpServletRequest request, @QueryParam("realm") String realm,
|
public Response executeActivity(@Context HttpServletRequest request, @QueryParam("realm") String realm,
|
||||||
@QueryParam("locator") String locatorS, @QueryParam("state") String stateS) {
|
@QueryParam("locator") String locatorS, @QueryParam("state") String stateS) {
|
||||||
|
|
||||||
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
|
Certificate cert = (Certificate) request.getAttribute(STROLCH_CERTIFICATE);
|
||||||
|
|
||||||
Locator locator = Locator.valueOf(locatorS);
|
Locator locator = Locator.valueOf(locatorS);
|
||||||
|
|
||||||
|
@ -99,7 +102,7 @@ public class ControlResource {
|
||||||
public Response removeActivityFromExecution(@Context HttpServletRequest request, @QueryParam("realm") String realm,
|
public Response removeActivityFromExecution(@Context HttpServletRequest request, @QueryParam("realm") String realm,
|
||||||
@QueryParam("locator") String locatorS) {
|
@QueryParam("locator") String locatorS) {
|
||||||
|
|
||||||
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
|
Certificate cert = (Certificate) request.getAttribute(STROLCH_CERTIFICATE);
|
||||||
|
|
||||||
RestfulStrolchComponent instance = RestfulStrolchComponent.getInstance();
|
RestfulStrolchComponent instance = RestfulStrolchComponent.getInstance();
|
||||||
|
|
||||||
|
@ -115,151 +118,48 @@ public class ControlResource {
|
||||||
return ResponseUtil.toResponse(svcResult);
|
return ResponseUtil.toResponse(svcResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("executionHandler/state")
|
||||||
|
public Response getExecutionHandlerState(@Context HttpServletRequest request, @QueryParam("realm") String realm) {
|
||||||
|
|
||||||
|
ExecutionHandler executionHandler = RestfulStrolchComponent.getInstance().getComponent(ExecutionHandler.class);
|
||||||
|
String state = executionHandler.getState(realm).name();
|
||||||
|
|
||||||
|
return ResponseUtil.toResponse(PARAM_STATE, state);
|
||||||
|
}
|
||||||
|
|
||||||
@PUT
|
@PUT
|
||||||
@Path("state")
|
@Path("executionHandler/state")
|
||||||
|
public Response setExecutionHandlerState(@Context HttpServletRequest request, @QueryParam("realm") String realm,
|
||||||
|
@QueryParam("state") String stateS) {
|
||||||
|
|
||||||
|
Certificate cert = (Certificate) request.getAttribute(STROLCH_CERTIFICATE);
|
||||||
|
|
||||||
|
SetExecutionHandlerStateService svc = new SetExecutionHandlerStateService();
|
||||||
|
StringMapArgument arg = svc.getArgumentInstance();
|
||||||
|
arg.realm = realm;
|
||||||
|
arg.map.put("state", stateS);
|
||||||
|
|
||||||
|
ServiceHandler serviceHandler = RestfulStrolchComponent.getInstance().getServiceHandler();
|
||||||
|
ServiceResult svcResult = serviceHandler.doService(cert, svc, arg);
|
||||||
|
return ResponseUtil.toResponse(svcResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("activity/state")
|
||||||
public Response setElementState(@Context HttpServletRequest request, @QueryParam("realm") String realm,
|
public Response setElementState(@Context HttpServletRequest request, @QueryParam("realm") String realm,
|
||||||
@QueryParam("locator") String locatorS, @QueryParam("state") String stateS) {
|
@QueryParam("locator") String locatorS, @QueryParam("state") String stateS) {
|
||||||
|
|
||||||
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
|
Certificate cert = (Certificate) request.getAttribute(STROLCH_CERTIFICATE);
|
||||||
|
|
||||||
RestfulStrolchComponent instance = RestfulStrolchComponent.getInstance();
|
SetActionStateService svc = new SetActionStateService();
|
||||||
|
StringMapArgument arg = svc.getArgumentInstance();
|
||||||
if (stateS.equals("Trigger")) {
|
|
||||||
|
|
||||||
TriggerExecutionForRealmService svc = new TriggerExecutionForRealmService();
|
|
||||||
ServiceArgument arg = svc.getArgumentInstance();
|
|
||||||
arg.realm = realm;
|
arg.realm = realm;
|
||||||
|
arg.map.put("locator", locatorS);
|
||||||
|
arg.map.put("state", stateS);
|
||||||
|
|
||||||
ServiceResult svcResult = instance.getServiceHandler().doService(cert, svc, arg);
|
ServiceHandler serviceHandler = RestfulStrolchComponent.getInstance().getServiceHandler();
|
||||||
return ResponseUtil.toResponse(svcResult);
|
ServiceResult svcResult = serviceHandler.doService(cert, svc, arg);
|
||||||
|
|
||||||
} else if (stateS.equals("ReloadActivities")) {
|
|
||||||
|
|
||||||
ReloadActivitiesInExecutionService svc = new ReloadActivitiesInExecutionService();
|
|
||||||
ServiceArgument arg = svc.getArgumentInstance();
|
|
||||||
arg.realm = realm;
|
|
||||||
|
|
||||||
ServiceResult svcResult = instance.getServiceHandler().doService(cert, svc, arg);
|
|
||||||
return ResponseUtil.toResponse(svcResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
State state = State.parse(stateS);
|
|
||||||
Locator locator = Locator.valueOf(locatorS);
|
|
||||||
|
|
||||||
ServiceResult svcResult;
|
|
||||||
switch (state) {
|
|
||||||
case CREATED: {
|
|
||||||
|
|
||||||
SetActionToCreatedService svc = new SetActionToCreatedService();
|
|
||||||
LocatorArgument arg = svc.getArgumentInstance();
|
|
||||||
arg.realm = realm;
|
|
||||||
arg.locator = locator;
|
|
||||||
|
|
||||||
svcResult = instance.getServiceHandler().doService(cert, svc, arg);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PLANNING: {
|
|
||||||
|
|
||||||
SetActionToPlanningService svc = new SetActionToPlanningService();
|
|
||||||
LocatorArgument arg = svc.getArgumentInstance();
|
|
||||||
arg.realm = realm;
|
|
||||||
arg.locator = locator;
|
|
||||||
|
|
||||||
svcResult = instance.getServiceHandler().doService(cert, svc, arg);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PLANNED: {
|
|
||||||
|
|
||||||
SetActionToPlannedService svc = new SetActionToPlannedService();
|
|
||||||
LocatorArgument arg = svc.getArgumentInstance();
|
|
||||||
arg.realm = realm;
|
|
||||||
arg.locator = locator;
|
|
||||||
|
|
||||||
svcResult = instance.getServiceHandler().doService(cert, svc, arg);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case EXECUTION: {
|
|
||||||
|
|
||||||
SetToExecutionService svc = new SetToExecutionService();
|
|
||||||
LocatorArgument arg = svc.getArgumentInstance();
|
|
||||||
arg.realm = realm;
|
|
||||||
arg.locator = locator;
|
|
||||||
|
|
||||||
svcResult = instance.getServiceHandler().doService(cert, svc, arg);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WARNING: {
|
|
||||||
|
|
||||||
SetActionToWarningService svc = new SetActionToWarningService();
|
|
||||||
LocatorArgument arg = svc.getArgumentInstance();
|
|
||||||
arg.realm = realm;
|
|
||||||
arg.locator = locator;
|
|
||||||
|
|
||||||
svcResult = instance.getServiceHandler().doService(cert, svc, arg);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ERROR: {
|
|
||||||
|
|
||||||
SetActionToErrorService svc = new SetActionToErrorService();
|
|
||||||
LocatorArgument arg = svc.getArgumentInstance();
|
|
||||||
arg.realm = realm;
|
|
||||||
arg.locator = locator;
|
|
||||||
|
|
||||||
svcResult = instance.getServiceHandler().doService(cert, svc, arg);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case STOPPED: {
|
|
||||||
|
|
||||||
SetActionToStoppedService svc = new SetActionToStoppedService();
|
|
||||||
LocatorArgument arg = svc.getArgumentInstance();
|
|
||||||
arg.realm = realm;
|
|
||||||
arg.locator = locator;
|
|
||||||
|
|
||||||
svcResult = instance.getServiceHandler().doService(cert, svc, arg);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case EXECUTED: {
|
|
||||||
|
|
||||||
SetActionToExecutedService svc = new SetActionToExecutedService();
|
|
||||||
LocatorArgument arg = svc.getArgumentInstance();
|
|
||||||
arg.realm = realm;
|
|
||||||
arg.locator = locator;
|
|
||||||
|
|
||||||
svcResult = instance.getServiceHandler().doService(cert, svc, arg);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case CLOSED: {
|
|
||||||
|
|
||||||
SetActionToClosedService svc = new SetActionToClosedService();
|
|
||||||
LocatorArgument arg = svc.getArgumentInstance();
|
|
||||||
arg.realm = realm;
|
|
||||||
arg.locator = locator;
|
|
||||||
|
|
||||||
svcResult = instance.getServiceHandler().doService(cert, svc, arg);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException("Unhandled state " + state);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResponseUtil.toResponse(svcResult);
|
return ResponseUtil.toResponse(svcResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
package li.strolch.execution;
|
package li.strolch.execution;
|
||||||
|
|
||||||
|
import static li.strolch.model.StrolchModelConstants.*;
|
||||||
import static li.strolch.runtime.StrolchConstants.SYSTEM_USER_AGENT;
|
import static li.strolch.runtime.StrolchConstants.SYSTEM_USER_AGENT;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.ResourceBundle;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
import li.strolch.agent.api.ComponentContainer;
|
import li.strolch.agent.api.ComponentContainer;
|
||||||
|
@ -16,13 +14,17 @@ import li.strolch.handler.operationslog.LogMessage;
|
||||||
import li.strolch.handler.operationslog.LogSeverity;
|
import li.strolch.handler.operationslog.LogSeverity;
|
||||||
import li.strolch.handler.operationslog.OperationsLog;
|
import li.strolch.handler.operationslog.OperationsLog;
|
||||||
import li.strolch.model.Locator;
|
import li.strolch.model.Locator;
|
||||||
|
import li.strolch.model.ParameterBag;
|
||||||
|
import li.strolch.model.Resource;
|
||||||
import li.strolch.model.State;
|
import li.strolch.model.State;
|
||||||
import li.strolch.model.activity.Action;
|
import li.strolch.model.activity.Action;
|
||||||
import li.strolch.model.activity.Activity;
|
import li.strolch.model.activity.Activity;
|
||||||
import li.strolch.model.activity.IActivityElement;
|
import li.strolch.model.activity.IActivityElement;
|
||||||
|
import li.strolch.model.parameter.StringParameter;
|
||||||
import li.strolch.model.policy.PolicyDef;
|
import li.strolch.model.policy.PolicyDef;
|
||||||
import li.strolch.persistence.api.StrolchTransaction;
|
import li.strolch.persistence.api.StrolchTransaction;
|
||||||
import li.strolch.policy.PolicyHandler;
|
import li.strolch.policy.PolicyHandler;
|
||||||
|
import li.strolch.privilege.model.Certificate;
|
||||||
import li.strolch.privilege.model.PrivilegeContext;
|
import li.strolch.privilege.model.PrivilegeContext;
|
||||||
import li.strolch.runtime.configuration.ComponentConfiguration;
|
import li.strolch.runtime.configuration.ComponentConfiguration;
|
||||||
import li.strolch.utils.collections.MapOfSets;
|
import li.strolch.utils.collections.MapOfSets;
|
||||||
|
@ -39,6 +41,7 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
||||||
private static final String KEY_DEFAULT_ACTIVITY_ARCHIVAL = "key:DefaultActivityArchival";
|
private static final String KEY_DEFAULT_ACTIVITY_ARCHIVAL = "key:DefaultActivityArchival";
|
||||||
private static final String PROP_RESTART_EXECUTION = "restartExecution";
|
private static final String PROP_RESTART_EXECUTION = "restartExecution";
|
||||||
|
|
||||||
|
private Map<String, ExecutionHandlerState> statesByRealm;
|
||||||
private MapOfSets<String, Locator> registeredActivities;
|
private MapOfSets<String, Locator> registeredActivities;
|
||||||
|
|
||||||
private DelayedExecutionTimer delayedExecutionTimer;
|
private DelayedExecutionTimer delayedExecutionTimer;
|
||||||
|
@ -58,6 +61,8 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
||||||
@Override
|
@Override
|
||||||
public void start() throws Exception {
|
public void start() throws Exception {
|
||||||
|
|
||||||
|
evaluateStateByRealm();
|
||||||
|
|
||||||
this.delayedExecutionTimer = new SimpleDurationExecutionTimer(getContainer().getAgent());
|
this.delayedExecutionTimer = new SimpleDurationExecutionTimer(getContainer().getAgent());
|
||||||
|
|
||||||
// restart execution of activities already in execution
|
// restart execution of activities already in execution
|
||||||
|
@ -94,6 +99,12 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addForExecution(String realm, Locator activityLoc) {
|
public void addForExecution(String realm, Locator activityLoc) {
|
||||||
|
|
||||||
|
ExecutionHandlerState state = this.statesByRealm.getOrDefault(realm, ExecutionHandlerState.Running);
|
||||||
|
if (state == ExecutionHandlerState.HaltNew)
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"ExecutionHandler state is " + state + ", can not add activities for execution!");
|
||||||
|
|
||||||
Locator rootElemLoc = activityLoc.trim(3);
|
Locator rootElemLoc = activityLoc.trim(3);
|
||||||
synchronized (this.registeredActivities) {
|
synchronized (this.registeredActivities) {
|
||||||
this.registeredActivities.addElement(realm, rootElemLoc);
|
this.registeredActivities.addElement(realm, rootElemLoc);
|
||||||
|
@ -163,6 +174,13 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void triggerExecution(String realm) {
|
public void triggerExecution(String realm) {
|
||||||
|
|
||||||
|
ExecutionHandlerState state = this.statesByRealm.getOrDefault(realm, ExecutionHandlerState.Running);
|
||||||
|
if (state == ExecutionHandlerState.Paused) {
|
||||||
|
logger.warn("Ignoring trigger for paused realm " + realm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
synchronized (this.registeredActivities) {
|
synchronized (this.registeredActivities) {
|
||||||
Set<Locator> locators = this.registeredActivities.getSet(realm);
|
Set<Locator> locators = this.registeredActivities.getSet(realm);
|
||||||
if (locators != null) {
|
if (locators != null) {
|
||||||
|
@ -174,8 +192,86 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExecutionHandlerState getState(String realm) {
|
||||||
|
return this.statesByRealm.getOrDefault(realm, ExecutionHandlerState.Running);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void evaluateStateByRealm() throws Exception {
|
||||||
|
|
||||||
|
this.statesByRealm = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
|
||||||
|
runAsAgent(ctx -> getContainer().getRealmNames().forEach(realm -> {
|
||||||
|
try (StrolchTransaction tx = openTx(realm, ctx.getCertificate(), false)) {
|
||||||
|
Resource executionHandlerConfig = tx
|
||||||
|
.getResourceBy(TYPE_CONFIGURATION, ExecutionHandler.class.getSimpleName());
|
||||||
|
if (executionHandlerConfig == null) {
|
||||||
|
this.statesByRealm.put(realm, ExecutionHandlerState.Running);
|
||||||
|
} else {
|
||||||
|
ParameterBag parameters = executionHandlerConfig.getParameterBag(BAG_PARAMETERS);
|
||||||
|
if (parameters == null) {
|
||||||
|
this.statesByRealm.put(realm, ExecutionHandlerState.Running);
|
||||||
|
} else {
|
||||||
|
StringParameter stateP = parameters.getParameter(PARAM_STATE);
|
||||||
|
if (stateP == null) {
|
||||||
|
this.statesByRealm.put(realm, ExecutionHandlerState.Running);
|
||||||
|
} else {
|
||||||
|
ExecutionHandlerState state;
|
||||||
|
try {
|
||||||
|
state = ExecutionHandlerState.valueOf(stateP.getValue());
|
||||||
|
} catch (Exception e) {
|
||||||
|
state = ExecutionHandlerState.Running;
|
||||||
|
stateP.setValue(ExecutionHandlerState.Running.name());
|
||||||
|
tx.update(executionHandlerConfig);
|
||||||
|
tx.commitOnClose();
|
||||||
|
logger.error("Failed to read unhandled state " + stateP.getValue(), e);
|
||||||
|
}
|
||||||
|
this.statesByRealm.put(realm, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setState(Certificate cert, String realm, ExecutionHandlerState state) {
|
||||||
|
try (StrolchTransaction tx = openTx(realm, cert, false)) {
|
||||||
|
Resource executionHandlerConfig = tx
|
||||||
|
.getResourceBy(TYPE_CONFIGURATION, ExecutionHandler.class.getSimpleName());
|
||||||
|
if (executionHandlerConfig == null) {
|
||||||
|
executionHandlerConfig = new Resource(ExecutionHandler.class.getSimpleName(),
|
||||||
|
"ExecutionHandler Configuration", TYPE_CONFIGURATION);
|
||||||
|
}
|
||||||
|
ParameterBag parameters = executionHandlerConfig.getParameterBag(BAG_PARAMETERS);
|
||||||
|
if (parameters == null) {
|
||||||
|
parameters = new ParameterBag(BAG_PARAMETERS, "Parameters", TYPE_PARAMETERS);
|
||||||
|
executionHandlerConfig.addParameterBag(parameters);
|
||||||
|
}
|
||||||
|
StringParameter stateP = parameters.getParameter(PARAM_STATE);
|
||||||
|
if (stateP == null) {
|
||||||
|
stateP = new StringParameter(PARAM_STATE, "State", state);
|
||||||
|
parameters.addParameter(stateP);
|
||||||
|
}
|
||||||
|
|
||||||
|
stateP.setValueE(state);
|
||||||
|
|
||||||
|
tx.addOrUpdate(executionHandlerConfig);
|
||||||
|
tx.commitOnClose();
|
||||||
|
|
||||||
|
this.statesByRealm.put(realm, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void toExecution(String realm, Locator locator) {
|
public void toExecution(String realm, Locator locator) {
|
||||||
|
|
||||||
|
ExecutionHandlerState state = this.statesByRealm.getOrDefault(realm, ExecutionHandlerState.Running);
|
||||||
|
if (state == ExecutionHandlerState.Paused) {
|
||||||
|
logger.warn("Ignoring execution of " + locator + " for paused realm " + realm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
getExecutor().execute(() -> {
|
getExecutor().execute(() -> {
|
||||||
try {
|
try {
|
||||||
runAsAgent(ctx -> {
|
runAsAgent(ctx -> {
|
||||||
|
@ -390,6 +486,11 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
||||||
logger.info("Archiving activity " + activityLoc + " with state " + activity.getState());
|
logger.info("Archiving activity " + activityLoc + " with state " + activity.getState());
|
||||||
archiveActivity(realm, activity.getLocator());
|
archiveActivity(realm, activity.getLocator());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
ExecutionHandlerState state = this.statesByRealm.getOrDefault(realm, ExecutionHandlerState.Running);
|
||||||
|
if (state == ExecutionHandlerState.Paused) {
|
||||||
|
logger.warn("Ignoring trigger for paused realm " + realm);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// otherwise execute any next action(s) for this action's activity
|
// otherwise execute any next action(s) for this action's activity
|
||||||
|
@ -402,6 +503,7 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
||||||
// flush so we can see the changes performed
|
// flush so we can see the changes performed
|
||||||
tx.flush();
|
tx.flush();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tx.commitOnClose();
|
tx.commitOnClose();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import li.strolch.model.State;
|
||||||
import li.strolch.model.activity.Action;
|
import li.strolch.model.activity.Action;
|
||||||
import li.strolch.model.activity.Activity;
|
import li.strolch.model.activity.Activity;
|
||||||
import li.strolch.model.activity.TimeOrdering;
|
import li.strolch.model.activity.TimeOrdering;
|
||||||
|
import li.strolch.privilege.model.Certificate;
|
||||||
import li.strolch.privilege.model.PrivilegeContext;
|
import li.strolch.privilege.model.PrivilegeContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,6 +38,8 @@ public abstract class ExecutionHandler extends StrolchComponent {
|
||||||
super(container, componentName);
|
super(container, componentName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final String PARAM_STATE = "state";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers the given {@link Locator} of an {@link Activity} for execution, and submits it for execution
|
* Registers the given {@link Locator} of an {@link Activity} for execution, and submits it for execution
|
||||||
* immediately in an asynchronous manner
|
* immediately in an asynchronous manner
|
||||||
|
@ -84,6 +87,28 @@ public abstract class ExecutionHandler extends StrolchComponent {
|
||||||
*/
|
*/
|
||||||
public abstract void triggerExecution(String realm);
|
public abstract void triggerExecution(String realm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the sate of the execution handler
|
||||||
|
*
|
||||||
|
* @param realm
|
||||||
|
* the realm for which to get the state
|
||||||
|
*
|
||||||
|
* @return the state of the execution handler
|
||||||
|
*/
|
||||||
|
public abstract ExecutionHandlerState getState(String realm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the state for the given realm
|
||||||
|
*
|
||||||
|
* @param cert
|
||||||
|
* certificate to use
|
||||||
|
* @param realm
|
||||||
|
* the realm to halt execution for
|
||||||
|
* @param state
|
||||||
|
* the state to set
|
||||||
|
*/
|
||||||
|
public abstract void setState(Certificate cert, String realm, ExecutionHandlerState state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Archives the given {@link Activity}
|
* Archives the given {@link Activity}
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package li.strolch.execution;
|
||||||
|
|
||||||
|
public enum ExecutionHandlerState {
|
||||||
|
Running,
|
||||||
|
HaltNew,
|
||||||
|
Paused;
|
||||||
|
}
|
|
@ -0,0 +1,139 @@
|
||||||
|
package li.strolch.execution.service;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
|
import li.strolch.exception.StrolchException;
|
||||||
|
import li.strolch.execution.ExecutionHandler;
|
||||||
|
import li.strolch.execution.command.*;
|
||||||
|
import li.strolch.model.Locator;
|
||||||
|
import li.strolch.model.State;
|
||||||
|
import li.strolch.model.activity.Action;
|
||||||
|
import li.strolch.model.activity.IActivityElement;
|
||||||
|
import li.strolch.persistence.api.StrolchTransaction;
|
||||||
|
import li.strolch.service.StringMapArgument;
|
||||||
|
import li.strolch.service.api.AbstractService;
|
||||||
|
import li.strolch.service.api.ServiceResult;
|
||||||
|
import li.strolch.service.api.ServiceResultState;
|
||||||
|
|
||||||
|
public class SetActionStateService extends AbstractService<StringMapArgument, ServiceResult> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ServiceResult getResultInstance() {
|
||||||
|
return new ServiceResult(ServiceResultState.FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringMapArgument getArgumentInstance() {
|
||||||
|
return new StringMapArgument();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ServiceResult internalDoService(StringMapArgument arg) throws Exception {
|
||||||
|
|
||||||
|
State state = State.parse(arg.map.get("state"));
|
||||||
|
Locator locator = Locator.valueOf(arg.map.get("locator"));
|
||||||
|
|
||||||
|
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
|
||||||
|
|
||||||
|
Action action = tx.findElement(locator);
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case CREATED: {
|
||||||
|
|
||||||
|
SetActionToCreatedCommand command = new SetActionToCreatedCommand(getContainer(), tx);
|
||||||
|
command.setAction(action);
|
||||||
|
tx.addCommand(command);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PLANNING: {
|
||||||
|
|
||||||
|
SetActionToPlanningCommand command = new SetActionToPlanningCommand(getContainer(), tx);
|
||||||
|
command.setAction(action);
|
||||||
|
tx.addCommand(command);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PLANNED: {
|
||||||
|
|
||||||
|
SetActionToPlannedCommand command = new SetActionToPlannedCommand(getContainer(), tx);
|
||||||
|
command.setAction(action);
|
||||||
|
tx.addCommand(command);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EXECUTION: {
|
||||||
|
|
||||||
|
tx.lock(locator);
|
||||||
|
|
||||||
|
IActivityElement element = tx.findElement(locator);
|
||||||
|
if (!element.getState().canSetToExecution()) {
|
||||||
|
String msg = "Current state is {0} and can not be changed to {1} for action {2}";
|
||||||
|
msg = MessageFormat.format(msg, element.getState(), State.EXECUTION, element.getLocator());
|
||||||
|
throw new StrolchException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecutionHandler executionHandler = getContainer().getComponent(ExecutionHandler.class);
|
||||||
|
executionHandler.toExecution(tx.getRealmName(), locator);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WARNING: {
|
||||||
|
|
||||||
|
SetActionToWarningCommand command = new SetActionToWarningCommand(getContainer(), tx);
|
||||||
|
command.setAction(action);
|
||||||
|
tx.addCommand(command);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ERROR: {
|
||||||
|
|
||||||
|
SetActionToErrorCommand command = new SetActionToErrorCommand(getContainer(), tx);
|
||||||
|
command.setAction(action);
|
||||||
|
tx.addCommand(command);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case STOPPED: {
|
||||||
|
|
||||||
|
SetActionToStoppedCommand command = new SetActionToStoppedCommand(getContainer(), tx);
|
||||||
|
command.setAction(action);
|
||||||
|
tx.addCommand(command);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EXECUTED: {
|
||||||
|
|
||||||
|
SetActionToExecutedCommand command = new SetActionToExecutedCommand(getContainer(), tx);
|
||||||
|
command.setAction(action);
|
||||||
|
tx.addCommand(command);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CLOSED: {
|
||||||
|
|
||||||
|
SetActionToClosedCommand command = new SetActionToClosedCommand(getContainer(), tx);
|
||||||
|
command.setAction(action);
|
||||||
|
tx.addCommand(command);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("Unhandled state " + state);
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.commitOnClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ServiceResult.success();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package li.strolch.execution.service;
|
||||||
|
|
||||||
|
import li.strolch.execution.ExecutionHandler;
|
||||||
|
import li.strolch.execution.ExecutionHandlerState;
|
||||||
|
import li.strolch.runtime.StrolchConstants;
|
||||||
|
import li.strolch.service.StringMapArgument;
|
||||||
|
import li.strolch.service.api.AbstractService;
|
||||||
|
import li.strolch.service.api.ServiceResult;
|
||||||
|
import li.strolch.service.api.ServiceResultState;
|
||||||
|
import li.strolch.utils.helper.StringHelper;
|
||||||
|
|
||||||
|
public class SetExecutionHandlerStateService extends AbstractService<StringMapArgument, ServiceResult> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ServiceResult getResultInstance() {
|
||||||
|
return new ServiceResult(ServiceResultState.FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringMapArgument getArgumentInstance() {
|
||||||
|
return new StringMapArgument();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ServiceResult internalDoService(StringMapArgument arg) throws Exception {
|
||||||
|
|
||||||
|
String realm = StringHelper.isEmpty(arg.realm) ? StrolchConstants.DEFAULT_REALM : arg.realm;
|
||||||
|
String state = arg.map.get("state");
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case "Running": {
|
||||||
|
|
||||||
|
ExecutionHandler executionHandler = getContainer().getComponent(ExecutionHandler.class);
|
||||||
|
executionHandler.setState(getCertificate(), realm, ExecutionHandlerState.Running);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "HaltNew": {
|
||||||
|
|
||||||
|
ExecutionHandler executionHandler = getContainer().getComponent(ExecutionHandler.class);
|
||||||
|
executionHandler.setState(getCertificate(), realm, ExecutionHandlerState.HaltNew);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "Paused": {
|
||||||
|
|
||||||
|
ExecutionHandler executionHandler = getContainer().getComponent(ExecutionHandler.class);
|
||||||
|
executionHandler.setState(getCertificate(), realm, ExecutionHandlerState.Paused);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "Trigger": {
|
||||||
|
|
||||||
|
ExecutionHandler executionHandler = getContainer().getComponent(ExecutionHandler.class);
|
||||||
|
executionHandler.triggerExecution(realm);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "ReloadActivities": {
|
||||||
|
|
||||||
|
ExecutionHandler executionHandler = getContainer().getComponent(ExecutionHandler.class);
|
||||||
|
executionHandler.reloadActivitiesInExecution(getPrivilegeContext(), realm);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("Unhandled state " + state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ServiceResult.success();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,12 @@
|
||||||
package li.strolch.execution.service;
|
package li.strolch.execution.service;
|
||||||
|
|
||||||
|
import static li.strolch.service.I18nServiceBundle.i18nServiceBundle;
|
||||||
|
|
||||||
import li.strolch.execution.ExecutionHandler;
|
import li.strolch.execution.ExecutionHandler;
|
||||||
|
import li.strolch.execution.ExecutionHandlerState;
|
||||||
import li.strolch.runtime.StrolchConstants;
|
import li.strolch.runtime.StrolchConstants;
|
||||||
import li.strolch.service.LocatorArgument;
|
import li.strolch.service.LocatorArgument;
|
||||||
|
import li.strolch.service.StrolchRootElementResult;
|
||||||
import li.strolch.service.api.AbstractService;
|
import li.strolch.service.api.AbstractService;
|
||||||
import li.strolch.service.api.ServiceResult;
|
import li.strolch.service.api.ServiceResult;
|
||||||
import li.strolch.service.api.ServiceResultState;
|
import li.strolch.service.api.ServiceResultState;
|
||||||
|
@ -26,6 +30,12 @@ public class StartActivityExecutionService extends AbstractService<LocatorArgume
|
||||||
String realm = StringHelper.isEmpty(arg.realm) ? StrolchConstants.DEFAULT_REALM : arg.realm;
|
String realm = StringHelper.isEmpty(arg.realm) ? StrolchConstants.DEFAULT_REALM : arg.realm;
|
||||||
|
|
||||||
ExecutionHandler executionHandler = getContainer().getComponent(ExecutionHandler.class);
|
ExecutionHandler executionHandler = getContainer().getComponent(ExecutionHandler.class);
|
||||||
|
ExecutionHandlerState executionHandlerState = executionHandler.getState(getRealmName());
|
||||||
|
if (executionHandlerState != ExecutionHandlerState.Running)
|
||||||
|
return new StrolchRootElementResult(ServiceResultState.WARNING,
|
||||||
|
"ExecutionHandler is not running, can not start new jobs!")
|
||||||
|
.i18n(i18nServiceBundle, "execution.handler.invalidState", "state", executionHandlerState);
|
||||||
|
|
||||||
executionHandler.addForExecution(realm, arg.locator);
|
executionHandler.addForExecution(realm, arg.locator);
|
||||||
|
|
||||||
return ServiceResult.success();
|
return ServiceResult.success();
|
||||||
|
|
Loading…
Reference in New Issue