use of org.openhab.core.automation.internal.ruleengine.WrappedAction in project openhab-core by openhab.
the class RuleEngineImpl method setModuleHandlers.
/**
* This method links modules to corresponding module handlers.
*
* @param rUID id of rule containing these modules
* @param modules list of modules
* @return null when all modules are connected or list of RuleErrors for missing handlers.
*/
@Nullable
private <T extends WrappedModule<?, ?>> String setModuleHandlers(String rUID, List<T> modules) {
StringBuilder sb = null;
for (T mm : modules) {
final Module m = mm.unwrap();
try {
ModuleHandler moduleHandler = getModuleHandler(m, rUID);
if (moduleHandler != null) {
if (mm instanceof WrappedAction) {
((WrappedAction) mm).setModuleHandler((ActionHandler) moduleHandler);
} else if (mm instanceof WrappedCondition) {
((WrappedCondition) mm).setModuleHandler((ConditionHandler) moduleHandler);
} else if (mm instanceof WrappedTrigger) {
((WrappedTrigger) mm).setModuleHandler((TriggerHandler) moduleHandler);
}
} else {
if (sb == null) {
sb = new StringBuilder();
}
String message = "Missing handler '" + m.getTypeUID() + "' for module '" + m.getId() + "'";
sb.append(message).append("\n");
logger.trace(message);
}
} catch (Throwable t) {
if (sb == null) {
sb = new StringBuilder();
}
String message = "Getting handler '" + m.getTypeUID() + "' for module '" + m.getId() + "' failed: " + t.getMessage();
sb.append(message).append("\n");
logger.trace(message);
}
}
return sb != null ? sb.toString() : null;
}
use of org.openhab.core.automation.internal.ruleengine.WrappedAction in project openhab-core by openhab.
the class RuleEngineImpl method autoMapConnections.
/**
* The auto mapping tries to link not connected module inputs to output of other modules. The auto mapping will link
* input to output only when following criteria are done: 1) input must not be connected. The auto mapping will not
* overwrite explicit connections done by the user. 2) input tags must be subset of the output tags. 3) condition
* inputs can be connected only to triggers' outputs 4) action outputs can be connected to both conditions and
* actions
* outputs 5) There is only one output, based on previous criteria, where the input can connect to. If more then one
* candidate outputs exists for connection, this is a conflict and the auto mapping leaves the input unconnected.
* Auto mapping is always applied when the rule is added or updated. It changes initial value of inputs of
* conditions and actions participating in the rule. If an "auto map" connection has to be removed, the tags of
* corresponding input/output have to be changed.
*
* @param rule updated rule
*/
private void autoMapConnections(WrappedRule rule) {
Map<Set<String>, OutputRef> triggerOutputTags = new HashMap<>(11);
for (WrappedTrigger mt : rule.getTriggers()) {
final Trigger t = mt.unwrap();
TriggerType tt = (TriggerType) mtRegistry.get(t.getTypeUID());
if (tt != null) {
initTagsMap(t.getId(), tt.getOutputs(), triggerOutputTags);
}
}
Map<Set<String>, OutputRef> actionOutputTags = new HashMap<>(11);
for (WrappedAction ma : rule.getActions()) {
final Action a = ma.unwrap();
ActionType at = (ActionType) mtRegistry.get(a.getTypeUID());
if (at != null) {
initTagsMap(a.getId(), at.getOutputs(), actionOutputTags);
}
}
// auto mapping of conditions
if (!triggerOutputTags.isEmpty()) {
for (WrappedCondition mc : rule.getConditions()) {
final Condition c = mc.unwrap();
boolean isConnectionChanged = false;
ConditionType ct = (ConditionType) mtRegistry.get(c.getTypeUID());
if (ct != null) {
Set<Connection> connections = copyConnections(mc.getConnections());
for (Input input : ct.getInputs()) {
if (isConnected(input, connections)) {
// the input is already connected. Skip it.
continue;
}
if (addAutoMapConnections(input, triggerOutputTags, connections)) {
isConnectionChanged = true;
}
}
if (isConnectionChanged) {
// update condition inputs
Map<String, String> connectionMap = getConnectionMap(connections);
mc.setInputs(connectionMap);
mc.setConnections(connections);
}
}
}
}
// auto mapping of actions
if (!triggerOutputTags.isEmpty() || !actionOutputTags.isEmpty()) {
for (final WrappedAction ma : rule.getActions()) {
final Action a = ma.unwrap();
boolean isConnectionChanged = false;
ActionType at = (ActionType) mtRegistry.get(a.getTypeUID());
if (at != null) {
Set<Connection> connections = copyConnections(ma.getConnections());
for (Input input : at.getInputs()) {
if (isConnected(input, connections)) {
// the input is already connected. Skip it.
continue;
}
if (addAutoMapConnections(input, triggerOutputTags, connections)) {
isConnectionChanged = true;
}
if (addAutoMapConnections(input, actionOutputTags, connections)) {
isConnectionChanged = true;
}
}
if (isConnectionChanged) {
// update condition inputs
Map<String, String> connectionMap = getConnectionMap(connections);
ma.setInputs(connectionMap);
ma.setConnections(connections);
}
}
}
}
}
use of org.openhab.core.automation.internal.ruleengine.WrappedAction in project openhab-core by openhab.
the class RuleEngineImpl method setRule.
/**
* This method tries to initialize the rule. It uses available {@link ModuleHandlerFactory}s to create
* {@link ModuleHandler}s for all {@link ModuleImpl}s of the {@link Rule} and to link them. When all the modules
* have associated module handlers then the {@link Rule} is initialized and it is ready to working. It goes into
* idle state. Otherwise the Rule stays into not initialized and continue to wait missing handlers, module types
* or templates.
*
* @param rule the rule which tried to be initialized.
*/
private void setRule(WrappedRule rule) {
if (isDisposed) {
return;
}
String rUID = rule.getUID();
setStatus(rUID, new RuleStatusInfo(RuleStatus.INITIALIZING));
try {
for (final WrappedAction action : rule.getActions()) {
updateMapModuleTypeToRule(rUID, action.unwrap().getTypeUID());
action.setConnections(ConnectionValidator.getConnections(action.getInputs()));
}
for (final WrappedCondition condition : rule.getConditions()) {
updateMapModuleTypeToRule(rUID, condition.unwrap().getTypeUID());
condition.setConnections(ConnectionValidator.getConnections(condition.getInputs()));
}
for (final WrappedTrigger trigger : rule.getTriggers()) {
updateMapModuleTypeToRule(rUID, trigger.unwrap().getTypeUID());
}
validateModuleIDs(rule);
autoMapConnections(rule);
ConnectionValidator.validateConnections(mtRegistry, rule.unwrap());
} catch (IllegalArgumentException e) {
// change status to UNINITIALIZED
setStatus(rUID, new RuleStatusInfo(RuleStatus.UNINITIALIZED, RuleStatusDetail.INVALID_RULE, "Validation of rule " + rUID + " has failed! " + e.getLocalizedMessage()));
return;
}
final boolean activated = activateRule(rule);
if (activated) {
Future<?> f = scheduleTasks.remove(rUID);
if (f != null) {
if (!f.isDone()) {
f.cancel(true);
}
}
}
}
use of org.openhab.core.automation.internal.ruleengine.WrappedAction in project openhab-core by openhab.
the class RuleEngineImpl method executeActions.
/**
* This method evaluates actions of the {@link Rule} and set their {@link Output}s when they exists.
*
* @param rule executed rule.
*/
private void executeActions(WrappedRule rule, boolean stopOnFirstFail) {
final String ruleUID = rule.getUID();
final Collection<WrappedAction> actions = rule.getActions();
if (actions.isEmpty()) {
return;
}
RuleStatus ruleStatus = null;
for (WrappedAction wrappedAction : actions) {
ruleStatus = getRuleStatus(ruleUID);
if (ruleStatus != RuleStatus.RUNNING) {
return;
}
final Action action = wrappedAction.unwrap();
ActionHandler aHandler = wrappedAction.getModuleHandler();
if (aHandler != null) {
Map<String, Object> context = getContext(ruleUID, wrappedAction.getConnections());
try {
Map<String, ?> outputs = aHandler.execute(Collections.unmodifiableMap(context));
if (outputs != null) {
context = getContext(ruleUID, null);
updateContext(ruleUID, action.getId(), outputs);
}
} catch (Throwable t) {
String errMessage = "Fail to execute action: " + action.getId();
if (stopOnFirstFail) {
RuntimeException re = new RuntimeException(errMessage, t);
throw re;
} else {
logger.warn(errMessage, t);
}
}
}
}
}
Aggregations