[Major] Implemented basic PlcExecutionPolicy with PlcGwService for activity execution

This commit is contained in:
Robert von Burg 2020-02-12 15:02:48 +01:00
parent 8d5b7dc4c2
commit b28e8ad4d8
7 changed files with 200 additions and 45 deletions

View File

@ -25,6 +25,7 @@ import li.strolch.privilege.model.Certificate;
import li.strolch.privilege.model.PrivilegeContext;
import li.strolch.runtime.configuration.ComponentConfiguration;
import li.strolch.utils.collections.MapOfMaps;
import li.strolch.utils.dbc.DBC;
public class DefaultPlcHandler extends StrolchComponent implements PlcHandler, PlcConnectionStateChangeListener {
@ -59,6 +60,8 @@ public class DefaultPlcHandler extends StrolchComponent implements PlcHandler, P
@Override
public PlcAddress getPlcAddress(String resource, String action) {
DBC.PRE.assertNotNull("resource must not be null", resource);
DBC.PRE.assertNotEmpty("action must not be empty", action);
PlcAddress plcAddress = this.plcAddresses.getElement(resource, action);
if (plcAddress == null)
throw new IllegalStateException("PlcAddress for " + resource + "-" + action + " does not exist!");
@ -67,6 +70,8 @@ public class DefaultPlcHandler extends StrolchComponent implements PlcHandler, P
@Override
public String getPlcAddressId(String resource, String action) {
DBC.PRE.assertNotNull("resource must not be null", resource);
DBC.PRE.assertNotEmpty("action must not be empty", action);
PlcAddress plcAddress = getPlcAddress(resource, action);
String addressId = this.addressesToResourceId.get(plcAddress);
if (addressId == null)

View File

@ -81,7 +81,7 @@ public abstract class PlcService implements PlcListener {
}
protected StrolchTransaction openTx(PrivilegeContext ctx, boolean readOnly) {
return this.plcHandler.openTx(ctx.getCertificate(), readOnly);
return this.container.getRealm(ctx.getCertificate()).openTx(ctx.getCertificate(), getClass(), readOnly);
}
protected void runAsAgent(PrivilegedRunnable runnable) throws Exception {

View File

@ -24,6 +24,7 @@ import li.strolch.privilege.model.Certificate;
import li.strolch.rest.StrolchSessionHandler;
import li.strolch.runtime.configuration.ComponentConfiguration;
import li.strolch.utils.collections.MapOfLists;
import li.strolch.utils.dbc.DBC;
import li.strolch.websocket.WebSocketRemoteIp;
public class PlcGwServerHandler extends StrolchComponent {
@ -54,10 +55,13 @@ public class PlcGwServerHandler extends StrolchComponent {
}
public boolean isPlcConnected(String plcId) {
DBC.PRE.assertNotEmpty("plcId must not be empty", plcId);
return this.plcSessionsByPlcId.containsKey(plcId);
}
public void register(PlcAddressKey addressKey, String plcId, PlcNotificationListener listener) {
DBC.PRE.assertNotNull("addressKey must not be null", addressKey);
DBC.PRE.assertNotEmpty("plcId must not be empty", plcId);
MapOfLists<PlcAddressKey, PlcNotificationListener> plcListeners = this.plcAddressListenersByPlcId.get(plcId);
if (plcListeners == null) {
plcListeners = new MapOfLists<>();
@ -67,9 +71,13 @@ public class PlcGwServerHandler extends StrolchComponent {
synchronized (plcListeners) {
plcListeners.addElement(addressKey, listener);
}
logger.info("Registered listener on plc " + plcId + " key " + addressKey + ": " + listener);
}
public void unregister(PlcAddressKey addressKey, String plcId, PlcNotificationListener listener) {
DBC.PRE.assertNotNull("addressKey must not be null", addressKey);
DBC.PRE.assertNotEmpty("plcId must not be empty", plcId);
MapOfLists<PlcAddressKey, PlcNotificationListener> plcListeners = this.plcAddressListenersByPlcId.get(plcId);
if (plcListeners == null)
return;
@ -77,6 +85,8 @@ public class PlcGwServerHandler extends StrolchComponent {
synchronized (plcListeners) {
plcListeners.removeElement(addressKey, listener);
}
logger.info("Unregistered listener from plc " + plcId + " key " + addressKey + ": " + listener);
}
public void sendMessage(PlcAddressKey addressKey, String plcId, boolean value,

View File

@ -0,0 +1,140 @@
package li.strolch.plc.gw.server;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.execution.ExecutionHandler;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.plc.model.PlcAddressKey;
import li.strolch.plc.model.PlcNotificationListener;
import li.strolch.plc.model.PlcServiceState;
import li.strolch.privilege.model.PrivilegeContext;
import li.strolch.runtime.privilege.PrivilegedRunnable;
import li.strolch.runtime.privilege.PrivilegedRunnableWithResult;
import li.strolch.utils.dbc.DBC;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class PlcGwService implements PlcNotificationListener, PlcAddressResponseListener {
protected static final Logger logger = LoggerFactory.getLogger(PlcGwService.class);
protected final String plcId;
protected final ComponentContainer container;
protected final PlcGwServerHandler plcHandler;
private PlcServiceState state;
public PlcGwService(String plcId, ComponentContainer container, PlcGwServerHandler plcHandler) {
DBC.PRE.assertNotEmpty("plcId must be set!", plcId);
DBC.PRE.assertNotNull("container must be set!", container);
DBC.PRE.assertNotNull("plcHandler must be set!", plcHandler);
this.plcId = plcId;
this.container = container;
this.plcHandler = plcHandler;
this.state = PlcServiceState.Unregistered;
}
public PlcServiceState getState() {
return this.state;
}
public void start(StrolchTransaction tx) {
this.state = PlcServiceState.Started;
}
public void stop() {
this.state = PlcServiceState.Stopped;
}
public void register() {
this.state = PlcServiceState.Registered;
}
public void unregister() {
this.state = PlcServiceState.Unregistered;
}
protected void register(PlcAddressKey key) {
this.plcHandler.register(key, this.plcId, this);
}
protected void unregister(PlcAddressKey key) {
this.plcHandler.unregister(key, this.plcId, this);
}
public void sendMessage(PlcAddressKey addressKey, String plcId, boolean value,
PlcAddressResponseListener listener) {
this.plcHandler.sendMessage(addressKey, plcId, value, this);
}
public void sendMessage(PlcAddressKey addressKey, String plcId, int value, PlcAddressResponseListener listener) {
this.plcHandler.sendMessage(addressKey, plcId, value, this);
}
public void sendMessage(PlcAddressKey addressKey, String plcId, double value, PlcAddressResponseListener listener) {
this.plcHandler.sendMessage(addressKey, plcId, value, this);
}
public void sendMessage(PlcAddressKey addressKey, String plcId, String value, PlcAddressResponseListener listener) {
this.plcHandler.sendMessage(addressKey, plcId, value, this);
}
public void sendMessage(PlcAddressKey addressKey, String plcId, PlcAddressResponseListener listener) {
this.plcHandler.sendMessage(addressKey, plcId, this);
}
protected StrolchTransaction openTx(PrivilegeContext ctx, boolean readOnly) {
return this.container.getRealm(ctx.getCertificate()).openTx(ctx.getCertificate(), getClass(), readOnly);
}
protected void runAsAgent(PrivilegedRunnable runnable) throws Exception {
this.container.getPrivilegeHandler().runAsAgent(runnable);
}
protected ExecutionHandler getExecutionHandler() {
return this.container.getComponent(ExecutionHandler.class);
}
protected <T> T runAsAgentWithResult(PrivilegedRunnableWithResult<T> runnable) throws Exception {
return this.container.getPrivilegeHandler().runAsAgentWithResult(runnable);
}
protected ScheduledFuture<?> schedule(PrivilegedRunnable runnable, long delay, TimeUnit delayUnit) {
return this.container.getAgent().getScheduledExecutor(PlcGwService.class.getSimpleName()).schedule(() -> {
try {
this.container.getPrivilegeHandler().runAsAgent(runnable);
} catch (Exception e) {
handleFailedSchedule(e);
}
}, delay, delayUnit);
}
protected ScheduledFuture<?> scheduleAtFixedRate(PrivilegedRunnable runnable, long initialDelay, long period,
TimeUnit delayUnit) {
return this.container.getAgent().getScheduledExecutor(PlcGwService.class.getSimpleName())
.scheduleAtFixedRate(() -> {
try {
this.container.getPrivilegeHandler().runAsAgent(runnable);
} catch (Exception e) {
handleFailedSchedule(e);
}
}, initialDelay, period, delayUnit);
}
protected ScheduledFuture<?> scheduleWithFixedDelay(PrivilegedRunnable runnable, long initialDelay, long period,
TimeUnit delayUnit) {
return this.container.getAgent().getScheduledExecutor(PlcGwService.class.getSimpleName())
.scheduleWithFixedDelay(() -> {
try {
this.container.getPrivilegeHandler().runAsAgent(runnable);
} catch (Exception e) {
handleFailedSchedule(e);
}
}, initialDelay, period, delayUnit);
}
protected void handleFailedSchedule(Exception e) {
logger.error("Failed to execute " + getClass().getSimpleName(), e);
}
}

View File

@ -1,8 +1,6 @@
package li.strolch.plc.gw.server.policy.execution;
import static li.strolch.model.StrolchModelConstants.BAG_PARAMETERS;
import static li.strolch.plc.gw.server.PlcServerContants.BUNDLE_STROLCH_PLC_GW_SERVER;
import static li.strolch.plc.model.PlcConstants.PARAM_PLC_ID;
import static li.strolch.runtime.StrolchConstants.SYSTEM_USER_AGENT;
import li.strolch.execution.policy.SimpleExecution;
@ -10,70 +8,62 @@ import li.strolch.handler.operationslog.LogMessage;
import li.strolch.handler.operationslog.LogSeverity;
import li.strolch.model.Locator;
import li.strolch.model.activity.Action;
import li.strolch.model.parameter.StringParameter;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.plc.gw.server.PlcGwServerHandler;
import li.strolch.plc.model.PlcAddressKey;
import li.strolch.plc.model.PlcNotificationListener;
import li.strolch.utils.helper.StringHelper;
public abstract class PlcExecutionPolicy extends SimpleExecution implements PlcNotificationListener {
private String realm;
protected String realm;
private Locator actionLoc;
private String plcId;
private PlcGwServerHandler plcHandler;
private PlcAddressKey addressKey;
protected String actionType;
protected Locator actionLoc;
protected PlcGwServerHandler plcHandler;
public PlcExecutionPolicy(StrolchTransaction tx) {
super(tx);
this.realm = tx.getRealmName();
}
protected void initialize(Action action) {
this.actionLoc = action.getLocator();
protected abstract String getPlcId();
// set all fields
getPlcId(action);
getPlcHandler();
getAddressKey(action);
protected void initialize(Action action) {
this.actionType = action.getType();
this.actionLoc = action.getLocator();
this.plcHandler = getComponent(PlcGwServerHandler.class);
}
protected void toExecuted() {
unregister();
long delay = 5L;
logger.info(
"Delaying toExecuted of " + getActionLoc() + " by " + StringHelper.formatMillisecondsDuration(delay));
getDelayedExecutionTimer().execute(this.realm, getContainer(), getActionLoc(), delay);
}
public String getActionType() {
return this.actionType;
}
public Locator getActionLoc() {
return this.actionLoc;
}
protected String getPlcId(Action action) {
if (this.plcId == null) {
StringParameter plcIdP = action.findParameter(BAG_PARAMETERS, PARAM_PLC_ID, true);
this.plcId = plcIdP.getValue();
}
return this.plcId;
protected void register() {
// do nothing
}
protected PlcAddressKey getAddressKey(Action action) {
if (this.addressKey == null)
this.addressKey = PlcAddressKey.valueOf(action.getResourceId(), action.getType());
return this.addressKey;
protected void unregister() {
// do nothing
}
protected PlcGwServerHandler getPlcHandler() {
if (this.plcHandler == null)
this.plcHandler = getComponent(PlcGwServerHandler.class);
return this.plcHandler;
}
protected void register(Action action) {
getPlcHandler().register(getAddressKey(action), getPlcId(action), this);
}
protected void unregister(Action action) {
getPlcHandler().unregister(getAddressKey(action), getPlcId(action), this);
}
protected boolean assertPlcConnected(Action action) {
if (getPlcHandler().isPlcConnected(getPlcId(action)))
protected boolean assertPlcConnected() {
if (this.plcHandler.isPlcConnected(getPlcId()))
return true;
toError(msgPlcNotConnected(this.realm));
@ -90,11 +80,11 @@ public abstract class PlcExecutionPolicy extends SimpleExecution implements PlcN
protected LogMessage msgPlcNotConnected(String realm) {
return new LogMessage(realm, SYSTEM_USER_AGENT, getActionLoc(), LogSeverity.Warning,
BUNDLE_STROLCH_PLC_GW_SERVER, "execution.plc.notConnected").value("plc", this.plcId);
BUNDLE_STROLCH_PLC_GW_SERVER, "execution.plc.notConnected").value("plc", getPlcId());
}
protected LogMessage msgConnectionLostToPlc(String realm) {
return new LogMessage(realm, SYSTEM_USER_AGENT, getActionLoc(), LogSeverity.Error, BUNDLE_STROLCH_PLC_GW_SERVER,
"execution.plc.connectionLost").value("plc", this.plcId);
"execution.plc.connectionLost").value("plc", getPlcId());
}
}

View File

@ -4,5 +4,7 @@ public interface PlcNotificationListener {
void handleNotification(PlcAddressKey addressKey, Object value);
void handleConnectionLost();
default void handleConnectionLost() {
// no-op
}
}

View File

@ -34,6 +34,14 @@ public class PlcResponse {
this.state = state;
}
public boolean isSent() {
return this.state == PlcResponseState.Sent;
}
public boolean isFailed() {
return this.state == PlcResponseState.Failed;
}
public String getStateMsg() {
return this.stateMsg;
}