Skip to content

Commit

Permalink
Merge pull request #66 from querdenker2k/memberof_trigger
Browse files Browse the repository at this point in the history
Memberof trigger
  • Loading branch information
seaside1 authored Nov 5, 2022
2 parents 31e3ad5 + 0d00531 commit ca9e8ff
Show file tree
Hide file tree
Showing 18 changed files with 454 additions and 56 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,19 @@ public void sendPushover(JRuleEvent event) {
}
```

## Example 35

Use case: Want to listen on all Item events of a group (without the groupstate must change)

```java
@JRuleName("MemberOfUpdateTrigger")
@JRuleWhenItemReceivedUpdate(item = _MySwitchGroup.ITEM, memberOf = true)
public synchronized void memberOfUpdateTrigger(JRuleItemEvent event) {
final String memberThatChangedStatus = event.getMemberName();
logInfo("Member that changed the status of the Group of switches: {}", memberThatChangedStatus);
}
```


# Changelog
## NEXT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import org.openhab.core.items.Item;
import org.openhab.core.items.ItemNotFoundException;
import org.openhab.core.items.ItemRegistry;
import org.openhab.core.items.events.ItemEvent;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.scheduler.CronScheduler;
import org.slf4j.Logger;
Expand Down Expand Up @@ -160,7 +161,8 @@ private void add(Method method, JRule jRule) {
Arrays.stream(method.getAnnotationsByType(JRuleWhenItemReceivedUpdate.class)).forEach(jRuleWhen -> {
JRuleCondition jRuleCondition = jRuleWhen.condition();
addToContext(new JRuleItemReceivedUpdateExecutionContext(jRule, logName, loggingTags, method,
jRuleWhen.item(), Optional.of(jRuleCondition.lt()).filter(aDouble -> aDouble != Double.MIN_VALUE),
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),
Expand All @@ -174,7 +176,8 @@ private void add(Method method, JRule jRule) {
Arrays.stream(method.getAnnotationsByType(JRuleWhenItemReceivedCommand.class)).forEach(jRuleWhen -> {
JRuleCondition jRuleCondition = jRuleWhen.condition();
addToContext(new JRuleItemReceivedCommandExecutionContext(jRule, logName, loggingTags, method,
jRuleWhen.item(), Optional.of(jRuleCondition.lt()).filter(aDouble -> aDouble != Double.MIN_VALUE),
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),
Expand All @@ -188,6 +191,7 @@ private void add(Method method, JRule jRule) {
Arrays.stream(method.getAnnotationsByType(JRuleWhenItemChange.class)).forEach(jRuleWhen -> {
JRuleCondition jRuleCondition = jRuleWhen.condition();
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),
Expand Down Expand Up @@ -252,10 +256,24 @@ private boolean addToContext(JRuleExecutionContext context) {
}

public void fire(AbstractEvent event) {
contextList.stream().filter(context -> context.match(event)).filter(this::matchPrecondition)
JRuleItemExecutionContext.JRuleAdditionalItemCheckData additionalCheckData = getAdditionalCheckData(event);

contextList.stream().filter(context -> context.match(event, additionalCheckData))
.filter(this::matchPrecondition)
.forEach(context -> invokeRule(context, context.createJRuleEvent(event)));
}

private JRuleItemExecutionContext.JRuleAdditionalItemCheckData getAdditionalCheckData(AbstractEvent event) {
return Optional.ofNullable(event instanceof ItemEvent ? ((ItemEvent) event).getItemName() : null).map(s -> {
try {
return itemRegistry.getItem(s);
} catch (ItemNotFoundException e) {
throw new IllegalStateException("this can never occur", e);
}
}).map(item -> new JRuleItemExecutionContext.JRuleAdditionalItemCheckData(item.getGroupNames()))
.orElse(new JRuleItemExecutionContext.JRuleAdditionalItemCheckData(List.of()));
}

public boolean matchPrecondition(JRuleExecutionContext jRuleExecutionContext) {
return jRuleExecutionContext.getPreconditionContextList().stream().allMatch(context -> {
final Item item;
Expand Down Expand Up @@ -327,9 +345,18 @@ public synchronized void reset() {
}

public boolean watchingForItem(String itemName) {
List<String> belongingGroups = Optional.of(itemName).map(s -> {
try {
return itemRegistry.getItem(s);
} catch (ItemNotFoundException e) {
throw new IllegalStateException("this can never occur", e);
}
}).map(Item::getGroupNames).orElse(List.of());

boolean b = this.contextList.stream().filter(context -> context instanceof JRuleItemExecutionContext)
.map(context -> ((JRuleItemExecutionContext) context))
.anyMatch(context -> context.getItemName().equals(itemName));
.anyMatch(context -> (context.getItemName().equals(itemName) && !context.isMemberOf())
|| (belongingGroups.contains(context.getItemName()) && context.isMemberOf()));
logDebug("watching for item: '{}'? -> {}", itemName, b);
return b;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.openhab.automation.jrule.internal.engine.excutioncontext;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

Expand Down Expand Up @@ -47,7 +48,7 @@ public Optional<String> getEvent() {
}

@Override
public boolean match(AbstractEvent event) {
public boolean match(AbstractEvent event, JRuleAdditionalCheckData checkData) {
return event instanceof ChannelTriggeredEvent
&& ((ChannelTriggeredEvent) event).getChannel().getAsString().equals(this.channel)
&& this.event.map(e -> e.equals(((ChannelTriggeredEvent) event).getEvent())).orElse(true);
Expand All @@ -58,4 +59,11 @@ public JRuleEvent createJRuleEvent(AbstractEvent event) {
return new JRuleChannelEvent(((ChannelTriggeredEvent) event).getChannel().getAsString(),
((ChannelTriggeredEvent) event).getEvent());
}

@Override
public String toString() {
return "JRuleChannelExecutionContext{" + "channel='" + channel + '\'' + ", event=" + event + ", logName='"
+ logName + '\'' + ", jRule=" + jRule + ", method=" + method + ", loggingTags="
+ Arrays.toString(loggingTags) + ", preconditionContextList=" + preconditionContextList + '}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
* @author Joseph (Seaside) Hagberg - Initial contribution
*/
public abstract class JRuleExecutionContext {
private final String logName;
protected final String logName;
protected final JRule jRule;
protected final Method method;
private final String[] loggingTags;
private final List<JRulePreconditionContext> preconditionContextList;
protected final String[] loggingTags;
protected final List<JRulePreconditionContext> preconditionContextList;

public JRuleExecutionContext(JRule jRule, String logName, String[] loggingTags, Method method,
List<JRulePreconditionContext> preconditionContextList) {
Expand Down Expand Up @@ -62,11 +62,22 @@ public String[] getLoggingTags() {
return loggingTags;
}

public abstract boolean match(AbstractEvent event);
public abstract boolean match(AbstractEvent event, JRuleAdditionalCheckData checkData);

public abstract JRuleEvent createJRuleEvent(AbstractEvent event);

public List<JRulePreconditionContext> getPreconditionContextList() {
return preconditionContextList;
}

@Override
public String toString() {
return "JRuleExecutionContext{" + "logName='" + logName + '\'' + ", jRule=" + jRule + ", method=" + method
+ ", loggingTags=" + Arrays.toString(loggingTags) + ", preconditionContextList="
+ preconditionContextList + '}';
}

public static class JRuleAdditionalCheckData {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,51 +13,83 @@
package org.openhab.automation.jrule.internal.engine.excutioncontext;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import org.openhab.automation.jrule.internal.JRuleLog;
import org.openhab.automation.jrule.rules.JRule;
import org.openhab.automation.jrule.rules.JRuleEventState;
import org.openhab.automation.jrule.rules.event.JRuleEvent;
import org.openhab.automation.jrule.rules.event.JRuleItemEvent;
import org.openhab.core.events.AbstractEvent;
import org.openhab.core.items.events.GroupItemStateChangedEvent;
import org.openhab.core.items.events.ItemEvent;
import org.openhab.core.items.events.ItemStateChangedEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The {@link JRuleItemChangeExecutionContext}
*
* @author Robert Delbrück - Initial contribution
*/
public class JRuleItemChangeExecutionContext extends JRuleItemExecutionContext {
private final Logger log = LoggerFactory.getLogger(JRuleItemChangeExecutionContext.class);
private final Optional<String> from;
private final Optional<String> to;

public JRuleItemChangeExecutionContext(JRule jRule, String logName, String[] loggingTags, Method method,
String itemName, Optional<Double> lt, Optional<Double> lte, Optional<Double> gt, Optional<Double> gte,
Optional<String> eq, Optional<String> neq, List<JRulePreconditionContext> preconditionContextList,
Optional<String> from, Optional<String> to) {
super(jRule, logName, loggingTags, method, itemName, lt, lte, gt, gte, eq, neq, preconditionContextList);
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, Optional<String> from, Optional<String> to) {
super(jRule, logName, loggingTags, method, itemName, memberOf, lt, lte, gt, gte, eq, neq,
preconditionContextList);
this.from = from;
this.to = to;
}

@Override
public boolean match(AbstractEvent event) {
return event instanceof ItemStateChangedEvent
&& ((ItemStateChangedEvent) event).getItemName().equals(this.getItemName())
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())
&& from.map(s -> ((ItemStateChangedEvent) event).getOldItemState().toString().equals(s)).orElse(true)
&& to.map(s -> ((ItemStateChangedEvent) event).getItemState().toString().equals(s)).orElse(true)
&& super.matchCondition(((ItemStateChangedEvent) event).getItemState().toString());
&& to.map(s -> ((ItemStateChangedEvent) event).getItemState().toString().equals(s)).orElse(true))) {
return false;
}
if (!isMemberOf() && ((ItemStateChangedEvent) event).getItemName().equals(this.getItemName())) {
return true;
}
if (isMemberOf() && checkData instanceof JRuleAdditionalItemCheckData
&& ((JRuleAdditionalItemCheckData) checkData).getBelongingGroups().contains(this.getItemName())) {
return true;
}
return false;
}

@Override
public JRuleEvent createJRuleEvent(AbstractEvent event) {
String memberName = event instanceof GroupItemStateChangedEvent
? ((GroupItemStateChangedEvent) event).getMemberName()
: null;
final String memberName;
if (isMemberOf()) {
memberName = ((ItemEvent) event).getItemName();
} else {
memberName = event instanceof GroupItemStateChangedEvent
? ((GroupItemStateChangedEvent) event).getMemberName()
: null;
}

return new JRuleItemEvent(this.getItemName(), memberName,
new JRuleEventState(((ItemStateChangedEvent) event).getItemState().toString()),
new JRuleEventState(((ItemStateChangedEvent) event).getOldItemState().toString()));
}

@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=" + jRule + ", method=" + method
+ ", loggingTags=" + Arrays.toString(loggingTags) + ", preconditionContextList="
+ preconditionContextList + '}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,21 @@
* @author Robert Delbrück - Initial contribution
*/
public abstract class JRuleItemExecutionContext extends JRuleExecutionContext {
private final String itemName;
private final Optional<Double> gt;
private final Optional<Double> gte;
private final Optional<Double> lt;
private final Optional<Double> lte;
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;

public JRuleItemExecutionContext(JRule jRule, String logName, String[] loggingTags, Method method, String itemName,
Optional<Double> lt, Optional<Double> lte, Optional<Double> gt, Optional<Double> gte, Optional<String> eq,
Optional<String> neq, List<JRulePreconditionContext> preconditionContextList) {
boolean memberOf, Optional<Double> lt, Optional<Double> lte, Optional<Double> gt, Optional<Double> gte,
Optional<String> eq, Optional<String> neq, List<JRulePreconditionContext> preconditionContextList) {
super(jRule, logName, loggingTags, method, preconditionContextList);
this.itemName = itemName;
this.memberOf = memberOf;
this.gt = gt;
this.gte = gte;
this.lt = lt;
Expand Down Expand Up @@ -97,4 +99,25 @@ public Optional<String> getEq() {
public Optional<String> getNeq() {
return neq;
}

public boolean isMemberOf() {
return memberOf;
}

public static class JRuleAdditionalItemCheckData extends JRuleAdditionalCheckData {
private final List<String> belongingGroups;

public JRuleAdditionalItemCheckData(List<String> belongingGroups) {
this.belongingGroups = belongingGroups;
}

public List<String> getBelongingGroups() {
return belongingGroups;
}

@Override
public String toString() {
return "JRuleAdditionalItemCheckData{" + "belongingGroups=" + belongingGroups + '}';
}
}
}
Loading

0 comments on commit ca9e8ff

Please sign in to comment.