Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add previousCondition to JRuleWhenItemChange #104

Merged
merged 3 commits into from
Dec 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,19 @@ Use case: Want to listen on all Item events of a group (without the groupstate m
}
```

## Example 36

Use case: Want to listen just on changes where the state is now greater/equals then 12 and was before less then 12.
Without the previous condition the rule will be triggered every time the state is greater/equals then 12.

```java
@JRuleName("Change from something less to something greater")
@JRuleWhenItemChange(item = ITEM_FROM_TO, previousCondition = @JRuleCondition(lt = 12), condition = @JRuleCondition(gte = 12))
public void itemChangeFromTo(JRuleEvent event) {
logInfo("state change to something >= 12 and was before < 12");
}
```

# Changelog
## BETA15
- BREAKING: All JRuleWhen has to be change to corresponding JRuleWhenItemChanged (as an example, look at JRule Examples documentation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,8 @@ private void add(Method method, JRule jRule) {
JRuleCondition jRuleCondition = jRuleWhen.condition();
addToContext(new JRuleItemReceivedUpdateExecutionContext(jRule, logName, loggingTags, method,
jRuleWhen.item(), jRuleWhen.memberOf(),
Optional.of(jRuleCondition.lt()).filter(aDouble -> aDouble != Double.MIN_VALUE),
Optional.of(jRuleCondition.lte()).filter(aDouble -> aDouble != Double.MIN_VALUE),
Optional.of(jRuleCondition.gt()).filter(aDouble -> aDouble != Double.MIN_VALUE),
Optional.of(jRuleCondition.gte()).filter(aDouble -> aDouble != Double.MIN_VALUE),
Optional.of(jRuleCondition.eq()).filter(StringUtils::isNotEmpty),
Optional.of(jRuleCondition.neq()).filter(StringUtils::isNotEmpty), jRulePreconditionContexts,
Optional.of(jRuleWhen.state()).filter(StringUtils::isNotEmpty)));
Optional.of(new JRuleItemExecutionContext.JRuleConditionContext(jRuleCondition)),
jRulePreconditionContexts, Optional.of(jRuleWhen.state()).filter(StringUtils::isNotEmpty)));
ruleLoadingStatistics.addItemStateTrigger();
addedToContext.set(true);
});
Expand All @@ -182,28 +177,20 @@ private void add(Method method, JRule jRule) {
JRuleCondition jRuleCondition = jRuleWhen.condition();
addToContext(new JRuleItemReceivedCommandExecutionContext(jRule, logName, loggingTags, method,
jRuleWhen.item(), jRuleWhen.memberOf(),
Optional.of(jRuleCondition.lt()).filter(aDouble -> aDouble != Double.MIN_VALUE),
Optional.of(jRuleCondition.lte()).filter(aDouble -> aDouble != Double.MIN_VALUE),
Optional.of(jRuleCondition.gt()).filter(aDouble -> aDouble != Double.MIN_VALUE),
Optional.of(jRuleCondition.gte()).filter(aDouble -> aDouble != Double.MIN_VALUE),
Optional.of(jRuleCondition.eq()).filter(StringUtils::isNotEmpty),
Optional.of(jRuleCondition.neq()).filter(StringUtils::isNotEmpty), jRulePreconditionContexts,
Optional.of(jRuleWhen.command()).filter(StringUtils::isNotEmpty)));
Optional.of(new JRuleItemExecutionContext.JRuleConditionContext(jRuleCondition)),
jRulePreconditionContexts, Optional.of(jRuleWhen.command()).filter(StringUtils::isNotEmpty)));
ruleLoadingStatistics.addItemStateTrigger();
addedToContext.set(true);
});

Arrays.stream(method.getAnnotationsByType(JRuleWhenItemChange.class)).forEach(jRuleWhen -> {
JRuleCondition jRuleCondition = jRuleWhen.condition();
JRuleCondition jRulePreviousCondition = jRuleWhen.previousCondition();
addToContext(new JRuleItemChangeExecutionContext(jRule, logName, loggingTags, method, jRuleWhen.item(),
jRuleWhen.memberOf(),
Optional.of(jRuleCondition.lt()).filter(aDouble -> aDouble != Double.MIN_VALUE),
Optional.of(jRuleCondition.lte()).filter(aDouble -> aDouble != Double.MIN_VALUE),
Optional.of(jRuleCondition.gt()).filter(aDouble -> aDouble != Double.MIN_VALUE),
Optional.of(jRuleCondition.gte()).filter(aDouble -> aDouble != Double.MIN_VALUE),
Optional.of(jRuleCondition.eq()).filter(StringUtils::isNotEmpty),
Optional.of(jRuleCondition.neq()).filter(StringUtils::isNotEmpty), jRulePreconditionContexts,
Optional.of(jRuleWhen.from()).filter(StringUtils::isNotEmpty),
Optional.of(new JRuleItemExecutionContext.JRuleConditionContext(jRuleCondition)),
Optional.of(new JRuleItemExecutionContext.JRuleConditionContext(jRulePreviousCondition)),
jRulePreconditionContexts, Optional.of(jRuleWhen.from()).filter(StringUtils::isNotEmpty),
Optional.of(jRuleWhen.to()).filter(StringUtils::isNotEmpty)));
ruleLoadingStatistics.addItemStateTrigger();
addedToContext.set(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,29 @@ public class JRuleItemChangeExecutionContext extends JRuleItemExecutionContext {
private final Logger log = LoggerFactory.getLogger(JRuleItemChangeExecutionContext.class);
private final Optional<String> from;
private final Optional<String> to;
private final Optional<JRuleConditionContext> previousConditionContext;

public JRuleItemChangeExecutionContext(JRule jRule, String logName, String[] loggingTags, Method method,
String itemName, boolean memberOf, Optional<Double> lt, Optional<Double> lte, Optional<Double> gt,
Optional<Double> gte, Optional<String> eq, Optional<String> neq,
String itemName, boolean memberOf, Optional<JRuleConditionContext> conditionContext,
Optional<JRuleConditionContext> previousConditionContext,
List<JRulePreconditionContext> preconditionContextList, Optional<String> from, Optional<String> to) {
super(jRule, logName, loggingTags, method, itemName, memberOf, lt, lte, gt, gte, eq, neq,
preconditionContextList);
super(jRule, logName, loggingTags, method, itemName, memberOf, conditionContext, preconditionContextList);
this.from = from;
this.to = to;
this.previousConditionContext = previousConditionContext;
}

public boolean matchCondition(String state, String previousState) {
return super.matchCondition(state, previousState)
&& previousConditionContext.map(c -> c.matchCondition(previousState)).orElse(true);
}

@Override
public boolean match(AbstractEvent event, JRuleAdditionalCheckData checkData) {
JRuleLog.debug(log, "JRuleItemChangeExecutionContext", "does it match?: {}, {}, {}", this, event, checkData);
if (!(event instanceof ItemStateChangedEvent
&& super.matchCondition(((ItemStateChangedEvent) event).getItemState().toString())
&& matchCondition(((ItemStateChangedEvent) event).getItemState().toString(),
((ItemStateChangedEvent) event).getOldItemState().toString())
&& from.map(s -> ((ItemStateChangedEvent) event).getOldItemState().toString().equals(s)).orElse(true)
&& to.map(s -> ((ItemStateChangedEvent) event).getItemState().toString().equals(s)).orElse(true))) {
return false;
Expand Down Expand Up @@ -87,9 +94,8 @@ public JRuleEvent createJRuleEvent(AbstractEvent event) {
@Override
public String toString() {
return "JRuleItemChangeExecutionContext{" + "from=" + from + ", to=" + to + ", itemName='" + itemName + '\''
+ ", memberOf=" + memberOf + ", gt=" + gt + ", gte=" + gte + ", lt=" + lt + ", lte=" + lte + ", eq="
+ eq + ", neq=" + neq + ", logName='" + logName + '\'' + ", jRule=" + rule + ", method=" + method
+ ", loggingTags=" + Arrays.toString(loggingTags) + ", preconditionContextList="
+ preconditionContextList + '}';
+ ", memberOf=" + memberOf + ", conditionContext=" + conditionContext + ", logName='" + logName + '\''
+ ", jRule=" + rule + ", method=" + method + ", loggingTags=" + Arrays.toString(loggingTags)
+ ", preconditionContextList=" + preconditionContextList + '}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
import java.util.List;
import java.util.Optional;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.openhab.automation.jrule.rules.JRule;
import org.openhab.automation.jrule.rules.JRuleCondition;
import org.openhab.core.library.types.QuantityType;

/**
Expand All @@ -28,79 +30,23 @@
public abstract class JRuleItemExecutionContext extends JRuleExecutionContext {
protected final String itemName;
protected final boolean memberOf;
protected final Optional<Double> gt;
protected final Optional<Double> gte;
protected final Optional<Double> lt;
protected final Optional<Double> lte;
protected final Optional<String> eq;
protected final Optional<String> neq;
protected final Optional<JRuleConditionContext> conditionContext;

public JRuleItemExecutionContext(JRule jRule, String logName, String[] loggingTags, Method method, String itemName,
boolean memberOf, Optional<Double> lt, Optional<Double> lte, Optional<Double> gt, Optional<Double> gte,
Optional<String> eq, Optional<String> neq, List<JRulePreconditionContext> preconditionContextList) {
boolean memberOf, Optional<JRuleConditionContext> conditionContext,
List<JRulePreconditionContext> preconditionContextList) {
super(jRule, logName, loggingTags, method, preconditionContextList);
this.itemName = itemName;
this.memberOf = memberOf;
this.gt = gt;
this.gte = gte;
this.lt = lt;
this.lte = lte;
this.eq = eq;
this.neq = neq;
this.conditionContext = conditionContext;
}

public String getItemName() {
return itemName;
}

public boolean matchCondition(String state) {
if (getEq().isPresent() && getEq().filter(state::equals).isEmpty()) {
return false;
}
if (getNeq().isPresent() && getNeq().filter(ref -> !state.equals(ref)).isEmpty()) {
return false;
}
if (getLt().isPresent() && (!NumberUtils.isCreatable(state)
|| getLt().filter(ref -> QuantityType.valueOf(state).doubleValue() < ref).isEmpty())) {
return false;
}
if (getLte().isPresent() && (!NumberUtils.isCreatable(state)
|| getLte().filter(ref -> QuantityType.valueOf(state).doubleValue() <= ref).isEmpty())) {
return false;
}
if (getGt().isPresent() && (!NumberUtils.isCreatable(state)
|| getGt().filter(ref -> QuantityType.valueOf(state).doubleValue() > ref).isEmpty())) {
return false;
}
if (getGte().isPresent() && (!NumberUtils.isCreatable(state)
|| getGte().filter(ref -> QuantityType.valueOf(state).doubleValue() >= ref).isEmpty())) {
return false;
}
return true;
}

public Optional<Double> getGt() {
return gt;
}

public Optional<Double> getGte() {
return gte;
}

public Optional<Double> getLt() {
return lt;
}

public Optional<Double> getLte() {
return lte;
}

public Optional<String> getEq() {
return eq;
}

public Optional<String> getNeq() {
return neq;
public boolean matchCondition(String state, String previousState) {
return conditionContext.map(c -> c.matchCondition(state)).orElse(true);
}

public boolean isMemberOf() {
Expand All @@ -123,4 +69,64 @@ public String toString() {
return "JRuleAdditionalItemCheckData{" + "belongingGroups=" + belongingGroups + '}';
}
}

public static class JRuleConditionContext {
protected final Optional<Double> gt;
protected final Optional<Double> gte;
protected final Optional<Double> lt;
protected final Optional<Double> lte;
protected final Optional<String> eq;
protected final Optional<String> neq;

public JRuleConditionContext(Optional<Double> gt, Optional<Double> gte, Optional<Double> lt,
Optional<Double> lte, Optional<String> eq, Optional<String> neq) {
this.gt = gt;
this.gte = gte;
this.lt = lt;
this.lte = lte;
this.eq = eq;
this.neq = neq;
}

public JRuleConditionContext(JRuleCondition jRuleCondition) {
this.lt = Optional.of(jRuleCondition.lt()).filter(aDouble -> aDouble != Double.MIN_VALUE);
this.lte = Optional.of(jRuleCondition.lte()).filter(aDouble -> aDouble != Double.MIN_VALUE);
this.gt = Optional.of(jRuleCondition.gt()).filter(aDouble -> aDouble != Double.MIN_VALUE);
this.gte = Optional.of(jRuleCondition.gte()).filter(aDouble -> aDouble != Double.MIN_VALUE);
this.eq = Optional.of(jRuleCondition.eq()).filter(StringUtils::isNotEmpty);
this.neq = Optional.of(jRuleCondition.neq()).filter(StringUtils::isNotEmpty);
}

public boolean matchCondition(String state) {
if (eq.isPresent() && eq.filter(state::equals).isEmpty()) {
return false;
}
if (neq.isPresent() && neq.filter(ref -> !state.equals(ref)).isEmpty()) {
return false;
}
if (lt.isPresent() && (!NumberUtils.isCreatable(state)
|| lt.filter(ref -> QuantityType.valueOf(state).doubleValue() < ref).isEmpty())) {
return false;
}
if (lte.isPresent() && (!NumberUtils.isCreatable(state)
|| lte.filter(ref -> QuantityType.valueOf(state).doubleValue() <= ref).isEmpty())) {
return false;
}
if (gt.isPresent() && (!NumberUtils.isCreatable(state)
|| gt.filter(ref -> QuantityType.valueOf(state).doubleValue() > ref).isEmpty())) {
return false;
}
if (gte.isPresent() && (!NumberUtils.isCreatable(state)
|| gte.filter(ref -> QuantityType.valueOf(state).doubleValue() >= ref).isEmpty())) {
return false;
}
return true;
}

@Override
public String toString() {
return "JRuleConditionContext{" + "gt=" + gt + ", gte=" + gte + ", lt=" + lt + ", lte=" + lte + ", eq=" + eq
+ ", neq=" + neq + '}';
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,9 @@ public class JRuleItemReceivedCommandExecutionContext extends JRuleItemExecution
protected final Optional<String> command;

public JRuleItemReceivedCommandExecutionContext(JRule jRule, String logName, String[] loggingTags, Method method,
String itemName, boolean memberOf, Optional<Double> lt, Optional<Double> lte, Optional<Double> gt,
Optional<Double> gte, Optional<String> eq, Optional<String> neq,
String itemName, boolean memberOf, Optional<JRuleConditionContext> conditionContext,
List<JRulePreconditionContext> preconditionContextList, Optional<String> command) {
super(jRule, logName, loggingTags, method, itemName, memberOf, lt, lte, gt, gte, eq, neq,
preconditionContextList);
super(jRule, logName, loggingTags, method, itemName, memberOf, conditionContext, preconditionContextList);
this.command = command;
}

Expand All @@ -51,7 +49,7 @@ public boolean match(AbstractEvent event, JRuleAdditionalCheckData checkData) {
JRuleLog.debug(log, "JRuleItemReceivedCommandExecutionContext", "does it match?: {}, {}, {}", this, event,
checkData);
if (!(event instanceof ItemCommandEvent
&& super.matchCondition(((ItemCommandEvent) event).getItemCommand().toString())
&& matchCondition(((ItemCommandEvent) event).getItemCommand().toString(), null)
&& command.map(s -> ((ItemCommandEvent) event).getItemCommand().toString().equals(s)).orElse(true))) {
return false;
}
Expand Down Expand Up @@ -82,9 +80,8 @@ public JRuleEvent createJRuleEvent(AbstractEvent event) {
@Override
public String toString() {
return "JRuleItemReceivedCommandExecutionContext{" + "command=" + command + ", itemName='" + itemName + '\''
+ ", memberOf=" + memberOf + ", gt=" + gt + ", gte=" + gte + ", lt=" + lt + ", lte=" + lte + ", eq="
+ eq + ", neq=" + neq + ", logName='" + logName + '\'' + ", jRule=" + rule + ", method=" + method
+ ", loggingTags=" + Arrays.toString(loggingTags) + ", preconditionContextList="
+ preconditionContextList + '}';
+ ", memberOf=" + memberOf + ", conditionContext=" + conditionContext + ", logName='" + logName + '\''
+ ", jRule=" + rule + ", method=" + method + ", loggingTags=" + Arrays.toString(loggingTags)
+ ", preconditionContextList=" + preconditionContextList + '}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,9 @@ public class JRuleItemReceivedUpdateExecutionContext extends JRuleItemExecutionC
private final Optional<String> state;

public JRuleItemReceivedUpdateExecutionContext(JRule jRule, String logName, String[] loggingTags, Method method,
String itemName, boolean memberOf, Optional<Double> lt, Optional<Double> lte, Optional<Double> gt,
Optional<Double> gte, Optional<String> eq, Optional<String> neq,
String itemName, boolean memberOf, Optional<JRuleConditionContext> conditionContext,
List<JRulePreconditionContext> preconditionContextList, Optional<String> state) {
super(jRule, logName, loggingTags, method, itemName, memberOf, lt, lte, gt, gte, eq, neq,
preconditionContextList);
super(jRule, logName, loggingTags, method, itemName, memberOf, conditionContext, preconditionContextList);
this.state = state;
}

Expand All @@ -51,7 +49,7 @@ public boolean match(AbstractEvent event, JRuleAdditionalCheckData checkData) {
JRuleLog.debug(log, "JRuleItemReceivedUpdateExecutionContext", "does it match?: {}, {}, {}", this, event,
checkData);
if (!(event instanceof ItemStateEvent
&& super.matchCondition(((ItemStateEvent) event).getItemState().toString())
&& matchCondition(((ItemStateEvent) event).getItemState().toString(), null)
&& state.map(s -> ((ItemStateEvent) event).getItemState().toString().equals(s)).orElse(true))) {
return false;
}
Expand Down Expand Up @@ -81,9 +79,8 @@ public JRuleEvent createJRuleEvent(AbstractEvent event) {
@Override
public String toString() {
return "JRuleItemReceivedUpdateExecutionContext{" + "state=" + state + ", itemName='" + itemName + '\''
+ ", memberOf=" + memberOf + ", gt=" + gt + ", gte=" + gte + ", lt=" + lt + ", lte=" + lte + ", eq="
+ eq + ", neq=" + neq + ", logName='" + logName + '\'' + ", jRule=" + rule + ", method=" + method
+ ", loggingTags=" + Arrays.toString(loggingTags) + ", preconditionContextList="
+ preconditionContextList + '}';
+ ", memberOf=" + memberOf + ", conditionContext=" + conditionContext + ", logName='" + logName + '\''
+ ", jRule=" + rule + ", method=" + method + ", loggingTags=" + Arrays.toString(loggingTags)
+ ", preconditionContextList=" + preconditionContextList + '}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,10 @@
boolean memberOf() default false;

JRuleCondition condition() default @JRuleCondition;

/**
*
* @return The condition of the previous state
*/
JRuleCondition previousCondition() default @JRuleCondition;
}
Loading