diff --git a/eraser-base/src/main/jastadd/Item.jrag b/eraser-base/src/main/jastadd/Item.jrag index 5c03824f96b9de7db5a5ddeb0c4a330b516db4f9..2473947b7cba1be7e26f5b265e41fc9e75fdec0c 100644 --- a/eraser-base/src/main/jastadd/Item.jrag +++ b/eraser-base/src/main/jastadd/Item.jrag @@ -300,9 +300,7 @@ aspect ItemHandling { logger.catching(e); } } - if (hasItemObserver()) { - getItemObserver().apply(); - } + getItemObserver().apply(); } //--- sendState --- @@ -407,6 +405,7 @@ aspect ItemHandling { SetStateFromTriggeringItemAction action = new SetStateFromTriggeringItemAction(); action.setAffectedItem(controlledItem); rule.addAction(action); + rule.activateFor(controllerItem); return rule; @@ -463,21 +462,21 @@ aspect ItemHandling { //--- copyStateTo --- - protected abstract void Item.copyStateTo(Item stateReceiver); - protected void ItemWithBooleanState.copyStateTo(Item stateReceiver) { - stateReceiver.setStateFromBoolean(this.getState()); + protected abstract void Item.copyStateTo(Item... stateReceivers); + protected void ItemWithBooleanState.copyStateTo(Item... stateReceivers) { + Arrays.asList(stateReceivers).forEach(s -> s.setStateFromBoolean(this.getState())); } - protected void ItemWithStringState.copyStateTo(Item stateReceiver) { - stateReceiver.setStateFromString(this.getState()); + protected void ItemWithStringState.copyStateTo(Item... stateReceivers) { + Arrays.asList(stateReceivers).forEach(s -> s.setStateFromString(this.getState())); } - protected void ItemWithDoubleState.copyStateTo(Item stateReceiver) { - stateReceiver.setStateFromDouble(this.getState()); + protected void ItemWithDoubleState.copyStateTo(Item... stateReceivers) { + Arrays.asList(stateReceivers).forEach(s -> s.setStateFromDouble(this.getState())); } - protected void ColorItem.copyStateTo(Item stateReceiver) { - stateReceiver.setStateFromColor(this.getState()); + protected void ColorItem.copyStateTo(Item... stateReceivers) { + Arrays.asList(stateReceivers).forEach(s -> s.setStateFromColor(this.getState())); } - protected void DateTimeItem.copyStateTo(Item stateReceiver) { - stateReceiver.setStateFromInstant(this.getState()); + protected void DateTimeItem.copyStateTo(Item... stateReceivers) { + Arrays.asList(stateReceivers).forEach(s -> s.setStateFromInstant(this.getState())); } private void ColorItem.setBrightness(int value) { diff --git a/eraser-base/src/main/jastadd/Rules.jrag b/eraser-base/src/main/jastadd/Rules.jrag index 26c18ae2f1faba258a2db6aa60d5b0c6cf974575..7e550453b2e7a0140b8a019fc885d509e8f67cdb 100644 --- a/eraser-base/src/main/jastadd/Rules.jrag +++ b/eraser-base/src/main/jastadd/Rules.jrag @@ -24,29 +24,20 @@ aspect Rules { eq Item.getItemObserver().observedItem() = this; public void Rule.activateFor(Item item) { - // 1) Get or create new ItemObserver, and add it to Root - ItemObserver itemObserver; - if (item.hasItemObserver()) { - itemObserver = item.getItemObserver(); - // 1.a) Check if observer already triggers this rule - for (Rule rule : itemObserver.getTriggeredRules()) { - if (rule.equals(this)) { - logger.warn("Rule already activated for item {}. Ignoring.", item); - return; - } + // 1) Get ItemObserver + ItemObserver itemObserver = item.getItemObserver(); + // 1.a) Check if observer already triggers this rule + for (Rule rule : itemObserver.getTriggeredRules()) { + if (rule.equals(this)) { + logger.warn("Rule already activated for item {}. Ignoring.", item); + return; } - } else { - itemObserver = new ItemObserver(); - item.setItemObserver(itemObserver); } - // 2) Link event and itemObserver itemObserver.addTriggeredRule(this); } public void Rule.deactivateFor(Item item) { - if (item.hasItemObserver()) { - item.getItemObserver().removeTriggeredRule(this); - } + item.getItemObserver().removeTriggeredRule(this); } @@ -74,12 +65,7 @@ aspect Rules { } public void Rule.removeActivationOf(Item item) { - if (item.hasItemObserver()) { - item.getItemObserver().removeTriggeredRule(this); - } else { - // there is no observer yet - logger.warn("Item {} was never activated before.", item); - } + item.getItemObserver().removeTriggeredRule(this); } // --- Condition.holdsFor --- @@ -122,3 +108,21 @@ aspect Rules { } } + +aspect StateSyncGroup { + rewrite StateSyncGroup { + to Rule { + Item controllingItem = ((ItemObserver)getParent()).observedItem(); + + SetStateFromTriggeringItemAction action = new SetStateFromTriggeringItemAction(); + + /* + action.setAffectedItems(getItems()) + */ + + Rule rule = new Rule(); + rule.addAction(action); + return rule; + } + } +} diff --git a/eraser-base/src/main/jastadd/Rules.relast b/eraser-base/src/main/jastadd/Rules.relast index 25a0fd2b41f3f1051e03d06ace4f41b6907030e6..79d24a4259ee7c37d3b587f9eab96d645bb3dc99 100644 --- a/eraser-base/src/main/jastadd/Rules.relast +++ b/eraser-base/src/main/jastadd/Rules.relast @@ -28,3 +28,7 @@ MultiplyDoubleToStateAction : SetStateAction ::= <Multiplier:double> ; ItemObserver ::= ; rel ItemObserver.TriggeredRule* <-> Rule.Observer* ; + + +StateSyncGroup : Rule ::= Item*; + diff --git a/eraser-base/src/main/jastadd/eraser.flex b/eraser-base/src/main/jastadd/eraser.flex index 5f70414fa4005ad1baf1b0623459ce7c5f2f69f2..e81c7f7f33cb847ead9d5caea9d273265869c084 100644 --- a/eraser-base/src/main/jastadd/eraser.flex +++ b/eraser-base/src/main/jastadd/eraser.flex @@ -57,6 +57,7 @@ Comment = "//" [^\n\r]+ "Influx" { return sym(Terminals.INFLUX); } "ML" { return sym(Terminals.ML); } "Rule" { return sym(Terminals.RULE); } +//"SyncState" { return sym(Terminals.SYNCSTATE); } // special items (group already has a token definition) "Activity" { return sym(Terminals.ACTIVITY); } "Color" { return sym(Terminals.COLOR); } diff --git a/eraser-base/src/main/jastadd/eraser.parser b/eraser-base/src/main/jastadd/eraser.parser index 68967a5655bf12cab2e2127db29e1f0ac5ebd808..74abecdd89e1817f8ae4dfe0ad997d470d24c8a2 100644 --- a/eraser-base/src/main/jastadd/eraser.parser +++ b/eraser-base/src/main/jastadd/eraser.parser @@ -154,6 +154,17 @@ Group group_body = | {: return new Group(); :} ; + + +// SYNCSTATE COLON syncstate_body.ssb SEMICOLON {: eph.addStateSyncGroup(ssb); :}; +// StateSyncGroup ssg = SYNCSTATE COLON syncstate_body.ssb SEMICOLON {: return ssb; :}; +// +//// SyncState: items=["ITEM_ID", "ITEM_ID"]; +//StateSyncGroup syncstate_body = +// ITEMS EQUALS string_list.items syncstate_body.ss {: return eph.setItems(ss, items); :} +// | {: return new StateSyncGroup(); :} +// ; + ThingType thing_type = THING_TYPE COLON thing_type_body.ttb SEMICOLON {: return ttb; :} ; diff --git a/eraser-base/src/main/jastadd/shem.relast b/eraser-base/src/main/jastadd/shem.relast index ca1878ac6d2722a3e2a1671e066b19c5175c7be6..9e7252ffc151f6b276b96dbe6ff3e0bad0479818 100644 --- a/eraser-base/src/main/jastadd/shem.relast +++ b/eraser-base/src/main/jastadd/shem.relast @@ -25,7 +25,7 @@ rel Channel.LinkedItem* <-> Item.Channel? ; Parameter : DescribableModelElement ::= <Type:ParameterValueType> [DefaultValue:ParameterDefaultValue] <Context:String> <Required:boolean> ; ParameterDefaultValue ::= <Value:String> ; -abstract Item : LabelledModelElement ::= <_fetched_data:boolean> MetaData:ItemMetaData* [ItemObserver] ; +abstract Item : LabelledModelElement ::= <_fetched_data:boolean> MetaData:ItemMetaData* ItemObserver; rel Item.Category? -> ItemCategory ; abstract ItemWithBooleanState : Item ::= <_state:boolean> ; diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java index 795d469bc786cfde73b12f8329956cbb79bb953a..87cd2764f8955c472b37e6abc887fa5c04d0a9b8 100644 --- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java +++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java @@ -24,6 +24,7 @@ public class EraserParserHelper { private Map<String, Parameter> parameterMap = new HashMap<>(); private Map<String, Item> itemMap = new HashMap<>(); private Map<String, Group> groupMap = new HashMap<>(); + private Map<String, StateSyncGroup> stateSyncMap = new HashMap<>(); private Map<Thing, String> missingThingTypeMap = new HashMap<>(); private Map<Channel, String> missingChannelTypeMap = new HashMap<>(); @@ -36,6 +37,7 @@ public class EraserParserHelper { private Map<Item, Iterable<String>> missingControllingListMap = new HashMap<>(); private Map<Group, Iterable<String>> missingSubGroupListMap = new HashMap<>(); private Map<Group, Iterable<String>> missingItemListMap = new HashMap<>(); + private Map<StateSyncGroup, Iterable<String>> missingSyncItemListMap = new HashMap<>(); private Map<ThingType, Iterable<String>> missingChannelTypeListMap = new HashMap<>(); private Map<ThingType, Iterable<String>> missingParameterListMap = new HashMap<>(); @@ -93,10 +95,15 @@ public class EraserParserHelper { resolveList(itemMap, missingItemLinkListMap, Channel::addLinkedItem); resolveList(groupMap, missingSubGroupListMap, Group::addGroup); resolveList(itemMap, missingItemListMap, this::addItemToGroup); + resolveList(itemMap, missingSyncItemListMap, this::addItemToStateSync); + resolveList(channelTypeMap, missingChannelTypeListMap, ThingType::addChannelType); resolveList(parameterMap, missingParameterListMap, ThingType::addParameter); resolveList(itemMap, missingControllingListMap, Item::addControlling); + // TODO: activate state sync stuff + this.activateStateSyncItems(); + createUnknownGroupIfNecessary(); createChannelCategories(); createItemCategories(); @@ -110,6 +117,12 @@ public class EraserParserHelper { group.addItem(item); } + private void addItemToStateSync(StateSyncGroup stateSyncGroup, Item item) { + stateSyncGroup.addItem(item); + } + + + private void fillUnused() { unusedElements.addAll(thingTypeMap.values()); unusedElements.addAll(channelTypeMap.values()); @@ -153,7 +166,7 @@ public class EraserParserHelper { unusedElements.forEach(elem -> logger.info("{} '{}' defined, but not referenced.", elem.getClass().getSimpleName(), ident(elem))); } - private String ident(ASTNode elem) { + private String ident(Object elem) { if (elem instanceof ModelElement) { return ((ModelElement) elem).getID(); } else if (elem instanceof MqttTopic) { @@ -166,7 +179,7 @@ public class EraserParserHelper { return elem.toString(); } - private <Src extends ASTNode, Target extends ASTNode> void resolveList( + private <Src, Target extends ASTNode> void resolveList( Map<String, Target> resolved, Map<Src, Iterable<String>> missing, BiConsumer<Src, Target> adder) { missing.forEach( (elem, keyList) -> keyList.forEach( @@ -174,14 +187,14 @@ public class EraserParserHelper { missing.clear(); } - private <Src extends ASTNode, Target extends ASTNode> void resolve( + private <Src, Target extends ASTNode> void resolve( Map<String, Target> resolved, Map<Src, String> missing, BiConsumer<Src, Target> setter) { missing.forEach( (elem, key) -> resolve0(resolved, key, elem, setter)); missing.clear(); } - private <Src extends ASTNode, Target extends ASTNode> void resolve0( + private <Src, Target extends ASTNode> void resolve0( Map<String, Target> resolved, String key, Src elem, BiConsumer<Src, Target> action) { Target value = resolved.get(key); if (value == null) { @@ -195,6 +208,14 @@ public class EraserParserHelper { action.accept(elem, value); } + private void activateStateSyncItems() { + for (StateSyncGroup stateSyncGroup : new ArrayList<StateSyncGroup>()) { + + for (Item item : stateSyncGroup.getItems()) { + } + } + } + //--- Thing and ThingType --- public Thing addThingType(Thing t, String typeName) { @@ -292,11 +313,6 @@ public class EraserParserHelper { return item; } - public Item setControlling(Item item, StringList controlling) { - missingControllingListMap.put(item, controlling); - return item; - } - public Item retype(Item itemWithCorrectType, Item prototype) { itemWithCorrectType.setID(prototype.getID()); itemWithCorrectType.setLabel(prototype.getLabel()); @@ -478,6 +494,17 @@ public class EraserParserHelper { return result; } + //--- SyncState --- + public StateSyncGroup setItems(StateSyncGroup ssg, StringList itemNames) { + missingSyncItemListMap.put(ssg, itemNames); + return ssg; + } + + public void addStateSyncGroup(StateSyncGroup ssg) { + System.out.println("Gotcha"); + } + + public Rule createRule(Condition c, Action a) { Rule result = new Rule(); result.addCondition(c);