Skip to content
Snippets Groups Projects
Commit 91a15d1e authored by Manuel Krombholz's avatar Manuel Krombholz Committed by René Schöne
Browse files

Added StateSyncGroup for different Item Types

parent adaa29b3
No related branches found
No related tags found
2 merge requests!19dev to master,!10Resolve "Check if item-controlling can be modeled using ECA rules"
Showing
with 499 additions and 166 deletions
aspect AdditionalTypes {
public class StringList extends beaver.Symbol implements Iterable<String> {
private java.util.Deque<String> delegatee = new java.util.ArrayDeque<>();
public class ReversedList<T> extends beaver.Symbol implements Iterable<T> {
private java.util.Deque<T> delegatee = new java.util.ArrayDeque<>();
public java.util.Iterator<String> iterator() {
public java.util.Iterator<T> iterator() {
return delegatee.descendingIterator();
}
public void add(String s) {
delegatee.add(s);
public void add(T t) {
delegatee.add(t);
}
}
public class StringList extends ReversedList<String> {}
public class ItemList extends ReversedList<Item> {}
public class TypedKeyMap<T> extends beaver.Symbol implements Iterable<AbstractMap.SimpleEntry<T, String>> {
private java.util.Deque<AbstractMap.SimpleEntry<T, String>> delegatee = new java.util.ArrayDeque<>();
......
......@@ -281,6 +281,8 @@ aspect ItemHandling {
stateUpdated(shouldSendState);
}
syn ItemObserver Item.getItemObserver() = new ItemObserver();
//--- stateUpdated ---
/**
* Called, whenever the state of an item is updated. Does various things including:
......@@ -300,10 +302,8 @@ aspect ItemHandling {
logger.catching(e);
}
}
if (hasItemObserver()) {
getItemObserver().apply();
}
}
//--- sendState ---
protected void Item.sendState() throws Exception {
......@@ -407,6 +407,7 @@ aspect ItemHandling {
SetStateFromTriggeringItemAction action = new SetStateFromTriggeringItemAction();
action.setAffectedItem(controlledItem);
rule.addAction(action);
rule.activateFor(controllerItem);
return rule;
......@@ -464,6 +465,7 @@ aspect ItemHandling {
//--- copyStateTo ---
protected abstract void Item.copyStateTo(Item stateReceiver);
protected void ItemWithBooleanState.copyStateTo(Item stateReceiver) {
stateReceiver.setStateFromBoolean(this.getState());
}
......@@ -480,6 +482,9 @@ aspect ItemHandling {
stateReceiver.setStateFromInstant(this.getState());
}
private void ColorItem.setBrightness(int value) {
setState(getState().withDifferentBrightness(value));
}
......
......@@ -29,104 +29,6 @@ aspect Navigation {
return result;
}
//--- resolveThingType ---
syn java.util.Optional<ThingType> SmartHomeEntityModel.resolveThingType(String thingTypeId) {
for (ThingType thingType : this.getThingTypeList()) {
if (thingType.getID().equals(thingTypeId)) {
return java.util.Optional.of(thingType);
}
}
return java.util.Optional.empty();
}
//--- resolveChannel ---
syn java.util.Optional<Channel> SmartHomeEntityModel.resolveChannel(String channelId) {
for (Thing thing : this.getThingList()) {
for (Channel channel : thing.getChannelList()) {
if (channel.getID().equals(channelId)) {
return java.util.Optional.of(channel);
}
}
}
return java.util.Optional.empty();
}
//--- resolveChannelType ---
syn java.util.Optional<ChannelType> SmartHomeEntityModel.resolveChannelType(String channelTypeId) {
for (ChannelType channelType : this.getChannelTypeList()) {
if (channelType.getID().equals(channelTypeId)) {
return java.util.Optional.of(channelType);
}
}
return java.util.Optional.empty();
}
//--- resolveItem ---
syn java.util.Optional<Item> SmartHomeEntityModel.resolveItem(String itemId) {
if ("activity".equals(itemId)) {
return Optional.of(getActivityItem());
}
for (Item item : items()) {
if (item.getID().equals(itemId)) {
return java.util.Optional.of(item);
}
}
return java.util.Optional.empty();
}
//--- resolveGroup ---
syn java.util.Optional<Group> SmartHomeEntityModel.resolveGroup(String groupId) {
for (Group group : this.getGroupList()) {
if (group.getID().equals(groupId)) {
return java.util.Optional.of(group);
}
}
return java.util.Optional.empty();
}
//--- resolveMqttTopic ---
syn java.util.Optional<MqttTopic> Root.resolveMqttTopic(String mqttTopicId) {
return this.getMqttRoot().resolveTopic(mqttTopicId);
}
//--- resolveItemCategory ---
syn java.util.Optional<ItemCategory> SmartHomeEntityModel.resolveItemCategory(String categoryName) {
for (ItemCategory category : getItemCategoryList()) {
if (category.getName().equals(categoryName)) {
return java.util.Optional.of(category);
}
}
return java.util.Optional.empty();
}
//--- resolveActivity ---
syn java.util.Optional<Activity> Root.resolveActivity(int identifier) {
for (Activity activity : getMachineLearningRoot().getActivityList()) {
if (activity.getIdentifier() == identifier) {
return java.util.Optional.of(activity);
}
}
return java.util.Optional.empty();
}
syn java.util.Optional<Activity> Root.resolveActivity(String label) {
for (Activity activity : getMachineLearningRoot().getActivityList()) {
if (activity.getLabel().equals(label)) {
return java.util.Optional.of(activity);
}
}
return java.util.Optional.empty();
}
//--- resolveChangeEvent ---
syn java.util.Optional<ChangeEvent> Root.resolveChangeEvent(int identifier) {
for (ChangeEvent changeEvent : getMachineLearningRoot().getChangeEventList()) {
if (changeEvent.getIdentifier() == identifier) {
return java.util.Optional.of(changeEvent);
}
}
return java.util.Optional.empty();
}
//--- containingThing ---
inh Thing Channel.containingThing();
eq Thing.getChannel().containingThing() = this;
......
......@@ -3,7 +3,7 @@ aspect Printing {
String ASTNode.safeID(ModelElement elem) { return elem == null ? "NULL" : elem.getID(); }
syn String Root.prettyPrint() {
eq Root.prettyPrint() {
StringBuilder sb = new StringBuilder();
sb.append(getSmartHomeEntityModel().prettyPrint());
sb.append(getMqttRoot().prettyPrint());
......@@ -13,7 +13,7 @@ aspect Printing {
}
//--- SmartHomeEntityModel.prettyPrint() ---
syn String SmartHomeEntityModel.prettyPrint() {
eq SmartHomeEntityModel.prettyPrint() {
StringBuilder sb = new StringBuilder();
for (Thing t : getThingList()) {
sb.append(t.prettyPrint());
......@@ -40,7 +40,7 @@ aspect Printing {
}
//Thing: id="" label="" type="" channels=["CHANNEL_ID", "CHANNEL_ID"] ;
syn String Thing.prettyPrint() {
eq Thing.prettyPrint() {
return new MemberPrinter("Thing")
.addRequired("id", getID())
.addNonDefault("label", getLabel())
......@@ -50,7 +50,7 @@ aspect Printing {
}
//ITEM_TYPE Item: id="" label="" state="" category="" topic="";
syn String Item.prettyPrint() {
eq Item.prettyPrint() {
return new MemberPrinter(prettyPrintType())
.addRequired("id", getID())
.addNonDefault("label", getLabel())
......@@ -79,7 +79,7 @@ aspect Printing {
eq DefaultItem.prettyPrintType() = "Item" ;
// special ActivityItem printing. Always omit state.
syn String ActivityItem.prettyPrint() {
eq ActivityItem.prettyPrint() {
return new MemberPrinter(prettyPrintType())
.addRequired("id", getID())
.addNonDefault("label", getLabel())
......@@ -94,7 +94,7 @@ aspect Printing {
//Group: id="" groups=["GROUP_ID", "GROUP_ID"] items=["ITEM_ID", "ITEM_ID"] aggregation=AGG;
// AGG either '"agg-name"', or '"agg-name" ("param1", "param2")'
syn String Group.prettyPrint() {
eq Group.prettyPrint() {
return new MemberPrinter("Group")
.addRequired("id", getID())
.addNonDefault("label", getLabel())
......@@ -104,7 +104,6 @@ aspect Printing {
.build();
}
syn String GroupAggregationFunction.prettyPrint();
eq SimpleGroupAggregationFunction.prettyPrint() {
if (getFunctionName() == SimpleGroupAggregationFunctionName.EQUALITY) {
return "";
......@@ -120,7 +119,7 @@ aspect Printing {
}
//ThingType: id="" label="" description="" parameters=["PARAM_ID", "PARAM_ID"] channelTypes=["CHANNEL_TYPE_ID", "CHANNEL_TYPE_ID"];
syn String ThingType.prettyPrint() {
eq ThingType.prettyPrint() {
return new MemberPrinter("ThingType")
.addRequired("id", getID())
.addNonDefault("label", getLabel())
......@@ -131,7 +130,7 @@ aspect Printing {
}
//Parameter: id="" label="" description="" type="" default="" required;
syn String Parameter.prettyPrint() {
eq Parameter.prettyPrint() {
return new MemberPrinter("Parameter")
.addRequired("id", getID())
.addNonDefault("label", getLabel())
......@@ -144,7 +143,7 @@ aspect Printing {
}
//ChannelType: id="" label="" description="" itemType="" category="" readyOnly;
syn String ChannelType.prettyPrint() {
eq ChannelType.prettyPrint() {
return new MemberPrinter("ChannelType")
.addRequired("id", getID())
.addNonDefault("label", getLabel())
......@@ -160,7 +159,7 @@ aspect Printing {
syn String SimpleChannelCategory.prettyPrint() = getValue();
//Channel: id="" type="" links=["ITEM_ID", "ITEM_ID"];
syn String Channel.prettyPrint() {
eq Channel.prettyPrint() {
return new MemberPrinter("Channel")
.addRequired("id", getID())
.addRequired("type", getType(), ChannelType::getID)
......@@ -178,7 +177,7 @@ aspect Printing {
}
//Mqtt: incoming="" outgoing="" host="";
syn String MqttRoot.prettyPrint() {
eq MqttRoot.prettyPrint() {
return new MemberPrinter("Mqtt")
.addNonDefault("incoming", getIncomingPrefix())
.addNonDefault("outgoing", getOutgoingPrefix())
......@@ -187,7 +186,7 @@ aspect Printing {
}
//Influx: user="" password="" dbName="" host="" ;
syn String InfluxRoot.prettyPrint() {
eq InfluxRoot.prettyPrint() {
return new MemberPrinter("Influx")
.addNonDefault("user", getUser(), DEFAULT_USER)
.addNonDefault("password", getPassword(), DEFAULT_PASSWORD)
......@@ -197,7 +196,7 @@ aspect Printing {
}
// Activities: { index: "name" }
syn String MachineLearningRoot.prettyPrint() {
eq MachineLearningRoot.prettyPrint() {
return new MemberPrinter("ML")
.addNodes("activities", getNumActivity(), getActivityList(),
activity -> activity.getIdentifier() + ":\"" + activity.getLabel() + "\"",
......@@ -215,7 +214,7 @@ aspect Printing {
syn String PowerExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " ^ " + getRightOperand().prettyPrint() + ")";
syn String ParenthesizedLogicalExpression.prettyPrint() = "(" + getOperand().prettyPrint() + ")";
syn String NotExpression.prettyPrint() = "!" + getOperand().prettyPrint();
syn String ComparingExpression.prettyPrint() {
eq ComparingExpression.prettyPrint() {
switch (getComparator()) {
case NotEquals: return "(" + getLeftOperand().prettyPrint() + " != " + getRightOperand().prettyPrint() + ")";
case Equals: return "(" + getLeftOperand().prettyPrint() + " == " + getRightOperand().prettyPrint() + ")";
......@@ -230,4 +229,16 @@ aspect Printing {
syn String OrExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " | " + getRightOperand().prettyPrint() + ")";
syn String Designator.prettyPrint() = getItem().getID();
// Rules
eq Rule.prettyPrint() {
return new MemberPrinter("Rule")
.addIds("TriggeringItems", getObserverList().size(), getObserverList(),
io -> io.observedItem().getID())
.addNodes("Condition", getNumCondition(), getConditionList(),
Condition::toString)
.addNodes("Action", getNumAction(), getActionList(),
Action::toString)
.build();
}
}
aspect Resolving {
//--- resolveThingType ---
syn java.util.Optional<ThingType> SmartHomeEntityModel.resolveThingType(String thingTypeId) {
for (ThingType thingType : this.getThingTypeList()) {
if (thingType.getID().equals(thingTypeId)) {
return java.util.Optional.of(thingType);
}
}
return java.util.Optional.empty();
}
//--- resolveChannel ---
syn java.util.Optional<Channel> SmartHomeEntityModel.resolveChannel(String channelId) {
for (Thing thing : this.getThingList()) {
for (Channel channel : thing.getChannelList()) {
if (channel.getID().equals(channelId)) {
return java.util.Optional.of(channel);
}
}
}
return java.util.Optional.empty();
}
//--- resolveChannelType ---
syn java.util.Optional<ChannelType> SmartHomeEntityModel.resolveChannelType(String channelTypeId) {
for (ChannelType channelType : this.getChannelTypeList()) {
if (channelType.getID().equals(channelTypeId)) {
return java.util.Optional.of(channelType);
}
}
return java.util.Optional.empty();
}
//--- resolveItem ---
syn java.util.Optional<Item> SmartHomeEntityModel.resolveItem(String itemId) {
if ("activity".equals(itemId)) {
return Optional.of(getActivityItem());
}
for (Item item : items()) {
if (item.getID().equals(itemId)) {
return java.util.Optional.of(item);
}
}
return java.util.Optional.empty();
}
//--- resolveGroup ---
syn java.util.Optional<Group> SmartHomeEntityModel.resolveGroup(String groupId) {
for (Group group : this.getGroupList()) {
if (group.getID().equals(groupId)) {
return java.util.Optional.of(group);
}
}
return java.util.Optional.empty();
}
//--- resolveMqttTopic ---
syn java.util.Optional<MqttTopic> Root.resolveMqttTopic(String mqttTopicId) {
return this.getMqttRoot().resolveTopic(mqttTopicId);
}
//--- resolveItemCategory ---
syn java.util.Optional<ItemCategory> SmartHomeEntityModel.resolveItemCategory(String categoryName) {
for (ItemCategory category : getItemCategoryList()) {
if (category.getName().equals(categoryName)) {
return java.util.Optional.of(category);
}
}
return java.util.Optional.empty();
}
//--- resolveActivity ---
syn java.util.Optional<Activity> Root.resolveActivity(int identifier) {
for (Activity activity : getMachineLearningRoot().getActivityList()) {
if (activity.getIdentifier() == identifier) {
return java.util.Optional.of(activity);
}
}
return java.util.Optional.empty();
}
syn java.util.Optional<Activity> Root.resolveActivity(String label) {
for (Activity activity : getMachineLearningRoot().getActivityList()) {
if (activity.getLabel().equals(label)) {
return java.util.Optional.of(activity);
}
}
return java.util.Optional.empty();
}
//--- resolveChangeEvent ---
syn java.util.Optional<ChangeEvent> Root.resolveChangeEvent(int identifier) {
for (ChangeEvent changeEvent : getMachineLearningRoot().getChangeEventList()) {
if (changeEvent.getIdentifier() == identifier) {
return java.util.Optional.of(changeEvent);
}
}
return java.util.Optional.empty();
}
// implementing resolving for relations
refine RefResolverStubs eq StateSyncGroup.resolveTargetItemByToken(String id, int position) {
return getRoot().getSmartHomeEntityModel().resolveItem(id).orElseThrow(() -> new RuntimeException("Item '" + id + "' not found!"));
}
}
......@@ -24,10 +24,8 @@ 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) Get ItemObserver
ItemObserver itemObserver = item.getItemObserver();
// 1.a) Check if observer already triggers this rule
for (Rule rule : itemObserver.getTriggeredRules()) {
if (rule.equals(this)) {
......@@ -35,18 +33,11 @@ aspect Rules {
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);
}
}
......@@ -73,14 +64,6 @@ aspect Rules {
return executor.scheduleAtFixedRate(() -> trigger(null), initialDelay, period, unit);
}
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);
}
}
// --- Condition.holdsFor ---
syn boolean Condition.holdsFor(Item item);
......@@ -109,7 +92,11 @@ aspect Rules {
getAffectedItem().setStateFromString(getNewStateProvider().get());
}
public void SetStateFromTriggeringItemAction.applyFor(Item item) {
item.copyStateTo(getAffectedItem());
Item target = getAffectedItem();
if (target==item) {
return;
}
item.copyStateTo(target);
}
public void SetStateFromItemsAction.applyFor(Item item) {
getAffectedItem().setStateFromString(getCombinator().apply(getSourceItems()));
......@@ -122,3 +109,18 @@ aspect Rules {
}
}
aspect StateSyncGroup {
rewrite StateSyncGroup {
to Rule {
Rule rule = new Rule();
for (Item item : getTargetItemList()) {
rule.addAction(new SetStateFromTriggeringItemAction(item));
rule.addObserver(item.getItemObserver());
}
return rule;
}
}
}
......@@ -28,3 +28,6 @@ MultiplyDoubleToStateAction : SetStateAction ::= <Multiplier:double> ;
ItemObserver ::= ;
rel ItemObserver.TriggeredRule* <-> Rule.Observer* ;
StateSyncGroup : Rule ;
rel StateSyncGroup.TargetItem* -> Item;
......@@ -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); }
......
......@@ -3,6 +3,7 @@ package de.tudresden.inf.st.eraser.jastadd.parser;
import de.tudresden.inf.st.eraser.jastadd.model.*;
import de.tudresden.inf.st.eraser.jastadd.model.Action;
import de.tudresden.inf.st.eraser.parser.EraserParserHelper;
import de.tudresden.inf.st.eraser.jastadd.model.StateSyncGroup;
import java.util.Map;
import java.util.HashMap;
:} ;
......@@ -31,6 +32,7 @@ Root goal =
thing.t goal.r {: insertZero(r.getSmartHomeEntityModel().getThingList(), t); return r; :}
| item.i goal.r {: return r; :}
| group.g goal.r {: insertZero(r.getSmartHomeEntityModel().getGroupList(), g); return r; :}
| state_sync_group.ss goal.r {: r.addRule(ss); return r; :}
| thing_type.tt goal.r {: insertZero(r.getSmartHomeEntityModel().getThingTypeList(), tt); return r; :}
| parameter goal.r {: return r; :}
| channel_type.ct goal.r {: insertZero(r.getSmartHomeEntityModel().getChannelTypeList(), ct); return r; :}
......@@ -42,6 +44,7 @@ Root goal =
| thing.t {: return eph.createRoot(t); :}
| item.i {: return eph.createRoot(); :}
| group.g {: return eph.createRoot(g); :}
| state_sync_group.ss {: return eph.createRoot(ss); :}
| thing_type.tt {: return eph.createRoot(tt); :}
| parameter {: return eph.createRoot(); :}
| channel_type.ct {: return eph.createRoot(ct); :}
......@@ -137,6 +140,10 @@ Item item_body =
| {: return eph.createItem(); :}
;
Item item_ref =
TEXT.n {: return Item.createRef(n); :}
;
Group group =
GROUP COLON group_body.gb SEMICOLON {: return gb; :}
;
......@@ -154,6 +161,21 @@ Group group_body =
| {: return new Group(); :}
;
StateSyncGroup state_sync_group = SYNCSTATE COLON syncstate_body.ssb SEMICOLON {: return ssb; :};
// SyncState: items=["ITEM_ID", "ITEM_ID"];
StateSyncGroup syncstate_body =
ITEMS EQUALS item_list.items syncstate_body.ss
{:
for (Item item : items) {
ss.addTargetItem(item);
}
return ss;
:}
| {: return new StateSyncGroup(); :}
;
ThingType thing_type =
THING_TYPE COLON thing_type_body.ttb SEMICOLON {: return ttb; :}
;
......@@ -284,6 +306,21 @@ StringList string_list_body =
:}
;
ItemList item_list =
LB_SQUARE item_list_body.ilb RB_SQUARE {: return ilb; :}
| LB_SQUARE RB_SQUARE {: return new ItemList(); :}
;
ItemList item_list_body =
item_ref.ir COMMA item_list_body.ilb {: ilb.add(ir); return ilb; :}
| item_ref.ir
{:
ItemList result = new ItemList();
result.add(ir);
return result;
:}
;
StringList round_string_list =
LB_ROUND round_string_list_body.slb RB_ROUND {: return slb; :}
| LB_ROUND RB_ROUND {: return new StringList(); :}
......
......@@ -25,7 +25,9 @@ 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> ;
......
......@@ -73,6 +73,7 @@ public class EraserParserHelper {
// when parsing expressions
this.root = EraserParserHelper.initialRoot != null ? EraserParserHelper.initialRoot : createRoot();
}
if (checkUnusedElements) {
fillUnused();
}
......@@ -93,6 +94,7 @@ public class EraserParserHelper {
resolveList(itemMap, missingItemLinkListMap, Channel::addLinkedItem);
resolveList(groupMap, missingSubGroupListMap, Group::addGroup);
resolveList(itemMap, missingItemListMap, this::addItemToGroup);
resolveList(channelTypeMap, missingChannelTypeListMap, ThingType::addChannelType);
resolveList(parameterMap, missingParameterListMap, ThingType::addParameter);
resolveList(itemMap, missingControllingListMap, Item::addControlling);
......@@ -103,6 +105,8 @@ public class EraserParserHelper {
if (checkUnusedElements) {
checkUnusedElements();
}
this.root.treeResolveAll();
}
private void addItemToGroup(Group group, Item item) {
......@@ -292,11 +296,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());
......
......@@ -80,9 +80,9 @@ public class MemberPrinter {
* @param listOfNodes the list of nodes
* @param mapping a function to map a node to a ModelElement
*/
private <T extends ASTNode> void concatIds(Iterable<T> listOfNodes,
Function<T, ? extends ModelElement> mapping) {
concatNodes(listOfNodes, t -> mapping.apply(t).getID(), true);
private <T extends ASTNode<?>> void concatIds(Iterable<T> listOfNodes,
Function<T, String> mapping) {
concatNodes(listOfNodes, mapping, true);
}
/**
......@@ -91,7 +91,7 @@ public class MemberPrinter {
* @param listOfNodes the list of nodes
* @param mapping a function to map a node to a String
*/
private <T extends ASTNode> void concatNodes(Iterable<T> listOfNodes,
private <T extends ASTNode<?>> void concatNodes(Iterable<T> listOfNodes,
Function<T, String> mapping,
boolean quote) {
boolean first = true;
......@@ -146,9 +146,9 @@ public class MemberPrinter {
* @param mapping A function to map a node to a ModelElement
* @return this
*/
public <T extends ASTNode> MemberPrinter addIds(
public <T extends ASTNode<?>> MemberPrinter addIds(
String name, int count, Iterable<T> listOfNodes,
Function<T, ? extends ModelElement> mapping) {
Function<T, String> mapping) {
if (count > 0) {
sb.append(' ').append(name).append("=[");
concatIds(listOfNodes, mapping);
......@@ -168,7 +168,7 @@ public class MemberPrinter {
* @param <T> The type of all nodes
* @return this
*/
public <T extends ASTNode> MemberPrinter addNodes(String name, int count, Iterable<T> listOfNodes,
public <T extends ASTNode<?>> MemberPrinter addNodes(String name, int count, Iterable<T> listOfNodes,
Function<T, String> mapping) {
return addNodes(name, count, listOfNodes, mapping, ListBracketType.SQUARE);
}
......@@ -183,7 +183,7 @@ public class MemberPrinter {
* @param bracketType The type of brackets to enclose the list with
* @return this
*/
public <T extends ASTNode> MemberPrinter addNodes(String name, int count, Iterable<T> listOfNodes,
public <T extends ASTNode<?>> MemberPrinter addNodes(String name, int count, Iterable<T> listOfNodes,
Function<T, String> mapping, ListBracketType bracketType) {
if (count > 0) {
sb.append(' ').append(name).append("=").append(bracketType.begin);
......@@ -214,7 +214,7 @@ public class MemberPrinter {
* @param child The child to append
* @return this
*/
public MemberPrinter addOptionalPrettyPrint(ASTNode child) {
public MemberPrinter addOptionalPrettyPrint(ASTNode<?> child) {
if (child != null) {
this.empty = false;
sb.append(child.prettyPrint());
......
......@@ -2,6 +2,8 @@ package de.tudresden.inf.st.eraser.util;
import de.tudresden.inf.st.eraser.jastadd.model.*;
import java.util.ArrayList;
/**
* Helper class to create models used in tests.
*
......@@ -35,6 +37,13 @@ public class TestUtils {
return ModelAndItem.of(root.getSmartHomeEntityModel(), item);
}
public static SmartHomeEntityModel createModelWithGroup() {
Root root = Root.createEmptyRoot();
ParserUtils.createUnknownGroup(root.getSmartHomeEntityModel(),new ArrayList<>());
return root.getSmartHomeEntityModel();
}
public static NumberItem addItemTo(SmartHomeEntityModel model, double initialValue) {
return addItemTo(model, initialValue, false);
}
......
......@@ -2,12 +2,17 @@ package de.tudresden.inf.st.eraser;
import beaver.Parser;
import de.tudresden.inf.st.eraser.jastadd.model.*;
import de.tudresden.inf.st.eraser.jastadd.model.Action;
import de.tudresden.inf.st.eraser.util.ParserUtils;
import de.tudresden.inf.st.eraser.util.TestUtils;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Disabled;
import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
......@@ -15,9 +20,9 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.StreamSupport;
import static de.tudresden.inf.st.eraser.util.TestUtils.getDefaultGroup;
import static org.assertj.core.api.Assertions.fail;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.*;
/**
* Testing the simple rule engine.
......@@ -205,7 +210,7 @@ public class RulesTest {
setState(item, 5);
assertEquals(1, counter.get(item), "Change of item state should trigger the rule");
rule.removeActivationOf(item);
rule.deactivateFor(item);
setState(item, 3);
assertEquals(1, counter.get(item), "Change of item state should not change the counter anymore");
......@@ -245,6 +250,254 @@ public class RulesTest {
assertEquals(2, counter.get(item), "Change of item to 7 should not trigger the rule, check2 violated");
}
@Test
public void testStateSyncGroupRewriteStructure() {
// init StateSyncGroup
StateSyncGroup group = new StateSyncGroup();
ArrayList<Item> items = new ArrayList<>();
// create model and an item
TestUtils.ModelAndItem mai = TestUtils.createModelAndItem(0, true);
NumberItem item0 = mai.item;
group.addTargetItem(item0);
items.add(item0);
// init more items
for (int i=1;i<=4;i++) {
NumberItem item = TestUtils.addItemTo(mai.model, i, true);
item.setID("item"+i);
group.addTargetItem(item);
items.add(item);
}
// add StateSyncGroup as rule to root
mai.model.getRoot().addRule(group);
// trace rewritten rule and its actions
Rule rewrittenRule = mai.model.getRoot().getRules().getChild(0);
ImmutableList<Action> actions = ImmutableList.copyOf(rewrittenRule.getActionList().iterator());
ImmutableList<ItemObserver> observers = ImmutableList.copyOf(rewrittenRule.getObservers().iterator());
// check general structure
assertEquals(ImmutableList.copyOf(rewrittenRule.getConditionList().iterator()).size(), 0);
assertEquals(actions.size(), 5);
// check actions and observers
for (int i=0;i<items.size();i++) {
assertTrue(actions.get(i) instanceof SetStateFromTriggeringItemAction);
assertTrue(observers.contains(items.get(i).getItemObserver()));
}
}
private static void addItemToModel(SmartHomeEntityModel model, Item item) {
getDefaultGroup(model).addItem(item);
}
@Test
public void testColorItemStateSyncGroup() {
StateSyncGroup group = new StateSyncGroup();
//init model and 3 items
SmartHomeEntityModel model = TestUtils.createModelWithGroup();
ColorItem colorItem1 = new ColorItem();
addItemToModel(model,colorItem1);
group.addTargetItem(colorItem1);
ColorItem colorItem2 = new ColorItem();
addItemToModel(model,colorItem2);
group.addTargetItem(colorItem2);
ColorItem colorItem3 = new ColorItem();
addItemToModel(model,colorItem3);
group.addTargetItem(colorItem3);
// add StateSyncGroup as rule to root and trigger rewrite
model.getRoot().addRule(group);
model.getRoot().doFullTraversal();
colorItem1.setState(TupleHSB.parse("0,0,100"));
assertEquals(colorItem1.getState(),TupleHSB.parse("0,0,100"));
assertEquals(colorItem2.getState(),TupleHSB.parse("0,0,100"));
assertEquals(colorItem3.getState(),TupleHSB.parse("0,0,100"));
colorItem3.setState(TupleHSB.parse("0,0,7"));
assertEquals(colorItem1.getState(),TupleHSB.parse("0,0,7"));
assertEquals(colorItem2.getState(),TupleHSB.parse("0,0,7"));
assertEquals(colorItem3.getState(),TupleHSB.parse("0,0,7"));
}
@Test
public void testDateTimeItemStateSyncGroup() {
StateSyncGroup group = new StateSyncGroup();
//init model and 3 items
SmartHomeEntityModel model = TestUtils.createModelWithGroup();
DateTimeItem dateTimeItem1 = new DateTimeItem();
addItemToModel(model,dateTimeItem1);
group.addTargetItem(dateTimeItem1);
DateTimeItem dateTimeItem2 = new DateTimeItem();
addItemToModel(model,dateTimeItem2);
group.addTargetItem(dateTimeItem2);
DateTimeItem dateTimeItem3 = new DateTimeItem();
addItemToModel(model,dateTimeItem3);
group.addTargetItem(dateTimeItem3);
// add StateSyncGroup as rule to root and trigger rewrite
model.getRoot().addRule(group);
model.getRoot().doFullTraversal();
Instant i1 = Instant.now();
dateTimeItem1.setState(i1);
assertEquals(dateTimeItem1.getState(),i1);
assertEquals(dateTimeItem2.getState(),i1);
assertEquals(dateTimeItem3.getState(),i1);
Instant i2 = Instant.now();
dateTimeItem3.setState(i2);
assertEquals(dateTimeItem1.getState(),i2);
assertEquals(dateTimeItem2.getState(),i2);
assertEquals(dateTimeItem3.getState(),i2);
}
/**
* Also for DimmerItem, RollerShutterItem, ActivityItem
*/
@Test
public void testDoubleStateItemStateSyncGroup() {
StateSyncGroup group = new StateSyncGroup();
//init model and 3 items
SmartHomeEntityModel model = TestUtils.createModelWithGroup();
NumberItem numberItem1 = new NumberItem();
addItemToModel(model,numberItem1);
group.addTargetItem(numberItem1);
NumberItem numberItem2 = new NumberItem();
addItemToModel(model,numberItem2);
group.addTargetItem(numberItem2);
NumberItem numberItem3 = new NumberItem();
addItemToModel(model,numberItem3);
group.addTargetItem(numberItem3);
// add StateSyncGroup as rule to root and trigger rewrite
model.getRoot().addRule(group);
model.getRoot().doFullTraversal();
numberItem1.setState(123);
assertEquals(numberItem1.getState(),123);
assertEquals(numberItem2.getState(),123);
assertEquals(numberItem3.getState(),123);
numberItem2.setState(42);
assertEquals(numberItem1.getState(),42);
assertEquals(numberItem2.getState(),42);
assertEquals(numberItem3.getState(),42);
}
/**
* Also for ImageItem, LocationItem, PlayerItem, DefaultItem
*/
@Test
public void testStringStateItemStateSyncGroup() {
StateSyncGroup group = new StateSyncGroup();
//init model and 3 items
SmartHomeEntityModel model = TestUtils.createModelWithGroup();
StringItem stringItem1 = new StringItem();
addItemToModel(model,stringItem1);
group.addTargetItem(stringItem1);
StringItem stringItem2 = new StringItem();
addItemToModel(model,stringItem2);
group.addTargetItem(stringItem2);
StringItem stringItem3 = new StringItem();
addItemToModel(model,stringItem3);
group.addTargetItem(stringItem3);
// add StateSyncGroup as rule to root and trigger rewrite
model.getRoot().addRule(group);
model.getRoot().doFullTraversal();
stringItem1.setState("123");
assertEquals(stringItem1.getState(),"123");
assertEquals(stringItem2.getState(),"123");
assertEquals(stringItem3.getState(),"123");
stringItem2.setState("Hermes");
assertEquals(stringItem1.getState(),"Hermes");
assertEquals(stringItem2.getState(),"Hermes");
assertEquals(stringItem3.getState(),"Hermes");
}
/**
* Also for ContactItem
*/
@Test
public void testBooleanStateItemStateSyncGroup() {
StateSyncGroup group = new StateSyncGroup();
//init model and 3 items
SmartHomeEntityModel model = TestUtils.createModelWithGroup();
SwitchItem switchItem1 = new SwitchItem();
addItemToModel(model,switchItem1);
group.addTargetItem(switchItem1);
SwitchItem switchItem2 = new SwitchItem();
addItemToModel(model,switchItem2);
group.addTargetItem(switchItem2);
SwitchItem switchItem3 = new SwitchItem();
addItemToModel(model,switchItem3);
group.addTargetItem(switchItem3);
// add StateSyncGroup as rule to root and trigger rewrite
model.getRoot().addRule(group);
model.getRoot().doFullTraversal();
switchItem3.setState(false);
assertFalse(switchItem1.getState());
assertFalse(switchItem2.getState());
assertFalse(switchItem3.getState());
switchItem1.setState(true);
assertTrue(switchItem1.getState());
assertTrue(switchItem2.getState());
assertTrue(switchItem3.getState());
}
@Test
public void testTwoActions() {
TestUtils.ModelAndItem modelAndItem = createModelAndItem(2);
......@@ -673,7 +926,7 @@ public class RulesTest {
private StringItem addStringItem(SmartHomeEntityModel model, String initialValue) {
StringItem item = new StringItem();
Group group = TestUtils.getDefaultGroup(model);
Group group = getDefaultGroup(model);
item.setID("item" + group.getNumItem());
item.setState(initialValue, false);
group.addItem(item);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment