[New] Extended ExecutionHandler to be paused, persisted over reboots

This commit is contained in:
Robert von Burg 2019-08-27 08:35:18 +02:00
parent d09fb9fa4b
commit 67d77bafea
8 changed files with 422 additions and 165 deletions

View File

@ -64,6 +64,7 @@ public class StrolchModelConstants {
public static final String BAG_PARAMETERS = "parameters";
public static final String TYPE_PARAMETERS = "Parameters";
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

View File

@ -1,29 +1,31 @@
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.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.Comparator;
import java.util.List;
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.ExecutionHandlerState;
import li.strolch.execution.service.*;
import li.strolch.model.Locator;
import li.strolch.model.State;
import li.strolch.model.activity.Activity;
import li.strolch.model.json.StrolchElementToJsonVisitor;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.privilege.model.Certificate;
import li.strolch.rest.RestfulStrolchComponent;
import li.strolch.rest.StrolchRestfulConstants;
import li.strolch.rest.helper.ResponseUtil;
import li.strolch.service.LocatorArgument;
import li.strolch.service.StringMapArgument;
import li.strolch.service.api.ServiceArgument;
import li.strolch.service.api.ServiceHandler;
import li.strolch.service.api.ServiceResult;
@Path("strolch/control")
@ -42,26 +44,27 @@ public class ControlResource {
@Produces(MediaType.APPLICATION_JSON)
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();
List<JsonElement> activities;
try (StrolchTransaction tx = openTx(cert, realm)) {
activities = tx.getContainer().getComponent(ExecutionHandler.class).getActiveActivitiesLocator(realm)
.stream().map(locator -> tx.getActivityBy(locator.get(1), locator.get(2))).filter(Objects::nonNull)
ExecutionHandler executionHandler = tx.getContainer().getComponent(ExecutionHandler.class);
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))
.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
@Path("all")
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();
@ -79,7 +82,7 @@ public class ControlResource {
public Response executeActivity(@Context HttpServletRequest request, @QueryParam("realm") String realm,
@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);
@ -99,7 +102,7 @@ public class ControlResource {
public Response removeActivityFromExecution(@Context HttpServletRequest request, @QueryParam("realm") String realm,
@QueryParam("locator") String locatorS) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
Certificate cert = (Certificate) request.getAttribute(STROLCH_CERTIFICATE);
RestfulStrolchComponent instance = RestfulStrolchComponent.getInstance();
@ -115,151 +118,48 @@ public class ControlResource {
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
@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,
@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();
if (stateS.equals("Trigger")) {
TriggerExecutionForRealmService svc = new TriggerExecutionForRealmService();
ServiceArgument arg = svc.getArgumentInstance();
arg.realm = realm;
ServiceResult svcResult = instance.getServiceHandler().doService(cert, svc, arg);
return ResponseUtil.toResponse(svcResult);
} 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);
}
SetActionStateService svc = new SetActionStateService();
StringMapArgument arg = svc.getArgumentInstance();
arg.realm = realm;
arg.map.put("locator", locatorS);
arg.map.put("state", stateS);
ServiceHandler serviceHandler = RestfulStrolchComponent.getInstance().getServiceHandler();
ServiceResult svcResult = serviceHandler.doService(cert, svc, arg);
return ResponseUtil.toResponse(svcResult);
}
}

View File

@ -1,11 +1,9 @@
package li.strolch.execution;
import static li.strolch.model.StrolchModelConstants.*;
import static li.strolch.runtime.StrolchConstants.SYSTEM_USER_AGENT;
import java.util.Collections;
import java.util.HashSet;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.*;
import java.util.concurrent.ExecutorService;
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.OperationsLog;
import li.strolch.model.Locator;
import li.strolch.model.ParameterBag;
import li.strolch.model.Resource;
import li.strolch.model.State;
import li.strolch.model.activity.Action;
import li.strolch.model.activity.Activity;
import li.strolch.model.activity.IActivityElement;
import li.strolch.model.parameter.StringParameter;
import li.strolch.model.policy.PolicyDef;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.policy.PolicyHandler;
import li.strolch.privilege.model.Certificate;
import li.strolch.privilege.model.PrivilegeContext;
import li.strolch.runtime.configuration.ComponentConfiguration;
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 PROP_RESTART_EXECUTION = "restartExecution";
private Map<String, ExecutionHandlerState> statesByRealm;
private MapOfSets<String, Locator> registeredActivities;
private DelayedExecutionTimer delayedExecutionTimer;
@ -58,6 +61,8 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
@Override
public void start() throws Exception {
evaluateStateByRealm();
this.delayedExecutionTimer = new SimpleDurationExecutionTimer(getContainer().getAgent());
// restart execution of activities already in execution
@ -94,6 +99,12 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
@Override
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);
synchronized (this.registeredActivities) {
this.registeredActivities.addElement(realm, rootElemLoc);
@ -163,6 +174,13 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
@Override
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) {
Set<Locator> locators = this.registeredActivities.getSet(realm);
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
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(() -> {
try {
runAsAgent(ctx -> {
@ -392,15 +488,21 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
} else {
// otherwise execute any next action(s) for this action's activity
ExecutionHandlerState state = this.statesByRealm.getOrDefault(realm, ExecutionHandlerState.Running);
if (state == ExecutionHandlerState.Paused) {
logger.warn("Ignoring trigger for paused realm " + realm);
} else {
ExecuteActivityCommand execCommand = new ExecuteActivityCommand(getContainer(), tx);
execCommand.setActivity(activity);
execCommand.validate();
execCommand.doCommand();
// otherwise execute any next action(s) for this action's activity
// flush so we can see the changes performed
tx.flush();
ExecuteActivityCommand execCommand = new ExecuteActivityCommand(getContainer(), tx);
execCommand.setActivity(activity);
execCommand.validate();
execCommand.doCommand();
// flush so we can see the changes performed
tx.flush();
}
}
tx.commitOnClose();

View File

@ -11,6 +11,7 @@ import li.strolch.model.State;
import li.strolch.model.activity.Action;
import li.strolch.model.activity.Activity;
import li.strolch.model.activity.TimeOrdering;
import li.strolch.privilege.model.Certificate;
import li.strolch.privilege.model.PrivilegeContext;
/**
@ -37,6 +38,8 @@ public abstract class ExecutionHandler extends StrolchComponent {
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
* immediately in an asynchronous manner
@ -84,6 +87,28 @@ public abstract class ExecutionHandler extends StrolchComponent {
*/
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}
*

View File

@ -0,0 +1,7 @@
package li.strolch.execution;
public enum ExecutionHandlerState {
Running,
HaltNew,
Paused;
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -1,8 +1,12 @@
package li.strolch.execution.service;
import static li.strolch.service.I18nServiceBundle.i18nServiceBundle;
import li.strolch.execution.ExecutionHandler;
import li.strolch.execution.ExecutionHandlerState;
import li.strolch.runtime.StrolchConstants;
import li.strolch.service.LocatorArgument;
import li.strolch.service.StrolchRootElementResult;
import li.strolch.service.api.AbstractService;
import li.strolch.service.api.ServiceResult;
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;
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);
return ServiceResult.success();