diff --git a/README.md b/README.md index 53e6274b..b1b06b42 100644 --- a/README.md +++ b/README.md @@ -718,11 +718,14 @@ public void testPower(JRuleEvent event) { ## Example 35 -Use case: Want to listen on all Item events of a group (without the groupstate must change) +Use case: Want to listen on all Item events of a group (without the groupstate must change). + Alternatively you could just listen to just Group changes or (real) Item changes ```java @JRuleName("MemberOfUpdateTrigger") - @JRuleWhenItemReceivedUpdate(item = _MySwitchGroup.ITEM, memberOf = true) + @JRuleWhenItemReceivedUpdate(item = _MySwitchGroup.ITEM, memberOf = JRuleMemberOf.All) + //@JRuleWhenItemReceivedUpdate(item = _MySwitchGroup.ITEM, memberOf = JRuleMemberOf.Items) + //@JRuleWhenItemReceivedUpdate(item = _MySwitchGroup.ITEM, memberOf = JRuleMemberOf.Groups) public synchronized void memberOfUpdateTrigger(JRuleItemEvent event) { final String memberThatChangedStatus = event.getMemberName(); logInfo("Member that changed the status of the Group of switches: {}", memberThatChangedStatus); diff --git a/src/main/java/org/openhab/automation/jrule/internal/engine/JRuleEngine.java b/src/main/java/org/openhab/automation/jrule/internal/engine/JRuleEngine.java index 339aa3f1..d2663823 100644 --- a/src/main/java/org/openhab/automation/jrule/internal/engine/JRuleEngine.java +++ b/src/main/java/org/openhab/automation/jrule/internal/engine/JRuleEngine.java @@ -38,6 +38,7 @@ import org.apache.commons.lang3.exception.ExceptionUtils; import org.eclipse.jdt.annotation.NonNull; import org.openhab.automation.jrule.exception.JRuleItemNotFoundException; +import org.openhab.automation.jrule.exception.JRuleRuntimeException; import org.openhab.automation.jrule.internal.JRuleConfig; import org.openhab.automation.jrule.internal.JRuleLog; import org.openhab.automation.jrule.internal.engine.excutioncontext.JRuleChannelExecutionContext; @@ -58,6 +59,7 @@ import org.openhab.automation.jrule.rules.JRuleCondition; import org.openhab.automation.jrule.rules.JRuleDebounce; import org.openhab.automation.jrule.rules.JRuleLogName; +import org.openhab.automation.jrule.rules.JRuleMemberOf; import org.openhab.automation.jrule.rules.JRuleName; import org.openhab.automation.jrule.rules.JRulePrecondition; import org.openhab.automation.jrule.rules.JRuleTag; @@ -71,9 +73,7 @@ import org.openhab.automation.jrule.rules.event.JRuleEvent; import org.openhab.automation.jrule.things.JRuleThingStatus; import org.openhab.core.events.AbstractEvent; -import org.openhab.core.items.Item; -import org.openhab.core.items.ItemNotFoundException; -import org.openhab.core.items.ItemRegistry; +import org.openhab.core.items.*; import org.openhab.core.items.events.ItemEvent; import org.openhab.core.library.types.QuantityType; import org.openhab.core.scheduler.CronScheduler; @@ -278,8 +278,17 @@ private JRuleItemExecutionContext.JRuleAdditionalItemCheckData getAdditionalChec } catch (ItemNotFoundException e) { throw new IllegalStateException("this can never occur", e); } - }).map(item -> new JRuleItemExecutionContext.JRuleAdditionalItemCheckData(item.getGroupNames())) - .orElse(new JRuleItemExecutionContext.JRuleAdditionalItemCheckData(List.of())); + }).map(item -> new JRuleItemExecutionContext.JRuleAdditionalItemCheckData(item.getType().equals(GroupItem.TYPE), + item.getGroupNames())) + .orElse(new JRuleItemExecutionContext.JRuleAdditionalItemCheckData(false, List.of())); + } + + private Item getItem(String name) { + try { + return itemRegistry.getItem(name); + } catch (ItemNotFoundException e) { + throw new JRuleRuntimeException(String.format("cannot find item: %s", name), e); + } } public boolean matchPrecondition(JRuleExecutionContext jRuleExecutionContext) { @@ -353,18 +362,14 @@ public synchronized void reset() { } public boolean watchingForItem(String itemName) { - List 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()); + List parentGroups = Optional.of(itemName).map(this::getItem).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) && !context.isMemberOf()) - || (belongingGroups.contains(context.getItemName()) && context.isMemberOf())); + .anyMatch(context -> (context.getItemName().equals(itemName) + && context.getMemberOf() == JRuleMemberOf.None) + || (parentGroups.contains(context.getItemName()) + && context.getMemberOf() != JRuleMemberOf.None)); logDebug("watching for item: '{}'? -> {}", itemName, b); return b; } diff --git a/src/main/java/org/openhab/automation/jrule/internal/engine/excutioncontext/JRuleItemChangeExecutionContext.java b/src/main/java/org/openhab/automation/jrule/internal/engine/excutioncontext/JRuleItemChangeExecutionContext.java index 79d13842..86e69030 100644 --- a/src/main/java/org/openhab/automation/jrule/internal/engine/excutioncontext/JRuleItemChangeExecutionContext.java +++ b/src/main/java/org/openhab/automation/jrule/internal/engine/excutioncontext/JRuleItemChangeExecutionContext.java @@ -20,6 +20,7 @@ import org.openhab.automation.jrule.internal.handler.JRuleEventHandler; import org.openhab.automation.jrule.rules.JRule; +import org.openhab.automation.jrule.rules.JRuleMemberOf; import org.openhab.automation.jrule.rules.event.JRuleEvent; import org.openhab.automation.jrule.rules.event.JRuleItemEvent; import org.openhab.core.events.AbstractEvent; @@ -41,7 +42,7 @@ public class JRuleItemChangeExecutionContext extends JRuleItemExecutionContext { private final Optional previousConditionContext; public JRuleItemChangeExecutionContext(JRule jRule, String logName, String[] loggingTags, Method method, - String itemName, boolean memberOf, Optional conditionContext, + String itemName, JRuleMemberOf memberOf, Optional conditionContext, Optional previousConditionContext, List preconditionContextList, Optional from, Optional to, Duration timedLock) { @@ -66,28 +67,41 @@ && 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())) { + if (getMemberOf() == JRuleMemberOf.None + && ((ItemStateChangedEvent) event).getItemName().equals(this.getItemName())) { return true; } - if (isMemberOf() && checkData instanceof JRuleAdditionalItemCheckData - && ((JRuleAdditionalItemCheckData) checkData).getBelongingGroups().contains(this.getItemName())) { - return true; + if (getMemberOf() != JRuleMemberOf.None && checkData instanceof JRuleAdditionalItemCheckData) { + JRuleAdditionalItemCheckData itemCheckData = (JRuleAdditionalItemCheckData) checkData; + switch (getMemberOf()) { + case All: + return itemCheckData.getBelongingGroups().contains(this.getItemName()); + case Groups: + return itemCheckData.getBelongingGroups().contains(this.getItemName()) && itemCheckData.isGroup(); + case Items: + return itemCheckData.getBelongingGroups().contains(this.getItemName()) && !itemCheckData.isGroup(); + default: + return false; + } } return false; } @Override public JRuleEvent createJRuleEvent(AbstractEvent event) { + final String itemName; final String memberName; - if (isMemberOf()) { + if (getMemberOf() != JRuleMemberOf.None) { + itemName = this.getItemName(); memberName = ((ItemEvent) event).getItemName(); } else { + itemName = this.getItemName(); memberName = event instanceof GroupItemStateChangedEvent ? ((GroupItemStateChangedEvent) event).getMemberName() : null; } - return new JRuleItemEvent(this.getItemName(), memberName, + return new JRuleItemEvent(itemName, memberName, JRuleEventHandler.get().toValue(((ItemStateChangedEvent) event).getItemState()), JRuleEventHandler.get().toValue(((ItemStateChangedEvent) event).getOldItemState())); } diff --git a/src/main/java/org/openhab/automation/jrule/internal/engine/excutioncontext/JRuleItemExecutionContext.java b/src/main/java/org/openhab/automation/jrule/internal/engine/excutioncontext/JRuleItemExecutionContext.java index b52abeda..e76f4532 100644 --- a/src/main/java/org/openhab/automation/jrule/internal/engine/excutioncontext/JRuleItemExecutionContext.java +++ b/src/main/java/org/openhab/automation/jrule/internal/engine/excutioncontext/JRuleItemExecutionContext.java @@ -21,6 +21,7 @@ import org.apache.commons.lang3.math.NumberUtils; import org.openhab.automation.jrule.rules.JRule; import org.openhab.automation.jrule.rules.JRuleCondition; +import org.openhab.automation.jrule.rules.JRuleMemberOf; import org.openhab.core.library.types.QuantityType; /** @@ -30,11 +31,11 @@ */ public abstract class JRuleItemExecutionContext extends JRuleExecutionContext { protected final String itemName; - protected final boolean memberOf; + protected final JRuleMemberOf memberOf; protected final Optional conditionContext; public JRuleItemExecutionContext(JRule jRule, String logName, String[] loggingTags, Method method, String itemName, - boolean memberOf, Optional conditionContext, + JRuleMemberOf memberOf, Optional conditionContext, List preconditionContextList, Duration timedLock) { super(jRule, logName, loggingTags, method, preconditionContextList, timedLock); this.itemName = itemName; @@ -50,14 +51,16 @@ public boolean matchCondition(String state, String previousState) { return conditionContext.map(c -> c.matchCondition(state)).orElse(true); } - public boolean isMemberOf() { + public JRuleMemberOf getMemberOf() { return memberOf; } public static class JRuleAdditionalItemCheckData extends JRuleAdditionalCheckData { + private final boolean group; private final List belongingGroups; - public JRuleAdditionalItemCheckData(List belongingGroups) { + public JRuleAdditionalItemCheckData(boolean group, List belongingGroups) { + this.group = group; this.belongingGroups = belongingGroups; } @@ -65,9 +68,13 @@ public List getBelongingGroups() { return belongingGroups; } + public boolean isGroup() { + return group; + } + @Override public String toString() { - return "JRuleAdditionalItemCheckData{" + "belongingGroups=" + belongingGroups + '}'; + return "JRuleAdditionalItemCheckData{" + "group=" + group + ", belongingGroups=" + belongingGroups + '}'; } } diff --git a/src/main/java/org/openhab/automation/jrule/internal/engine/excutioncontext/JRuleItemReceivedCommandExecutionContext.java b/src/main/java/org/openhab/automation/jrule/internal/engine/excutioncontext/JRuleItemReceivedCommandExecutionContext.java index a2bf21ce..c0bf4c2c 100644 --- a/src/main/java/org/openhab/automation/jrule/internal/engine/excutioncontext/JRuleItemReceivedCommandExecutionContext.java +++ b/src/main/java/org/openhab/automation/jrule/internal/engine/excutioncontext/JRuleItemReceivedCommandExecutionContext.java @@ -20,6 +20,7 @@ import org.openhab.automation.jrule.internal.handler.JRuleEventHandler; import org.openhab.automation.jrule.rules.JRule; +import org.openhab.automation.jrule.rules.JRuleMemberOf; import org.openhab.automation.jrule.rules.event.JRuleEvent; import org.openhab.automation.jrule.rules.event.JRuleItemEvent; import org.openhab.core.events.AbstractEvent; @@ -38,7 +39,7 @@ public class JRuleItemReceivedCommandExecutionContext extends JRuleItemExecution protected final Optional command; public JRuleItemReceivedCommandExecutionContext(JRule jRule, String logName, String[] loggingTags, Method method, - String itemName, boolean memberOf, Optional conditionContext, + String itemName, JRuleMemberOf memberOf, Optional conditionContext, List preconditionContextList, Optional command, Duration timedLock) { super(jRule, logName, loggingTags, method, itemName, memberOf, conditionContext, preconditionContextList, timedLock); @@ -53,26 +54,39 @@ && matchCondition(((ItemCommandEvent) event).getItemCommand().toString(), null) return false; } - if (!isMemberOf() && ((ItemCommandEvent) event).getItemName().equals(this.getItemName())) { + if (getMemberOf() == JRuleMemberOf.None + && ((ItemCommandEvent) event).getItemName().equals(this.getItemName())) { return true; } - if (isMemberOf() && checkData instanceof JRuleAdditionalItemCheckData - && ((JRuleAdditionalItemCheckData) checkData).getBelongingGroups().contains(this.getItemName())) { - return true; + if (getMemberOf() != JRuleMemberOf.None && checkData instanceof JRuleAdditionalItemCheckData) { + JRuleAdditionalItemCheckData itemCheckData = (JRuleAdditionalItemCheckData) checkData; + switch (getMemberOf()) { + case All: + return true; + case Groups: + return itemCheckData.getBelongingGroups().contains(this.getItemName()) && itemCheckData.isGroup(); + case Items: + return itemCheckData.getBelongingGroups().contains(this.getItemName()) && !itemCheckData.isGroup(); + default: + return false; + } } return false; } @Override public JRuleEvent createJRuleEvent(AbstractEvent event) { + final String itemName; final String memberName; - if (isMemberOf()) { + if (getMemberOf() != JRuleMemberOf.None) { memberName = ((ItemEvent) event).getItemName(); + itemName = ((ItemEvent) event).getItemName(); } else { memberName = null; + itemName = this.getItemName(); } - return new JRuleItemEvent(this.getItemName(), memberName, + return new JRuleItemEvent(itemName, memberName, JRuleEventHandler.get().toValue(((ItemCommandEvent) event).getItemCommand()), null); } diff --git a/src/main/java/org/openhab/automation/jrule/internal/engine/excutioncontext/JRuleItemReceivedUpdateExecutionContext.java b/src/main/java/org/openhab/automation/jrule/internal/engine/excutioncontext/JRuleItemReceivedUpdateExecutionContext.java index 55e98ac8..c2f0b800 100644 --- a/src/main/java/org/openhab/automation/jrule/internal/engine/excutioncontext/JRuleItemReceivedUpdateExecutionContext.java +++ b/src/main/java/org/openhab/automation/jrule/internal/engine/excutioncontext/JRuleItemReceivedUpdateExecutionContext.java @@ -20,6 +20,7 @@ import org.openhab.automation.jrule.internal.handler.JRuleEventHandler; import org.openhab.automation.jrule.rules.JRule; +import org.openhab.automation.jrule.rules.JRuleMemberOf; import org.openhab.automation.jrule.rules.event.JRuleEvent; import org.openhab.automation.jrule.rules.event.JRuleItemEvent; import org.openhab.core.events.AbstractEvent; @@ -38,7 +39,7 @@ public class JRuleItemReceivedUpdateExecutionContext extends JRuleItemExecutionC private final Optional state; public JRuleItemReceivedUpdateExecutionContext(JRule jRule, String logName, String[] loggingTags, Method method, - String itemName, boolean memberOf, Optional conditionContext, + String itemName, JRuleMemberOf memberOf, Optional conditionContext, List preconditionContextList, Optional state, Duration timedLock) { super(jRule, logName, loggingTags, method, itemName, memberOf, conditionContext, preconditionContextList, timedLock); @@ -52,26 +53,38 @@ && matchCondition(((ItemStateEvent) event).getItemState().toString(), null) && state.map(s -> ((ItemStateEvent) event).getItemState().toString().equals(s)).orElse(true))) { return false; } - if (!isMemberOf() && ((ItemStateEvent) event).getItemName().equals(this.getItemName())) { + if (getMemberOf() == JRuleMemberOf.None && ((ItemStateEvent) event).getItemName().equals(this.getItemName())) { return true; } - if (isMemberOf() && checkData instanceof JRuleAdditionalItemCheckData - && ((JRuleAdditionalItemCheckData) checkData).getBelongingGroups().contains(this.getItemName())) { - return true; + if (getMemberOf() != JRuleMemberOf.None && checkData instanceof JRuleAdditionalItemCheckData) { + JRuleAdditionalItemCheckData itemCheckData = (JRuleAdditionalItemCheckData) checkData; + switch (getMemberOf()) { + case All: + return true; + case Groups: + return itemCheckData.getBelongingGroups().contains(this.getItemName()) && itemCheckData.isGroup(); + case Items: + return itemCheckData.getBelongingGroups().contains(this.getItemName()) && !itemCheckData.isGroup(); + default: + return false; + } } return false; } @Override public JRuleEvent createJRuleEvent(AbstractEvent event) { + final String itemName; final String memberName; - if (isMemberOf()) { + if (getMemberOf() != JRuleMemberOf.None) { memberName = ((ItemEvent) event).getItemName(); + itemName = ((ItemEvent) event).getItemName(); } else { memberName = null; + itemName = this.getItemName(); } - return new JRuleItemEvent(this.getItemName(), memberName, + return new JRuleItemEvent(itemName, memberName, JRuleEventHandler.get().toValue(((ItemStateEvent) event).getItemState()), null); } diff --git a/src/main/java/org/openhab/automation/jrule/rules/JRuleMemberOf.java b/src/main/java/org/openhab/automation/jrule/rules/JRuleMemberOf.java new file mode 100644 index 00000000..54133ead --- /dev/null +++ b/src/main/java/org/openhab/automation/jrule/rules/JRuleMemberOf.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2010-2022 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.jrule.rules; + +/** + * The {@link JRuleMemberOf} + * + * @author Robert Delbrück + */ +public enum JRuleMemberOf { + /** + * Not using memberOf + */ + None, + /** + * Listen on all child items + */ + All, + /** + * Just listen on child groups + */ + Groups, + /** + * Just listen on concrete Items (without groups) + */ + Items +} diff --git a/src/main/java/org/openhab/automation/jrule/rules/JRuleWhenItemChange.java b/src/main/java/org/openhab/automation/jrule/rules/JRuleWhenItemChange.java index 7a314dd0..326e5ba5 100644 --- a/src/main/java/org/openhab/automation/jrule/rules/JRuleWhenItemChange.java +++ b/src/main/java/org/openhab/automation/jrule/rules/JRuleWhenItemChange.java @@ -33,7 +33,7 @@ String to() default ""; - boolean memberOf() default false; + JRuleMemberOf memberOf() default JRuleMemberOf.None; JRuleCondition condition() default @JRuleCondition; diff --git a/src/main/java/org/openhab/automation/jrule/rules/JRuleWhenItemReceivedCommand.java b/src/main/java/org/openhab/automation/jrule/rules/JRuleWhenItemReceivedCommand.java index 7b4006e2..bdb1396c 100644 --- a/src/main/java/org/openhab/automation/jrule/rules/JRuleWhenItemReceivedCommand.java +++ b/src/main/java/org/openhab/automation/jrule/rules/JRuleWhenItemReceivedCommand.java @@ -31,7 +31,7 @@ String command() default ""; - boolean memberOf() default false; + JRuleMemberOf memberOf() default JRuleMemberOf.None; JRuleCondition condition() default @JRuleCondition; } diff --git a/src/main/java/org/openhab/automation/jrule/rules/JRuleWhenItemReceivedUpdate.java b/src/main/java/org/openhab/automation/jrule/rules/JRuleWhenItemReceivedUpdate.java index f972a302..2f33be45 100644 --- a/src/main/java/org/openhab/automation/jrule/rules/JRuleWhenItemReceivedUpdate.java +++ b/src/main/java/org/openhab/automation/jrule/rules/JRuleWhenItemReceivedUpdate.java @@ -31,7 +31,7 @@ String state() default ""; - boolean memberOf() default false; + JRuleMemberOf memberOf() default JRuleMemberOf.None; JRuleCondition condition() default @JRuleCondition; } diff --git a/src/test/java/org/openhab/automation/jrule/rules/integration_test/ITJRule.java b/src/test/java/org/openhab/automation/jrule/rules/integration_test/ITJRule.java index 2282cbb3..073dbbbb 100644 --- a/src/test/java/org/openhab/automation/jrule/rules/integration_test/ITJRule.java +++ b/src/test/java/org/openhab/automation/jrule/rules/integration_test/ITJRule.java @@ -103,6 +103,20 @@ public void memberOfGroupReceivedCommand() throws IOException { verifyRuleWasExecuted(TestRules.NAME_MEMBER_OF_GROUP_RECEIVED_COMMAND); } + @Test + public void triggerJustItems() throws IOException { + sendCommand(TestRules.ITEM_STRING_GROUP_MEMBER_1, "123"); + verifyRuleWasExecuted(TestRules.NAME_TRIGGER_JUST_ITEMS); + verifyRuleWasNotExecuted(TestRules.NAME_TRIGGER_JUST_GROUPS); + } + + @Test + public void triggerJustGroups() throws IOException { + sendCommand(TestRules.ITEM_STRING_GROUP_MEMBER, "234"); + verifyRuleWasExecuted(TestRules.NAME_TRIGGER_JUST_GROUPS); + verifyRuleWasNotExecuted(TestRules.NAME_TRIGGER_JUST_ITEMS); + } + @Test public void memberOfGroupReceivedUpdate() throws IOException { postUpdate(TestRules.ITEM_SWITCH_GROUP_MEMBER1, JRuleSwitchItem.ON); diff --git a/src/test/java/org/openhab/automation/jrule/rules/user/TestRules.java b/src/test/java/org/openhab/automation/jrule/rules/user/TestRules.java index 0b12e22c..12218612 100755 --- a/src/test/java/org/openhab/automation/jrule/rules/user/TestRules.java +++ b/src/test/java/org/openhab/automation/jrule/rules/user/TestRules.java @@ -42,6 +42,17 @@ import org.openhab.automation.jrule.items.JRuleSwitchGroupItem; import org.openhab.automation.jrule.items.JRuleSwitchItem; import org.openhab.automation.jrule.rules.*; +import org.openhab.automation.jrule.rules.JRule; +import org.openhab.automation.jrule.rules.JRuleCondition; +import org.openhab.automation.jrule.rules.JRuleMemberOf; +import org.openhab.automation.jrule.rules.JRuleName; +import org.openhab.automation.jrule.rules.JRulePrecondition; +import org.openhab.automation.jrule.rules.JRuleWhenChannelTrigger; +import org.openhab.automation.jrule.rules.JRuleWhenCronTrigger; +import org.openhab.automation.jrule.rules.JRuleWhenItemChange; +import org.openhab.automation.jrule.rules.JRuleWhenItemReceivedCommand; +import org.openhab.automation.jrule.rules.JRuleWhenItemReceivedUpdate; +import org.openhab.automation.jrule.rules.JRuleWhenThingTrigger; import org.openhab.automation.jrule.rules.event.JRuleChannelEvent; import org.openhab.automation.jrule.rules.event.JRuleItemEvent; import org.openhab.automation.jrule.rules.event.JRuleThingEvent; @@ -97,7 +108,11 @@ public class TestRules extends JRule { public static final String ITEM_IMAGE_TO_CAST = "Image_To_Cast"; public static final String ITEM_ROLLERSHUTTER_TO_CAST = "Rollershutter_To_Cast"; public static final String ITEM_LOCATION_TO_CAST = "Location_To_Cast"; - private static final String ITEM_NUMBER_GROUP = "Number_Group"; + public static final String ITEM_NUMBER_GROUP_MEMBER_3 = "Number_Group_Member3"; + public static final String ITEM_STRING_GROUP_MEMBER_3 = "String_Group_Member3"; + public static final String ITEM_STRING_GROUP_MEMBER_1 = "String_Group_Member1"; + public static final String ITEM_NUMBER_GROUP = "Number_Group"; + public static final String ITEM_STRING_GROUP = "String_Group"; public static final String ITEM_RULE_FROM_RULE = "Rule_From_Rule"; public static final String NAME_TRIGGER_RULE_FROM_RULE = "Trigger Rule From Rule"; public static final String ITEM_TRIGGER_RULE_FROM_RULE = "Trigger_Rule_From_Rule"; @@ -111,6 +126,10 @@ public class TestRules extends JRule { public static final String COMMAND_TIMERS = "timers"; public static final String NAME_DEBOUNCE = "debounce"; public static final String COMMAND_DEBOUNCE = "debounce"; + public static final String NAME_TRIGGER_JUST_ITEMS = "trigger just items"; + public static final String NAME_TRIGGER_JUST_GROUPS = "trigger just groups"; + public static final String ITEM_NUMBER_GROUP_MEMBER = "Number_Group_Member"; + public static final String ITEM_STRING_GROUP_MEMBER = "String_Group_Member"; @JRuleName(NAME_SWITCH_ITEM_RECEIVED_ANY_COMMAND) @JRuleWhenItemReceivedCommand(item = ITEM_RECEIVING_COMMAND_SWITCH) @@ -177,20 +196,20 @@ public void mqttThingChangedToOffline(JRuleThingEvent event) { } @JRuleName(NAME_MEMBER_OF_GROUP_RECEIVED_COMMAND) - @JRuleWhenItemReceivedCommand(item = ITEM_SWITCH_GROUP, memberOf = true) + @JRuleWhenItemReceivedCommand(item = ITEM_SWITCH_GROUP, memberOf = JRuleMemberOf.All) public synchronized void memberOfGroupReceivedCommand(JRuleItemEvent event) { logInfo("Member of Group ({}) received command", event.getMemberName()); } @JRuleName(NAME_MEMBER_OF_GROUP_RECEIVED_UPDATE) - @JRuleWhenItemReceivedUpdate(item = ITEM_SWITCH_GROUP, memberOf = true) + @JRuleWhenItemReceivedUpdate(item = ITEM_SWITCH_GROUP, memberOf = JRuleMemberOf.All) public synchronized void memberOfGroupReceivedUpdate(JRuleItemEvent event) { final String memberThatChangedStatus = event.getMemberName(); logInfo("Member of Group ({}) received update", event.getMemberName()); } @JRuleName(NAME_MEMBER_OF_GROUP_CHANGED) - @JRuleWhenItemChange(item = ITEM_SWITCH_GROUP, memberOf = true) + @JRuleWhenItemChange(item = ITEM_SWITCH_GROUP, memberOf = JRuleMemberOf.All) public synchronized void memberOfGroupChanged(JRuleItemEvent event) { final String memberThatChangedStatus = event.getMemberName(); logInfo("Member of Group ({}) changed", event.getMemberName()); @@ -251,6 +270,18 @@ public void getMembersOfNumberGroup(JRuleItemEvent event) throws JRuleExecutionE .map(jRuleItem -> jRuleItem.getName() + ":" + jRuleItem.getType()).collect(Collectors.joining(", "))); } + @JRuleName(NAME_TRIGGER_JUST_ITEMS) + @JRuleWhenItemReceivedCommand(item = ITEM_STRING_GROUP, memberOf = JRuleMemberOf.Items) + public void triggerJustItems() { + logInfo("Triggered for Item"); + } + + @JRuleName(NAME_TRIGGER_JUST_GROUPS) + @JRuleWhenItemReceivedCommand(item = ITEM_STRING_GROUP, memberOf = JRuleMemberOf.Groups) + public void triggerJustGroups() { + logInfo("Triggered for Group"); + } + @JRuleName(NAME_CAST_ALL_TYPES) @JRuleWhenItemReceivedCommand(item = ITEM_CAST_ALL_TYPES_SWITCH) public void castAllTypes(JRuleItemEvent event) throws JRuleExecutionException { diff --git a/src/test/java/org/openhab/binding/jrule/internal/triggers/itemchange/JRuleGroupItemChangeRules.java b/src/test/java/org/openhab/binding/jrule/internal/triggers/itemchange/JRuleGroupItemChangeRules.java index 75031bab..6310f8ae 100644 --- a/src/test/java/org/openhab/binding/jrule/internal/triggers/itemchange/JRuleGroupItemChangeRules.java +++ b/src/test/java/org/openhab/binding/jrule/internal/triggers/itemchange/JRuleGroupItemChangeRules.java @@ -13,6 +13,7 @@ package org.openhab.binding.jrule.internal.triggers.itemchange; import org.openhab.automation.jrule.rules.JRule; +import org.openhab.automation.jrule.rules.JRuleMemberOf; import org.openhab.automation.jrule.rules.JRuleName; import org.openhab.automation.jrule.rules.JRuleWhenItemChange; import org.openhab.automation.jrule.rules.event.JRuleEvent; @@ -26,27 +27,40 @@ public class JRuleGroupItemChangeRules extends JRule { public static final String GROUP_ITEM = "group_item"; + public static final String SUB_GROUP_ITEM = "sub_group_item"; + public static final String GROUP_ITEM_JUST_ITEMS = "group_item_just_items"; + public static final String GROUP_ITEM_JUST_GROUPS = "group_item_just_groups"; public static final String GROUP_ITEM_FROM = "group_item_from"; public static final String GROUP_ITEM_TO = "group_item_to"; public static final String GROUP_ITEM_FROM_TO = "group_item_from_to"; @JRuleName("Test JRuleWhenGroupItemChange") - @JRuleWhenItemChange(item = GROUP_ITEM, memberOf = true) + @JRuleWhenItemChange(item = GROUP_ITEM, memberOf = JRuleMemberOf.All) public void groupItemChange(JRuleEvent event) { } + @JRuleName("Test JRuleWhenGroupItemChange/JustItems") + @JRuleWhenItemChange(item = GROUP_ITEM_JUST_ITEMS, memberOf = JRuleMemberOf.Items) + public void groupItemChangeJustItems(JRuleEvent event) { + } + + @JRuleName("Test JRuleWhenGroupItemChange/JustGroups") + @JRuleWhenItemChange(item = GROUP_ITEM_JUST_GROUPS, memberOf = JRuleMemberOf.Groups) + public void groupItemChangeJustGroups(JRuleEvent event) { + } + @JRuleName("Test JRuleWhenGroupItemChange/from") - @JRuleWhenItemChange(item = GROUP_ITEM_FROM, from = "1", memberOf = true) + @JRuleWhenItemChange(item = GROUP_ITEM_FROM, from = "1", memberOf = JRuleMemberOf.All) public void groupItemChangeFrom(JRuleEvent event) { } @JRuleName("Test JRuleWhenGroupItemChange/to") - @JRuleWhenItemChange(item = GROUP_ITEM_TO, to = "1", memberOf = true) + @JRuleWhenItemChange(item = GROUP_ITEM_TO, to = "1", memberOf = JRuleMemberOf.All) public void groupItemChangeTo(JRuleEvent event) { } @JRuleName("Test JRuleWhenGroupItemChange/from/to") - @JRuleWhenItemChange(item = GROUP_ITEM_FROM_TO, from = "1", to = "2", memberOf = true) + @JRuleWhenItemChange(item = GROUP_ITEM_FROM_TO, from = "1", to = "2", memberOf = JRuleMemberOf.All) public void groupItemChangeFromTo(JRuleEvent event) { } } diff --git a/src/test/java/org/openhab/binding/jrule/internal/triggers/itemchange/JRuleGroupItemChangeTest.java b/src/test/java/org/openhab/binding/jrule/internal/triggers/itemchange/JRuleGroupItemChangeTest.java index 21c05e0b..7cb923d7 100644 --- a/src/test/java/org/openhab/binding/jrule/internal/triggers/itemchange/JRuleGroupItemChangeTest.java +++ b/src/test/java/org/openhab/binding/jrule/internal/triggers/itemchange/JRuleGroupItemChangeTest.java @@ -25,9 +25,11 @@ import org.openhab.automation.jrule.rules.event.JRuleEvent; import org.openhab.binding.jrule.internal.rules.JRuleAbstractTest; import org.openhab.core.events.Event; +import org.openhab.core.items.GroupItem; import org.openhab.core.items.Item; import org.openhab.core.items.ItemNotFoundException; import org.openhab.core.items.events.ItemEventFactory; +import org.openhab.core.library.CoreItemFactory; import org.openhab.core.library.items.StringItem; import org.openhab.core.library.types.StringType; @@ -63,6 +65,15 @@ public void testItemChange_no_from_to() throws ItemNotFoundException { StringItem stringItem = Mockito.mock(StringItem.class); Mockito.when(stringItem.getName()).thenReturn(invocationOnMock.getArgument(0)); Mockito.when(stringItem.getGroupNames()).thenReturn(List.of(JRuleGroupItemChangeRules.GROUP_ITEM)); + Mockito.when(stringItem.getType()).thenReturn(CoreItemFactory.STRING); + return stringItem; + }); + + Mockito.when(itemRegistry.getItem(OTHER_ITEM)).then((Answer) invocationOnMock -> { + StringItem stringItem = Mockito.mock(StringItem.class); + Mockito.when(stringItem.getName()).thenReturn(invocationOnMock.getArgument(0)); + Mockito.when(stringItem.getGroupNames()).thenReturn(List.of(JRuleGroupItemChangeRules.GROUP_ITEM_TO)); + Mockito.when(stringItem.getType()).thenReturn(CoreItemFactory.STRING); return stringItem; }); @@ -72,12 +83,65 @@ public void testItemChange_no_from_to() throws ItemNotFoundException { verify(rule, times(1)).groupItemChange(Mockito.any(JRuleEvent.class)); } + @Test + public void testItemChangeJustItems() throws ItemNotFoundException { + Mockito.when(itemRegistry.getItem(MEMBER_ITEM)).then((Answer) invocationOnMock -> { + StringItem stringItem = Mockito.mock(StringItem.class); + Mockito.when(stringItem.getName()).thenReturn(invocationOnMock.getArgument(0)); + Mockito.when(stringItem.getGroupNames()) + .thenReturn(List.of(JRuleGroupItemChangeRules.GROUP_ITEM_JUST_ITEMS)); + Mockito.when(stringItem.getType()).thenReturn(CoreItemFactory.STRING); + return stringItem; + }); + Mockito.when(itemRegistry.getItem(JRuleGroupItemChangeRules.GROUP_ITEM_JUST_ITEMS)) + .thenAnswer(invocationOnMock -> new GroupItem(JRuleGroupItemChangeRules.GROUP_ITEM_JUST_ITEMS, + new StringItem("Any"))); + + JRuleGroupItemChangeRules rule = initRule(JRuleGroupItemChangeRules.class); + fireEvents(List.of(itemChangeEvent(MEMBER_ITEM, "2", "1"))); + verify(rule, times(0)).groupItemChangeJustGroups(Mockito.any(JRuleEvent.class)); + verify(rule, times(1)).groupItemChangeJustItems(Mockito.any(JRuleEvent.class)); + } + + @Test + public void testItemChangeJustGroups() throws ItemNotFoundException { + // should not trigger + Mockito.when(itemRegistry.getItem(MEMBER_ITEM)).then((Answer) invocationOnMock -> { + StringItem stringItem = Mockito.mock(StringItem.class); + Mockito.when(stringItem.getName()).thenReturn(invocationOnMock.getArgument(0)); + Mockito.when(stringItem.getGroupNames()) + .thenReturn(List.of(JRuleGroupItemChangeRules.GROUP_ITEM_JUST_GROUPS)); + Mockito.when(stringItem.getType()).thenReturn(CoreItemFactory.STRING); + return stringItem; + }); + + // should trigger + Mockito.when(itemRegistry.getItem(JRuleGroupItemChangeRules.SUB_GROUP_ITEM)) + .then((Answer) invocationOnMock -> { + GroupItem groupItem = Mockito.mock(GroupItem.class); + Mockito.when(groupItem.getName()).thenReturn(invocationOnMock.getArgument(0)); + Mockito.when(groupItem.getGroupNames()) + .thenReturn(List.of(JRuleGroupItemChangeRules.GROUP_ITEM_JUST_GROUPS)); + Mockito.when(groupItem.getType()).thenReturn(GroupItem.TYPE); + return groupItem; + }); + Mockito.when(itemRegistry.getItem(JRuleGroupItemChangeRules.GROUP_ITEM_JUST_GROUPS)) + .thenAnswer(invocationOnMock -> new GroupItem(invocationOnMock.getArgument(0), new StringItem("Any"))); + + JRuleGroupItemChangeRules rule = initRule(JRuleGroupItemChangeRules.class); + fireEvents(List.of(itemChangeEvent(JRuleGroupItemChangeRules.SUB_GROUP_ITEM, "2", "1"), + itemChangeEvent(MEMBER_ITEM, "2", "1"))); + verify(rule, times(1)).groupItemChangeJustGroups(Mockito.any(JRuleEvent.class)); + verify(rule, times(0)).groupItemChangeJustItems(Mockito.any(JRuleEvent.class)); + } + @Test public void testItemChange_from() throws ItemNotFoundException { Mockito.when(itemRegistry.getItem(MEMBER_ITEM)).then((Answer) invocationOnMock -> { StringItem stringItem = Mockito.mock(StringItem.class); Mockito.when(stringItem.getName()).thenReturn(invocationOnMock.getArgument(0)); Mockito.when(stringItem.getGroupNames()).thenReturn(List.of(JRuleGroupItemChangeRules.GROUP_ITEM_FROM)); + Mockito.when(stringItem.getType()).thenReturn(CoreItemFactory.STRING); return stringItem; }); @@ -93,6 +157,7 @@ public void testItemChange_to() throws ItemNotFoundException { StringItem stringItem = Mockito.mock(StringItem.class); Mockito.when(stringItem.getName()).thenReturn(invocationOnMock.getArgument(0)); Mockito.when(stringItem.getGroupNames()).thenReturn(List.of(JRuleGroupItemChangeRules.GROUP_ITEM_TO)); + Mockito.when(stringItem.getType()).thenReturn(CoreItemFactory.STRING); return stringItem; }); @@ -108,6 +173,7 @@ public void testItemChange_from_to() throws ItemNotFoundException { StringItem stringItem = Mockito.mock(StringItem.class); Mockito.when(stringItem.getName()).thenReturn(invocationOnMock.getArgument(0)); Mockito.when(stringItem.getGroupNames()).thenReturn(List.of(JRuleGroupItemChangeRules.GROUP_ITEM_FROM_TO)); + Mockito.when(stringItem.getType()).thenReturn(CoreItemFactory.STRING); return stringItem; }); diff --git a/src/test/resources/docker/conf/items/default.items b/src/test/resources/docker/conf/items/default.items index 73fd6af2..f757c216 100644 --- a/src/test/resources/docker/conf/items/default.items +++ b/src/test/resources/docker/conf/items/default.items @@ -17,6 +17,13 @@ Number Number_Group_Member1 (Number_Group) Number Number_Group_Member2 (Number_Group_Member) Number Number_Group_Member3 (Number_Group_Member) + +Group String_Group +Group String_Group_Member (String_Group) +String String_Group_Member1 (String_Group) +String String_Group_Member2 (String_Group_Member) +String String_Group_Member3 (String_Group_Member) + Switch Cast_All_Types_Switch Switch Switch_To_Cast Number Number_To_Cast