mirror of
https://github.com/danieldemus/openhab-core.git
synced 2025-01-10 21:31:53 +01:00
Add unmanaged scripts to rule engine (#3156)
Signed-off-by: Jan N. Klug <github@klug.nrw>
This commit is contained in:
parent
d4ceca9fe0
commit
64a31026cd
@ -35,12 +35,14 @@ public interface RuleManager {
|
||||
* This method gets <b>enabled</b> {@link RuleStatus} for a {@link Rule}.
|
||||
* The <b>enabled</b> rule statuses are {@link RuleStatus#UNINITIALIZED}, {@link RuleStatus#IDLE} and
|
||||
* {@link RuleStatus#RUNNING}.
|
||||
* The <b>disabled</b> rule status is {@link RuleStatus#DISABLED}.
|
||||
* The <b>disabled</b> rule status is {@link RuleStatus#UNINITIALIZED} with {@link RuleStatusDetail#DISABLED}.
|
||||
*
|
||||
* @param ruleUID UID of the {@link Rule}
|
||||
* @return {@code true} when the {@link RuleStatus} is one of the {@link RuleStatus#UNINITIALIZED},
|
||||
* @return {@code true} when the {@link RuleStatus} is one of the {@link RuleStatus#UNINITIALIZED} with any other
|
||||
* {@link RuleStatusDetail} than {@link RuleStatusDetail#DISABLED},
|
||||
* {@link RuleStatus#IDLE} and {@link RuleStatus#RUNNING}, {@code false} when it is
|
||||
* {@link RuleStatus#DISABLED} and {@code null} when it is not available.
|
||||
* {@link RuleStatus#UNINITIALIZED} with {@link RuleStatusDetail#DISABLED} and {@code null} when it is not
|
||||
* available.
|
||||
*/
|
||||
@Nullable
|
||||
Boolean isEnabled(String ruleUID);
|
||||
@ -49,7 +51,7 @@ public interface RuleManager {
|
||||
* This method is used for changing <b>enabled</b> state of the {@link Rule}.
|
||||
* The <b>enabled</b> rule statuses are {@link RuleStatus#UNINITIALIZED}, {@link RuleStatus#IDLE} and
|
||||
* {@link RuleStatus#RUNNING}.
|
||||
* The <b>disabled</b> rule status is {@link RuleStatus#DISABLED}.
|
||||
* The <b>disabled</b> rule status is {@link RuleStatus#UNINITIALIZED} with {@link RuleStatusDetail#DISABLED}.
|
||||
*
|
||||
* @param uid the unique identifier of the {@link Rule}.
|
||||
* @param isEnabled a new <b>enabled / disabled</b> state of the {@link Rule}.
|
||||
@ -81,19 +83,21 @@ public interface RuleManager {
|
||||
* This should always be possible unless an action has a mandatory input that is linked to a trigger.
|
||||
* In that case the action is skipped and the rule engine continues execution of rest actions.
|
||||
*
|
||||
* @param ruleUID id of the rule whose actions have to be executed.
|
||||
* @param uid id of the rule whose actions have to be executed.
|
||||
* @return a copy of the rule context, including possible return values
|
||||
*/
|
||||
void runNow(String uid);
|
||||
Map<String, Object> runNow(String uid);
|
||||
|
||||
/**
|
||||
* Same as {@link #runNow(String)} with the additional option to enable/disable evaluation of
|
||||
* conditions defined in the target rule. The context can be set here, too, but also might be {@code null}.
|
||||
*
|
||||
* @param ruleUID id of the rule whose actions have to be executed.
|
||||
* @param uid id of the rule whose actions have to be executed.
|
||||
* @param considerConditions if {@code true} the conditions of the rule will be checked.
|
||||
* @param context the context that is passed to the conditions and the actions of the rule.
|
||||
* @return a copy of the rule context, including possible return values
|
||||
*/
|
||||
void runNow(String uid, boolean considerConditions, @Nullable Map<String, Object> context);
|
||||
Map<String, Object> runNow(String uid, boolean considerConditions, @Nullable Map<String, Object> context);
|
||||
|
||||
/**
|
||||
* Simulates the execution of all rules with tag 'Schedule' for the given time interval.
|
||||
|
@ -440,7 +440,7 @@ public class RuleEngineImpl implements RuleManager, RegistryChangeListener<Modul
|
||||
/**
|
||||
* This method add a new rule into rule engine. Scope identity of the Rule is the identity of the caller.
|
||||
*
|
||||
* @param rule a rule which has to be added.
|
||||
* @param newRule a rule which has to be added.
|
||||
*/
|
||||
protected void addRule(Rule newRule) {
|
||||
synchronized (this) {
|
||||
@ -587,7 +587,7 @@ public class RuleEngineImpl implements RuleManager, RegistryChangeListener<Modul
|
||||
* Gets {@link TriggerHandlerCallback} for passed {@link Rule}. If it does not exists, a callback object is
|
||||
* created.
|
||||
*
|
||||
* @param rule rule object for which the callback is looking for.
|
||||
* @param ruleUID rule object for which the callback is looking for.
|
||||
* @return a {@link TriggerHandlerCallback} corresponding to the passed {@link Rule} object.
|
||||
*/
|
||||
private synchronized TriggerHandlerCallbackImpl getTriggerHandlerCallback(String ruleUID) {
|
||||
@ -1005,17 +1005,19 @@ public class RuleEngineImpl implements RuleManager, RegistryChangeListener<Modul
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runNow(String ruleUID, boolean considerConditions, @Nullable Map<String, Object> context) {
|
||||
public Map<String, Object> runNow(String ruleUID, boolean considerConditions,
|
||||
@Nullable Map<String, Object> context) {
|
||||
Map<String, Object> returnContext = new HashMap<>();
|
||||
final WrappedRule rule = getManagedRule(ruleUID);
|
||||
if (rule == null) {
|
||||
logger.warn("Failed to execute rule '{}': Invalid Rule UID", ruleUID);
|
||||
return;
|
||||
return returnContext;
|
||||
}
|
||||
synchronized (this) {
|
||||
final RuleStatus ruleStatus = getRuleStatus(ruleUID);
|
||||
if (ruleStatus != null && ruleStatus != RuleStatus.IDLE) {
|
||||
logger.error("Failed to execute rule ‘{}' with status '{}'", ruleUID, ruleStatus.name());
|
||||
return;
|
||||
return returnContext;
|
||||
}
|
||||
// change state to RUNNING
|
||||
setStatus(ruleUID, new RuleStatusInfo(RuleStatus.RUNNING));
|
||||
@ -1025,14 +1027,11 @@ public class RuleEngineImpl implements RuleManager, RegistryChangeListener<Modul
|
||||
if (context != null && !context.isEmpty()) {
|
||||
getContext(ruleUID, null).putAll(context);
|
||||
}
|
||||
if (considerConditions) {
|
||||
if (calculateConditions(rule)) {
|
||||
executeActions(rule, false);
|
||||
}
|
||||
} else {
|
||||
if (!considerConditions || calculateConditions(rule)) {
|
||||
executeActions(rule, false);
|
||||
}
|
||||
logger.debug("The rule '{}' is executed.", ruleUID);
|
||||
returnContext.putAll(getContext(ruleUID, null));
|
||||
} catch (Throwable t) {
|
||||
logger.error("Failed to execute rule '{}': ", ruleUID, t);
|
||||
}
|
||||
@ -1042,11 +1041,12 @@ public class RuleEngineImpl implements RuleManager, RegistryChangeListener<Modul
|
||||
setStatus(ruleUID, new RuleStatusInfo(RuleStatus.IDLE));
|
||||
}
|
||||
}
|
||||
return returnContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runNow(String ruleUID) {
|
||||
runNow(ruleUID, false, null);
|
||||
public Map<String, Object> runNow(String ruleUID) {
|
||||
return runNow(ruleUID, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1092,11 +1092,7 @@ public class RuleEngineImpl implements RuleManager, RegistryChangeListener<Modul
|
||||
* @return copy of current context in rule engine
|
||||
*/
|
||||
private Map<String, Object> getContext(String ruleUID, @Nullable Set<Connection> connections) {
|
||||
Map<String, Object> context = contextMap.get(ruleUID);
|
||||
if (context == null) {
|
||||
context = new HashMap<>();
|
||||
contextMap.put(ruleUID, context);
|
||||
}
|
||||
Map<String, Object> context = contextMap.computeIfAbsent(ruleUID, k -> new HashMap<>());
|
||||
if (connections != null) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (Connection c : connections) {
|
||||
|
@ -20,6 +20,7 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
@ -58,6 +59,7 @@ import org.openhab.core.model.rule.rules.TimerTrigger;
|
||||
import org.openhab.core.model.rule.rules.DateTimeTrigger;
|
||||
import org.openhab.core.model.rule.rules.UpdateEventTrigger;
|
||||
import org.openhab.core.model.script.runtime.DSLScriptContextProvider;
|
||||
import org.openhab.core.model.script.script.Script;
|
||||
import org.openhab.core.service.ReadyMarker;
|
||||
import org.openhab.core.service.ReadyMarkerFilter;
|
||||
import org.openhab.core.service.ReadyService;
|
||||
@ -170,6 +172,28 @@ public class DSLRuleProvider
|
||||
default:
|
||||
logger.debug("Unknown event type.");
|
||||
}
|
||||
} else if ("script".equals(ruleModelType)) {
|
||||
switch (type) {
|
||||
case MODIFIED:
|
||||
Rule oldRule = rules.remove(modelFileName);
|
||||
if (oldRule != null) {
|
||||
removeRule(oldRule);
|
||||
}
|
||||
case ADDED:
|
||||
EObject model = modelRepository.getModel(modelFileName);
|
||||
if (model instanceof Script) {
|
||||
addRule(toRule(modelFileName, ((Script) model)));
|
||||
}
|
||||
break;
|
||||
case REMOVED:
|
||||
oldRule = rules.remove(modelFileName);
|
||||
if (oldRule != null) {
|
||||
removeRule(oldRule);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.debug("Unknown event type.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,6 +268,18 @@ public class DSLRuleProvider
|
||||
}
|
||||
}
|
||||
|
||||
private Rule toRule(String modelName, Script script) {
|
||||
String scriptText = NodeModelUtils.findActualNodeFor(script).getText();
|
||||
|
||||
Configuration cfg = new Configuration();
|
||||
cfg.put("script", removeIndentation(scriptText));
|
||||
cfg.put("type", MIMETYPE_OPENHAB_DSL_RULE);
|
||||
List<Action> actions = List.of(ActionBuilder.create().withId("script").withTypeUID("script.ScriptAction")
|
||||
.withConfiguration(cfg).build());
|
||||
|
||||
return RuleBuilder.create(modelName).withTags("Script").withName(modelName).withActions(actions).build();
|
||||
}
|
||||
|
||||
private Rule toRule(String modelName, org.openhab.core.model.rule.rules.Rule rule, int index) {
|
||||
String name = rule.getName();
|
||||
String uid = modelName + "-" + index;
|
||||
|
Loading…
Reference in New Issue
Block a user