Merge branch 'feature/planning' into develop

This commit is contained in:
Robert von Burg 2020-02-18 18:12:10 +01:00
commit c312f4b5b0
94 changed files with 1599 additions and 1307 deletions

View File

@ -425,7 +425,7 @@ public class StrolchComponent {
* @return the newly created transaction
*/
protected StrolchTransaction openTx(Certificate cert, boolean readOnly) {
return getContainer().getRealm(cert).openTx(cert, this.getClass(), readOnly);
return getContainer().getRealm(cert).openTx(cert, getClass(), readOnly);
}
/**
@ -457,7 +457,7 @@ public class StrolchComponent {
* @return the newly created transaction
*/
protected StrolchTransaction openTx(String realm, Certificate cert, boolean readOnly) {
return getContainer().getRealm(realm).openTx(cert, this.getClass(), readOnly);
return getContainer().getRealm(realm).openTx(cert, getClass(), readOnly);
}
/**

View File

@ -319,6 +319,10 @@ public abstract class AbstractTransaction implements StrolchTransaction {
@Override
public void addCommand(Command command) {
add(command);
}
public void add(Command command) {
assertNotReadOnly();
this.commands.add(command);
}
@ -416,13 +420,14 @@ public abstract class AbstractTransaction implements StrolchTransaction {
}
@Override
public <T extends StrolchElement> T findElement(Locator locator) throws StrolchException, ClassCastException {
public <T extends StrolchElement> T findElement(Locator locator) throws StrolchModelException, ClassCastException {
return findElement(locator, false);
}
@SuppressWarnings("unchecked")
@Override
public <T extends StrolchElement> T findElement(Locator locator, boolean allowNull) {
public <T extends StrolchElement> T findElement(Locator locator, boolean allowNull)
throws StrolchModelException, ClassCastException {
// Resource/<type>/<id>
// Resource/<type>/<id>/Bag/<id>
@ -435,7 +440,7 @@ public abstract class AbstractTransaction implements StrolchTransaction {
if (locator.getSize() < 3) {
String msg = "The locator is invalid as it does not have at least three path elements (e.g. Resource/MyType/@id): {0}"; //$NON-NLS-1$
msg = MessageFormat.format(msg, locator.toString());
throw new StrolchException(msg);
throw new StrolchModelException(msg);
}
List<String> elements = locator.getPathElements();
@ -454,14 +459,15 @@ public abstract class AbstractTransaction implements StrolchTransaction {
groupedParameterizedElement = getActivityBy(type, id);
break;
default:
throw new StrolchException(MessageFormat.format("Unknown object class {0}", objectClassType)); //$NON-NLS-1$
throw new StrolchModelException(
MessageFormat.format("Unknown object class {0}", objectClassType)); //$NON-NLS-1$
}
if (groupedParameterizedElement == null) {
if (allowNull)
return null;
String msg = "No top level object could be found with locator {0}"; //$NON-NLS-1$
throw new StrolchException(MessageFormat.format(msg, locator));
throw new StrolchModelException(MessageFormat.format(msg, locator));
}
if (elements.size() == 3)
@ -477,7 +483,7 @@ public abstract class AbstractTransaction implements StrolchTransaction {
if (allowNull)
return null;
String msg = "Could not find ParameterBag for locator {0} on element {1}"; //$NON-NLS-1$
throw new StrolchException(
throw new StrolchModelException(
MessageFormat.format(msg, locator, groupedParameterizedElement.getLocator()));
}
@ -490,7 +496,7 @@ public abstract class AbstractTransaction implements StrolchTransaction {
if (allowNull)
return null;
String msg = "Could not find Parameter for locator {0} on element {1}"; //$NON-NLS-1$
throw new StrolchException(MessageFormat.format(msg, locator, bag.getLocator()));
throw new StrolchModelException(MessageFormat.format(msg, locator, bag.getLocator()));
}
return (T) parameter;
@ -498,9 +504,10 @@ public abstract class AbstractTransaction implements StrolchTransaction {
if (elements.size() != 5) {
String msg = "Missing state Id on locator {0}"; //$NON-NLS-1$
throw new StrolchException(MessageFormat.format(msg, locator));
throw new StrolchModelException(MessageFormat.format(msg, locator));
}
@SuppressWarnings("ConstantConditions")
Resource resource = (Resource) groupedParameterizedElement;
String stateId = elements.get(4);
@ -518,7 +525,7 @@ public abstract class AbstractTransaction implements StrolchTransaction {
if (!(element instanceof Activity)) {
String msg = "Invalid locator {0} with part {1} as not an Activity but deeper element specified"; //$NON-NLS-1$
throw new StrolchException(MessageFormat.format(msg, locator, next));
throw new StrolchModelException(MessageFormat.format(msg, locator, next));
}
element = ((Activity) element).getElement(next);
@ -531,7 +538,7 @@ public abstract class AbstractTransaction implements StrolchTransaction {
return null;
String msg = "Invalid locator {0} with part {1}"; //$NON-NLS-1$
throw new StrolchException(MessageFormat.format(msg, locator, stateOrBagOrActivity));
throw new StrolchModelException(MessageFormat.format(msg, locator, stateOrBagOrActivity));
}
@Override
@ -1044,6 +1051,14 @@ public abstract class AbstractTransaction implements StrolchTransaction {
return getActivitiesBy(refsP, assertExists);
}
@Override
public void removeFromCache(Locator locator) {
if (this.resourceCache != null)
this.resourceCache.removeElement(locator.get(1), locator.get(2));
if (this.objectFilter != null)
this.objectFilter.removeObjectCache(locator.get(0), locator);
}
@Override
public Resource getCachedResource(String type, String id) {
if (this.resourceCache == null)

View File

@ -445,6 +445,24 @@ public interface StrolchTransaction extends AutoCloseable {
*/
void addCommand(Command command);
/**
* Adds the given {@link Command} to the transaction. Using this method guarantees that a {@link Command} is
* executed properly:
* <ul>
* <li>{@link Command#validate()}</li>
* <li>{@link Command#doCommand()}</li>
* </ul>
*
* and if an exception occurs:
* <ul>
* <li>{@link Command#undo()}</li>
* </ul>
*
* @param command
* the command to add
*/
void add(Command command);
/**
* Helper method to create an {@link Audit} with the given arguments. The audit can then be saved by calling {@link
* AuditTrail#add(StrolchTransaction, Audit)}
@ -534,11 +552,11 @@ public interface StrolchTransaction extends AutoCloseable {
* Used to find a {@link StrolchElement} by a {@link Locator}, throwing exception if the element is not found
* </p>
*
* @throws StrolchException
* @throws StrolchModelException
* if the element could not be found
* @see #findElement(Locator, boolean)
*/
<T extends StrolchElement> T findElement(Locator locator) throws StrolchException, ClassCastException;
<T extends StrolchElement> T findElement(Locator locator) throws StrolchModelException, ClassCastException;
/**
* <p>
@ -565,14 +583,14 @@ public interface StrolchTransaction extends AutoCloseable {
* an inexistant {@link Resource} or an inexistand {@link Parameter} on a Resource, then a {@link StrolchException}
* is thrown
*
* @throws StrolchException
* @throws StrolchModelException
* if the element could not be found and {@code allowNull} is false
* @throws ClassCastException
* if the querying code is not asking for the correct instance. Do not query a {@link Parameter} if the variable
* to which the result is to be is stored is a {@link Resource}, etc.
*/
<T extends StrolchElement> T findElement(Locator locator, boolean allowNull)
throws StrolchException, ClassCastException;
throws StrolchModelException, ClassCastException;
/**
* <p>Finds a parameter with the given @bagKey and @paramKey on the given @element, but if it does not exists
@ -1361,6 +1379,14 @@ public interface StrolchTransaction extends AutoCloseable {
List<Order> getOrdersByRelation(StrolchRootElement element, String refId, boolean assertExists)
throws StrolchException;
/**
* Allows to evict a {@link Locator} from the transaction's cache and object filter
*
* @param locator
* the locator of the object to remove from cache
*/
void removeFromCache(Locator locator);
/**
* Returns the cached resource with the given type and id, or null if not yet fetched
*

View File

@ -16,20 +16,15 @@
package li.strolch.policy;
import static li.strolch.runtime.StrolchConstants.PolicyConstants.PARAM_ORDER;
import static li.strolch.utils.helper.StringHelper.DASH;
import li.strolch.model.Order;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.StrolchComponent;
import li.strolch.exception.StrolchException;
import li.strolch.model.Resource;
import li.strolch.model.Order;
import li.strolch.model.activity.Action;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.service.api.Command;
import li.strolch.utils.helper.StringHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Interface for all Strolch policies, which are instantiated by the {@link PolicyHandler}
@ -86,30 +81,6 @@ public abstract class StrolchPolicy {
return this.tx;
}
/**
* Return the defined {@link Resource} on the given {@link Action}
*
* @param action
* the action for which to get the {@link Resource}
*
* @return the {@link Resource}
*
* @throws IllegalArgumentException
* if the resource is not defined on the action, i.e. fields are empty or a dash
* @throws StrolchException
* if the resource does not exist, which is referenced by the action
*/
protected Resource getResource(Action action) throws IllegalArgumentException, StrolchException {
String resourceId = action.getResourceId();
if (StringHelper.isEmpty(resourceId) || resourceId.equals(DASH))
throw new IllegalArgumentException("No resourceId defined on action " + action.getLocator());
String resourceType = action.getResourceType();
if (StringHelper.isEmpty(resourceType) || resourceType.equals(DASH))
throw new IllegalArgumentException("No resourceType defined on action " + action.getLocator());
return this.tx.getResourceBy(resourceType, resourceId, true);
}
protected Order getOrder(Action action) {
return tx().getOrderByRelation(action.getRootElement(), PARAM_ORDER, true);
}

View File

@ -304,11 +304,12 @@ public abstract class Command implements Restrictable {
/**
* <p>
* Should the transaction fail, either due to a {@link Command} throwing an exception when {@link #validate()} is
* called, or while committing the transaction, then this method should properly undo any changes it has done. It is
* imperative that this method does not throw further exceptions and that the state to be rolled back is remembered
* in the Command during committing
* This method can be used to undo actions peformed during the command, should the TX fail. In earlier versions of
* Strolch this was important to undo model changes, but the model changes are only visible after a commit succeeds,
* so this is no longer necessary.
* </p>
*/
public abstract void undo();
public void undo() {
// do nothing
}
}

View File

@ -1,12 +1,12 @@
/*
* Copyright 2015 Robert von Burg <eitch@eitchnet.ch>
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -32,9 +32,4 @@ public class TestNoConfirmationPolicy extends TestConfirmationPolicy {
public void confirm(Action action) {
action.setState(State.CLOSED);
}
@Override
public void undo() {
// do nothing
}
}

View File

@ -1,12 +1,12 @@
/*
* Copyright 2015 Robert von Burg <eitch@eitchnet.ch>
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -32,9 +32,4 @@ public class TestSimplePlanningPolicy extends TestPlanningPolicy {
public void plan(Action action) {
action.setState(State.PLANNED);
}
@Override
public void undo() {
// do nothing
}
}

View File

@ -1,12 +1,12 @@
/*
* Copyright 2015 Robert von Burg <eitch@eitchnet.ch>
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -32,9 +32,4 @@ public class TestSimulatedExecutionPolicy extends TestExecutionPolicy {
public void execute(Action action) {
action.setState(State.EXECUTION);
}
@Override
public void undo() {
// do nothing
}
}

View File

@ -154,6 +154,20 @@ public class Order extends AbstractStrolchRootElement implements StrolchRootElem
return getPolicyDefs().getPolicyDef(type);
}
@Override
public PolicyDef getPolicyDef(Class<?> clazz, PolicyDef defaultDef) {
if (!hasPolicyDefs())
return defaultDef;
return getPolicyDefs().getPolicyDef(clazz.getSimpleName(), defaultDef);
}
@Override
public PolicyDef getPolicyDef(String type, PolicyDef defaultDef) {
if (!hasPolicyDefs())
return defaultDef;
return getPolicyDefs().getPolicyDef(type, defaultDef);
}
@Override
public boolean hasPolicyDefs() {
return this.policyDefs != null;

View File

@ -20,12 +20,12 @@ public interface PolicyContainer {
* @throws StrolchPolicyException
* if no {@link PolicyDefs} are available
*/
public PolicyDefs getPolicyDefs() throws StrolchPolicyException;
PolicyDefs getPolicyDefs() throws StrolchPolicyException;
/**
* @return true if this container has {@link PolicyDefs}, false if not
*/
public boolean hasPolicyDefs();
boolean hasPolicyDefs();
/**
* Returns true if this container has the {@link PolicyDef} with the given type, false if not
@ -35,7 +35,7 @@ public interface PolicyContainer {
*
* @return true if this container has the {@link PolicyDef} with the given type, false if not
*/
public boolean hasPolicyDef(String type);
boolean hasPolicyDef(String type);
/**
* Returns the {@link PolicyDef} for the given type
@ -45,7 +45,19 @@ public interface PolicyContainer {
*
* @return the policy def of the given type
*/
public PolicyDef getPolicyDef(String type);
PolicyDef getPolicyDef(String type);
/**
* Returns the {@link PolicyDef} for the given type
*
* @param type
* the type of policy def to return
* @param defaultDef
* the default policy definition to return if the given type is not defined
*
* @return the policy def of the given type
*/
PolicyDef getPolicyDef(String type, PolicyDef defaultDef);
/**
* Returns the {@link PolicyDef} for the given class
@ -55,7 +67,19 @@ public interface PolicyContainer {
*
* @return the policy def of the given class
*/
public PolicyDef getPolicyDef(Class<?> clazz);
PolicyDef getPolicyDef(Class<?> clazz);
/**
* Returns the {@link PolicyDef} for the given class
*
* @param clazz
* the type of policy def to return
* @param defaultDef
* the default policy definition to return if the given type is not defined
*
* @return the policy def of the given class
*/
PolicyDef getPolicyDef(Class<?> clazz, PolicyDef defaultDef);
/**
* Set the reference to the {@link PolicyDefs}
@ -63,5 +87,5 @@ public interface PolicyContainer {
* @param policyDefs
* the {@link PolicyDefs} to set
*/
public void setPolicyDefs(PolicyDefs policyDefs);
void setPolicyDefs(PolicyDefs policyDefs);
}

View File

@ -252,6 +252,20 @@ public class Resource extends AbstractStrolchRootElement implements StrolchRootE
return getPolicyDefs().getPolicyDef(type);
}
@Override
public PolicyDef getPolicyDef(Class<?> clazz, PolicyDef defaultDef) {
if (!hasPolicyDefs())
return defaultDef;
return getPolicyDefs().getPolicyDef(clazz.getSimpleName(), defaultDef);
}
@Override
public PolicyDef getPolicyDef(String type, PolicyDef defaultDef) {
if (!hasPolicyDefs())
return defaultDef;
return getPolicyDefs().getPolicyDef(type, defaultDef);
}
@Override
public boolean hasPolicyDefs() {
return this.policyDefs != null;

View File

@ -30,6 +30,7 @@ public enum State {
CREATED("Created"), //$NON-NLS-1$
PLANNING("Planning"), //$NON-NLS-1$
PLANNED("Planned"), //$NON-NLS-1$
EXECUTABLE("Executable"), //$NON-NLS-1$
EXECUTION("Execution"), //$NON-NLS-1$
WARNING("Warning"), //$NON-NLS-1$
ERROR("Error"), //$NON-NLS-1$
@ -39,7 +40,7 @@ public enum State {
private String state;
private State(String state) {
State(String state) {
this.state = state;
}
@ -62,8 +63,8 @@ public enum State {
}
/**
* @return true if the state is one of {@link #EXECUTION}, {@link #STOPPED}, {@link #WARNING}, {@link #ERROR} or
* {@link #EXECUTED}
* @return true if the state is one of {@link #EXECUTABLE} {@link #EXECUTION}, {@link #STOPPED}, {@link #WARNING},
* {@link #ERROR} or {@link #EXECUTED}
*/
public boolean inExecutionPhase() {
return this == EXECUTION || this == STOPPED || this == WARNING || this == ERROR;
@ -168,10 +169,24 @@ public enum State {
}
/**
* @return true if {@link #CREATED} or {@link #PLANNING} or {@link #PLANNED} or {@link #EXECUTION} or {@link #STOPPED}
* @return true if {@link #PLANNED} or {@link #EXECUTABLE} or {@link #STOPPED}
*/
public boolean canSetToExecution() {
return this == CREATED || this == PLANNING || this == PLANNED || this == EXECUTION || this == State.STOPPED;
public boolean canSetToExecutable() {
return this == PLANNED || this == EXECUTABLE || this == State.STOPPED;
}
/**
* @return true if {@link #PLANNED} or {@link #EXECUTABLE} or {@link #EXECUTION}
*/
public boolean isExecutable() {
return this == PLANNED || this == EXECUTABLE || this == EXECUTION;
}
/**
* @return true if state >= {@link #EXECUTED}
*/
public boolean canNotSetToExecution() {
return this.compareTo(State.EXECUTED) >= 0;
}
/**
@ -249,7 +264,7 @@ public enum State {
return WARNING;
// execution
if (states.contains(EXECUTION))
if (states.contains(EXECUTABLE) || states.contains(EXECUTION))
return EXECUTION;
if (states.contains(EXECUTED) && (states.contains(CREATED) || states.contains(PLANNING) || states
.contains(PLANNED)))
@ -275,4 +290,5 @@ public enum State {
// should never happen, unless new state is introduced
throw new IllegalStateException("Unhandled situation with states: " + states.stream().map(e -> e.state)
.collect(Collectors.joining(", ")));
}}
}
}

View File

@ -16,6 +16,8 @@
package li.strolch.model.activity;
import static li.strolch.utils.helper.StringHelper.isNotEmpty;
import java.text.MessageFormat;
import java.util.*;
@ -142,6 +144,16 @@ public class Action extends GroupedParameterizedElement implements IActivityElem
this.resourceId = resource.getId();
}
public boolean hasResourceDefined() {
return isNotEmpty(this.resourceType) && isNotEmpty(this.resourceId);
}
public Locator getResourceLocator() {
if (!hasResourceDefined())
throw new IllegalStateException("Resource not set on " + getLocator());
return Resource.locatorFor(this.resourceType, this.resourceId);
}
/**
* Returns true if this {@link Action} contains any {@link IValueChange changes}, false if not
*
@ -245,6 +257,20 @@ public class Action extends GroupedParameterizedElement implements IActivityElem
return getPolicyDefs().getPolicyDef(clazz.getSimpleName());
}
@Override
public PolicyDef getPolicyDef(Class<?> clazz, PolicyDef defaultDef) {
if (!hasPolicyDefs())
return defaultDef;
return getPolicyDefs().getPolicyDef(clazz.getSimpleName(), defaultDef);
}
@Override
public PolicyDef getPolicyDef(String type, PolicyDef defaultDef) {
if (!hasPolicyDefs())
return defaultDef;
return getPolicyDefs().getPolicyDef(type, defaultDef);
}
@Override
public boolean hasPolicyDef(String type) {
return this.policyDefs != null && policyDefs.hasPolicyDef(type);

View File

@ -20,6 +20,7 @@ import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Stream;
import li.strolch.exception.StrolchElementNotFoundException;
import li.strolch.exception.StrolchException;
import li.strolch.exception.StrolchModelException;
import li.strolch.exception.StrolchPolicyException;
@ -381,6 +382,29 @@ public class Activity extends AbstractStrolchRootElement
}
}
public <T extends IActivityElement> T getElementByLocator(Locator locator) {
DBC.PRE.assertEquals("Locator is not for this activity!", getLocator(), locator.trim(3));
DBC.PRE.assertTrue("Locator must have at least 5 parts", locator.getSize() >= 4);
IActivityElement element = this;
for (int i = 3; i < locator.getSize(); i++) {
String next = locator.get(i);
if (!(element instanceof Activity)) {
String msg = "Invalid locator {0} with part {1} as not an Activity but deeper element specified"; //$NON-NLS-1$
throw new StrolchModelException(MessageFormat.format(msg, locator, next));
}
element = ((Activity) element).getElement(next);
if (element == null)
throw new StrolchElementNotFoundException(locator + " does not exist!");
}
@SuppressWarnings("unchecked")
T t = (T) element;
return t;
}
/**
* @return the iterator for entries, which include the id as key and the {@link IActivityElement} as value
*/
@ -449,6 +473,20 @@ public class Activity extends AbstractStrolchRootElement
return getPolicyDefs().getPolicyDef(type);
}
@Override
public PolicyDef getPolicyDef(Class<?> clazz, PolicyDef defaultDef) {
if (!hasPolicyDefs())
return defaultDef;
return getPolicyDefs().getPolicyDef(clazz.getSimpleName(), defaultDef);
}
@Override
public PolicyDef getPolicyDef(String type, PolicyDef defaultDef) {
if (!hasPolicyDefs())
return defaultDef;
return getPolicyDefs().getPolicyDef(type, defaultDef);
}
@Override
public boolean hasPolicyDefs() {
return this.policyDefs != null;

View File

@ -55,7 +55,14 @@ public class PolicyDefs {
}
public PolicyDef getPolicyDef(String type) {
return getPolicyDef(type, null);
}
public PolicyDef getPolicyDef(String type, PolicyDef defaultDef) {
if (!this.policyDefMap.containsKey(type)) {
if (defaultDef != null)
return defaultDef;
throw new StrolchPolicyException(
"The PolicyDef does not exist with type " + type + " on " + this.parent.getLocator());
}

View File

@ -16,6 +16,7 @@ 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;
@ -133,15 +134,84 @@ public class ControlResource {
@QueryParam("locator") String locatorS, @QueryParam("state") String stateS) {
Certificate cert = (Certificate) request.getAttribute(STROLCH_CERTIFICATE);
State state = State.parse(stateS);
Locator locator = Locator.valueOf(locatorS);
SetActionStateService svc = new SetActionStateService();
StringMapArgument arg = svc.getArgumentInstance();
arg.realm = realm;
arg.map.put("locator", locatorS);
arg.map.put("state", stateS);
LocatorArgument arg = new LocatorArgument();
arg.locator = locator;
ServiceHandler serviceHandler = RestfulStrolchComponent.getInstance().getServiceHandler();
ServiceResult svcResult = serviceHandler.doService(cert, svc, arg);
ServiceResult svcResult;
switch (state) {
case CREATED: {
SetActionToCreatedService svc = new SetActionToCreatedService();
svcResult = serviceHandler.doService(cert, svc, arg);
break;
}
case PLANNED: {
SetActionToPlannedService svc = new SetActionToPlannedService();
svcResult = serviceHandler.doService(cert, svc, arg);
break;
}
case EXECUTION: {
ExecuteActionService svc = new ExecuteActionService();
svcResult = serviceHandler.doService(cert, svc, arg);
break;
}
case WARNING: {
SetActionToWarningService svc = new SetActionToWarningService();
svcResult = serviceHandler.doService(cert, svc, arg);
break;
}
case ERROR: {
SetActionToErrorService svc = new SetActionToErrorService();
svcResult = serviceHandler.doService(cert, svc, arg);
break;
}
case STOPPED: {
SetActionToStoppedService svc = new SetActionToStoppedService();
svcResult = serviceHandler.doService(cert, svc, arg);
break;
}
case EXECUTED: {
SetActionToExecutedService svc = new SetActionToExecutedService();
svcResult = serviceHandler.doService(cert, svc, arg);
break;
}
case CLOSED: {
SetActionToClosedService svc = new SetActionToClosedService();
svcResult = serviceHandler.doService(cert, svc, arg);
break;
}
default:
throw new UnsupportedOperationException("Unhandled state " + state);
}
return ResponseUtil.toResponse(svcResult);
}

View File

@ -3,6 +3,7 @@ package li.strolch.execution;
import java.util.concurrent.TimeUnit;
import li.strolch.agent.api.StrolchAgent;
import li.strolch.execution.command.ArchiveActivityCommand;
import li.strolch.job.JobMode;
import li.strolch.job.StrolchJob;
import li.strolch.model.State;
@ -23,13 +24,16 @@ public class ArchiveExecutedActivitiesJob extends StrolchJob {
@Override
protected void execute(PrivilegeContext ctx) {
ExecutionHandler executionHandler = getComponent(ExecutionHandler.class);
try (StrolchTransaction tx = openTx(ctx.getCertificate(), true)) {
try (StrolchTransaction tx = openTx(ctx.getCertificate())) {
tx.streamActivities().forEach(activity -> {
if (activity.getState() == State.EXECUTED)
executionHandler.archiveActivity(tx.getRealmName(), activity.getLocator());
if (activity.getState() == State.EXECUTED) {
ArchiveActivityCommand command = new ArchiveActivityCommand(tx);
command.setActivityLoc(activity.getLocator());
tx.addCommand(command);
}
});
tx.commitOnClose();
}
}
}

View File

@ -0,0 +1,331 @@
package li.strolch.execution;
import static li.strolch.runtime.StrolchConstants.SYSTEM_USER_AGENT;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.ObserverEvent;
import li.strolch.agent.api.StrolchRealm;
import li.strolch.execution.command.*;
import li.strolch.execution.policy.ExecutionPolicy;
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.Resource;
import li.strolch.model.State;
import li.strolch.model.Tags;
import li.strolch.model.activity.Action;
import li.strolch.model.activity.Activity;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.privilege.base.PrivilegeException;
import li.strolch.privilege.model.Certificate;
import li.strolch.runtime.privilege.PrivilegedRunnable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Controller {
private static final Logger logger = LoggerFactory.getLogger(Controller.class);
private final String realm;
private ComponentContainer container;
private ExecutionHandler executionHandler;
private final String activityType;
private final String activityId;
private final Locator locator;
private Activity activity;
private Map<Locator, ExecutionPolicy> inExecution;
public Controller(String realm, ExecutionHandler executionHandler, Activity activity) {
this.realm = realm;
this.container = executionHandler.getContainer();
this.executionHandler = executionHandler;
this.locator = activity.getLocator();
this.activityType = activity.getType();
this.activityId = activity.getId();
this.activity = activity;
this.inExecution = Collections.synchronizedMap(new HashMap<>());
}
public String getRealm() {
return this.realm;
}
public boolean isStopped(Locator locator) {
ExecutionPolicy executionPolicy = this.inExecution.get(locator);
return executionPolicy == null || executionPolicy.isStopped();
}
public Locator getLocator() {
return this.locator;
}
public Activity getActivity() {
return this.activity;
}
public ExecutionPolicy getExecutionPolicy(StrolchTransaction tx, Action action) {
ExecutionPolicy executionPolicy = this.inExecution.computeIfAbsent(action.getLocator(), e -> {
Resource resource = tx.getResourceFor(action, true);
return tx.getPolicy(resource.getPolicyDef(ExecutionPolicy.class));
});
// always update the TX and controller
executionPolicy.setController(tx, this);
return executionPolicy;
}
protected StrolchTransaction openTx(Certificate cert) {
return this.executionHandler.openTx(this.realm, cert, getClass(), false);
}
protected void runAsAgent(PrivilegedRunnable runnable) throws PrivilegeException, Exception {
this.executionHandler.runAsAgent(runnable);
}
private boolean refreshActivity(StrolchTransaction tx) {
Activity activity = tx.getActivityBy(this.activityType, this.activityId, false);
if (activity == null) {
logger.error("Element " + this.locator + " does not exist anymore. Removing from execution");
this.executionHandler.removeFromExecution(this);
return false;
}
this.activity = activity;
return true;
}
/**
* Starts the execution of this {@link Activity}
*/
public void execute() throws Exception {
boolean[] trigger = new boolean[1];
this.executionHandler.runAsAgent(ctx -> {
try (StrolchTransaction tx = openTx(ctx.getCertificate())) {
tx.lock(this.locator);
trigger[0] = execute(tx);
if (tx.needsCommit()) {
tx.commitOnClose();
}
}
});
if (trigger[0])
this.executionHandler.triggerExecution(this.realm);
}
private boolean execute(StrolchTransaction tx) {
if (!refreshActivity(tx))
return false;
if (this.activity.getState().isExecuted()) {
this.executionHandler.removeFromExecution(this);
logger.info("Archiving executed activity " + this.locator + " with state " + this.activity.getState());
this.executionHandler.archiveActivity(this.realm, this.activity);
return false;
}
ExecutionHandlerState state = this.executionHandler.getState(this.realm);
if (state == ExecutionHandlerState.Paused) {
logger.warn("Ignoring trigger for paused realm " + this.realm);
return false;
}
ExecuteActivityCommand command = new ExecuteActivityCommand(tx);
command.setController(this);
command.validate();
command.doCommand();
notifyObserverUpdate();
return command.needsRetriggerOfExecution();
}
/**
* Completes the execution of the given {@link Action} with the given {@link Locator}
*
* @param actionLoc
* the {@link Locator} of the {@link Action}
*/
public void toExecuted(Locator actionLoc) throws Exception {
this.executionHandler.runAsAgent(ctx -> {
try (StrolchTransaction tx = openTx(ctx.getCertificate())) {
tx.lock(this.locator);
if (!refreshActivity(tx))
return;
Action action = this.activity.getElementByLocator(actionLoc);
// set this action to executed
SetActionToExecutedCommand command = new SetActionToExecutedCommand(tx);
command.setExecutionPolicy(getExecutionPolicy(tx, action));
command.setAction(action);
command.validate();
command.doCommand();
notifyObserverUpdate();
// flush so we can see the changes performed
tx.flush();
// now try and execute the next action(s)
execute(tx);
if (tx.needsCommit())
tx.commitOnClose();
}
});
this.executionHandler.triggerExecution(this.realm);
}
/**
* Sets the state of the {@link Action} with the given {@link Locator} to {@link State#STOPPED}
*
* @param actionLoc
* the {@link Locator} of the {@link Action}
*/
public void toStopped(Locator actionLoc) throws Exception {
this.executionHandler.runAsAgent(ctx -> {
try (StrolchTransaction tx = openTx(ctx.getCertificate())) {
tx.lock(this.locator);
if (!refreshActivity(tx))
return;
Action action = this.activity.getElementByLocator(actionLoc);
// set this action to executed
SetActionToStoppedCommand command = new SetActionToStoppedCommand(tx);
command.setExecutionPolicy(getExecutionPolicy(tx, action));
command.setAction(action);
command.validate();
command.doCommand();
tx.commitOnClose();
}
});
}
/**
* Sets the state of the {@link Action} with the given {@link Locator} to {@link State#ERROR}
*
* @param actionLoc
* the {@link Locator} of the {@link Action}
*/
public void toError(Locator actionLoc) throws Exception {
this.executionHandler.runAsAgent(ctx -> {
try (StrolchTransaction tx = openTx(ctx.getCertificate())) {
tx.lock(this.locator);
if (!refreshActivity(tx))
return;
Action action = this.activity.getElementByLocator(actionLoc);
// set this action to executed
SetActionToErrorCommand command = new SetActionToErrorCommand(tx);
command.setExecutionPolicy(getExecutionPolicy(tx, action));
command.setAction(action);
command.validate();
command.doCommand();
tx.commitOnClose();
}
});
}
/**
* Sets the state of the {@link Action} with the given {@link Locator} to {@link State#WARNING}
*
* @param actionLoc
* the {@link Locator} of the {@link Action}
*/
public void toWarning(Locator actionLoc) throws Exception {
this.executionHandler.runAsAgent(ctx -> {
try (StrolchTransaction tx = openTx(ctx.getCertificate())) {
tx.lock(this.locator);
if (!refreshActivity(tx))
return;
Action action = this.activity.getElementByLocator(actionLoc);
// set this action to executed
SetActionToWarningCommand command = new SetActionToWarningCommand(tx);
command.setExecutionPolicy(getExecutionPolicy(tx, action));
command.setAction(action);
command.validate();
command.doCommand();
tx.commitOnClose();
}
});
}
/**
* Sets the state of the {@link Action} with the given {@link Locator} to {@link State#ERROR}
*
* @param actionLoc
* the {@link Locator} of the {@link Action}
*/
public void asyncToError(Locator actionLoc) {
this.executionHandler.getExecutor().submit(() -> {
try {
toError(actionLoc);
} catch (Exception e) {
logger.error("Failed to set " + locator + " to error due to " + e.getMessage(), e);
if (this.container.hasComponent(OperationsLog.class)) {
this.container.getComponent(OperationsLog.class).addMessage(
new LogMessage(realm, SYSTEM_USER_AGENT, locator, LogSeverity.Exception,
ResourceBundle.getBundle("strolch-service"), "execution.handler.failed.error")
.withException(e).value("reason", e));
}
}
});
}
/**
* Sets the state of the {@link Action} with the given {@link Locator} to {@link State#WARNING}
*
* @param actionLoc
* the {@link Locator} of the {@link Action}
*/
public void asyncToWarning(Locator actionLoc) {
this.executionHandler.getExecutor().submit(() -> {
try {
toWarning(actionLoc);
} catch (Exception e) {
logger.error("Failed to set " + locator + " to warning due to " + e.getMessage(), e);
if (this.container.hasComponent(OperationsLog.class)) {
this.container.getComponent(OperationsLog.class).addMessage(
new LogMessage(realm, SYSTEM_USER_AGENT, locator, LogSeverity.Exception,
ResourceBundle.getBundle("strolch-service"), "execution.handler.failed.warning")
.withException(e).value("reason", e));
}
}
});
}
private void notifyObserverUpdate() {
StrolchRealm realm = this.executionHandler.getContainer().getRealm(this.realm);
if (!realm.isUpdateObservers())
return;
ObserverEvent observerEvent = new ObserverEvent();
observerEvent.updated.addElement(Tags.CONTROLLER, this.activity);
realm.getObserverHandler().notify(observerEvent);
}
}

View File

@ -1,15 +1,16 @@
package li.strolch.execution;
import static java.util.Collections.emptySet;
import static li.strolch.model.StrolchModelConstants.*;
import static li.strolch.runtime.StrolchConstants.SYSTEM_USER_AGENT;
import static li.strolch.utils.collections.SynchronizedCollections.synchronizedMapOfMaps;
import java.util.*;
import java.util.concurrent.ExecutorService;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.ObserverEvent;
import li.strolch.execution.command.*;
import li.strolch.execution.policy.ActivityArchivalPolicy;
import li.strolch.agent.api.StrolchRealm;
import li.strolch.execution.command.ArchiveActivityCommand;
import li.strolch.execution.policy.ExecutionPolicy;
import li.strolch.handler.operationslog.LogMessage;
import li.strolch.handler.operationslog.LogSeverity;
@ -17,16 +18,12 @@ import li.strolch.handler.operationslog.OperationsLog;
import li.strolch.model.*;
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;
import li.strolch.utils.dbc.DBC;
import li.strolch.utils.collections.MapOfMaps;
/**
* The event based execution handler waits for events in that the {@link ExecutionPolicy} implementations must call the
@ -36,11 +33,10 @@ import li.strolch.utils.dbc.DBC;
*/
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 MapOfMaps<String, Locator, Controller> controllers;
private DelayedExecutionTimer delayedExecutionTimer;
@ -48,11 +44,29 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
super(container, componentName);
}
@Override
public Controller getController(String realm, Activity activity) {
return this.controllers.getElement(realm, activity.getLocator());
}
@Override
public Controller getController(String realm, Locator locator) {
return this.controllers.getElement(realm, locator.trim(3));
}
@Override
public Set<Locator> getActiveActivitiesLocator(String realm) {
if (this.controllers == null)
return emptySet();
Map<Locator, Controller> activities = this.controllers.getMap(realm);
if (activities == null)
return emptySet();
return activities.keySet();
}
@Override
public void initialize(ComponentConfiguration configuration) throws Exception {
this.registeredActivities = new MapOfSets<>();
this.controllers = synchronizedMapOfMaps(new MapOfMaps<>());
super.initialize(configuration);
}
@ -86,66 +100,46 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
}
@Override
public Set<Locator> getActiveActivitiesLocator(String realm) {
if (this.registeredActivities == null || !this.registeredActivities.containsSet(realm))
return Collections.emptySet();
synchronized (this.registeredActivities) {
return new HashSet<>(this.registeredActivities.getSet(realm));
}
}
@Override
public void addForExecution(String realm, Activity activity) {
public void toExecution(String realm, Activity activity) {
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 = activity.getLocator();
synchronized (this.registeredActivities) {
this.registeredActivities.addElement(realm, rootElemLoc);
Controller controller = this.controllers.getElement(realm, activity.getLocator());
if (controller == null) {
controller = new Controller(realm, this, activity);
this.controllers.addElement(realm, activity.getLocator(), controller);
notifyObserverAdd(controller);
}
notifyObserverAdd(realm, activity);
toExecution(realm, rootElemLoc);
toExecution(controller);
}
@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);
public void removeFromExecution(Controller controller) {
logger.info("Removing controller " + controller.getLocator() + " from execution...");
if (this.controllers.removeElement(controller.getRealm(), controller.getLocator()) != null) {
logger.info("Removed controller " + controller.getLocator() + " from execution.");
getExecutor().submit(() -> notifyObserverRemove(controller));
}
getExecutor().submit(() -> notifyObserverAdd(realm, activityLoc));
toExecution(realm, activityLoc);
}
@Override
public void removeFromExecution(String realm, Locator activityLoc) {
Locator rootElemLoc = activityLoc.trim(3);
synchronized (this.registeredActivities) {
this.registeredActivities.removeElement(realm, rootElemLoc);
}
getExecutor().submit(() -> notifyObserverRemove(realm, activityLoc));
Controller controller = this.controllers.removeElement(realm, rootElemLoc);
if (controller != null)
getExecutor().submit(() -> notifyObserverRemove(controller));
}
@Override
public void clearAllCurrentExecutions(String realm) {
Set<Locator> removed = this.registeredActivities.removeSet(realm);
Map<Locator, Controller> removed = this.controllers.removeMap(realm);
getExecutor().submit(() -> notifyObserverRemove(realm, removed));
}
private void restartActivityExecution(PrivilegeContext ctx) {
// iterate the realms
for (String realmName : getContainer().getRealmNames()) {
reloadActivitiesInExecution(ctx, realmName);
@ -180,7 +174,8 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
tx.update(activity);
// register for execution
this.registeredActivities.addElement(realmName, activity.getLocator());
Controller controller = new Controller(realmName, this, activity);
this.controllers.addElement(realmName, activity.getLocator(), controller);
});
// commit changes to state
@ -200,12 +195,12 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
return;
}
synchronized (this.registeredActivities) {
Set<Locator> locators = this.registeredActivities.getSet(realm);
if (locators != null) {
for (Locator locator : locators) {
synchronized (this.controllers) {
Map<Locator, Controller> controllers = this.controllers.getMap(realm);
if (controllers != null) {
for (Controller controller : controllers.values()) {
// execute async
toExecution(realm, locator);
toExecution(controller);
}
}
}
@ -282,24 +277,26 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
}
}
@Override
public void toExecution(String realm, Locator locator) {
private void toExecution(Controller controller) {
String realm = controller.getRealm();
ExecutionHandlerState state = this.statesByRealm.getOrDefault(realm, ExecutionHandlerState.Running);
if (state == ExecutionHandlerState.Paused) {
logger.warn("Ignoring execution of " + locator + " for paused realm " + realm);
logger.warn("Ignoring execution of " + controller.getLocator() + " for paused realm " + realm);
return;
}
logger.info("Adding async " + controller.getLocator() + " for execution!");
getExecutor().execute(() -> {
try {
runAsAgent(ctx -> toExecution(realm, locator, ctx));
controller.execute();
} catch (Exception e) {
logger.error("Failed to set " + locator + " to execution due to " + e.getMessage(), e);
logger.error("Failed to set " + controller.getLocator() + " to execution", e);
if (getContainer().hasComponent(OperationsLog.class)) {
getComponent(OperationsLog.class).addMessage(
new LogMessage(realm, SYSTEM_USER_AGENT, locator, LogSeverity.Exception,
new LogMessage(realm, SYSTEM_USER_AGENT, controller.getLocator(), LogSeverity.Exception,
ResourceBundle.getBundle("strolch-service"), "execution.handler.failed.execution")
.withException(e).value("reason", e));
}
@ -307,17 +304,15 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
});
}
private ExecutorService getExecutor() {
return getExecutorService("ExecutionHandler");
}
@Override
public void toExecuted(String realm, Locator locator) {
getExecutor().execute(() -> {
try {
runAsAgent(ctx -> {
toExecuted(realm, locator, ctx);
});
Controller controller = this.controllers.getElement(realm, locator.trim(3));
if (controller != null)
controller.toExecuted(locator);
} catch (Exception e) {
logger.error("Failed to set " + locator + " to executed due to " + e.getMessage(), e);
@ -335,9 +330,11 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
public void toStopped(String realm, Locator locator) {
getExecutor().execute(() -> {
try {
runAsAgent(ctx -> {
toStopped(realm, locator, ctx);
});
Controller controller = this.controllers.getElement(realm, locator.trim(3));
if (controller != null)
controller.toStopped(locator);
} catch (Exception e) {
logger.error("Failed to set " + locator + " to stopped due to " + e.getMessage(), e);
@ -355,9 +352,11 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
public void toError(String realm, Locator locator) {
getExecutor().execute(() -> {
try {
runAsAgent(ctx -> {
toError(realm, locator, ctx);
});
Controller controller = this.controllers.getElement(realm, locator.trim(3));
if (controller != null)
controller.toError(locator);
} catch (Exception e) {
logger.error("Failed to set " + locator + " to error due to " + e.getMessage(), e);
@ -375,9 +374,11 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
public void toWarning(String realm, Locator locator) {
getExecutor().execute(() -> {
try {
runAsAgent(ctx -> {
toWarning(realm, locator, ctx);
});
Controller controller = this.controllers.getElement(realm, locator.trim(3));
if (controller != null)
controller.toWarning(locator);
} catch (Exception e) {
logger.error("Failed to set " + locator + " to warning due to " + e.getMessage(), e);
@ -392,42 +393,24 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
}
@Override
public void archiveActivity(String realm, Locator activityLoc) {
public void archiveActivity(String realm, Activity activity) {
getExecutor().execute(() -> {
try {
runAsAgent(ctx -> {
try (StrolchTransaction tx = openTx(realm, ctx.getCertificate(), ActivityArchivalPolicy.class,
try (StrolchTransaction tx = openTx(realm, ctx.getCertificate(), ArchiveActivityCommand.class,
false)) {
tx.lock(activityLoc);
Activity activity = tx.findElement(activityLoc, true);
if (activity == null) {
return;
}
logger.info("Activity " + activity.getLocator() + " is in state " + activity.getState());
PolicyDef policyDef;
if (activity.hasPolicyDef(ActivityArchivalPolicy.class.getSimpleName())) {
policyDef = activity.getPolicyDef(ActivityArchivalPolicy.class.getSimpleName());
} else {
policyDef = PolicyDef.valueOf(ActivityArchivalPolicy.class.getSimpleName(),
KEY_DEFAULT_ACTIVITY_ARCHIVAL);
}
PolicyHandler policyHandler = getComponent(PolicyHandler.class);
ActivityArchivalPolicy archivalPolicy = policyHandler.getPolicy(policyDef, tx);
archivalPolicy.archive(activity);
ArchiveActivityCommand command = new ArchiveActivityCommand(tx);
command.setActivityLoc(activity.getLocator());
tx.addCommand(command);
tx.commitOnClose();
}
});
} catch (Exception e) {
logger.error("Failed to archive " + activityLoc + " due to " + e.getMessage(), e);
logger.error("Failed to archive " + activity.getLocator() + " due to " + e.getMessage(), e);
if (getContainer().hasComponent(OperationsLog.class)) {
getComponent(OperationsLog.class).addMessage(
new LogMessage(realm, SYSTEM_USER_AGENT, activityLoc, LogSeverity.Exception,
new LogMessage(realm, SYSTEM_USER_AGENT, activity.getLocator(), LogSeverity.Exception,
ResourceBundle.getBundle("strolch-service"), "execution.handler.failed.archive")
.withException(e).value("reason", e));
}
@ -435,255 +418,36 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
});
}
private void toExecution(String realm, Locator elementLoc, PrivilegeContext ctx) {
try (StrolchTransaction tx = openTx(realm, ctx.getCertificate(), ExecuteActivityCommand.class, false)) {
Locator activityLoc = elementLoc.trim(3);
tx.lock(activityLoc);
Activity activity = tx.findElement(activityLoc, true);
if (activity == null) {
logger.error("Element for locator " + elementLoc + " does not exist!");
synchronized (this.registeredActivities) {
this.registeredActivities.removeElement(realm, activityLoc);
}
notifyObserverRemove(realm, activityLoc);
return;
}
if (activity.getState().isExecuted()) {
synchronized (this.registeredActivities) {
if (!this.registeredActivities.removeElement(realm, activityLoc))
logger.warn("Activity " + activityLoc + " already removed from registered activities!");
}
notifyObserverRemove(tx, activity);
logger.info("Archiving activity " + activityLoc + " with state " + activity.getState());
archiveActivity(realm, activity.getLocator());
} else {
ExecuteActivityCommand command = new ExecuteActivityCommand(getContainer(), tx);
command.setActivity(activity);
command.validate();
command.doCommand();
notifyObserverUpdate(tx, activity);
tx.commitOnClose();
}
}
}
private void toExecuted(String realm, Locator actionLoc, PrivilegeContext ctx) {
Locator activityLoc = actionLoc.trim(3);
try (StrolchTransaction tx = openTx(realm, ctx.getCertificate(), SetActionToExecutedCommand.class, false)) {
tx.lock(activityLoc);
Action action = tx.findElement(actionLoc);
// set this action to executed
SetActionToExecutedCommand command = new SetActionToExecutedCommand(getContainer(), tx);
command.setAction(action);
command.validate();
command.doCommand();
notifyObserverUpdate(tx, action.getRootElement());
// flush so we can see the changes performed
tx.flush();
// if the activity is now executed, remove it from the registered activities
Activity activity = action.getRootElement().getClone(true);
if (activity.getState().isExecuted()) {
synchronized (this.registeredActivities) {
if (!this.registeredActivities.removeElement(realm, activityLoc))
logger.warn("Activity " + activityLoc + " already removed from registered activities!");
}
notifyObserverRemove(tx, action.getRootElement());
logger.info("Archiving activity " + activityLoc + " with state " + activity.getState());
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 {
// otherwise execute any next action(s) for this action's activity
ExecuteActivityCommand execCommand = new ExecuteActivityCommand(getContainer(), tx);
execCommand.setActivity(activity);
execCommand.validate();
execCommand.doCommand();
notifyObserverUpdate(tx, action.getRootElement());
// flush so we can see the changes performed
tx.flush();
}
}
tx.commitOnClose();
}
// now trigger a further execution of any other activities needed execution in this realm
triggerExecution(realm);
}
private void toWarning(String realm, Locator actionLoc, PrivilegeContext ctx) {
try (StrolchTransaction tx = openTx(realm, ctx.getCertificate(), SetActionToExecutedCommand.class, false)) {
Locator rootElemLoc = actionLoc.trim(3);
tx.lock(rootElemLoc);
IActivityElement elem = tx.findElement(actionLoc);
DBC.INTERIM.assertEquals("toWarning only for Action!", Action.class, elem.getClass());
SetActionToWarningCommand command = new SetActionToWarningCommand(getContainer(), tx);
command.setAction((Action) elem);
command.validate();
command.doCommand();
notifyObserverUpdate(tx, elem.getRootElement());
tx.commitOnClose();
}
}
private void toError(String realm, Locator actionLoc, PrivilegeContext ctx) {
try (StrolchTransaction tx = openTx(realm, ctx.getCertificate(), SetActionToExecutedCommand.class, false)) {
Locator rootElemLoc = actionLoc.trim(3);
tx.lock(rootElemLoc);
IActivityElement elem = tx.findElement(actionLoc);
DBC.INTERIM.assertEquals("toError only for Action!", Action.class, elem.getClass());
SetActionToErrorCommand command = new SetActionToErrorCommand(getContainer(), tx);
command.setAction((Action) elem);
command.validate();
command.doCommand();
notifyObserverUpdate(tx, elem.getRootElement());
tx.commitOnClose();
}
}
private void toStopped(String realm, Locator actionLoc, PrivilegeContext ctx) {
try (StrolchTransaction tx = openTx(realm, ctx.getCertificate(), SetActionToStoppedCommand.class, false)) {
Locator rootElemLoc = actionLoc.trim(3);
tx.lock(rootElemLoc);
IActivityElement elem = tx.findElement(actionLoc);
DBC.INTERIM.assertEquals("toStopped only for Action!", Action.class, elem.getClass());
SetActionToStoppedCommand command = new SetActionToStoppedCommand(getContainer(), tx);
command.setAction((Action) elem);
command.validate();
command.doCommand();
notifyObserverUpdate(tx, elem.getRootElement());
tx.commitOnClose();
}
// now trigger a further execution of any other activities needed execution in this realm
triggerExecution(realm);
}
private void notifyObserverAdd(String realm, Locator activityLoc) {
if (!getContainer().getRealm(realm).isUpdateObservers())
return;
try {
runAsAgent(ctx -> {
try (StrolchTransaction tx = openTx(realm, ctx.getCertificate(), true)) {
Activity activity = tx.findElement(activityLoc, true);
if (activity != null) {
ObserverEvent observerEvent = new ObserverEvent();
observerEvent.added.addElement(Tags.CONTROLLER, activity);
getContainer().getRealm(realm).getObserverHandler().notify(observerEvent);
}
}
});
} catch (Exception e) {
logger.error("Failed to notify observers of new controller " + activityLoc);
}
}
private void notifyObserverAdd(String realm, Activity rootElement) {
if (!getContainer().getRealm(realm).isUpdateObservers())
private void notifyObserverAdd(Controller controller) {
StrolchRealm realm = getContainer().getRealm(controller.getRealm());
if (!realm.isUpdateObservers())
return;
ObserverEvent observerEvent = new ObserverEvent();
observerEvent.added.addElement(Tags.CONTROLLER, rootElement);
getContainer().getRealm(realm).getObserverHandler().notify(observerEvent);
observerEvent.added.addElement(Tags.CONTROLLER, controller.getActivity());
realm.getObserverHandler().notify(observerEvent);
}
private void notifyObserverUpdate(StrolchTransaction tx, Activity rootElement) {
if (!getContainer().getRealm(tx.getRealmName()).isUpdateObservers())
private void notifyObserverRemove(Controller controller) {
StrolchRealm realm = getContainer().getRealm(controller.getRealm());
if (!realm.isUpdateObservers())
return;
ObserverEvent observerEvent = new ObserverEvent();
observerEvent.updated.addElement(Tags.CONTROLLER, rootElement);
tx.getContainer().getRealm(tx.getRealmName()).getObserverHandler().notify(observerEvent);
observerEvent.removed.addElement(Tags.CONTROLLER, controller.getActivity());
realm.getObserverHandler().notify(observerEvent);
}
private void notifyObserverRemove(StrolchTransaction tx, Activity rootElement) {
if (!getContainer().getRealm(tx.getRealmName()).isUpdateObservers())
private void notifyObserverRemove(String realmName, Map<Locator, Controller> removed) {
StrolchRealm realm = getContainer().getRealm(realmName);
if (!realm.isUpdateObservers())
return;
ObserverEvent observerEvent = new ObserverEvent();
observerEvent.removed.addElement(Tags.CONTROLLER, rootElement);
tx.getContainer().getRealm(tx.getRealmName()).getObserverHandler().notify(observerEvent);
}
private void notifyObserverRemove(String realm, Locator activityLoc) {
if (!getContainer().getRealm(realm).isUpdateObservers())
return;
try {
runAsAgent(ctx -> {
try (StrolchTransaction tx = openTx(realm, ctx.getCertificate(), true)) {
Activity activity = tx.findElement(activityLoc, true);
if (activity != null) {
ObserverEvent observerEvent = new ObserverEvent();
observerEvent.removed.addElement(Tags.CONTROLLER, activity);
getContainer().getRealm(realm).getObserverHandler().notify(observerEvent);
}
}
});
} catch (Exception e) {
logger.error("Failed to notify observers of removed controller " + activityLoc);
}
}
private void notifyObserverRemove(String realm, Set<Locator> activityLocs) {
if (!getContainer().getRealm(realm).isUpdateObservers())
return;
try {
runAsAgent(ctx -> {
try (StrolchTransaction tx = openTx(realm, ctx.getCertificate(), true)) {
ObserverEvent observerEvent = new ObserverEvent();
for (Locator activityLoc : activityLocs) {
Activity activity = tx.findElement(activityLoc, true);
if (activity != null)
observerEvent.removed.addElement(Tags.CONTROLLER, activity);
}
getContainer().getRealm(realm).getObserverHandler().notify(observerEvent);
}
});
} catch (Exception e) {
logger.error("Failed to notify observers of removed controllers " + activityLocs);
for (Controller controller : removed.values()) {
observerEvent.removed.addElement(Tags.CONTROLLER, controller.getActivity());
}
realm.getObserverHandler().notify(observerEvent);
}
@Override

View File

@ -1,6 +1,7 @@
package li.strolch.execution;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.StrolchComponent;
@ -11,8 +12,11 @@ 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.persistence.api.StrolchTransaction;
import li.strolch.privilege.base.PrivilegeException;
import li.strolch.privilege.model.Certificate;
import li.strolch.privilege.model.PrivilegeContext;
import li.strolch.runtime.privilege.PrivilegedRunnable;
/**
* <p>
@ -21,7 +25,7 @@ import li.strolch.privilege.model.PrivilegeContext;
*
* <p>
* To start the execution of an {@link Activity} add it to the {@link ExecutionHandler} by calling {@link
* #addForExecution(String, Activity)} or {@link #addForExecution(String, Locator)}. Actual execution is asynchronously
* #toExecution(String, Activity)} or {@link #toExecution(String, Activity)}. Actual execution is asynchronously
* performed and the {@link ExecutionPolicy} of the resources of the {@link Action Actions} will perform the actual
* execution.
* </p>
@ -41,16 +45,41 @@ public abstract class ExecutionHandler extends StrolchComponent {
public static final String PARAM_STATE = "state";
public StrolchTransaction openTx(String realm, Certificate cert, Class<?> action, boolean readOnly) {
return super.openTx(realm, cert, action.getName(), readOnly);
}
public void runAsAgent(PrivilegedRunnable runnable) throws PrivilegeException, Exception {
super.runAsAgent(runnable);
}
public ExecutorService getExecutor() {
return getExecutorService("ExecutionHandler");
}
/**
* Registers the given {@link Locator} of an {@link Activity} for execution, and submits it for execution
* immediately in an asynchronous manner
* Returns the controller for the given realm and activity, null if it does not exist
*
* @param realm
* the realm where the {@link Activity} resides
* @param activityLoc
* the {@link Locator} of the {@link Activity}
* the realm for which to get the controller
* @param activity
* the activity for which to get the controller
*
* @return the controller, or null if it does not exist
*/
public abstract void addForExecution(String realm, Locator activityLoc);
public abstract Controller getController(String realm, Activity activity);
/**
* Returns the controller for the given realm and activity, null if it does not exist
*
* @param realm
* the realm for which to get the controller
* @param locator
* the locator of the activity for which to get the controller
*
* @return the controller, or null if it does not exist
*/
public abstract Controller getController(String realm, Locator locator);
/**
* Registers the given {@link Activity} for execution, and submits it for execution immediately in an asynchronous
@ -61,7 +90,15 @@ public abstract class ExecutionHandler extends StrolchComponent {
* @param activity
* the the {@link Activity}
*/
public abstract void addForExecution(String realm, Activity activity);
public abstract void toExecution(String realm, Activity activity);
/**
* Removes the given {@link Controller} from execution, so it is not executed further
*
* @param controller
* the controller to remove
*/
public abstract void removeFromExecution(Controller controller);
/**
* Removes the given {@link Locator} for an {@link Activity} from execution, so it is not executed further
@ -92,7 +129,7 @@ public abstract class ExecutionHandler extends StrolchComponent {
public abstract void clearAllCurrentExecutions(String realm);
/**
* Triggers a to execution for all registered activities in the given realm
* Triggers execution for all registered activities in the given realm
*
* @param realm
* the realm to trigger execution for
@ -126,10 +163,10 @@ public abstract class ExecutionHandler extends StrolchComponent {
*
* @param realm
* the realm where the activity resides
* @param activityLoc
* the {@link Locator} of the {@link Activity}
* @param activity
* the {@link Activity}
*/
public abstract void archiveActivity(String realm, Locator activityLoc);
public abstract void archiveActivity(String realm, Activity activity);
/**
* Returns the {@link Set} of {@link Locator Locators} of {@link Activity Activities} which are registered for
@ -148,24 +185,14 @@ public abstract class ExecutionHandler extends StrolchComponent {
* </p>
*
* <p>
* The {@link DelayedExecutionTimer} allows to delay the {@link #toExecuted(String, Locator)} call by a given time.
* See the {@link DurationExecution} policy
* The {@link DelayedExecutionTimer} allows to delay the {@link Controller#toExecuted(Locator)} call by a given
* time. See the {@link DurationExecution} policy
* </p>
*
* @return the {@link DelayedExecutionTimer}
*/
public abstract DelayedExecutionTimer getDelayedExecutionTimer();
/**
* Starts the execution of the given {@link Activity} with the given {@link Locator}
*
* @param realm
* the realm where the {@link Activity} resides
* @param activityLoc
* the {@link Locator} of the {@link Activity}
*/
public abstract void toExecution(String realm, Locator activityLoc);
/**
* Completes the execution of the given {@link Action} with the given {@link Locator}
*

View File

@ -1,14 +1,20 @@
package li.strolch.execution;
import static li.strolch.runtime.StrolchConstants.SYSTEM_USER_AGENT;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.StrolchAgent;
import li.strolch.handler.operationslog.LogMessage;
import li.strolch.handler.operationslog.LogSeverity;
import li.strolch.handler.operationslog.OperationsLog;
import li.strolch.model.Locator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -65,7 +71,22 @@ public class SimpleDurationExecutionTimer implements DelayedExecutionTimer {
this.simulationTasks.remove(locator);
ExecutionHandler executionHandler = container.getComponent(ExecutionHandler.class);
executionHandler.toExecuted(realm, locator);
Controller controller = executionHandler.getController(realm, locator);
if (controller != null) {
try {
if (!controller.isStopped(locator))
controller.toExecuted(locator);
} catch (Exception e) {
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,
ResourceBundle.getBundle("strolch-service"), "execution.handler.failed.executed")
.withException(e).value("reason", e));
}
}
}
}
private class SimulationTask implements Runnable {

View File

@ -0,0 +1,35 @@
package li.strolch.execution.command;
import li.strolch.execution.policy.ExecutionPolicy;
import li.strolch.model.activity.Action;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.utils.dbc.DBC;
public abstract class ActionExecutionCommand extends BasePlanningAndExecutionCommand {
protected Action action;
private ExecutionPolicy executionPolicy;
public ActionExecutionCommand(StrolchTransaction tx) {
super(tx);
}
public void setAction(Action action) {
this.action = action;
}
public void setExecutionPolicy(ExecutionPolicy executionPolicy) {
this.executionPolicy = executionPolicy;
}
protected ExecutionPolicy getExecutionPolicy(Action action) {
if (this.executionPolicy != null)
return this.executionPolicy;
return tx().getPolicy(action.getPolicyDef(ExecutionPolicy.class));
}
@Override
public void validate() {
DBC.PRE.assertNotNull("action can not be null", this.action);
}
}

View File

@ -0,0 +1,44 @@
package li.strolch.execution.command;
import static li.strolch.execution.policy.ActivityArchivalPolicy.DEFAULT_ACTIVITY_ARCHIVAL;
import li.strolch.execution.policy.ActivityArchivalPolicy;
import li.strolch.model.Locator;
import li.strolch.model.activity.Activity;
import li.strolch.model.policy.PolicyDef;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.service.api.Command;
import li.strolch.utils.dbc.DBC;
public class ArchiveActivityCommand extends Command {
private Locator activityLoc;
public ArchiveActivityCommand(StrolchTransaction tx) {
super(tx);
}
public void setActivityLoc(Locator activityLoc) {
this.activityLoc = activityLoc;
}
@Override
public void validate() {
DBC.PRE.assertNotNull("activity can not be null!", this.activityLoc);
}
@Override
public void doCommand() {
Activity activity = tx().getActivityBy(this.activityLoc.get(1), this.activityLoc.get(2));
if (activity == null) {
logger.error("Activity " + this.activityLoc + " does not exist anymore, can not archive!");
return;
}
logger.info("Activity " + activity.getLocator() + " is in state " + activity.getState());
PolicyDef policyDef = activity.getPolicyDef(ActivityArchivalPolicy.class, DEFAULT_ACTIVITY_ARCHIVAL);
ActivityArchivalPolicy archivalPolicy = tx().getPolicy(policyDef);
archivalPolicy.archive(activity);
}
}

View File

@ -15,8 +15,7 @@
*/
package li.strolch.execution.command;
import static li.strolch.execution.command.ExecutionCommand.updateOrderState;
import static li.strolch.execution.policy.NoPlanning.NO_PLANNING;
import static li.strolch.execution.policy.NoPlanning.DEFAULT_PLANNING;
import li.strolch.execution.policy.PlanningPolicy;
import li.strolch.model.Resource;
@ -69,14 +68,9 @@ public class AssignActionCommand extends PlanningCommand {
@Override
public void doCommand() {
validate();
Activity rootElement = this.action.getRootElement();
tx().lock(rootElement);
State currentState = rootElement.getState();
this.action.accept(this);
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
}
@ -85,7 +79,7 @@ public class AssignActionCommand extends PlanningCommand {
// unplan the action
if (action.getState() == State.PLANNED) {
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, NO_PLANNING));
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, DEFAULT_PLANNING));
planningPolicy.unplan(action);
}
@ -94,7 +88,7 @@ public class AssignActionCommand extends PlanningCommand {
action.setResourceType(this.targetResourceType);
// finally plan the action to the assigned resource
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, NO_PLANNING));
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, DEFAULT_PLANNING));
planningPolicy.plan(action);
return null;

View File

@ -0,0 +1,63 @@
package li.strolch.execution.command;
import static li.strolch.execution.policy.ConfirmationPolicy.DEFAULT_CONFIRMATION;
import static li.strolch.execution.policy.NoPlanning.DEFAULT_PLANNING;
import static li.strolch.runtime.StrolchConstants.PolicyConstants.PARAM_ORDER;
import li.strolch.execution.policy.ConfirmationPolicy;
import li.strolch.execution.policy.PlanningPolicy;
import li.strolch.model.Locator;
import li.strolch.model.Order;
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.policy.PolicyDef;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.policy.PolicyHandler;
import li.strolch.service.api.Command;
public abstract class BasePlanningAndExecutionCommand extends Command {
public BasePlanningAndExecutionCommand(StrolchTransaction tx) {
super(tx);
}
protected Resource getResource(Action action) {
Locator resourceLocator = action.getResourceLocator();
return tx().getResourceBy(resourceLocator.get(1), resourceLocator.get(2), true);
}
protected static void updateOrderState(StrolchTransaction tx, Activity rootElement, State currentState,
State newState) {
if (currentState == newState)
return;
Order order = tx.getOrderByRelation(rootElement, PARAM_ORDER);
if (order == null) {
logger.warn("Did not find activity order by relation " + PARAM_ORDER + " for activity " + rootElement
.getLocator() + ", trying by Activity type and id");
order = tx.getOrderBy(rootElement.getType(), rootElement.getId());
if (order == null) {
logger.error("Could not find order by Activity type and id either, not updating order state!");
return;
}
}
order.setState(rootElement.getState());
tx.update(order);
}
protected ConfirmationPolicy getConfirmationPolicy(Action action) {
Resource resource = getResource(action);
PolicyDef executionPolicyDef = resource.getPolicyDefs()
.getPolicyDef(ConfirmationPolicy.class.getSimpleName(), DEFAULT_CONFIRMATION);
return getComponent(PolicyHandler.class).getPolicy(executionPolicyDef, tx());
}
protected PlanningPolicy getPlanningPolicy(Action action) {
PolicyDef planningPolicyDef = action.findPolicy(PlanningPolicy.class, DEFAULT_PLANNING);
return getComponent(PolicyHandler.class).getPolicy(planningPolicyDef, tx());
}
}

View File

@ -1,42 +1,186 @@
package li.strolch.execution.command;
import li.strolch.agent.api.ComponentContainer;
import java.util.Iterator;
import java.util.Map.Entry;
import li.strolch.execution.Controller;
import li.strolch.execution.policy.ConfirmationPolicy;
import li.strolch.execution.policy.ExecutionPolicy;
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.activity.TimeOrderingVisitor;
import li.strolch.model.visitor.IActivityElementVisitor;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.utils.dbc.DBC;
public class ExecuteActivityCommand extends ExecutionCommand {
public class ExecuteActivityCommand extends BasePlanningAndExecutionCommand
implements TimeOrderingVisitor, IActivityElementVisitor<Void> {
private Activity activity;
private Controller controller;
private boolean needsRetriggerOfExecution;
public ExecuteActivityCommand(ComponentContainer container, StrolchTransaction tx) {
super(container, tx);
public ExecuteActivityCommand(StrolchTransaction tx) {
super(tx);
}
public void setActivity(Activity activity) {
this.activity = activity;
public void setController(Controller controller) {
this.controller = controller;
}
private ExecutionPolicy getExecutionPolicy(Action action) {
return this.controller.getExecutionPolicy(tx(), action);
}
public boolean needsRetriggerOfExecution() {
return this.needsRetriggerOfExecution;
}
@Override
public void validate() {
DBC.PRE.assertNotNull("activity can not be null!", this.activity);
tx().lock(this.activity.getRootElement());
DBC.PRE.assertNotNull("controller can not be null!", this.controller);
}
@Override
public void doCommand() {
Activity rootElement = this.activity.getRootElement();
tx().lock(rootElement);
State currentState = rootElement.getState();
this.activity.accept(this);
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
Activity activity = this.controller.getActivity();
State currentState = activity.getState();
activity.accept(this);
updateOrderState(tx(), activity, currentState, activity.getState());
}
@Override
public void undo() {
// can't undo execution
public Void visitAction(Action action) {
execute(action);
return null;
}
public void execute(Action action) {
// first plan
if (action.getState().compareTo(State.PLANNED) < 0) {
getPlanningPolicy(action).plan(action);
if (action.getState() != State.PLANNED) {
logger.info("Action " + action.getLocator() + " was not planned, can thus not executed.");
return;
}
}
tx().lock(action.getResourceLocator());
tx().removeFromCache(action.getResourceLocator());
ConfirmationPolicy confirmationPolicy = getConfirmationPolicy(action);
ExecutionPolicy executionPolicy = getExecutionPolicy(action);
if (!executionPolicy.isExecutable(action)) {
logger.info("Action " + action.getLocator() + " is not yet executable.");
return;
}
logger.info("Action " + action.getLocator() + " is now being executed...");
// we catch all exceptions because we can't undo, thus need to set the state to ERROR in this case
// this is only required because we execute actions in same TX as we set to executed any previous actions
try {
executionPolicy.initialize(action);
executionPolicy.toExecution(action);
confirmationPolicy.toExecution(action);
if (action.getState() == State.EXECUTED)
this.needsRetriggerOfExecution = true;
} catch (Exception e) {
logger.error("Failed to set " + action.getLocator() + " to execution due to " + e.getMessage(), e);
try {
executionPolicy.stop();
} catch (Exception ex) {
logger.error("Failed to stop execution policy for " + action.getLocator(), e);
}
action.setState(State.ERROR);
tx().update(action.getRootElement());
confirmationPolicy.toError(action);
}
}
protected boolean isExecutable(IActivityElement element) {
State state = element.getState();
if (state.compareTo(State.EXECUTED) >= 0)
return false;
if (element instanceof Activity)
return true;
// not yet in execution
if (state.compareTo(State.EXECUTION) < 0)
return true;
// in stopped, means we can re-execute
if (state == State.STOPPED)
return true;
// if in ERROR, then must first be handled
return false;
}
@Override
public void visitSeries(Activity activity) {
if (activity.getState().compareTo(State.EXECUTED) >= 0)
return;
Iterator<Entry<String, IActivityElement>> iter = activity.elementIterator();
while (iter.hasNext()) {
IActivityElement element = iter.next().getValue();
State state = element.getState();
if (element.getState().compareTo(State.EXECUTED) >= 0)
continue;
// in series we can never have two Actions in execution, so if we found the action in execution, we stop
if (element instanceof Action //
&& (state == State.EXECUTION //
|| state == State.WARNING //
|| state == State.ERROR)) {
break;
}
boolean canExecute = isExecutable(element);
if (canExecute) {
element.accept(this);
// in series we stop when the first action is set to execution
break;
}
}
}
@Override
public void visitParallel(Activity activity) {
if (activity.getState().compareTo(State.EXECUTED) >= 0)
return;
Iterator<Entry<String, IActivityElement>> iter = activity.elementIterator();
while (iter.hasNext()) {
IActivityElement element = iter.next().getValue();
if (element.getState().isExecuted())
continue;
// in parallel we execute all the actions in the activity
boolean canExecute = isExecutable(element);
if (canExecute) {
element.accept(this);
}
}
}
@Override
public Void visitActivity(Activity activity) {
activity.getTimeOrdering().accept(this, activity);
return null;
}
}

View File

@ -1,55 +0,0 @@
package li.strolch.execution.command;
import java.text.MessageFormat;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.exception.StrolchException;
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.utils.dbc.DBC;
public class ExecuteStoppedActionCommand extends ExecutionCommand {
private Action action;
public ExecuteStoppedActionCommand(ComponentContainer container, StrolchTransaction tx) {
super(container, tx);
}
public void setAction(Action action) {
this.action = action;
}
@Override
public void validate() {
DBC.PRE.assertNotNull("action can not be null", this.action);
tx().lock(this.action.getRootElement());
tx().lock(getResourceLocator(this.action));
if (this.action.getState() != State.STOPPED) {
String msg = "Action {0} is not in state " + State.STOPPED + " and can thus not be put into execution!";
msg = MessageFormat.format(msg, this.action.getState(), State.ERROR, this.action.getLocator());
throw new StrolchException(msg);
}
}
@Override
public void doCommand() {
Activity rootElement = this.action.getRootElement();
tx().lock(rootElement);
tx().lock(getResourceLocator(this.action));
State currentState = rootElement.getState();
rootElement.accept(this);
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
}
@Override
public void undo() {
// can't undo execution
}
}

View File

@ -1,209 +0,0 @@
package li.strolch.execution.command;
import static li.strolch.execution.policy.NoPlanning.NO_PLANNING;
import static li.strolch.runtime.StrolchConstants.PolicyConstants.PARAM_ORDER;
import static li.strolch.utils.helper.StringHelper.DASH;
import static li.strolch.utils.helper.StringHelper.isEmpty;
import java.util.Iterator;
import java.util.Map.Entry;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.exception.StrolchException;
import li.strolch.execution.policy.ConfirmationPolicy;
import li.strolch.execution.policy.ExecutionPolicy;
import li.strolch.execution.policy.PlanningPolicy;
import li.strolch.model.Locator;
import li.strolch.model.Order;
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.activity.TimeOrderingVisitor;
import li.strolch.model.policy.PolicyDef;
import li.strolch.model.visitor.IActivityElementVisitor;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.policy.PolicyHandler;
import li.strolch.service.api.Command;
public abstract class ExecutionCommand extends Command implements TimeOrderingVisitor, IActivityElementVisitor<Void> {
public ExecutionCommand(ComponentContainer container, StrolchTransaction tx) {
super(container, tx);
}
protected Locator getResourceLocator(Action action) {
String resourceId = action.getResourceId();
if (isEmpty(resourceId) || resourceId.equals(DASH))
throw new StrolchException("No resourceId defined on action " + action.getLocator());
String resourceType = action.getResourceType();
if (isEmpty(resourceType) || resourceType.equals(DASH))
throw new StrolchException("No resourceType defined on action " + action.getLocator());
return Resource.locatorFor(resourceType, resourceId);
}
protected Resource getResource(Action action) {
String resourceId = action.getResourceId();
if (isEmpty(resourceId) || resourceId.equals(DASH))
throw new StrolchException("No resourceId defined on action " + action.getLocator());
String resourceType = action.getResourceType();
if (isEmpty(resourceType) || resourceType.equals(DASH))
throw new StrolchException("No resourceType defined on action " + action.getLocator());
return tx().getResourceBy(resourceType, resourceId, true);
}
protected static void updateOrderState(StrolchTransaction tx, Activity rootElement, State currentState,
State newState) {
if (currentState == newState)
return;
Order order = tx.getOrderByRelation(rootElement, PARAM_ORDER);
if (order == null) {
logger.warn("Did not find activity order by relation " + PARAM_ORDER + " for activity " + rootElement
.getLocator() + ", trying by Activity type and id");
order = tx.getOrderBy(rootElement.getType(), rootElement.getId());
if (order == null) {
logger.error("Could not find order by Activity type and id either, not updating order state!");
return;
}
}
order.setState(rootElement.getState());
tx.update(order);
}
protected ExecutionPolicy getExecutionPolicy(Action action) {
Resource resource = getResource(action);
PolicyDef executionPolicyDef = resource.getPolicyDefs().getPolicyDef(ExecutionPolicy.class.getSimpleName());
return getComponent(PolicyHandler.class).getPolicy(executionPolicyDef, tx());
}
protected ConfirmationPolicy getConfirmationPolicy(Action action) {
Resource resource = getResource(action);
PolicyDef executionPolicyDef = resource.getPolicyDefs().getPolicyDef(ConfirmationPolicy.class.getSimpleName());
return getComponent(PolicyHandler.class).getPolicy(executionPolicyDef, tx());
}
@Override
public void visitSeries(Activity activity) {
if (activity.getState().compareTo(State.EXECUTED) >= 0)
return;
Iterator<Entry<String, IActivityElement>> iter = activity.elementIterator();
while (iter.hasNext()) {
IActivityElement element = iter.next().getValue();
State state = element.getState();
if (element.getState().compareTo(State.EXECUTED) >= 0)
continue;
// in series we can never have two Actions in execution, so if we found the action in execution, we stop
if (element instanceof Action //
&& (state == State.EXECUTION //
|| state == State.WARNING //
|| state == State.ERROR)) {
break;
}
boolean canExecute = isExecutable(element);
if (canExecute) {
element.accept(this);
// in series we stop when the first action is set to execution
break;
}
}
}
@Override
public void visitParallel(Activity activity) {
if (activity.getState().compareTo(State.EXECUTED) >= 0)
return;
Iterator<Entry<String, IActivityElement>> iter = activity.elementIterator();
while (iter.hasNext()) {
IActivityElement element = iter.next().getValue();
if (element.getState().isExecuted())
continue;
// in parallel we execute all the actions in the activity
boolean canExecute = isExecutable(element);
if (canExecute) {
element.accept(this);
}
}
}
protected boolean isExecutable(IActivityElement element) {
State state = element.getState();
if (state.compareTo(State.EXECUTED) >= 0)
return false;
if (element instanceof Activity)
return true;
// not yet in execution
if (state.compareTo(State.EXECUTION) < 0)
return true;
// in stopped, means we can re-execute
if (state == State.STOPPED)
return true;
// if in ERROR, then must first be handled
return false;
}
@Override
public Void visitActivity(Activity activity) {
activity.getTimeOrdering().accept(this, activity);
return null;
}
@Override
public Void visitAction(Action action) {
// first plan
if (action.getState().compareTo(State.PLANNED) < 0) {
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, NO_PLANNING));
planningPolicy.plan(action);
if (action.getState() != State.PLANNED) {
logger.info("Action " + action.getLocator() + " was not planned, can thus not executed.");
return null;
}
}
ExecutionPolicy executionPolicy = getExecutionPolicy(action);
tx().lock(getResourceLocator(action));
if (!executionPolicy.isExecutable(action)) {
logger.info("Action " + action.getLocator() + " is not yet executable.");
return null;
}
logger.info("Action " + action.getLocator() + " is now being executed...");
// we catch all exceptions because we can't undo, thus need to set the state to ERROR in this case
// this is only required because we execute actions in same TX as we set to executed any previous actions
try {
executionPolicy.toExecution(action);
getConfirmationPolicy(action).toExecution(action);
} catch (Exception e) {
logger.error("Failed to set " + action.getLocator() + " to execution due to " + e.getMessage(), e);
action.setState(State.ERROR);
tx().update(action.getRootElement());
getConfirmationPolicy(action).toError(action);
}
return null;
}
}

View File

@ -15,8 +15,7 @@
*/
package li.strolch.execution.command;
import static li.strolch.execution.command.ExecutionCommand.updateOrderState;
import static li.strolch.execution.policy.NoPlanning.NO_PLANNING;
import static li.strolch.execution.policy.NoPlanning.DEFAULT_PLANNING;
import li.strolch.execution.policy.PlanningPolicy;
import li.strolch.model.Resource;
@ -59,21 +58,18 @@ public class PlanActionCommand extends PlanningCommand {
@Override
public void doCommand() {
validate();
Activity rootElement = this.action.getRootElement();
tx().lock(rootElement);
State currentState = rootElement.getState();
this.action.accept(this);
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
}
@Override
public Void visitAction(Action action) {
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, NO_PLANNING));
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, DEFAULT_PLANNING));
planningPolicy.plan(action);
if (action.getState() == State.PLANNED)
getConfirmationPolicy(action).toPlanned(action);
return null;
}
}

View File

@ -15,8 +15,7 @@
*/
package li.strolch.execution.command;
import static li.strolch.execution.command.ExecutionCommand.updateOrderState;
import static li.strolch.execution.policy.NoPlanning.NO_PLANNING;
import static li.strolch.execution.policy.NoPlanning.DEFAULT_PLANNING;
import li.strolch.execution.policy.PlanningPolicy;
import li.strolch.model.Resource;
@ -59,21 +58,18 @@ public class PlanActivityCommand extends PlanningCommand {
@Override
public void doCommand() {
validate();
Activity rootElement = this.activity.getRootElement();
tx().lock(rootElement);
State currentState = rootElement.getState();
this.activity.accept(this);
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
}
@Override
public Void visitAction(Action action) {
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, NO_PLANNING));
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, DEFAULT_PLANNING));
planningPolicy.plan(action);
if (action.getState() == State.PLANNED)
getConfirmationPolicy(action).toPlanned(action);
return null;
}
}

View File

@ -23,22 +23,16 @@ import li.strolch.model.activity.Activity;
import li.strolch.model.activity.IActivityElement;
import li.strolch.model.visitor.IActivityElementVisitor;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.service.api.Command;
/**
* @author Martin Smock <martin.smock@bluewin.ch>
*/
public abstract class PlanningCommand extends Command implements IActivityElementVisitor<Void> {
public abstract class PlanningCommand extends BasePlanningAndExecutionCommand implements IActivityElementVisitor<Void> {
public PlanningCommand(StrolchTransaction tx) {
super(tx);
}
@Override
public void undo() {
// do nothing
}
@Override
public Void visitActivity(Activity activity) {
if (activity.getState().compareTo(State.PLANNED) >= 0)

View File

@ -2,7 +2,6 @@ package li.strolch.execution.command;
import java.text.MessageFormat;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.exception.StrolchException;
import li.strolch.model.State;
import li.strolch.model.activity.Action;
@ -10,12 +9,12 @@ import li.strolch.model.activity.Activity;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.utils.dbc.DBC;
public class SetActionToClosedCommand extends ExecutionCommand {
public class SetActionToClosedCommand extends BasePlanningAndExecutionCommand {
private Action action;
public SetActionToClosedCommand(ComponentContainer container, StrolchTransaction tx) {
super(container, tx);
public SetActionToClosedCommand(StrolchTransaction tx) {
super(tx);
}
public void setAction(Action action) {
@ -26,9 +25,6 @@ public class SetActionToClosedCommand extends ExecutionCommand {
public void validate() {
DBC.PRE.assertNotNull("action can not be null", this.action);
tx().lock(this.action.getRootElement());
tx().lock(getResourceLocator(this.action));
if (!this.action.getState().canSetToClosed()) {
String msg = "Current state is {0} and can not be changed to {1} for action {2}";
msg = MessageFormat.format(msg, this.action.getState(), State.CLOSED, this.action.getLocator());
@ -38,15 +34,12 @@ public class SetActionToClosedCommand extends ExecutionCommand {
@Override
public void doCommand() {
Activity rootElement = this.action.getRootElement();
tx().lock(rootElement);
tx().lock(getResourceLocator(this.action));
if (this.action.getState() == State.CLOSED) {
logger.warn("Action " + this.action.getLocator() + " is already in state CLOSED! Not changing.");
return;
}
Activity rootElement = this.action.getRootElement();
State currentState = rootElement.getState();
this.action.setState(State.CLOSED);
@ -55,9 +48,4 @@ public class SetActionToClosedCommand extends ExecutionCommand {
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
}
@Override
public void undo() {
// can not undo
}
}

View File

@ -2,7 +2,6 @@ package li.strolch.execution.command;
import java.text.MessageFormat;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.exception.StrolchException;
import li.strolch.model.State;
import li.strolch.model.activity.Action;
@ -10,12 +9,12 @@ import li.strolch.model.activity.Activity;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.utils.dbc.DBC;
public class SetActionToCreatedCommand extends ExecutionCommand {
public class SetActionToCreatedCommand extends BasePlanningAndExecutionCommand {
private Action action;
public SetActionToCreatedCommand(ComponentContainer container, StrolchTransaction tx) {
super(container, tx);
public SetActionToCreatedCommand(StrolchTransaction tx) {
super(tx);
}
public void setAction(Action action) {
@ -26,9 +25,6 @@ public class SetActionToCreatedCommand extends ExecutionCommand {
public void validate() {
DBC.PRE.assertNotNull("action can not be null", this.action);
tx().lock(this.action.getRootElement());
tx().lock(getResourceLocator(this.action));
if (!this.action.getState().canSetToCreated()) {
String msg = "Current state is {0} and can not be changed to {1} for action {2}";
msg = MessageFormat.format(msg, this.action.getState(), State.CREATED, this.action.getLocator());
@ -38,15 +34,12 @@ public class SetActionToCreatedCommand extends ExecutionCommand {
@Override
public void doCommand() {
Activity rootElement = this.action.getRootElement();
tx().lock(rootElement);
tx().lock(getResourceLocator(this.action));
if (this.action.getState() == State.CREATED) {
logger.warn("Action " + this.action.getLocator() + " is already in state CREATED! Not changing.");
return;
}
Activity rootElement = this.action.getRootElement();
State currentState = rootElement.getState();
this.action.setState(State.CREATED);
@ -55,9 +48,4 @@ public class SetActionToCreatedCommand extends ExecutionCommand {
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
}
@Override
public void undo() {
// can not undo
}
}

View File

@ -2,32 +2,20 @@ package li.strolch.execution.command;
import java.text.MessageFormat;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.exception.StrolchException;
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.utils.dbc.DBC;
public class SetActionToErrorCommand extends ExecutionCommand {
public class SetActionToErrorCommand extends ActionExecutionCommand {
private Action action;
public SetActionToErrorCommand(ComponentContainer container, StrolchTransaction tx) {
super(container, tx);
}
public void setAction(Action action) {
this.action = action;
public SetActionToErrorCommand(StrolchTransaction tx) {
super(tx);
}
@Override
public void validate() {
DBC.PRE.assertNotNull("action can not be null", this.action);
tx().lock(this.action.getRootElement());
tx().lock(getResourceLocator(this.action));
super.validate();
if (!this.action.getState().canSetToError()) {
String msg = "Current state is {0} and can not be changed to {1} for action {2}";
@ -38,15 +26,12 @@ public class SetActionToErrorCommand extends ExecutionCommand {
@Override
public void doCommand() {
Activity rootElement = this.action.getRootElement();
tx().lock(rootElement);
tx().lock(getResourceLocator(this.action));
if (this.action.getState() == State.ERROR) {
logger.warn("Action " + this.action.getLocator() + " is already in state ERROR! Not changing.");
return;
}
Activity rootElement = this.action.getRootElement();
State currentState = rootElement.getState();
getExecutionPolicy(this.action).toError(this.action);
@ -54,9 +39,4 @@ public class SetActionToErrorCommand extends ExecutionCommand {
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
}
@Override
public void undo() {
// can not undo
}
}

View File

@ -0,0 +1,43 @@
package li.strolch.execution.command;
import java.text.MessageFormat;
import li.strolch.exception.StrolchException;
import li.strolch.model.State;
import li.strolch.model.activity.Activity;
import li.strolch.persistence.api.StrolchTransaction;
public class SetActionToExecutableCommand extends ActionExecutionCommand {
public SetActionToExecutableCommand(StrolchTransaction tx) {
super(tx);
}
@Override
public void validate() {
super.validate();
if (!this.action.getState().canSetToExecutable()) {
String msg = "Current state is {0} and can not be changed to {1} for action {2}";
msg = MessageFormat.format(msg, this.action.getState(), State.EXECUTABLE, this.action.getLocator());
throw new StrolchException(msg);
}
}
@Override
public void doCommand() {
if (this.action.getState() == State.EXECUTABLE) {
logger.warn("Action " + this.action.getLocator() + " is already in state EXECUTABLE! Not changing.");
return;
}
Activity rootElement = this.action.getRootElement();
State currentState = rootElement.getState();
this.action.setState(State.EXECUTABLE);
getConfirmationPolicy(this.action).toExecutable(this.action);
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
}
}

View File

@ -2,32 +2,20 @@ package li.strolch.execution.command;
import java.text.MessageFormat;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.exception.StrolchException;
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.utils.dbc.DBC;
public class SetActionToExecutedCommand extends ExecutionCommand {
public class SetActionToExecutedCommand extends ActionExecutionCommand {
private Action action;
public SetActionToExecutedCommand(ComponentContainer container, StrolchTransaction tx) {
super(container, tx);
}
public void setAction(Action action) {
this.action = action;
public SetActionToExecutedCommand(StrolchTransaction tx) {
super(tx);
}
@Override
public void validate() {
DBC.PRE.assertNotNull("action can not be null", this.action);
tx().lock(this.action.getRootElement());
tx().lock(getResourceLocator(this.action));
super.validate();
if (!this.action.getState().canSetToExecuted()) {
String msg = "Current state is {0} can not be changed to {1} for action {2}";
@ -38,15 +26,12 @@ public class SetActionToExecutedCommand extends ExecutionCommand {
@Override
public void doCommand() {
Activity rootElement = this.action.getRootElement();
tx().lock(rootElement);
tx().lock(getResourceLocator(this.action));
if (this.action.getState() == State.EXECUTED) {
logger.warn("Action " + this.action.getLocator() + " is already in state EXECUTED! Not changing.");
return;
}
Activity rootElement = this.action.getRootElement();
State currentState = rootElement.getState();
getExecutionPolicy(this.action).toExecuted(this.action);
@ -54,9 +39,4 @@ public class SetActionToExecutedCommand extends ExecutionCommand {
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
}
@Override
public void undo() {
// can not undo
}
}

View File

@ -2,7 +2,6 @@ package li.strolch.execution.command;
import java.text.MessageFormat;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.exception.StrolchException;
import li.strolch.model.State;
import li.strolch.model.activity.Action;
@ -10,12 +9,12 @@ import li.strolch.model.activity.Activity;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.utils.dbc.DBC;
public class SetActionToPlannedCommand extends ExecutionCommand {
public class SetActionToPlannedCommand extends BasePlanningAndExecutionCommand {
private Action action;
public SetActionToPlannedCommand(ComponentContainer container, StrolchTransaction tx) {
super(container, tx);
public SetActionToPlannedCommand(StrolchTransaction tx) {
super(tx);
}
public void setAction(Action action) {
@ -26,9 +25,6 @@ public class SetActionToPlannedCommand extends ExecutionCommand {
public void validate() {
DBC.PRE.assertNotNull("action can not be null", this.action);
tx().lock(this.action.getRootElement());
tx().lock(getResourceLocator(this.action));
if (!this.action.getState().canSetToPlanned()) {
String msg = "Current state is {0} and can not be changed to {1} for action {2}";
msg = MessageFormat.format(msg, this.action.getState(), State.PLANNED, this.action.getLocator());
@ -38,15 +34,12 @@ public class SetActionToPlannedCommand extends ExecutionCommand {
@Override
public void doCommand() {
Activity rootElement = this.action.getRootElement();
tx().lock(rootElement);
tx().lock(getResourceLocator(this.action));
if (this.action.getState() == State.PLANNED) {
logger.warn("Action " + this.action.getLocator() + " is already in state PLANNED! Not changing.");
return;
}
Activity rootElement = this.action.getRootElement();
State currentState = rootElement.getState();
this.action.setState(State.PLANNED);
@ -55,9 +48,4 @@ public class SetActionToPlannedCommand extends ExecutionCommand {
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
}
@Override
public void undo() {
// can not undo
}
}

View File

@ -1,63 +0,0 @@
package li.strolch.execution.command;
import java.text.MessageFormat;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.exception.StrolchException;
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.utils.dbc.DBC;
public class SetActionToPlanningCommand extends ExecutionCommand {
private Action action;
public SetActionToPlanningCommand(ComponentContainer container, StrolchTransaction tx) {
super(container, tx);
}
public void setAction(Action action) {
this.action = action;
}
@Override
public void validate() {
DBC.PRE.assertNotNull("action can not be null", this.action);
tx().lock(this.action.getRootElement());
tx().lock(getResourceLocator(this.action));
if (!this.action.getState().canSetToPlanning()) {
String msg = "Current state is {0} and can not be changed to {1} for action {2}";
msg = MessageFormat.format(msg, this.action.getState(), State.PLANNING, this.action.getLocator());
throw new StrolchException(msg);
}
}
@Override
public void doCommand() {
Activity rootElement = this.action.getRootElement();
tx().lock(rootElement);
tx().lock(getResourceLocator(this.action));
if (this.action.getState() == State.PLANNING) {
logger.warn("Action " + this.action.getLocator() + " is already in state PLANNING! Not changing.");
return;
}
State currentState = rootElement.getState();
this.action.setState(State.PLANNING);
getConfirmationPolicy(this.action).toPlanning(this.action);
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
}
@Override
public void undo() {
// can not undo
}
}

View File

@ -2,32 +2,20 @@ package li.strolch.execution.command;
import java.text.MessageFormat;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.exception.StrolchException;
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.utils.dbc.DBC;
public class SetActionToStoppedCommand extends ExecutionCommand {
public class SetActionToStoppedCommand extends ActionExecutionCommand {
private Action action;
public SetActionToStoppedCommand(ComponentContainer container, StrolchTransaction tx) {
super(container, tx);
}
public void setAction(Action action) {
this.action = action;
public SetActionToStoppedCommand(StrolchTransaction tx) {
super(tx);
}
@Override
public void validate() {
DBC.PRE.assertNotNull("action can not be null", this.action);
tx().lock(this.action.getRootElement());
tx().lock(getResourceLocator(this.action));
super.validate();
if (!this.action.getState().canSetToStopped()) {
String msg = "Current state is {0} and can not be changed to {1} for action {2}";
@ -38,15 +26,12 @@ public class SetActionToStoppedCommand extends ExecutionCommand {
@Override
public void doCommand() {
Activity rootElement = this.action.getRootElement();
tx().lock(rootElement);
tx().lock(getResourceLocator(this.action));
if (this.action.getState() == State.STOPPED) {
logger.warn("Action " + this.action.getLocator() + " is already in state STOPPED! Not changing.");
return;
}
Activity rootElement = this.action.getRootElement();
State currentState = rootElement.getState();
getExecutionPolicy(this.action).toStopped(this.action);
@ -54,9 +39,4 @@ public class SetActionToStoppedCommand extends ExecutionCommand {
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
}
@Override
public void undo() {
// can not undo
}
}

View File

@ -2,32 +2,20 @@ package li.strolch.execution.command;
import java.text.MessageFormat;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.exception.StrolchException;
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.utils.dbc.DBC;
public class SetActionToWarningCommand extends ExecutionCommand {
public class SetActionToWarningCommand extends ActionExecutionCommand {
private Action action;
public SetActionToWarningCommand(ComponentContainer container, StrolchTransaction tx) {
super(container, tx);
}
public void setAction(Action action) {
this.action = action;
public SetActionToWarningCommand(StrolchTransaction tx) {
super(tx);
}
@Override
public void validate() {
DBC.PRE.assertNotNull("action can not be null", this.action);
tx().lock(this.action.getRootElement());
tx().lock(getResourceLocator(this.action));
super.validate();
if (!this.action.getState().canSetToWarning()) {
String msg = "Current state is {0} and can not be changed to {1} for action {2}";
@ -38,15 +26,12 @@ public class SetActionToWarningCommand extends ExecutionCommand {
@Override
public void doCommand() {
Activity rootElement = this.action.getRootElement();
tx().lock(rootElement);
tx().lock(getResourceLocator(this.action));
if (this.action.getState() == State.WARNING) {
logger.warn("Action " + this.action.getLocator() + " is already in state WARNING! Not changing.");
return;
}
Activity rootElement = this.action.getRootElement();
State currentState = rootElement.getState();
getExecutionPolicy(this.action).toWarning(this.action);
@ -54,9 +39,4 @@ public class SetActionToWarningCommand extends ExecutionCommand {
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
}
@Override
public void undo() {
// can not undo
}
}

View File

@ -15,8 +15,7 @@
*/
package li.strolch.execution.command;
import static li.strolch.execution.command.ExecutionCommand.updateOrderState;
import static li.strolch.execution.policy.NoPlanning.NO_PLANNING;
import static li.strolch.execution.policy.NoPlanning.DEFAULT_PLANNING;
import java.util.List;
@ -59,14 +58,9 @@ public class ShiftActionCommand extends PlanningCommand {
@Override
public void doCommand() {
validate();
Activity rootElement = this.action.getRootElement();
tx().lock(rootElement);
State currentState = rootElement.getState();
this.action.accept(this);
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
}
@ -75,8 +69,10 @@ public class ShiftActionCommand extends PlanningCommand {
// unplan the action
if (action.getState() == State.PLANNED) {
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, NO_PLANNING));
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, DEFAULT_PLANNING));
planningPolicy.unplan(action);
if (action.getState() == State.CREATED)
getConfirmationPolicy(action).toCreated(action);
}
// iterate all changes and shift
@ -86,8 +82,10 @@ public class ShiftActionCommand extends PlanningCommand {
}
// finally plan the action
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, NO_PLANNING));
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, DEFAULT_PLANNING));
planningPolicy.plan(action);
if (action.getState() == State.PLANNED)
getConfirmationPolicy(action).toPlanned(action);
return null;
}
}

View File

@ -15,8 +15,7 @@
*/
package li.strolch.execution.command;
import static li.strolch.execution.command.ExecutionCommand.updateOrderState;
import static li.strolch.execution.policy.NoPlanning.NO_PLANNING;
import static li.strolch.execution.policy.NoPlanning.DEFAULT_PLANNING;
import li.strolch.execution.policy.PlanningPolicy;
import li.strolch.model.Resource;
@ -61,21 +60,18 @@ public class UnplanActionCommand extends PlanningCommand {
@Override
public void doCommand() {
validate();
Activity rootElement = this.action.getRootElement();
tx().lock(rootElement);
State currentState = rootElement.getState();
this.action.accept(this);
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
}
@Override
public Void visitAction(Action action) {
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, NO_PLANNING));
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, DEFAULT_PLANNING));
planningPolicy.unplan(action);
if (action.getState() == State.CREATED)
getConfirmationPolicy(action).toCreated(action);
return null;
}
}

View File

@ -15,8 +15,7 @@
*/
package li.strolch.execution.command;
import static li.strolch.execution.command.ExecutionCommand.updateOrderState;
import static li.strolch.execution.policy.NoPlanning.NO_PLANNING;
import static li.strolch.execution.policy.NoPlanning.DEFAULT_PLANNING;
import li.strolch.execution.policy.PlanningPolicy;
import li.strolch.model.Resource;
@ -59,21 +58,18 @@ public class UnplanActivityCommand extends PlanningCommand {
@Override
public void doCommand() {
validate();
Activity rootElement = this.activity.getRootElement();
tx().lock(rootElement);
State currentState = rootElement.getState();
this.activity.accept(this);
updateOrderState(tx(), rootElement, currentState, rootElement.getState());
}
@Override
public Void visitAction(Action action) {
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, NO_PLANNING));
PlanningPolicy planningPolicy = tx().getPolicy(action.findPolicy(PlanningPolicy.class, DEFAULT_PLANNING));
planningPolicy.unplan(action);
if (action.getState() == State.CREATED)
getConfirmationPolicy(action).toCreated(action);
return null;
}
}

View File

@ -2,6 +2,7 @@ package li.strolch.execution.policy;
import li.strolch.model.State;
import li.strolch.model.activity.Activity;
import li.strolch.model.policy.PolicyDef;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.policy.StrolchPolicy;
@ -14,6 +15,9 @@ import li.strolch.policy.StrolchPolicy;
*/
public class ActivityArchivalPolicy extends StrolchPolicy {
public static PolicyDef DEFAULT_ACTIVITY_ARCHIVAL = PolicyDef
.valueOf(ActivityArchivalPolicy.class.getSimpleName(), "key:DefaultActivityArchival");
public ActivityArchivalPolicy(StrolchTransaction tx) {
super(tx);
}

View File

@ -1,6 +1,7 @@
package li.strolch.execution.policy;
import li.strolch.model.activity.Action;
import li.strolch.model.policy.PolicyDef;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.policy.StrolchPolicy;
@ -12,6 +13,9 @@ import li.strolch.policy.StrolchPolicy;
*/
public class ConfirmationPolicy extends StrolchPolicy {
public static PolicyDef DEFAULT_CONFIRMATION = PolicyDef
.valueOf(ConfirmationPolicy.class.getSimpleName(), "key:DefaultConfirmation");
public ConfirmationPolicy(StrolchTransaction tx) {
super(tx);
}
@ -20,11 +24,11 @@ public class ConfirmationPolicy extends StrolchPolicy {
// do nothing
}
public void toPlanning(Action action) {
public void toPlanned(Action action) {
// do nothing
}
public void toPlanned(Action action) {
public void toExecutable(Action action) {
// do nothing
}

View File

@ -16,6 +16,8 @@ import li.strolch.runtime.StrolchConstants.PolicyConstants;
*/
public class DurationExecution extends SimpleExecution {
protected Locator actionLoc;
public DurationExecution(StrolchTransaction tx) {
super(tx);
}
@ -27,10 +29,15 @@ public class DurationExecution extends SimpleExecution {
.findParameter(PolicyConstants.BAG_OBJECTIVES, PolicyConstants.PARAM_DURATION, true);
String realmName = tx().getRealmName();
Locator locator = action.getLocator();
logger.info("Executing action " + action.getLocator() + " has a duration of " + durationP.getValueAsString());
getDelayedExecutionTimer().execute(realmName, getContainer(), locator, durationP.toMillis());
this.actionLoc = action.getLocator();
logger.info("Executing action " + actionLoc + " has a duration of " + durationP.getValueAsString());
getDelayedExecutionTimer().execute(realmName, getContainer(), this.actionLoc, durationP.toMillis());
super.toExecution(action);
}
@Override
protected void handleStopped() {
getDelayedExecutionTimer().cancel(this.actionLoc);
}
}

View File

@ -3,8 +3,10 @@ package li.strolch.execution.policy;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.StrolchRealm;
import li.strolch.exception.StrolchException;
import li.strolch.execution.Controller;
import li.strolch.execution.DelayedExecutionTimer;
import li.strolch.execution.ExecutionHandler;
import li.strolch.model.Locator;
import li.strolch.model.State;
import li.strolch.model.activity.Action;
import li.strolch.model.activity.Activity;
@ -33,6 +35,12 @@ import li.strolch.runtime.privilege.PrivilegedRunnableWithResult;
*/
public abstract class ExecutionPolicy extends StrolchPolicy {
private Controller controller;
private boolean stopped;
protected String actionType;
protected Locator actionLoc;
/**
* 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
@ -44,6 +52,19 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
this.tx = tx;
}
public void setController(StrolchTransaction tx, Controller controller) {
this.tx = tx;
this.controller = controller;
}
public Controller getController() {
return this.controller;
}
public boolean isStopped() {
return this.stopped;
}
/**
* Returns the TX which is defined on this class, not the one defined on {@link StrolchPolicy}
*/
@ -76,6 +97,18 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
return true;
}
/**
* 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
*/
public void initialize(Action action) {
this.actionType = action.getType();
this.actionLoc = action.getLocator();
}
/**
* Starts the execution of the given {@link Action}, i.e. sets the state to {@link State#EXECUTION}
*
@ -119,6 +152,21 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
*/
public abstract void toWarning(Action action);
/**
* Stops any active components in this {@link ExecutionPolicy}. This is used to notify the {@link ExecutionPolicy}
* that any scheduled actions should be stopped, that listening and observing registrations can be taken back, etc.
*/
public void stop() {
this.stopped = true;
try {
handleStopped();
} catch (Exception e) {
logger.error("Stopping failed for " + this.actionLoc, e);
}
}
protected abstract void handleStopped();
protected void setActionState(Action action, State state) {
action.setState(state);
@ -142,15 +190,6 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
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.
@ -206,9 +245,4 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
throws PrivilegeException, Exception {
return getContainer().getPrivilegeHandler().runWithResult(StrolchConstants.SYSTEM_USER_AGENT, runnable);
}
@Override
public void undo() {
// do nothing
}
}

View File

@ -9,7 +9,7 @@ import li.strolch.utils.dbc.DBC;
public class NoPlanning extends PlanningPolicy {
public static PolicyDef NO_PLANNING = PolicyDef
public static PolicyDef DEFAULT_PLANNING = PolicyDef
.valueOf(PlanningPolicy.class.getSimpleName(), "key:DefaultPlanning");
public NoPlanning(StrolchTransaction tx) {

View File

@ -52,8 +52,9 @@ public class ReservationExecution extends DurationExecution {
}
protected boolean isReserved(Action action) {
// get resource
Resource resource = getResource(action);
Resource resource = tx().getResourceFor(action, true);
if (!resource.hasParameter(BAG_PARAMETERS, PARAM_RESERVED))
throw new StrolchModelException(
@ -66,55 +67,55 @@ public class ReservationExecution extends DurationExecution {
@Override
public void toExecution(Action action) {
switch (action.getType()) {
// only do if reserve or release
boolean isReserve = action.getType().equals(TYPE_RESERVE);
boolean isRelease = action.getType().equals(TYPE_RELEASE);
if (!isReserve && !isRelease) {
// otherwise delegate to super class
case TYPE_RESERVE:
case TYPE_RELEASE:
boolean isReserve = action.getType().equals(TYPE_RESERVE);
setReservation(action, isReserve);
String realmName = tx().getRealmName();
Locator locator = action.getLocator();
getDelayedExecutionTimer().execute(realmName, getContainer(), locator, 0L);
setActionState(action, State.EXECUTION);
break;
default:
super.toExecution(action);
return;
}
setReservation(action);
String realmName = tx().getRealmName();
Locator locator = action.getLocator();
getDelayedExecutionTimer().execute(realmName, getContainer(), locator, 0L);
setActionState(action, State.EXECUTION);
}
@Override
public void toExecuted(Action action) {
// only do if reserve or release
boolean isReserve = action.getType().equals(TYPE_RESERVE);
boolean isRelease = action.getType().equals(TYPE_RELEASE);
if (!isReserve && !isRelease) {
// otherwise delegate to super class
switch (action.getType()) {
case TYPE_RESERVE:
case TYPE_RELEASE:
boolean isReserve = action.getType().equals(TYPE_RESERVE);
setReservation(action, isReserve);
FloatValue value = new FloatValue(isReserve ? 1.0D : 0.0D);
action.addChange(new ValueChange<>(System.currentTimeMillis(), value, ""));
setActionState(action, State.EXECUTED);
break;
default:
super.toExecuted(action);
return;
}
setReservation(action);
setActionState(action, State.EXECUTED);
FloatValue value = new FloatValue(isReserve ? 1.0D : 0.0D);
action.addChange(new ValueChange<>(System.currentTimeMillis(), value, ""));
}
public void setReservation(Action action) {
private void setReservation(Action action, boolean isReserve) {
Resource resource = getResource(action);
boolean reserved = action.getType().equals(TYPE_RESERVE);
Resource resource = tx().getResourceFor(action, true);
// release the resource
BooleanParameter reservedP = resource.getParameter(BAG_PARAMETERS, PARAM_RESERVED);
reservedP.setValue(reserved);
reservedP.setValue(isReserve);
// save changes
tx().update(resource);

View File

@ -36,6 +36,8 @@ public class SimpleExecution extends ExecutionPolicy {
@Override
public void toExecuted(Action action) {
stop();
setActionState(action, State.EXECUTED);
FloatValue value = new FloatValue(0.0D);
@ -44,7 +46,8 @@ public class SimpleExecution extends ExecutionPolicy {
@Override
public void toStopped(Action action) {
getDelayedExecutionTimer().cancel(action.getLocator());
stop();
setActionState(action, State.STOPPED);
FloatValue value = new FloatValue(0.0D);
@ -53,7 +56,8 @@ public class SimpleExecution extends ExecutionPolicy {
@Override
public void toError(Action action) {
getDelayedExecutionTimer().cancel(action.getLocator());
stop();
setActionState(action, State.ERROR);
FloatValue value = new FloatValue(0.0D);
@ -68,18 +72,20 @@ public class SimpleExecution extends ExecutionPolicy {
}
protected void toError(LogMessage message) {
stop();
logger.error("Action " + message.getLocator() + " failed because of: " + message.formatMessage());
addMessage(message);
getExecutionHandler().toError(message.getRealm(), message.getLocator());
getController().asyncToError(message.getLocator());
}
protected void toWarning(LogMessage message) {
stop();
addMessage(message);
getExecutionHandler().toWarning(message.getRealm(), message.getLocator());
getController().asyncToWarning(message.getLocator());
}
@Override
public void undo() {
logger.error("Can not undo execution policy " + getClass());
protected void handleStopped() {
getDelayedExecutionTimer().cancel(this.actionLoc);
}
}

View File

@ -29,8 +29,6 @@ public class ToErrorReservationExecution extends ReservationExecution {
@Override
public boolean isExecutable(Action action) {
tx().lock(getResource(action));
if (action.getType().equals(TYPE_RESERVE)) {
return true;
}
@ -41,14 +39,12 @@ public class ToErrorReservationExecution extends ReservationExecution {
@Override
public void toExecution(Action action) {
tx().lock(getResource(action));
if (action.getType().equals(TYPE_RESERVE) && isReserved(action)) {
setActionState(action, State.EXECUTION);
toError(new LogMessage(tx().getRealmName(), tx().getCertificate().getUsername(), action.getLocator(),
LogSeverity.Error, ResourceBundle.getBundle("strolch-service"),
"execution.policy.reservation.alreadyReserved")
.value("resourceLoc", getResource(action).getLocator().toString()));
.value("resourceLoc", action.getResourceLocator().toString()));
} else {
super.toExecution(action);
}

View File

@ -1,14 +1,16 @@
package li.strolch.execution.service;
import li.strolch.execution.command.SetActionToPlanningCommand;
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.service.LocatorArgument;
import li.strolch.service.api.AbstractService;
import li.strolch.service.api.ServiceResult;
import li.strolch.service.api.ServiceResultState;
public class SetActionToPlanningService extends AbstractService<LocatorArgument, ServiceResult> {
public class ExecuteActionService extends AbstractService<LocatorArgument, ServiceResult> {
@Override
protected ServiceResult getResultInstance() {
@ -23,17 +25,27 @@ public class SetActionToPlanningService extends AbstractService<LocatorArgument,
@Override
protected ServiceResult internalDoService(LocatorArgument arg) throws Exception {
String realm;
Activity activity;
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
realm = tx.getRealmName();
tx.lock(arg.locator.trim(3));
Action action = tx.findElement(arg.locator);
SetActionToPlanningCommand command = new SetActionToPlanningCommand(getContainer(), tx);
command.setAction(action);
tx.addCommand(command);
// this is so we can re-execute stopped actions
if (action.getState() == State.STOPPED) {
action.setState(State.EXECUTABLE);
tx.commitOnClose();
tx.update(action.getRootElement());
tx.commitOnClose();
}
activity = action.getRootElement();
}
getComponent(ExecutionHandler.class).toExecution(realm, activity);
return ServiceResult.success();
}
}

View File

@ -1,144 +0,0 @@
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"));
String realm;
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
realm = tx.getRealmName();
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();
}
ExecutionHandler executionHandler = getContainer().getComponent(ExecutionHandler.class);
executionHandler.triggerExecution(realm);
return ServiceResult.success();
}
}

View File

@ -25,9 +25,11 @@ public class SetActionToClosedService extends AbstractService<LocatorArgument, S
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
tx.lock(arg.locator.trim(3));
Action action = tx.findElement(arg.locator);
tx.lock(action.getResourceLocator());
SetActionToClosedCommand command = new SetActionToClosedCommand(getContainer(), tx);
SetActionToClosedCommand command = new SetActionToClosedCommand(tx);
command.setAction(action);
tx.addCommand(command);

View File

@ -25,9 +25,12 @@ public class SetActionToCreatedService extends AbstractService<LocatorArgument,
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
tx.lock(arg.locator.trim(3));
Action action = tx.findElement(arg.locator);
if (action.hasResourceDefined())
tx.lock(action.getResourceLocator());
SetActionToCreatedCommand command = new SetActionToCreatedCommand(getContainer(), tx);
SetActionToCreatedCommand command = new SetActionToCreatedCommand(tx);
command.setAction(action);
tx.addCommand(command);

View File

@ -1,5 +1,7 @@
package li.strolch.execution.service;
import li.strolch.execution.Controller;
import li.strolch.execution.ExecutionHandler;
import li.strolch.execution.command.SetActionToErrorCommand;
import li.strolch.model.activity.Action;
import li.strolch.persistence.api.StrolchTransaction;
@ -25,11 +27,20 @@ public class SetActionToErrorService extends AbstractService<LocatorArgument, Se
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
tx.lock(arg.locator.trim(3));
Action action = tx.findElement(arg.locator);
tx.lock(action.getResourceLocator());
SetActionToErrorCommand command = new SetActionToErrorCommand(getContainer(), tx);
command.setAction(action);
tx.addCommand(command);
ExecutionHandler executionHandler = getComponent(ExecutionHandler.class);
Controller controller = executionHandler.getController(tx.getRealmName(), action.getRootElement());
if (controller != null) {
controller.toError(action.getLocator());
} else {
SetActionToErrorCommand command = new SetActionToErrorCommand(tx);
command.setAction(action);
tx.addCommand(command);
}
tx.commitOnClose();
}

View File

@ -1,5 +1,7 @@
package li.strolch.execution.service;
import li.strolch.execution.Controller;
import li.strolch.execution.ExecutionHandler;
import li.strolch.execution.command.SetActionToExecutedCommand;
import li.strolch.model.activity.Action;
import li.strolch.persistence.api.StrolchTransaction;
@ -25,11 +27,19 @@ public class SetActionToExecutedService extends AbstractService<LocatorArgument,
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
tx.lock(arg.locator.trim(3));
Action action = tx.findElement(arg.locator);
tx.lock(action.getResourceLocator());
SetActionToExecutedCommand command = new SetActionToExecutedCommand(getContainer(), tx);
command.setAction(action);
tx.addCommand(command);
ExecutionHandler executionHandler = getComponent(ExecutionHandler.class);
Controller controller = executionHandler.getController(tx.getRealmName(), action.getRootElement());
if (controller != null) {
controller.toExecuted(action.getLocator());
} else {
SetActionToExecutedCommand command = new SetActionToExecutedCommand(tx);
command.setAction(action);
tx.addCommand(command);
}
tx.commitOnClose();
}

View File

@ -25,9 +25,12 @@ public class SetActionToPlannedService extends AbstractService<LocatorArgument,
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
tx.lock(arg.locator.trim(3));
Action action = tx.findElement(arg.locator);
if (!action.hasResourceDefined())
return ServiceResult.error("Resource not defined for " + action.getLocator());
SetActionToPlannedCommand command = new SetActionToPlannedCommand(getContainer(), tx);
SetActionToPlannedCommand command = new SetActionToPlannedCommand(tx);
command.setAction(action);
tx.addCommand(command);

View File

@ -1,5 +1,7 @@
package li.strolch.execution.service;
import li.strolch.execution.Controller;
import li.strolch.execution.ExecutionHandler;
import li.strolch.execution.command.SetActionToStoppedCommand;
import li.strolch.model.activity.Action;
import li.strolch.persistence.api.StrolchTransaction;
@ -25,11 +27,19 @@ public class SetActionToStoppedService extends AbstractService<LocatorArgument,
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
tx.lock(arg.locator.trim(3));
Action action = tx.findElement(arg.locator);
tx.lock(action.getResourceLocator());
SetActionToStoppedCommand command = new SetActionToStoppedCommand(getContainer(), tx);
command.setAction(action);
tx.addCommand(command);
ExecutionHandler executionHandler = getComponent(ExecutionHandler.class);
Controller controller = executionHandler.getController(tx.getRealmName(), action.getRootElement());
if (controller != null) {
controller.toStopped(action.getLocator());
} else {
SetActionToStoppedCommand command = new SetActionToStoppedCommand(tx);
command.setAction(action);
tx.addCommand(command);
}
tx.commitOnClose();
}

View File

@ -1,5 +1,7 @@
package li.strolch.execution.service;
import li.strolch.execution.Controller;
import li.strolch.execution.ExecutionHandler;
import li.strolch.execution.command.SetActionToWarningCommand;
import li.strolch.model.activity.Action;
import li.strolch.persistence.api.StrolchTransaction;
@ -25,11 +27,19 @@ public class SetActionToWarningService extends AbstractService<LocatorArgument,
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
tx.lock(arg.locator.trim(3));
Action action = tx.findElement(arg.locator);
tx.lock(action.getResourceLocator());
SetActionToWarningCommand command = new SetActionToWarningCommand(getContainer(), tx);
command.setAction(action);
tx.addCommand(command);
ExecutionHandler executionHandler = getComponent(ExecutionHandler.class);
Controller controller = executionHandler.getController(tx.getRealmName(), action.getRootElement());
if (controller != null) {
controller.toWarning(action.getLocator());
} else {
SetActionToWarningCommand command = new SetActionToWarningCommand(tx);
command.setAction(action);
tx.addCommand(command);
}
tx.commitOnClose();
}

View File

@ -1,51 +0,0 @@
package li.strolch.execution.service;
import static li.strolch.utils.helper.StringHelper.isEmpty;
import java.text.MessageFormat;
import li.strolch.exception.StrolchException;
import li.strolch.execution.ExecutionHandler;
import li.strolch.model.State;
import li.strolch.model.activity.IActivityElement;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.runtime.StrolchConstants;
import li.strolch.service.LocatorArgument;
import li.strolch.service.api.AbstractService;
import li.strolch.service.api.ServiceResult;
import li.strolch.service.api.ServiceResultState;
public class SetToExecutionService extends AbstractService<LocatorArgument, ServiceResult> {
@Override
protected ServiceResult getResultInstance() {
return new ServiceResult(ServiceResultState.FAILED);
}
@Override
public LocatorArgument getArgumentInstance() {
return new LocatorArgument();
}
@Override
protected ServiceResult internalDoService(LocatorArgument arg) throws Exception {
String realm = isEmpty(arg.realm) ? StrolchConstants.DEFAULT_REALM : arg.realm;
try (StrolchTransaction tx = openTx(realm)) {
tx.lock(arg.locator);
IActivityElement element = tx.findElement(arg.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(realm, arg.locator);
}
return ServiceResult.success();
}
}

View File

@ -4,6 +4,8 @@ import static li.strolch.service.I18nService.i18nService;
import li.strolch.execution.ExecutionHandler;
import li.strolch.execution.ExecutionHandlerState;
import li.strolch.model.activity.Activity;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.runtime.StrolchConstants;
import li.strolch.service.LocatorArgument;
import li.strolch.service.StrolchRootElementResult;
@ -36,7 +38,12 @@ public class StartActivityExecutionService extends AbstractService<LocatorArgume
"ExecutionHandler is not running, can not start new jobs!")
.i18n(i18nService, "execution.handler.invalidState", "state", executionHandlerState);
executionHandler.addForExecution(realm, arg.locator);
Activity activity;
try (StrolchTransaction tx = openTx(realm, true)) {
activity = tx.getActivityBy(arg.locator.get(1), arg.locator.get(2), true);
}
executionHandler.toExecution(realm, activity);
return ServiceResult.success();
}

View File

@ -1,6 +1,6 @@
execution.handler.invalidState=ExecutionHandler has state {state}, can not start new jobs!
execution.handler.failed.execution=Failed to set to execution due to {reason}
execution.handler.failed.executed=Failed to set to execution due to {reason}
execution.handler.failed.executed=Failed to set to executed due to {reason}
execution.handler.failed.stopped=Failed to set to execution due to {reason}
execution.handler.failed.error=Failed to set to execution due to {reason}
execution.handler.failed.warning=Failed to set to execution due to {reason}

View File

@ -23,9 +23,13 @@ import li.strolch.testbase.runtime.RuntimeMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ReservationExecutionTest extends RuntimeMock {
private static final Logger logger = LoggerFactory.getLogger(ReservationExecutionTest.class);
@Before
public void before() {
mockRuntime(new File("target/" + ReservationExecutionTest.class.getName()),
@ -83,6 +87,7 @@ public class ReservationExecutionTest extends RuntimeMock {
// verify that the machine is not reserved
Resource machine = tx.getResourceBy("Machine", "machine1");
BooleanParameter reservedP = machine.getParameter(BAG_PARAMETERS, PARAM_RESERVED);
logger.info("Checking machine is not reserved initially");
assertFalse(reservedP.getValue());
}
@ -105,6 +110,7 @@ public class ReservationExecutionTest extends RuntimeMock {
// verify that the machine is reserved
Resource machine = tx.getResourceBy("Machine", "machine1");
BooleanParameter reservedP = machine.getParameter(BAG_PARAMETERS, PARAM_RESERVED);
logger.info("Checking machine is reserved, after reserve action is executed.");
assertTrue(reservedP.getValue());
}
@ -120,6 +126,7 @@ public class ReservationExecutionTest extends RuntimeMock {
// verify that the machine is not reserved anymore
Resource machine = tx.getResourceBy("Machine", "machine1");
BooleanParameter reservedP = machine.getParameter(BAG_PARAMETERS, PARAM_RESERVED);
logger.info("Checking machine is released, after release action is executed.");
assertFalse(reservedP.getValue());
}
}

View File

@ -52,7 +52,10 @@ public class SynchronizedCollections {
@Override
public List<U> getList(T t) {
synchronized (this.mutex) {
return new SynchronizedList<>(this.m.getList(t), this.mutex);
List<U> list = this.m.getList(t);
if (list == null)
return null;
return new SynchronizedList<>(list, this.mutex);
}
}
@ -194,7 +197,10 @@ public class SynchronizedCollections {
@Override
public Map<U, V> getMap(T t) {
synchronized (this.mutex) {
return new SynchronizedMap<>(this.m.getMap(t), this.mutex);
Map<U, V> map = this.m.getMap(t);
if (map == null)
return null;
return new SynchronizedMap<>(map, this.mutex);
}
}
@ -358,7 +364,10 @@ public class SynchronizedCollections {
@Override
public Set<U> getSet(T t) {
synchronized (this.mutex) {
return new SynchronizedSet<>(this.m.getSet(t), this.mutex);
Set<U> set = this.m.getSet(t);
if (set == null)
return null;
return new SynchronizedSet<>(set, this.mutex);
}
}

View File

@ -463,6 +463,19 @@ public class ObjectFilter {
return this.cache.containsElement(key, objectKey);
}
/**
* Allows clearing the object cache for an element
*
* @param key
* the key under which it was registered
* @param objectKey
* the objectKey
*/
public void removeObjectCache(String key, Object objectKey) {
this.keySet.remove(key);
this.cache.removeElement(key, objectKey);
}
/**
* Get all objects that were registered under the given key and that have as a resulting final action an addition.
*

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li class="active"><a href="api.html">API</a></li>
<li><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -33,6 +33,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li class="active"><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -33,6 +33,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li class="active"><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li class="active"><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li class="active"><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -0,0 +1,109 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="google-site-verification" content="CPhbjooaiTdROm7Vs4E7kuHZvBfkeLUtonGgcVUbTL8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="ico/favicon.ico">
<title>Strolch: PLC</title>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="css/custom.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --><!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script><![endif]-->
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="index.html">Strolch</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li><a href="documentation.html">Documentation</a></li>
<li class="active"><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>
<li><a href="blog.html">Blog</a></li>
</ul>
</div>
<!--/.nav-collapse -->
</div>
</div>
<div class="container">
<div class="page-header">
<h1 class="page-title">Strolch as a PLC</h1>
<p class="lead page-description">This page how Strolch can act as software based PLC with soft realtime.</p>
</div>
<div class="content">
<!-- content here -->
<h2>Overview</h2>
<p>Using Strolch as a PLC has certain advantages and disadvantages. The following is a list of advantages:</p>
<ul>
<li>Same programming model and language for server and PLC</li>
<li>PLC has the same privilege handling as in Strolch</li>
<li>Simulating down to the PLC level is easily possible to quickly test the server logic</li>
</ul>
</div>
<!-- /.content -->
<div id="footer">
<div class="container">
<p class="text-muted">&copy; Strolch / <a href="mailto:eitch@eitchnet.ch">Robert von Burg</a> / Hosting by
<a href="http://www.eitchnet.ch">eitchnet.ch</a></p>
</div>
</div>
</div>
<!-- /.container -->
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual xsd as needed -->
<script src="js/bootstrap.min.js"></script>
<!-- Piwik -->
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function () {
var u = (("https:" == document.location.protocol) ? "https" : "http") + "://piwik.eitchnet.ch/";
_paq.push(['setTrackerUrl', u + 'piwik.php']);
_paq.push(['setSiteId', 2]);
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
g.type = 'text/javascript';
g.defer = true;
g.async = true;
g.src = u + 'piwik.js';
s.parentNode.insertBefore(g, s);
})();
</script>
<noscript><p><img src="http://piwik.eitchnet.ch/piwik.php?idsite=2" style="border:0;" alt="" /></p></noscript>
<!-- End Piwik Code -->
</body>
</html>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li class="active"><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li class="active"><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li class="active"><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -32,6 +32,7 @@
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li class="active"><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>

View File

@ -97,7 +97,6 @@
<!-- test time dependencies -->
<junit.version>4.12</junit.version>
<hamcrest.version>2.1</hamcrest.version>
<mockito.version>2.28.2</mockito.version>
<!-- maven plug-in dependencies -->
<maven-scm-plugin.version>1.11.2</maven-scm-plugin.version>
@ -328,12 +327,6 @@
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>