diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a4809bd6690274cea3db131f6ed49289898027cb..e86bf3282801b54c1a6a592dc6b388f595684e6a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,7 +12,7 @@ variables: # # Improve performance with overlayfs. # DOCKER_DRIVER: overlay2 GRADLE_OPTS: "-Dorg.gradle.daemon=false" - TEST_REPORTS: "eraser-base/build/reports/tests/" + TEST_REPORTS: "*/build/test-results/**/TEST-*.xml" TEST_LOG: "eraser-base/logs/eraser-test.log" JACOCO_REPORT: "*/build/reports/jacoco/all-tests/jacoco*Report.xml" # settings for influxdb @@ -55,8 +55,9 @@ test: when: always paths: - $TEST_LOG - - $TEST_REPORTS - $JACOCO_REPORT + reports: + junit: $TEST_REPORTS coverage: image: python:3.7.1-alpine @@ -121,4 +122,4 @@ pages: - master artifacts: paths: - - "public" + - "public" diff --git a/buildSrc/src/main/groovy/eraser.java-common-conventions.gradle b/buildSrc/src/main/groovy/eraser.java-common-conventions.gradle index 35d106e2f655c9e9d6b627913c4e9d68ba82480f..690297198bac473226b40d4da608316b7997e531 100644 --- a/buildSrc/src/main/groovy/eraser.java-common-conventions.gradle +++ b/buildSrc/src/main/groovy/eraser.java-common-conventions.gradle @@ -23,6 +23,10 @@ tasks.named('test') { } } +tasks.withType(JavaCompile) { + options.deprecation = true +} + task allTests(type: Test, dependsOn: testClasses) { description = 'Run every test' group = 'verification' diff --git a/eraser-base/src/main/jastadd/Expression.jrag b/eraser-base/src/main/jastadd/Expression.jrag index e3d6a6b6b01effb2b014bbe85b7360aea5314a3a..9e1d4f52d57a1aab055a397983578f2e38f356ab 100644 --- a/eraser-base/src/main/jastadd/Expression.jrag +++ b/eraser-base/src/main/jastadd/Expression.jrag @@ -30,4 +30,15 @@ aspect Expression { eq Designator.eval() = getItem().getStateAsDouble(); eq ParenthesizedNumberExpression.eval() = getOperand().eval(); eq NumberLiteralExpression.eval() = getValue(); + + // is-X + syn boolean Expression.isLogicalExpression() = false; + eq LogicalExpression.isLogicalExpression() = true; + syn boolean Expression.isNumberExpression() = false; + eq NumberExpression.isNumberExpression() = true; + // as-X + syn LogicalExpression Expression.asLogicalExpression() = null; + eq LogicalExpression.asLogicalExpression() = this; + syn NumberExpression Expression.asNumberExpression() = null; + eq NumberExpression.asNumberExpression() = this; } diff --git a/eraser-base/src/main/jastadd/Item.jrag b/eraser-base/src/main/jastadd/Item.jrag index 94ebdce1bc189ccbfa73b767ccacd9488936fc5c..967cc061d56453edbe95dee5cc4eba3583eb8c5a 100644 --- a/eraser-base/src/main/jastadd/Item.jrag +++ b/eraser-base/src/main/jastadd/Item.jrag @@ -375,6 +375,8 @@ aspect ItemHandling { syn boolean ItemWithDoubleState.isItemWithDoubleState() = true; syn boolean Item.isDateTimeItem() = false; syn boolean DateTimeItem.isDateTimeItem() = true; + syn boolean Item.isActivityItem() = false; + syn boolean ActivityItem.isActivityItem() = true; //--- as$ItemType --- // those attributes will raise a ClassCastException if called on the wrong item type. But what else can we do? @@ -471,7 +473,7 @@ aspect ItemHandling { //Instant lastChange = this. } - + @@ -519,5 +521,5 @@ aspect ItemHandling { eq ItemUpdateColor.getNewStateAsString() = getNewHSB().toString(); eq ItemUpdateDouble.getNewStateAsString() = Double.toString(getNewValue()); - + } diff --git a/eraser-base/src/main/jastadd/LastChanged.jrag b/eraser-base/src/main/jastadd/LastChanged.jrag index e79bfe7c8c394154f78307ca629ff64ddfd4eb2f..2ac7dfc95e247aa988f9c518b64c687477b9bbb5 100644 --- a/eraser-base/src/main/jastadd/LastChanged.jrag +++ b/eraser-base/src/main/jastadd/LastChanged.jrag @@ -1,20 +1,18 @@ aspect LastChanged { - public void LastChanged.afterStateChangeProcessed() { - this.setValue(Instant.now()); - } - - public boolean LastChanged.checkStateProcessingTime(FrequencySetting FrequencySetting) { - if (FrequencySetting==null) { - return true; - } - double frequency = FrequencySetting.getEventProcessingFrequency(); - Instant lastStateChange = this.getValue(); - if (lastStateChange==null) { - return true; - } - - return lastStateChange.toEpochMilli() + (1/frequency)*1000 < Instant.now().toEpochMilli(); + public void LastChanged.afterStateChangeProcessed() { + this.setValue(Instant.now()); + } + public boolean LastChanged.checkStateProcessingTime(FrequencySetting FrequencySetting) { + if (FrequencySetting == null) { + return true; + } + double frequency = FrequencySetting.getEventProcessingFrequency(); + Instant lastStateChange = this.getValue(); + if (lastStateChange == null) { + return true; } + return lastStateChange.toEpochMilli() + (1 / frequency) * 1000 < Instant.now().toEpochMilli(); + } -} \ No newline at end of file +} diff --git a/eraser-base/src/main/jastadd/ModelStatistics.jrag b/eraser-base/src/main/jastadd/ModelStatistics.jrag index 9ed07bd1947dd5c83792f7371d2c209e88ea3329..786f00e4b5b48ee9857d5b4154cee90aa6803880 100644 --- a/eraser-base/src/main/jastadd/ModelStatistics.jrag +++ b/eraser-base/src/main/jastadd/ModelStatistics.jrag @@ -1,19 +1,10 @@ aspect ModelStatistics { - //--- numChannels --- - syn int SmartHomeEntityModel.numChannels() { - int sum = 0; - for (Thing thing : getThingList()) { - sum += thing.getNumChannel(); - } - return sum; - } - //--- description --- syn String SmartHomeEntityModel.description() = "[" + this.getNumThingType() + " thing type(s), " + this.getNumChannelType() + " channel type(s), " - + this.numChannels() + " channel(s), " + + this.getNumChannel() + " channel(s), " + this.getNumThing() + " thing(s), " + this.getNumGroup() + " group(s), " + this.items().size() + " item(s)]"; diff --git a/eraser-base/src/main/jastadd/Navigation.jrag b/eraser-base/src/main/jastadd/Navigation.jrag index 984e1029e1aa7817396d6676f7772d9bc824d1ba..acadcc8b1a9bec73378c33aea27dc95b9ee94ecb 100644 --- a/eraser-base/src/main/jastadd/Navigation.jrag +++ b/eraser-base/src/main/jastadd/Navigation.jrag @@ -7,7 +7,27 @@ aspect Navigation { //--- items --- syn java.util.List<Item> SmartHomeEntityModel.items() { java.util.List<Item> result = new java.util.ArrayList<>(); - addItems(result, getGroupList()); + getGroupList().forEach(group -> result.addAll(group.items())); + result.addAll(unknownGroup().items()); + return result; + } + syn java.util.List<Item> Group.items() { + java.util.List<Item> result = new java.util.ArrayList<>(); + getItemList().forEach(item -> result.add(item)); + getGroupList().forEach(subgroup -> result.addAll(subgroup.items())); + return result; + } + + //--- groups --- + syn java.util.List<Group> SmartHomeEntityModel.groups() { + java.util.List<Group> result = new java.util.ArrayList<>(); + getGroupList().forEach(group -> result.addAll(group.groups())); + return result; + } + syn java.util.List<Group> Group.groups() { + java.util.List<Group> result = new java.util.ArrayList<>(); + getGroupList().forEach(subgroup -> result.addAll(subgroup.groups())); + result.add(this); return result; } @@ -16,9 +36,22 @@ aspect Navigation { inh Group Item.enclosingGroup(); eq Group.getItem().enclosingGroup() = this; eq Group.getGroup().enclosingGroup() = this; + eq SmartHomeEntityModel.unknownGroup().enclosingGroup() = null; eq SmartHomeEntityModel.getGroup().enclosingGroup() = null; eq SmartHomeEntityModel.getActivityItem().enclosingGroup() = null; + //--- containingSmartHomeEntityModel --- + inh SmartHomeEntityModel Thing.containingSmartHomeEntityModel(); + inh SmartHomeEntityModel Group.containingSmartHomeEntityModel(); + inh SmartHomeEntityModel Item.containingSmartHomeEntityModel(); + inh SmartHomeEntityModel ThingType.containingSmartHomeEntityModel(); + inh SmartHomeEntityModel Parameter.containingSmartHomeEntityModel(); + inh SmartHomeEntityModel ChannelType.containingSmartHomeEntityModel(); + inh SmartHomeEntityModel Channel.containingSmartHomeEntityModel(); + inh SmartHomeEntityModel ItemCategory.containingSmartHomeEntityModel(); + inh SmartHomeEntityModel ChannelCategory.containingSmartHomeEntityModel(); + eq SmartHomeEntityModel.getChild().containingSmartHomeEntityModel() = this; + //--- relevantFrequencySetting --- syn FrequencySetting Group.relevantFrequencySetting() { // first, use value defined on group itself, if any @@ -52,11 +85,6 @@ aspect Navigation { return null; } - //--- addItems --- - private void SmartHomeEntityModel.addItems(java.util.List<Item> result, JastAddList<Group> groups) { - groups.forEach(group -> group.getItemList().forEach(item -> result.add(item))); - } - //--- parameters --- syn java.util.Set<Parameter> SmartHomeEntityModel.parameters() { java.util.Set<Parameter> result = new java.util.TreeSet<>(modelElementComparator()); @@ -71,10 +99,6 @@ aspect Navigation { return result; } - //--- containingThing --- - inh Thing Channel.containingThing(); - eq Thing.getChannel().containingThing() = this; - //--- containingNeuralNetwork --- inh NeuralNetworkRoot OutputLayer.containingNeuralNetwork(); eq NeuralNetworkRoot.getOutputLayer().containingNeuralNetwork() = this; @@ -85,7 +109,7 @@ aspect Navigation { return Optional.empty(); } Channel channel = this.getChannel(); - Thing thing = channel.containingThing(); + Thing thing = channel.getThing(); return Optional.of(thing); } diff --git a/eraser-base/src/main/jastadd/Printing.jrag b/eraser-base/src/main/jastadd/Printing.jrag index 80661e43e7f221d38f8c5e242abe0bd3753259ec..ba63b98b78dfeaaa99a4df1fbcdc117ac05ec7ff 100644 --- a/eraser-base/src/main/jastadd/Printing.jrag +++ b/eraser-base/src/main/jastadd/Printing.jrag @@ -1,3 +1,5 @@ +import java.util.StringJoiner; + aspect Printing { syn String ASTNode.prettyPrint() { throw new UnsupportedOperationException(); } @@ -12,7 +14,7 @@ aspect Printing { return sb.toString(); } -//--- SmartHomeEntityModel.prettyPrint() --- + //--- SmartHomeEntityModel.prettyPrint() --- eq SmartHomeEntityModel.prettyPrint() { StringBuilder sb = new StringBuilder(); for (Thing t : getThingList()) { @@ -21,9 +23,12 @@ aspect Printing { for (Item i : items()) { sb.append(i.prettyPrint()); } - for (Group g : getGroupList()) { + for (Group g : groups()) { sb.append(g.prettyPrint()); } + if (unknownGroup().getNumItem() > 0 ) { + sb.append(unknownGroup().prettyPrint()); + } for (ThingType tt : getThingTypeList()) { sb.append(tt.prettyPrint()); } @@ -39,17 +44,17 @@ aspect Printing { return sb.toString(); } -//Thing: id="" label="" type="" channels=["CHANNEL_ID", "CHANNEL_ID"] ; + // Thing: id="" label="" type="" channels=["CHANNEL_ID", "CHANNEL_ID"] ; eq Thing.prettyPrint() { return new MemberPrinter("Thing") .addRequired("id", getID()) .addNonDefault("label", getLabel()) .addRequired("type", getType(), ThingType::getID) - .addIds("channels", getNumChannel(), getChannelList()) + .addIds("channels", getChannelList()) .build(); } -//ITEM_TYPE Item: id="" label="" state="" category="" topic=""; + // ITEM_TYPE Item: id="" label="" state="" category="" topic=""; eq Item.prettyPrint() { return new MemberPrinter(prettyPrintType()) .addRequired("id", getID()) @@ -57,9 +62,7 @@ aspect Printing { .addRequired("state", getStateAsString()) .addOptional("category", hasCategory(), () -> getCategory().getName()) .addOptional("topic", hasTopic(), () -> getTopic().getTopicString()) - .addNodes("metaData", getNumMetaData(), getMetaDataList(), - md -> "\"" + md.getKey() + "\":\"" + md.getValue() + "\"", - MemberPrinter.ListBracketType.CURLY) + .addOptionalPrettyPrint(getMetaData()) .build(); } @@ -77,6 +80,7 @@ aspect Printing { eq SwitchItem.prettyPrintType() = "Switch Item" ; eq ActivityItem.prettyPrintType() = "Activity Item" ; eq DefaultItem.prettyPrintType() = "Item" ; + eq ItemPrototype.prettyPrintType() = "!! prototype not converted !!" ; // special ActivityItem printing. Always omit state. eq ActivityItem.prettyPrint() { @@ -85,15 +89,24 @@ aspect Printing { .addNonDefault("label", getLabel()) .addOptional("category", hasCategory(), () -> getCategory().getName()) .addOptional("topic", hasTopic(), () -> getTopic().getTopicString()) - .addNodes("metaData", getNumMetaData(), getMetaDataList(), - md -> "\"" + md.getKey() + "\":\"" + md.getValue() + "\"", - MemberPrinter.ListBracketType.CURLY) + .addOptionalPrettyPrint(getMetaData()) .build(); } + // MetaData: metaData={"key": "value", "key": "value"} + eq MetaData.prettyPrint() { + if (getNumKeyValuePair() == 0) { + return ""; + } + StringJoiner sj = new StringJoiner(", ", " metaData={", "}"); + for (KeyValuePair keyValuePair : getKeyValuePairList()) { + sj.add("\"" + keyValuePair.getKey() + "\":\"" + keyValuePair.getValue() + "\""); + } + return sj.toString(); + } -//Group: id="" groups=["GROUP_ID", "GROUP_ID"] items=["ITEM_ID", "ITEM_ID"] aggregation=AGG; -// AGG either '"agg-name"', or '"agg-name" ("param1", "param2")' + // Group: id="" groups=["GROUP_ID", "GROUP_ID"] items=["ITEM_ID", "ITEM_ID"] aggregation=AGG; + // AGG either '"agg-name"', or '"agg-name" ("param1", "param2")' eq Group.prettyPrint() { return new MemberPrinter("Group") .addRequired("id", getID()) @@ -118,18 +131,18 @@ aspect Printing { return sb.toString(); } -//ThingType: id="" label="" description="" parameters=["PARAM_ID", "PARAM_ID"] channelTypes=["CHANNEL_TYPE_ID", "CHANNEL_TYPE_ID"]; + // ThingType: id="" label="" description="" parameters=["PARAM_ID", "PARAM_ID"] channelTypes=["CHANNEL_TYPE_ID", "CHANNEL_TYPE_ID"]; eq ThingType.prettyPrint() { return new MemberPrinter("ThingType") .addRequired("id", getID()) .addNonDefault("label", getLabel()) .addNonDefault("description", getDescription()) - .addIds("parameters", getNumParameter(), getParameters()) + .addIds("parameters", getParameters()) .addIds("channelTypes", getChannelTypes()) .build(); } -//Parameter: id="" label="" description="" type="" default="" required; + // Parameter: id="" label="" description="" type="" default="" required; eq Parameter.prettyPrint() { return new MemberPrinter("Parameter") .addRequired("id", getID()) @@ -142,7 +155,7 @@ aspect Printing { .build(); } -//ChannelType: id="" label="" description="" itemType="" category="" readyOnly; + // ChannelType: id="" label="" description="" itemType="" category="" readyOnly; eq ChannelType.prettyPrint() { return new MemberPrinter("ChannelType") .addRequired("id", getID()) @@ -154,11 +167,12 @@ aspect Printing { .build(); } + // ChannelCategory syn String DefaultChannelCategory.prettyPrint() = getValue().name(); - syn String SimpleChannelCategory.prettyPrint() = getValue(); + syn String ReferringChannelCategory.prettyPrint() = getChannelCategory().prettyPrint(); -//Channel: id="" type="" links=["ITEM_ID", "ITEM_ID"]; + // Channel: id="" type="" links=["ITEM_ID", "ITEM_ID"]; eq Channel.prettyPrint() { return new MemberPrinter("Channel") .addRequired("id", getID()) @@ -167,7 +181,7 @@ aspect Printing { .build(); } -//ExternalHost: "hostName:port" + // ExternalHost: "hostName:port" syn String ExternalHost.prettyPrint(int defaultPort) { if (getPort() == defaultPort) { // default port, do not add @@ -176,7 +190,7 @@ aspect Printing { return getHostName() + ":" + getPort(); } -//Mqtt: incoming="" outgoing="" host=""; + // Mqtt: incoming="" outgoing="" host=""; eq MqttRoot.prettyPrint() { return new MemberPrinter("Mqtt") .addNonDefault("incoming", getIncomingPrefix()) @@ -185,7 +199,7 @@ aspect Printing { .build(); } -//Influx: user="" password="" dbName="" host="" ; + // Influx: user="" password="" dbName="" host="" ; eq InfluxRoot.prettyPrint() { return new MemberPrinter("Influx") .addNonDefault("user", getUser(), DEFAULT_USER) @@ -195,7 +209,7 @@ aspect Printing { .build(); } -// Activities: { index: "name" } + // Activities: { index: "name" } eq MachineLearningRoot.prettyPrint() { return new MemberPrinter("ML") .addNodes("activities", getNumActivity(), getActivityList(), @@ -204,7 +218,7 @@ aspect Printing { .build(); } -// Expressions + // Expressions syn String ParenthesizedNumberExpression.prettyPrint() = "(" + getOperand().prettyPrint() + ")"; syn String NumberLiteralExpression.prettyPrint() = Double.toString(getValue()); syn String AddExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " + " + getRightOperand().prettyPrint() + ")"; diff --git a/eraser-base/src/main/jastadd/Resolving.jrag b/eraser-base/src/main/jastadd/Resolving.jrag index 2d3a99f76bb63228bf41c315c9c9a86a768653cd..f93ac84b73cb0032a2eec15a0f949ee9a35c9e1b 100644 --- a/eraser-base/src/main/jastadd/Resolving.jrag +++ b/eraser-base/src/main/jastadd/Resolving.jrag @@ -12,11 +12,9 @@ aspect Resolving { //--- 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); - } + for (Channel channel : this.getChannelList()) { + if (channel.getID().equals(channelId)) { + return java.util.Optional.of(channel); } } return java.util.Optional.empty(); @@ -32,13 +30,33 @@ aspect Resolving { return java.util.Optional.empty(); } + //--- resolveDefaultChannelCategory --- + syn java.util.Optional<DefaultChannelCategory> SmartHomeEntityModel.resolveDefaultChannelCategory(String name) { + for (DefaultChannelCategory dcc : this.defaultChannelCategoryList()) { + if (dcc.getValue().name().equals(name)) { + return java.util.Optional.of(dcc); + } + } + return java.util.Optional.empty(); + } + + //--- resolveParameter --- + syn java.util.Optional<Parameter> SmartHomeEntityModel.resolveParameter(String parameterId) { + for (Parameter parameter : this.getParameterList()) { + if (parameter.getID().equals(parameterId)) { + return java.util.Optional.of(parameter); + } + } + 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)) { + if (item.getID().equals(itemId) && !item.isItemPlaceHolder()) { return java.util.Optional.of(item); } } @@ -108,12 +126,51 @@ aspect Resolving { } // implementing resolving for relations - refine RefResolverStubs eq StateSyncGroup.resolveTargetItemByToken(String id, int position) { + // _._ -> Item + refine RefResolverStubs eq ASTNode.globallyResolveItemByToken(String id) { return getRoot().getSmartHomeEntityModel().resolveItem(id).orElseThrow(() -> new RuntimeException("Item '" + id + "' not found!")); } + // _._ -> FrequencySetting refine RefResolverStubs eq ASTNode.globallyResolveFrequencySettingByToken(String id) { return getRoot().resolveFrequencySetting(id).orElseThrow(() -> new RuntimeException("FrequencySetting '" + id + "' not found!")); } + // Thing.Channel* -> Channel + refine RefResolverStubs eq Thing.resolveChannelByToken(String id, int position) { + return containingSmartHomeEntityModel().resolveChannel(id).orElseThrow(() -> new RuntimeException("Channel '" + id + "' not found!")); + } + + // Thing.Type -> ThingType + refine RefResolverStubs eq Thing.resolveTypeByToken(String id) { + return containingSmartHomeEntityModel().resolveThingType(id).orElseThrow(() -> new RuntimeException("ThingType '" + id + "' not found!")); + } + + // ThingType.Parameter* -> Parameter + refine RefResolverStubs eq ThingType.resolveParameterByToken(String id, int position) { + return containingSmartHomeEntityModel().resolveParameter(id).orElseThrow(() -> new RuntimeException("Parameter '" + id + "' not found!")); + } + + // _._ -> ChannelType + refine RefResolverStubs eq ASTNode.globallyResolveChannelTypeByToken(String id) { + return getRoot().getSmartHomeEntityModel().resolveChannelType(id).orElseThrow(() -> new RuntimeException("ChannelType '" + id + "' not found!")); + } + + // ReferringChannelCategory.ChannelCategory -> DefaultChannelCategory + refine RefResolverStubs eq ReferringChannelCategory.resolveChannelCategoryByToken(String id) { + return containingSmartHomeEntityModel().resolveDefaultChannelCategory(id).orElseThrow(() -> new RuntimeException("DefaultChannelCategory '" + id + "' not found!")); + } + + // Item.Topic? <-> MqttTopic.Item* + refine RefResolverStubs eq Item.resolveTopicByToken(String id) { + // not an actual resolving, also adds the new mqtt-topic under mqtt-root + return getRoot().getMqttRoot().getOrCreateMqttTopic(id); + } + + // Item.Category? <-> ItemCategory.Items* + refine RefResolverStubs eq Item.resolveCategoryByToken(String id) { + // not an actual resolving, also adds the new item-category under containing model + return containingSmartHomeEntityModel().getOrCreateCategoryByName(id); + } + } diff --git a/eraser-base/src/main/jastadd/Util.jrag b/eraser-base/src/main/jastadd/Util.jrag index de0dfb9ef17a41f46885ca2432ced96dd5b5c449..201582e3b9facf3029ffe799a4f69c66c3671174 100644 --- a/eraser-base/src/main/jastadd/Util.jrag +++ b/eraser-base/src/main/jastadd/Util.jrag @@ -34,4 +34,35 @@ aspect Util { model.setMachineLearningRoot(new MachineLearningRoot()); return model; } + /** + * Performs a safe full traversal of the tree using getChild to trigger rewrites + */ + public void ASTNode.doSafeFullTraversal() { + for (int i = 0; i < getNumChild(); i++) { + ASTNode child = getChild(i); + if (child != null) { + child.doSafeFullTraversal(); + } + } + } + + /** + * removes the object from the AST, i.e. removes the reference from its parent to the object + * + * Please note that any intrinsic non-containment relations to the object are not removed. + * @return true, if the object had a parent. + */ + public boolean ASTNode.removeSelf() { + if (getParent() == null) { + return false; + } else { + for (int childIndex = 0; childIndex < getParent().numChildren(); childIndex++) { + if (getParent().getChild(childIndex) == this) { + getParent().removeChild(childIndex); + return true; + } + } + } + throw new RuntimeException("unable to remove child, because it was not contained in its parent!"); + } } diff --git a/eraser-base/src/main/jastadd/eraser.flex b/eraser-base/src/main/jastadd/eraser.flex index 621d9d044c0dc2d82695221d28c1da16f6dadd5c..54dff35b310e573c8efe700596f57b36b276235a 100644 --- a/eraser-base/src/main/jastadd/eraser.flex +++ b/eraser-base/src/main/jastadd/eraser.flex @@ -57,7 +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); } +"SyncState" { return sym(Terminals.SYNC_STATE); } // 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 f58525a329bc0e858283e1b5f95ef14297a3f14c..019e0c309eba8f991dc5749da407be5261a7a7ea 100644 --- a/eraser-base/src/main/jastadd/eraser.parser +++ b/eraser-base/src/main/jastadd/eraser.parser @@ -1,61 +1,137 @@ %header {: 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 de.tudresden.inf.st.eraser.jastadd.model.Action; // explicit import need to distinguish from beaver.Action +import de.tudresden.inf.st.eraser.jastadd.scanner.EraserScanner; +import de.tudresden.inf.st.eraser.util.JavaUtils; import java.util.Map; import java.util.HashMap; :} ; %embed {: - private EraserParserHelper eph = new EraserParserHelper(); private static <T extends ASTNode<?>> void insertZero(JastAddList<T> listNode, T child) { listNode.insertChild(child, 0); } + private static boolean checkUnusedElements = true; + private static Root initialRoot = null; + /** - * Post processing step after parsing a model, to resolve all references within the model. - * @throws java.util.NoSuchElementException if a reference can not be resolved + * Changes the behavior of the parser to check for unused elements. (Default: true) + * @param checkUnusedElements <code>true</code> to check for unused elements, <code>false</code> to skip the check */ - public void resolveReferences() { - eph.resolveReferences(); + public static void setCheckUnusedElements(boolean checkUnusedElements) { + checkUnusedElements = checkUnusedElements; + } + + public static void setNextInitialRoot(Root root) { + initialRoot = root; + } + + private String ensureTrailingSlash(String input) { + return input != null && !input.isEmpty() && !input.endsWith("/") ? input + "/" : input; + } + + private GroupPlaceHolder createGroupPlaceHolder(String id) { + GroupPlaceHolder result = new GroupPlaceHolder(); + result.setID(id); + return result; + } + + private ItemPlaceHolder createItemPlaceHolder(String id) { + ItemPlaceHolder result = new ItemPlaceHolder(); + result.setID(id); + return result; + } + + public Root parseRoot(EraserScanner scanner) throws java.io.IOException, beaver.Parser.Exception { + if (checkUnusedElements) { + //fillUnused(); + } + Root root = (Root) parse(scanner); + root.treeResolveAll(); + root.doSafeFullTraversal(); + + // resolve ItemPlaceHolders + for (Group g : root.getSmartHomeEntityModel().groups()) { + JastAddList<Item> items = g.getItemList(); + for (int i = 0; i < g.getNumItem(); i++) { + Item item = items.getChild(i); + Item realItem = item.realItem(); + if (item != realItem) { + realItem.removeSelf(); + item.removeSelf(); + items.insertChild(realItem, i); + } + } + } + // resolve GroupPlaceHolders + for (Group g : root.getSmartHomeEntityModel().groups()) { + JastAddList<Group> groups = g.getGroupList(); + for (int i = 0; i < g.getNumGroup(); i++) { + Group group = groups.getChild(i); + Group realGroup = group.realGroup(); + if (group != realGroup) { + realGroup.removeSelf(); + group.removeSelf(); + groups.insertChild(realGroup, i); + } + } + } + return root; + } + + public Expression parseExpression(EraserScanner scanner, short alt_goal) throws java.io.IOException, beaver.Parser.Exception { + Expression exp = (Expression) parse(scanner, alt_goal); + + // create some rule containing the expression to make resolving work + Root root = initialRoot != null ? initialRoot : Root.createEmptyRoot(); + initialRoot = null; + Rule rule = new Rule(); + switch (alt_goal) { + case AltGoals.logical_expression: + ExpressionCondition condition = new ExpressionCondition(); + condition.setLogicalExpression(exp.asLogicalExpression()); + rule.addCondition(condition); + break; + case AltGoals.number_expression: + SetStateFromExpression action = new SetStateFromExpression(); + action.setNumberExpression(exp.asNumberExpression()); + rule.addAction(action); + break; + default: + throw new IllegalArgumentException("Wrong goal passed " + alt_goal); + } + root.addRule(rule); + exp.treeResolveAll(); + exp.doSafeFullTraversal(); + return exp; } :} ; -%goal goal; +%goal root; %goal number_expression; %goal logical_expression; -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; :} - | channel.c goal.r {: return r; :} - | mqtt_root.mr goal.r {: r.setMqttRoot(mr); return r; :} - | influx_root.ir goal.r {: r.setInfluxRoot(ir); return r; :} - | machine_learning_root.ml goal.r {: r.setMachineLearningRoot(ml); return r; :} - | rule.rule goal.r {: r.addRule(rule); return r; :} - | frequency_setting.ip goal.r {: r.addFrequencySetting(ip); return r; :} - | 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); :} - | channel.c {: return eph.createRoot(); :} - | mqtt_root.mr {: return eph.createRoot(mr); :} - | influx_root.ir {: return eph.createRoot(ir); :} - | machine_learning_root.ml {: return eph.createRoot(ml); :} - | rule.rule {: return eph.createRoot(rule); :} - | frequency_setting.ip {: return eph.createRoot(ip); :} - ; +Root root = + thing.t root.r {: insertZero(r.getSmartHomeEntityModel().getThingList(), t); return r; :} + | item.i root.r {: insertZero(r.getSmartHomeEntityModel().unknownGroup().getItemList(), i); return r; :} + | group.g root.r {: insertZero(r.getSmartHomeEntityModel().getGroupList(), g); return r; :} + | state_sync_group.ss root.r {: r.addRule(ss); return r; :} + | thing_type.tt root.r {: insertZero(r.getSmartHomeEntityModel().getThingTypeList(), tt); return r; :} + | parameter.p root.r {: insertZero(r.getSmartHomeEntityModel().getParameterList(), p); return r; :} + | channel_type.ct root.r {: insertZero(r.getSmartHomeEntityModel().getChannelTypeList(), ct); return r; :} + | channel.c root.r {: insertZero(r.getSmartHomeEntityModel().getChannelList(), c); return r; :} + | mqtt_root.mr root.r {: r.setMqttRoot(mr); return r; :} + | influx_root.ir root.r {: r.setInfluxRoot(ir); return r; :} + | machine_learning_root.ml root.r {: r.setMachineLearningRoot(ml); return r; :} + | rule.rule root.r {: r.addRule(rule); return r; :} + | frequency_setting.ip root.r {: r.addFrequencySetting(ip); return r; :} + | {: return Root.createEmptyRoot(); :} + ; + +/// Expressions /// %left RB_ROUND; %left MULT, DIV; @@ -66,86 +142,81 @@ Root goal = %left AND; NumberExpression number_expression = - LB_ROUND number_expression.a MULT number_expression.b RB_ROUND {: return new MultExpression(a, b); :} - | LB_ROUND number_expression.a DIV number_expression.b RB_ROUND {: return new DivExpression(a, b); :} - | LB_ROUND number_expression.a PLUS number_expression.b RB_ROUND {: return new AddExpression(a, b); :} - | LB_ROUND number_expression.a MINUS number_expression.b RB_ROUND {: return new SubExpression(a, b); :} - | LB_ROUND number_expression.a POW number_expression.b RB_ROUND {: return new PowerExpression(a, b); :} - | literal_expression.l {: return l; :} - | designator.d {: return d; :} - | LB_ROUND number_expression.e RB_ROUND {: return new ParenthesizedNumberExpression(e); :} + LB_ROUND number_expression.a MULT number_expression.b RB_ROUND {: return new MultExpression(a, b); :} + | LB_ROUND number_expression.a DIV number_expression.b RB_ROUND {: return new DivExpression(a, b); :} + | LB_ROUND number_expression.a PLUS number_expression.b RB_ROUND {: return new AddExpression(a, b); :} + | LB_ROUND number_expression.a MINUS number_expression.b RB_ROUND {: return new SubExpression(a, b); :} + | LB_ROUND number_expression.a POW number_expression.b RB_ROUND {: return new PowerExpression(a, b); :} + | literal_expression.l {: return l; :} + | designator.d {: return d; :} + | LB_ROUND number_expression.e RB_ROUND {: return new ParenthesizedNumberExpression(e); :} ; LogicalExpression logical_expression = - LB_ROUND logical_expression.a AND logical_expression.b RB_ROUND {: return new AndExpression(a, b); :} - | LB_ROUND logical_expression.a OR logical_expression.b RB_ROUND {: return new OrExpression(a, b); :} - | EXCLAMATION logical_expression.e {: return new NotExpression(e); :} - | LB_ROUND logical_expression.e RB_ROUND {: return new ParenthesizedLogicalExpression(e); :} - | LB_ROUND number_expression.a LT number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.LessThan); :} - | LB_ROUND number_expression.a LE number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.LessOrEqualThan); :} - | LB_ROUND number_expression.a EQ number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.Equals); :} - | LB_ROUND number_expression.a NE number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.NotEquals); :} - | LB_ROUND number_expression.a GE number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.GreaterOrEqualThan); :} - | LB_ROUND number_expression.a GT number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.GreaterThan); :} + LB_ROUND logical_expression.a AND logical_expression.b RB_ROUND {: return new AndExpression(a, b); :} + | LB_ROUND logical_expression.a OR logical_expression.b RB_ROUND {: return new OrExpression(a, b); :} + | EXCLAMATION logical_expression.e {: return new NotExpression(e); :} + | LB_ROUND logical_expression.e RB_ROUND {: return new ParenthesizedLogicalExpression(e); :} + | LB_ROUND number_expression.a LT number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.LessThan); :} + | LB_ROUND number_expression.a LE number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.LessOrEqualThan); :} + | LB_ROUND number_expression.a EQ number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.Equals); :} + | LB_ROUND number_expression.a NE number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.NotEquals); :} + | LB_ROUND number_expression.a GE number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.GreaterOrEqualThan); :} + | LB_ROUND number_expression.a GT number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.GreaterThan); :} ; NumberLiteralExpression literal_expression = - INTEGER.n {: return new NumberLiteralExpression(Integer.parseInt(n)); :} - | REAL.n {: return new NumberLiteralExpression(Double.parseDouble(n)); :} + INTEGER.n {: return new NumberLiteralExpression(Integer.parseInt(n)); :} + | REAL.n {: return new NumberLiteralExpression(Double.parseDouble(n)); :} ; Designator designator = - NAME.n {: return eph.createDesignator(n); :} + NAME.n {: Designator result = new Designator(); result.setItem(Item.createRef(n)); return result; :} ; +/// SHEM /// + Thing thing = - THING COLON thing_body.tb SEMICOLON {: return tb; :} + THING COLON thing_body.tb SEMICOLON {: return tb; :} ; // Thing: id="" label="" type="" channels=["CHANNEL_ID", "CHANNEL_ID"] ; Thing thing_body = - ID EQUALS TEXT.n thing_body.t {: return eph.setID(t, n); :} + ID EQUALS TEXT.n thing_body.t {: t.setID(n); return t; :} | LABEL EQUALS TEXT.n thing_body.t {: t.setLabel(n); return t; :} - | TYPE EQUALS TEXT.n thing_body.t {: return eph.addThingType(t, n); :} - | CHANNELS EQUALS string_list.channels thing_body.t {: return eph.setChannels(t, channels); :} - | ID EQUALS TEXT.n {: return eph.setID(new Thing(), n); :} - | LABEL EQUALS TEXT.n {: Thing t = new Thing(); t.setLabel(n); return t; :} - | TYPE EQUALS TEXT.n {: return eph.addThingType(new Thing(), n); :} - | CHANNELS EQUALS string_list.channels {: return eph.setChannels(new Thing(), channels); :} + | TYPE EQUALS TEXT.n thing_body.t {: t.setType(ThingType.createRef(n)); return t; :} + | CHANNELS EQUALS string_list.channels thing_body.t {: channels.forEach(ch -> t.addChannel(Channel.createRef(ch))); return t; :} + | {: return new Thing(); :} ; Item item = - COLOR ITEM COLON item_body.ib SEMICOLON {: return eph.retype(new ColorItem(), ib); :} - | CONTACT ITEM COLON item_body.ib SEMICOLON {: return eph.retype(new ContactItem(), ib); :} - | DATE_TIME ITEM COLON item_body.ib SEMICOLON {: return eph.retype(new DateTimeItem(), ib); :} - | DIMMER ITEM COLON item_body.ib SEMICOLON {: return eph.retype(new DimmerItem(), ib); :} - | IMAGE ITEM COLON item_body.ib SEMICOLON {: return eph.retype(new ImageItem(), ib); :} - | LOCATION ITEM COLON item_body.ib SEMICOLON {: return eph.retype(new LocationItem(), ib); :} - | NUMBER ITEM COLON item_body.ib SEMICOLON {: return eph.retype(new NumberItem(), ib); :} - | PLAYER ITEM COLON item_body.ib SEMICOLON {: return eph.retype(new PlayerItem(), ib); :} - | ROLLER_SHUTTER ITEM COLON item_body.ib SEMICOLON {: return eph.retype(new RollerShutterItem(), ib); :} - | STRING ITEM COLON item_body.ib SEMICOLON {: return eph.retype(new StringItem(), ib); :} - | SWITCH ITEM COLON item_body.ib SEMICOLON {: return eph.retype(new SwitchItem(), ib); :} - | ACTIVITY ITEM COLON item_body.ib SEMICOLON {: return eph.retype(new ActivityItem(), ib); :} - | ITEM COLON item_body.ib SEMICOLON {: return eph.retype(new DefaultItem(), ib); :} + COLOR ITEM COLON item_body.ib SEMICOLON {: ib.setItemWithCorrectType(new ColorItem()); return ib; :} + | CONTACT ITEM COLON item_body.ib SEMICOLON {: ib.setItemWithCorrectType(new ContactItem()); return ib; :} + | DATE_TIME ITEM COLON item_body.ib SEMICOLON {: ib.setItemWithCorrectType(new DateTimeItem()); return ib; :} + | DIMMER ITEM COLON item_body.ib SEMICOLON {: ib.setItemWithCorrectType(new DimmerItem()); return ib; :} + | IMAGE ITEM COLON item_body.ib SEMICOLON {: ib.setItemWithCorrectType(new ImageItem()); return ib; :} + | LOCATION ITEM COLON item_body.ib SEMICOLON {: ib.setItemWithCorrectType(new LocationItem()); return ib; :} + | NUMBER ITEM COLON item_body.ib SEMICOLON {: ib.setItemWithCorrectType(new NumberItem()); return ib; :} + | PLAYER ITEM COLON item_body.ib SEMICOLON {: ib.setItemWithCorrectType(new PlayerItem()); return ib; :} + | ROLLER_SHUTTER ITEM COLON item_body.ib SEMICOLON {: ib.setItemWithCorrectType(new RollerShutterItem()); return ib; :} + | STRING ITEM COLON item_body.ib SEMICOLON {: ib.setItemWithCorrectType(new StringItem()); return ib; :} + | SWITCH ITEM COLON item_body.ib SEMICOLON {: ib.setItemWithCorrectType(new SwitchItem()); return ib; :} + | ACTIVITY ITEM COLON item_body.ib SEMICOLON {: ib.setItemWithCorrectType(new ActivityItem()); return ib; :} + | ITEM COLON item_body.ib SEMICOLON {: ib.setItemWithCorrectType(new DefaultItem()); return ib; :} ; // ITEM_TYPE Item: id="" label="" state="" category="" topic="" performance="" metaData={"key":"value"} ; -Item item_body = - ID EQUALS TEXT.n item_body.i {: return eph.setID(i, n); :} - | LABEL EQUALS TEXT.n item_body.i {: i.setLabel(n); return i; :} - | STATE EQUALS TEXT.n item_body.i {: i.setStateFromString(n); return i; :} - | TOPIC EQUALS TEXT.n item_body.i {: return eph.setTopic(i, n); :} - | CATEGORY EQUALS TEXT.n item_body.i {: return eph.setCategory(i, n); :} - | PERFORMANCE EQUALS frequency_setting_ref.ip item_body.i {: i.setFrequencySetting(ip); return i; :} - | META_DATA EQUALS string_map.md item_body.i - {: return eph.setMetaData(i, md); :} - | {: return eph.createItem(); :} - ; - -Item item_ref = TEXT.n {: return Item.createRef(n); :}; -FrequencySetting frequency_setting_ref = TEXT.n {: return FrequencySetting.createRef(n); :}; - +ItemPrototype item_body = + ID EQUALS TEXT.n item_body.i {: i.setID(n); return i; :} + | LABEL EQUALS TEXT.n item_body.i {: i.setLabel(n); return i; :} + | STATE EQUALS TEXT.n item_body.i {: i.setStateFromString(n); return i; :} + | TOPIC EQUALS TEXT.n item_body.i {: i.setTopic(MqttTopic.createRef(n)); return i; :} + | CATEGORY EQUALS TEXT.n item_body.i {: i.setCategory(ItemCategory.createRef(n)); return i; :} + | PERFORMANCE EQUALS TEXT.n item_body.i {: i.setFrequencySetting(FrequencySetting.createRef(n)); return i; :} + | META_DATA EQUALS meta_data.md item_body.i {: i.setMetaData(md); return i; :} + | {: ItemPrototype result = new ItemPrototype(); + result.disableSendState(); + return result; :}; Group group = GROUP COLON group_body.gb SEMICOLON {: return gb; :} ; @@ -153,30 +224,35 @@ Group group = // Group: id="" groups=["GROUP_ID", "GROUP_ID"] items=["ITEM_ID", "ITEM_ID"] performance="" aggregation=""; // Group: id="" groups=["GROUP_ID", "GROUP_ID"] items=["ITEM_ID", "ITEM_ID"] performance="" aggregation="" ("",""); Group group_body = - ID EQUALS TEXT.n group_body.g {: return eph.setID(g, n); :} - | LABEL EQUALS TEXT.n group_body.g {: g.setLabel(n); return g; :} - | GROUPS EQUALS string_list.groups group_body.g {: return eph.setSubGroups(g, groups); :} - | ITEMS EQUALS string_list.items group_body.g {: return eph.setItems(g, items); :} - | AGGREGATION EQUALS TEXT.n group_body.g {: return eph.setSimpleAggregationFunction(g, n); :} - | AGGREGATION EQUALS TEXT.n round_string_list.params group_body.g - {: return eph.setParameterizedAggregationFunction(g, n, params); :} - | PERFORMANCE EQUALS frequency_setting_ref.ip group_body.g {: g.setFrequencySetting(ip); return g; :} + ID EQUALS TEXT.n group_body.g {: g.setID(n); return g; :} + | LABEL EQUALS TEXT.n group_body.g {: g.setLabel(n); return g; :} + | GROUPS EQUALS string_list.groups group_body.g {: groups.forEach(sg -> g.addGroup(createGroupPlaceHolder(sg))); return g; :} + | ITEMS EQUALS string_list.items group_body.g {: items.forEach(i -> g.addItem(createItemPlaceHolder(i))); return g; :} + | AGGREGATION EQUALS TEXT.n group_body.g {: SimpleGroupAggregationFunctionName name = SimpleGroupAggregationFunctionName.valueOf(n.toUpperCase()); + g.setAggregationFunction(new SimpleGroupAggregationFunction(name)); + return g; :} + | AGGREGATION EQUALS TEXT.n round_string_list.p group_body.g {: ParameterizedGroupAggregationFunctionName name = ParameterizedGroupAggregationFunctionName.valueOf(n.toUpperCase()); + String[] params = { "?", "?" }; + java.util.Iterator<String> iterator = p.iterator(); + for (int index = 0; index < 2; index++) { + params[index] = iterator.next(); + } + g.setAggregationFunction(new ParameterizedGroupAggregationFunction(name, params[0], params[1])); + return g; :} + | PERFORMANCE EQUALS TEXT.n group_body.g {: g.setFrequencySetting(FrequencySetting.createRef(n)); return g; :} | {: return new Group(); :} ; -StateSyncGroup state_sync_group = SYNCSTATE COLON syncstate_body.ssb SEMICOLON {: return ssb; :}; +StateSyncGroup state_sync_group = SYNC_STATE COLON sync_state_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(); :} +StateSyncGroup sync_state_body = + ITEMS EQUALS string_list.items sync_state_body.ssb {: for (String itemName : items) { + ssb.addTargetItem(Item.createRef(itemName)); + } + return ssb; :} + | {: return new StateSyncGroup(); :} ; ThingType thing_type = @@ -185,16 +261,12 @@ ThingType thing_type = // ThingType: id="" label="" description="" parameters=[] channelTypes=[]; ThingType thing_type_body = - ID EQUALS TEXT.n thing_type_body.ttb {: return eph.setID(ttb, n); :} - | LABEL EQUALS TEXT.n thing_type_body.ttb {: ttb.setLabel(n); return ttb; :} - | DESCRIPTION EQUALS TEXT.n thing_type_body.ttb {: ttb.setDescription(n); return ttb; :} - | PARAMETERS EQUALS string_list.p thing_type_body.ttb {: return eph.setParameters(ttb, p); :} - | CHANNEL_TYPES EQUALS string_list.c thing_type_body.ttb {: return eph.setChannelTypes(ttb, c); :} - | ID EQUALS TEXT.n {: return eph.setID(new ThingType(), n); :} - | LABEL EQUALS TEXT.n {: ThingType tt = new ThingType(); tt.setLabel(n); return tt; :} - | DESCRIPTION EQUALS TEXT.n {: ThingType tt = new ThingType(); tt.setDescription(n); return tt; :} - | PARAMETERS EQUALS string_list.p {: return eph.setParameters(new ThingType(), p); :} - | CHANNEL_TYPES EQUALS string_list.c {: return eph.setChannelTypes(new ThingType(), c); :} + ID EQUALS TEXT.n thing_type_body.t {: t.setID(n); return t; :} + | LABEL EQUALS TEXT.n thing_type_body.t {: t.setLabel(n); return t; :} + | DESCRIPTION EQUALS TEXT.n thing_type_body.t {: t.setDescription(n); return t; :} + | PARAMETERS EQUALS string_list.ps thing_type_body.t {: ps.forEach(p -> t.addParameter(Parameter.createRef(p))); return t; :} + | CHANNEL_TYPES EQUALS string_list.cts thing_type_body.t {: cts.forEach(ct -> t.addChannelType(ChannelType.createRef(ct))); return t; :} + | {: return new ThingType(); :} ; Parameter parameter = @@ -204,14 +276,14 @@ Parameter parameter = // Parameter: id="" label="" description="" type="" default="" required; // Parameter: id="" label="" description="" type="" ; Parameter parameter_body = - ID EQUALS TEXT.n parameter_body.pb {: return eph.setID(pb, n); :} - | LABEL EQUALS TEXT.n parameter_body.pb {: pb.setLabel(n); return pb; :} - | DESCRIPTION EQUALS TEXT.n parameter_body.pb {: pb.setDescription(n); return pb; :} - | CONTEXT EQUALS TEXT.n parameter_body.pb {: pb.setContext(n); return pb; :} - | TYPE EQUALS TEXT.n parameter_body.pb {: return eph.setParameterValueType(pb, n); :} - | DEFAULT EQUALS TEXT.n parameter_body.pb {: return eph.setDefault(pb, n); :} - | REQUIRED parameter_body.pb {: pb.setRequired(true); return pb; :} - | {: return new Parameter(); :} + ID EQUALS TEXT.n parameter_body.p {: p.setID(n); return p; :} + | LABEL EQUALS TEXT.n parameter_body.p {: p.setLabel(n); return p; :} + | DESCRIPTION EQUALS TEXT.n parameter_body.p {: p.setDescription(n); return p; :} + | CONTEXT EQUALS TEXT.n parameter_body.p {: p.setContext(n); return p; :} + | TYPE EQUALS TEXT.n parameter_body.p {: p.setType(ParameterValueType.valueOf(JavaUtils.toTitleCase(n))); return p; :} + | DEFAULT EQUALS TEXT.n parameter_body.p {: p.setDefaultValue(new ParameterDefaultValue(n)); return p; :} + | REQUIRED parameter_body.p {: p.setRequired(true); return p; :} + | {: return new Parameter(); :} ; ChannelType channel_type = @@ -220,13 +292,21 @@ ChannelType channel_type = // ChannelType: id="" label="" description="" itemType="" category="TEXT" readyOnly; ChannelType channel_type_body = - ID EQUALS TEXT.n channel_type_body.ctb {: return eph.setID(ctb, n); :} - | LABEL EQUALS TEXT.n channel_type_body.ctb {: ctb.setLabel(n); return ctb; :} - | DESCRIPTION EQUALS TEXT.n channel_type_body.ctb {: ctb.setDescription(n); return ctb; :} - | ITEM_TYPE EQUALS TEXT.n channel_type_body.ctb {: return eph.setItemType(ctb, n); :} - | CATEGORY EQUALS TEXT.c channel_type_body.ctb {: return eph.setChannelCategory(ctb, c); :} - | READ_ONLY channel_type_body.ctb {: ctb.setReadOnly(true); return ctb; :} - | {: return new ChannelType(); :} + ID EQUALS TEXT.n channel_type_body.c {: c.setID(n); return c; :} + | LABEL EQUALS TEXT.n channel_type_body.c {: c.setLabel(n); return c; :} + | DESCRIPTION EQUALS TEXT.n channel_type_body.c {: c.setDescription(n); return c; :} + | ITEM_TYPE EQUALS TEXT.n channel_type_body.c {: c.setItemType(ItemType.valueOf(n)); return c; :} + | CATEGORY EQUALS TEXT.n channel_type_body.c {: try { + DefaultChannelCategoryValue.valueOf(n); + ReferringChannelCategory rcc = new ReferringChannelCategory(); + rcc.setChannelCategory(DefaultChannelCategory.createRef(n)); + c.setChannelCategory(rcc); + } catch (IllegalArgumentException e) { + c.setChannelCategory(new SimpleChannelCategory(n)); + } + return c; :} + | READ_ONLY channel_type_body.c {: c.setReadOnly(true); return c; :} + | {: return new ChannelType(); :} ; Channel channel = @@ -235,26 +315,30 @@ Channel channel = // Channel: id="" type="" links=["ITEM_ID", "ITEM_ID"]; Channel channel_body = - ID EQUALS TEXT.n channel_body.c {: return eph.setID(c, n); :} - | TYPE EQUALS TEXT.n channel_body.c {: return eph.setChannelType(c, n); :} - | LINKS EQUALS string_list.links channel_body.c {: return eph.setLinks(c, links); :} + ID EQUALS TEXT.n channel_body.c {: c.setID(n); return c; :} + | TYPE EQUALS TEXT.n channel_body.c {: c.setType(ChannelType.createRef(n)); return c; :} + | LINKS EQUALS string_list.links channel_body.c {: links.forEach(i -> c.addLinkedItem(Item.createRef(i))); return c; :} | {: return new Channel(); :} ; +/// MQTT /// + MqttRoot mqtt_root = MQTT COLON mqtt_root_body.mrb SEMICOLON {: return mrb; :} ; // Mqtt: incoming="" outgoing="" host=""; MqttRoot mqtt_root_body = - INCOMING EQUALS TEXT.n mqtt_root_body.mrb {: mrb.setIncomingPrefix(n); return mrb; :} - | OUTGOING EQUALS TEXT.n mqtt_root_body.mrb {: mrb.setOutgoingPrefix(n); return mrb; :} + INCOMING EQUALS TEXT.n mqtt_root_body.mrb {: mrb.setIncomingPrefix(ensureTrailingSlash(n)); return mrb; :} + | OUTGOING EQUALS TEXT.n mqtt_root_body.mrb {: mrb.setOutgoingPrefix(ensureTrailingSlash(n)); return mrb; :} | HOST EQUALS TEXT.n mqtt_root_body.mrb {: mrb.setHostByName(n); return mrb; :} | USER EQUALS TEXT.n mqtt_root_body.mrb {: mrb.setUser(n); return mrb; :} | PASSWORD EQUALS TEXT.n mqtt_root_body.mrb {: mrb.setPassword(n); return mrb; :} | {: return new MqttRoot(); :} ; +/// Influx /// + InfluxRoot influx_root = INFLUX COLON influx_root_body.irb SEMICOLON {: return irb; :} ; @@ -268,25 +352,35 @@ InfluxRoot influx_root_body = | {: return InfluxRoot.createDefault(); :} ; -// Machine Learning +/// Machine Learning /// + MachineLearningRoot machine_learning_root = ML COLON machine_learning_root_body.b SEMICOLON {: return b; :} ; // ML: activities={index:"name"} ; MachineLearningRoot machine_learning_root_body = - ACTIVITIES EQUALS integer_map.map machine_learning_root_body.b {: return eph.setActivities(b, map); :} + ACTIVITIES EQUALS integer_map.map machine_learning_root_body.b {: for (java.util.AbstractMap.SimpleEntry<Integer,String> entry : map) { + Activity activity = new Activity(); + activity.setIdentifier(entry.getKey()); + activity.setLabel(entry.getValue()); + b.addActivity(activity); + } + return b; :} | {: return MachineLearningRoot.createDefault(); :} ; // Rule: condition=condition action=a1 action=a2; // (only allow one condition and action for now) Rule rule = - RULE COLON CONDITION EQUALS condition.c action.a SEMICOLON {: return eph.createRule(c, a); :} + RULE COLON CONDITION EQUALS condition.c action.a SEMICOLON {: Rule result = new Rule(); + result.addCondition(c); + result.addAction(a); + return result; :} ; Condition condition = - logical_expression.be {: return new ExpressionCondition(be); :} + logical_expression.be {: return new ExpressionCondition(be); :} ; // TODO implement action cases @@ -309,64 +403,40 @@ 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(); :} ; StringList round_string_list_body = - TEXT.n COMMA round_string_list_body.slb {: slb.add(n); return slb; :} - | TEXT.n - {: - StringList result = new StringList(); - result.add(n); - return result; - :} + TEXT.n COMMA round_string_list_body.slb {: slb.add(n); return slb; :} + | TEXT.n {: StringList result = new StringList(); + result.add(n); + return result; :} ; -StringKeyMap string_map = - LB_CURLY string_map_body.smb RB_CURLY {: return smb; :} - | LB_CURLY RB_CURLY {: return new StringKeyMap(); :} +MetaData meta_data = + LB_CURLY meta_data_body.mdb RB_CURLY {: return mdb; :} ; -StringKeyMap string_map_body = - TEXT.key COLON TEXT.value COMMA string_map_body.smb {: smb.put(key, value); return smb; :} - | TEXT.key COLON TEXT.value - {: - StringKeyMap result = new StringKeyMap(); - result.put(key, value); - return result; - :} +MetaData meta_data_body = + TEXT.key COLON TEXT.value COMMA meta_data_body.mdb {: insertZero(mdb.getKeyValuePairList(), new KeyValuePair(key, value)); return mdb; :} + | TEXT.key COLON TEXT.value {: MetaData mdb = new MetaData(); + insertZero(mdb.getKeyValuePairList(), new KeyValuePair(key, value)); + return mdb; :} + | {: return new MetaData(); :} ; IntegerKeyMap integer_map = - LB_CURLY integer_map_body.imb RB_CURLY {: return imb; :} - | LB_CURLY RB_CURLY {: return new IntegerKeyMap(); :} + LB_CURLY integer_map_body.imb RB_CURLY {: return imb; :} + | LB_CURLY RB_CURLY {: return new IntegerKeyMap(); :} ; IntegerKeyMap integer_map_body = - INTEGER.key COLON TEXT.value COMMA integer_map_body.imb {: imb.put(Integer.parseInt(key), value); return imb; :} - | INTEGER.key COLON TEXT.value - {: - IntegerKeyMap result = new IntegerKeyMap(); - result.put(Integer.parseInt(key), value); - return result; - :} + INTEGER.key COLON TEXT.value COMMA integer_map_body.imb {: imb.put(Integer.parseInt(key), value); return imb; :} + | INTEGER.key COLON TEXT.value {: IntegerKeyMap result = new IntegerKeyMap(); + result.put(Integer.parseInt(key), value); + return result; :} ; FrequencySetting frequency_setting = @@ -375,7 +445,7 @@ FrequencySetting frequency_setting = // FrequencySetting: id="" procFreq="" persFreq=""; FrequencySetting frequency_setting_body = - ID EQUALS TEXT.n frequency_setting_body.ip {: return eph.setID(ip, n); :} - | PROCESS_FREQUENCY EQUALS TEXT.n frequency_setting_body.ip {: ip.setEventProcessingFrequency(Double.parseDouble(n)); return ip; :} - | {: return new FrequencySetting(); :} + ID EQUALS TEXT.n frequency_setting_body.fs {: fs.setID(n); return fs; :} + | PROCESS_FREQUENCY EQUALS TEXT.n frequency_setting_body.fs {: fs.setEventProcessingFrequency(Double.parseDouble(n)); return fs; :} + | {: return new FrequencySetting(); :} ; diff --git a/eraser-base/src/main/jastadd/mqtt.jrag b/eraser-base/src/main/jastadd/mqtt.jrag index 93e11442e9f277455b8b2a62e32375fd091c94e8..a33f024b510ce0b3fb642a3a2fcae98cf43eb29b 100644 --- a/eraser-base/src/main/jastadd/mqtt.jrag +++ b/eraser-base/src/main/jastadd/mqtt.jrag @@ -77,11 +77,16 @@ aspect MQTT { refine SmartHomeEntityModel public void SmartHomeEntityModel.addNewItem(Item item) { refined(item); // update mqtt-topic to new mqtt-root - JavaUtils.ifPresentOrElse( - getRoot().getMqttRoot().resolveTopicSuffix(item.getTopic().getTopicString()), - topic -> item.setTopic(topic), - () -> de.tudresden.inf.st.eraser.util.ParserUtils.createMqttTopic(item, item.getTopic().getTopicString(), getRoot()) - ); + item.setTopic(getRoot().getMqttRoot().getOrCreateMqttTopic(item.getTopic().getTopicString())); + } + + public MqttTopic MqttRoot.getOrCreateMqttTopic(String topicString) { + return resolveTopicSuffix(topicString).orElseGet(() -> { + MqttTopic result = new MqttTopic(); + result.setTopicString(topicString); + addTopic(result); + return result; + }); } } diff --git a/eraser-base/src/main/jastadd/shem.jrag b/eraser-base/src/main/jastadd/shem.jrag index 4cdc35da0e05c77be4ea4ab58d0f5699f87ae100..f163ebf4824dab8d3c3107a35fe4654b48e6c2ad 100644 --- a/eraser-base/src/main/jastadd/shem.jrag +++ b/eraser-base/src/main/jastadd/shem.jrag @@ -4,10 +4,73 @@ aspect SmartHomeEntityModel { } public void SmartHomeEntityModel.addNewItem(Item item) { - JavaUtils.ifPresentOrElse( - resolveGroup(de.tudresden.inf.st.eraser.util.ParserUtils.UNKNOWN_GROUP_NAME), - group -> group.addItem(item), - () -> de.tudresden.inf.st.eraser.util.ParserUtils.createUnknownGroup(this, Collections.singletonList(item))); + unknownGroup().addItem(item); + } + + public MetaData MetaData.add(String key, String value) { + addKeyValuePair(new KeyValuePair(key, value)); + return this; + } + + syn nta Group SmartHomeEntityModel.unknownGroup() { + return new Group().setID("Unknown"); + } + + syn nta JastAddList<DefaultChannelCategory> SmartHomeEntityModel.defaultChannelCategoryList() { + JastAddList<DefaultChannelCategory> result = new JastAddList<>(); + Arrays.stream(DefaultChannelCategoryValue.values()).sorted().forEach(ccv -> result.add(new DefaultChannelCategory(ccv))); + return result; + } + + rewrite ItemPrototype { + to Item { + Item result = getItemWithCorrectType(); + result.setID(this.getID()); + result.setLabel(this.getLabel()); + result.setMetaData(this.getMetaData()); + if (this.hasTopic()) { + result.setTopic(this.getTopic()); + } + if (this.hasCategory()) { + result.setCategory(this.getCategory()); + } + if (!result.isActivityItem()) { + String state = this.getStateAsString(); + result.disableSendState(); + if (state.isEmpty()) { + result.setStateToDefault(); + } else { + result.setStateFromString(state); + } + result.enableSendState(); + } + return result; + } + } + + // PlaceHolders + // ItemPlaceHolder + syn Item Item.realItem() = this; + eq ItemPlaceHolder.realItem() { + return containingSmartHomeEntityModel().resolveItem(getID()).orElseThrow(() -> new RuntimeException("Item '" + getID() + "' not found!")); + } + eq ItemPlaceHolder.prettyPrintType() = "<placeholder>"; + syn boolean Item.isItemPlaceHolder() = false; + eq ItemPlaceHolder.isItemPlaceHolder() = true; + + // GroupPlaceHolder + syn Group Group.realGroup() = this; + eq GroupPlaceHolder.realGroup() { + return containingSmartHomeEntityModel().resolveGroup(getID()).orElseThrow(() -> new RuntimeException("Group '" + getID() + "' not found!")); + } + + public ItemCategory SmartHomeEntityModel.getOrCreateCategoryByName(String categoryName) { + return this.resolveItemCategory(categoryName).orElseGet(() -> { + ItemCategory result = new ItemCategory(); + result.setName(categoryName); + addItemCategory(result); + return result; + }); } } diff --git a/eraser-base/src/main/jastadd/shem.relast b/eraser-base/src/main/jastadd/shem.relast index 62cb25506245a5f7d04dcea483cfa11c07d1d179..165666746b6cd509b5046eeab257cd15289c5602 100644 --- a/eraser-base/src/main/jastadd/shem.relast +++ b/eraser-base/src/main/jastadd/shem.relast @@ -1,23 +1,26 @@ // ---------------- openHAB ------------------------------ -SmartHomeEntityModel ::= Thing* Group* ThingType* ChannelType* ChannelCategory* ItemCategory* /ActivityItem:Item/ ; +SmartHomeEntityModel ::= Thing* Group* ThingType* Parameter* ChannelType* Channel* ItemCategory* /ActivityItem:Item/ ; abstract ModelElement ::= <ID:String> ; abstract LabelledModelElement : ModelElement ::= <Label:String> ; abstract DescribableModelElement : LabelledModelElement ::= <Description:String> ; -ThingType : DescribableModelElement ::= Parameter* ; +ThingType : DescribableModelElement ::= ; +rel ThingType.Parameter* -> Parameter ; rel ThingType.ChannelType* -> ChannelType ; -Thing : LabelledModelElement ::= Channel* ; +Thing : LabelledModelElement ::= ; +rel Thing.Channel* <-> Channel.Thing ; rel Thing.Type -> ThingType ; -ChannelType : DescribableModelElement ::= <ItemType:ItemType> <ReadOnly:boolean> ; -rel ChannelType.ChannelCategory -> ChannelCategory ; +ChannelType : DescribableModelElement ::= <ItemType:ItemType> <ReadOnly:boolean> ChannelCategory ; abstract ChannelCategory ; -DefaultChannelCategory : ChannelCategory ::= <Value:DefaultChannelCategoryValue> ; +ReferringChannelCategory : ChannelCategory ; +rel ReferringChannelCategory.ChannelCategory -> DefaultChannelCategory ; SimpleChannelCategory : ChannelCategory ::= <Value:String> ; +DefaultChannelCategory ::= <Value:DefaultChannelCategoryValue> ; Channel : ModelElement ::= ; rel Channel.Type -> ChannelType ; @@ -26,8 +29,8 @@ 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/ /LastChanged/; -rel Item.Category? -> ItemCategory ; +abstract Item : LabelledModelElement ::= <_fetched_data:boolean> [MetaData] /ItemObserver/ /LastChanged/; +rel Item.Category? <-> ItemCategory.Items* ; rel Item.FrequencySetting? -> FrequencySetting ; abstract ItemWithBooleanState : Item ::= <_state:boolean> ; @@ -46,16 +49,19 @@ StringItem : ItemWithStringState ; SwitchItem : ItemWithBooleanState ; DefaultItem : ItemWithStringState ; ActivityItem : ItemWithDoubleState ; +ItemPrototype : ItemWithStringState ::= ItemWithCorrectType:Item ; // only used for parsing +ItemPlaceHolder : ItemWithStringState ; // only used for parsing -ItemMetaData ::= <Key:String> <Value:String> ; +MetaData ::= KeyValuePair* ; +KeyValuePair ::= <Key:String> <Value:String> ; ItemCategory ::= <Name:String> ; LastChanged ::= <Value:Instant> ; - Group : LabelledModelElement ::= Group* Item* [AggregationFunction:GroupAggregationFunction] ; rel Group.FrequencySetting? -> FrequencySetting ; +GroupPlaceHolder : Group ; // only used for parsing abstract GroupAggregationFunction ; SimpleGroupAggregationFunction : GroupAggregationFunction ::= <FunctionName:SimpleGroupAggregationFunctionName> ; diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/openhab2/OpenHab2Importer.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/openhab2/OpenHab2Importer.java index d3fcaefa4cf16a7114406ac69f399dc029e1c7a7..bc3dab425186024202d91c3ad659898f6d06b3e0 100644 --- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/openhab2/OpenHab2Importer.java +++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/openhab2/OpenHab2Importer.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import de.tudresden.inf.st.eraser.jastadd.model.*; import de.tudresden.inf.st.eraser.openhab2.data.*; +import de.tudresden.inf.st.eraser.util.JavaUtils; import de.tudresden.inf.st.eraser.util.ParserUtils; import de.tudresden.inf.st.eraser.util.Tuple; import org.apache.logging.log4j.LogManager; @@ -76,6 +77,9 @@ public class OpenHab2Importer { logger.info("Read a total of {} item(s) including groups.", itemList.length); update(model, itemList); + root.treeResolveAll(); + root.doSafeFullTraversal(); + LinkData[] linkList = mapper.readValue(makeURL(linksUrl, hostAndPort), LinkData[].class); logger.info("Read a total of {} link(s).", linkList.length); update(model, linkList); @@ -113,13 +117,13 @@ public class OpenHab2Importer { private void update(SmartHomeEntityModel model, ChannelTypeData[] channelTypeList) { for (ChannelTypeData channelTypeData : channelTypeList) { ChannelType channelType = new ChannelType(); + model.addChannelType(channelType); channelType.setID(channelTypeData.UID); channelType.setLabel(channelTypeData.label); channelType.setDescription(channelTypeData.description); maybeSetItemType(channelType, channelTypeData.itemType); maybeSetChannelCategory(channelType, channelTypeData.category); maybeSetReadOnly(channelType, channelTypeData.stateDescription); - model.addChannelType(channelType); } } @@ -144,17 +148,16 @@ public class OpenHab2Importer { if (category == null) { return; } - try { - DefaultChannelCategoryValue dccv = DefaultChannelCategoryValue.valueOf(category); - channelType.setChannelCategory(new DefaultChannelCategory(dccv)); - } catch (IllegalArgumentException e) { - // channel category was not found - // store in unresolved and only warn once about it - if (nonDefaultChannelCategories.add(category)) { - logger.warn("Could not find ChannelCategory for '{}'", category); - } - channelType.setChannelCategory(new SimpleChannelCategory(category)); - } + JavaUtils.ifPresentOrElse(channelType.getRoot().getSmartHomeEntityModel().resolveDefaultChannelCategory(category), + dcc -> channelType.setChannelCategory(new ReferringChannelCategory(dcc)), + () -> { + // channel category was not found + // store in unresolved and only warn once about it + if (nonDefaultChannelCategories.add(category)) { + logger.warn("Could not find ChannelCategory for '{}'", category); + } + channelType.setChannelCategory(new SimpleChannelCategory(category)); + }); } private void maybeSetReadOnly(ChannelType channelType, StateDescriptionData stateDescription) { @@ -177,6 +180,8 @@ public class OpenHab2Importer { channel.setID(channelData.uid); ifPresent(model.resolveChannelType(channelData.channelTypeUID), "channelType", channelData, channel::setType); + model.addChannel(channel); + // now set relation thing.addChannel(channel); } } @@ -243,10 +248,12 @@ public class OpenHab2Importer { } item.enableSendState(); if (itemData.metadata != null) { + MetaData metaData = new MetaData(); + item.setMetaData(metaData); for (Map.Entry<String, MetaDataData> entry : itemData.metadata.entrySet()) { logger.debug("Add metadata for namespace {}", entry.getKey()); for (Map.Entry<String, String> metaDataEntry : entry.getValue().config.entrySet()) { - item.addMetaData(new ItemMetaData(metaDataEntry.getKey(), metaDataEntry.getValue())); + metaData.add(metaDataEntry.getKey(), metaDataEntry.getValue()); } } } @@ -278,7 +285,7 @@ public class OpenHab2Importer { } } if (!itemsWithoutGroup.isEmpty()) { - ParserUtils.createUnknownGroup(model, itemsWithoutGroup); + ParserUtils.addToUnknownGroup(model, itemsWithoutGroup); } } 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 32be358baf48a7cd2af133d0fe3e1a3dca97aa02..abb789b66118b14c609711de134de169e9cde565 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 @@ -14,7 +14,8 @@ import java.util.function.BiConsumer; * * @author rschoene - Initial contribution */ -public class EraserParserHelper { +@Deprecated +class EraserParserHelper { private Logger logger = LogManager.getLogger(EraserParserHelper.class); private Map<String, ThingType> thingTypeMap = new HashMap<>(); @@ -89,7 +90,7 @@ public class EraserParserHelper { } else { resolve(itemMap, missingItemForDesignator, Designator::setItem); } - missingTopicMap.forEach((topic, parts) -> ParserUtils.createMqttTopic(topic, parts, this.root)); +// missingTopicMap.forEach((item, s) -> item.setMqttTopic(s)); this.root.getMqttRoot().ensureCorrectPrefixes(); resolveList(channelMap, missingChannelListMap, Thing::addChannel); @@ -101,7 +102,7 @@ public class EraserParserHelper { createUnknownGroupIfNecessary(); - createChannelCategories(); +// createChannelCategories(); createItemCategories(); if (checkUnusedElements) { @@ -139,16 +140,10 @@ public class EraserParserHelper { sortedDanglingItems.add(item); } } - ParserUtils.createUnknownGroup(this.root.getSmartHomeEntityModel(), sortedDanglingItems); + ParserUtils.addToUnknownGroup(this.root.getSmartHomeEntityModel(), sortedDanglingItems); } } - private void createChannelCategories() { - channelCategoryMap.values().stream().sorted(Comparator.comparing(this::ident)).forEach( - cc -> root.getSmartHomeEntityModel().addChannelCategory(cc)); - channelCategoryMap.clear(); - } - private void createItemCategories() { Map<String, ItemCategory> newCategories = new HashMap<>(); missingItemCategoryMap.forEach((item, category) -> @@ -248,21 +243,6 @@ public class EraserParserHelper { return ct; } - public ChannelType setChannelCategory(ChannelType ct, String name) { - ChannelCategory result = channelCategoryMap.get(name); - if (result == null) { - try { - DefaultChannelCategoryValue dccv = DefaultChannelCategoryValue.valueOf(name); - result = new DefaultChannelCategory(dccv); - } catch (IllegalArgumentException e) { - result = new SimpleChannelCategory(name); - } - channelCategoryMap.put(name, result); - } - ct.setChannelCategory(result); - return ct; - } - public Channel setChannelType(Channel c, String channelTypeName) { missingChannelTypeMap.put(c, channelTypeName); return c; @@ -299,17 +279,10 @@ public class EraserParserHelper { return item; } - public Item setMetaData(Item item, StringKeyMap metaData) { - for (AbstractMap.SimpleEntry<String, String> entry : metaData) { - item.addMetaData(new ItemMetaData(entry.getKey(), entry.getValue())); - } - return item; - } - public Item retype(Item itemWithCorrectType, Item prototype) { itemWithCorrectType.setID(prototype.getID()); itemWithCorrectType.setLabel(prototype.getLabel()); - itemWithCorrectType.setMetaDataList(prototype.getMetaDataList()); + itemWithCorrectType.setMetaData(prototype.getMetaData()); itemWithCorrectType.setFrequencySetting(prototype.getFrequencySetting()); if (!(itemWithCorrectType instanceof ActivityItem)) { String state = prototype.getStateAsString(); diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/ParserUtils.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/ParserUtils.java index c1b75ba26b03db32a52fadec3436dc5fdbcbeff0..5b365efb7b3e184a76396411a659ce624c76a779 100644 --- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/ParserUtils.java +++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/ParserUtils.java @@ -8,7 +8,6 @@ import com.fasterxml.jackson.databind.SerializationFeature; import de.tudresden.inf.st.eraser.jastadd.model.*; import de.tudresden.inf.st.eraser.jastadd.parser.EraserParser; import de.tudresden.inf.st.eraser.jastadd.scanner.EraserScanner; -import de.tudresden.inf.st.eraser.parser.EraserParserHelper; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -26,7 +25,6 @@ import java.util.Objects; */ public class ParserUtils { - public static final String UNKNOWN_GROUP_NAME = "Unknown"; private static boolean verboseLoading = false; private static final Logger logger = LogManager.getLogger(ParserUtils.class); private static final ObjectMapper OBJECT_MAPPER_INSTANCE = new ObjectMapper() @@ -145,8 +143,7 @@ public class ParserUtils { EraserScanner scanner = new EraserScanner(reader); EraserParser parser = new EraserParser(); - Root result = (Root) parser.parse(scanner); - parser.resolveReferences(); + Root result = parser.parseRoot(scanner); reader.close(); return result; } @@ -172,31 +169,14 @@ public class ParserUtils { } /** - * Create well-known group call "Unknown" and add all dangling items to it. + * Add all dangling items to unknown group. * @param model The model to operate on * @param danglingItems A list of items to add to the new group */ - public static void createUnknownGroup(SmartHomeEntityModel model, Collection<Item> danglingItems) { - Group unknownGroup = new Group(); - unknownGroup.setID(UNKNOWN_GROUP_NAME); - model.addGroup(unknownGroup); + public static void addToUnknownGroup(SmartHomeEntityModel model, Collection<Item> danglingItems) { + Group unknownGroup = model.unknownGroup(); danglingItems.forEach(unknownGroup::addItem); - logger.info("Created new {}", unknownGroup.prettyPrint().trim()); - } - - /** - * Create a topic for the given topic name and assign it to the given item. - * @param item The item to which the topic will be assigned to - * @param topicSuffix The full topic name - * @param root The model to operate on - */ - public static void createMqttTopic(Item item, String topicSuffix, Root root) { - item.setTopic(root.getMqttRoot().resolveTopicSuffix(topicSuffix).orElseGet(() -> { - MqttTopic result = new MqttTopic(); - result.setTopicString(topicSuffix); - root.getMqttRoot().addTopic(result); - return result; - })); + logger.info("Updated unknown group {}", unknownGroup.prettyPrint().trim()); } public static NumberExpression parseNumberExpression(String expression_string) throws IOException, Parser.Exception { @@ -216,7 +196,6 @@ public class ParserUtils { } private static Expression parseExpression(String expression_string, short alt_goal, Root root) throws IOException, Parser.Exception { - EraserParserHelper.setInitialRoot(root); StringReader reader = new StringReader(expression_string); if (verboseLoading) { EraserScanner scanner = new EraserScanner(reader); @@ -230,13 +209,12 @@ public class ParserUtils { e.printStackTrace(); } } + EraserParser.setNextInitialRoot(root); reader = new StringReader(expression_string); EraserScanner scanner = new EraserScanner(reader); EraserParser parser = new EraserParser(); - Expression result = (Expression) parser.parse(scanner, alt_goal); - parser.resolveReferences(); + Expression result = parser.parseExpression(scanner, alt_goal); reader.close(); - EraserParserHelper.setInitialRoot(null); return result; } @@ -245,8 +223,7 @@ public class ParserUtils { StringReader reader = new StringReader(definition); EraserScanner scanner = new EraserScanner(reader); EraserParser parser = new EraserParser(); - Root root = (Root) parser.parse(scanner); - parser.resolveReferences(); + Root root = parser.parseRoot(scanner); reader.close(); int size = root.getSmartHomeEntityModel().items().size(); if (size == 0) { diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/TestUtils.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/TestUtils.java index 3654470a6285e3424d750043b0df66cec295361b..1e215384019efafe9139a8139d5034e9cc10f864 100644 --- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/TestUtils.java +++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/TestUtils.java @@ -39,7 +39,9 @@ public class TestUtils { public static SmartHomeEntityModel createModelWithGroup() { Root root = Root.createEmptyRoot(); - ParserUtils.createUnknownGroup(root.getSmartHomeEntityModel(),new ArrayList<>()); + Group group0 = new Group(); + group0.setID("Group0"); + root.getSmartHomeEntityModel().addGroup(group0); return root.getSmartHomeEntityModel(); } diff --git a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/MarshallingTests.java b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/MarshallingTests.java index 60bfd0a759a03ce485bc8aa158b2ac8770340d47..2184860192791bc358fdc2987679098366b930db 100644 --- a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/MarshallingTests.java +++ b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/MarshallingTests.java @@ -1,10 +1,10 @@ package de.tudresden.inf.st.eraser; +import de.tudresden.inf.st.eraser.jastadd.parser.EraserParser; import de.tudresden.inf.st.eraser.jastadd_test.core.TestConfiguration; import de.tudresden.inf.st.eraser.jastadd_test.core.TestProperties; import de.tudresden.inf.st.eraser.jastadd_test.core.TestRunner; import de.tudresden.inf.st.eraser.jastadd_test.core.Util; -import de.tudresden.inf.st.eraser.parser.EraserParserHelper; import de.tudresden.inf.st.eraser.util.ParserUtils; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -25,7 +25,7 @@ public class MarshallingTests { @ParameterizedTest @MethodSource("getTests") public void runTest(TestConfiguration unitTest) throws Exception { - EraserParserHelper.setCheckUnusedElements(false); + EraserParser.setCheckUnusedElements(false); ParserUtils.setVerboseLoading(false); TestRunner.runTest(unitTest); } diff --git a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/OpenHabImporterTest.java b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/OpenHabImporterTest.java index c6ebe6ce0e35e17fc157bd25ba5c9d2289635c71..6daa513b7d87fdae87d514c586da61b9ad8993e7 100644 --- a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/OpenHabImporterTest.java +++ b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/OpenHabImporterTest.java @@ -8,11 +8,12 @@ import org.junit.jupiter.params.provider.MethodSource; import java.net.MalformedURLException; import java.net.URL; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; /** * Testing import from openHAB using {@link OpenHab2Importer}. @@ -49,8 +50,13 @@ public class OpenHabImporterTest { } private URL makeFileUrl(String fileName, String emptyFileName) throws MalformedURLException { - Path path = Paths.get(directory, fileName); - if (!path.toFile().exists() || !path.toFile().isFile()) { + Path path = null; + try { + path = Paths.get(directory, fileName); + } catch (InvalidPathException e) { + // use empty file + } + if (path == null || !path.toFile().exists() || !path.toFile().isFile()) { path = Paths.get(directory, "..", emptyFileName); } return path.toUri().toURL(); diff --git a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/RulesTest.java b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/RulesTest.java index f4da998f546f33e1ad976b2d9aef08b329185966..b056ba020adc39a9d6bcf5c17a7563acf5da6184 100644 --- a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/RulesTest.java +++ b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/RulesTest.java @@ -324,7 +324,7 @@ public class RulesTest { // add StateSyncGroup as rule to root and trigger rewrite model.getRoot().addRule(group); - model.getRoot().doFullTraversal(); + model.getRoot().doSafeFullTraversal(); colorItem1.setState(TupleHSB.parse("0,0,100")); @@ -362,7 +362,7 @@ public class RulesTest { // add StateSyncGroup as rule to root and trigger rewrite model.getRoot().addRule(group); - model.getRoot().doFullTraversal(); + model.getRoot().doSafeFullTraversal(); Instant i1 = Instant.now(); dateTimeItem1.setState(i1); @@ -402,7 +402,7 @@ public class RulesTest { // add StateSyncGroup as rule to root and trigger rewrite model.getRoot().addRule(group); - model.getRoot().doFullTraversal(); + model.getRoot().doSafeFullTraversal(); numberItem1.setState(123); @@ -441,7 +441,7 @@ public class RulesTest { // add StateSyncGroup as rule to root and trigger rewrite model.getRoot().addRule(group); - model.getRoot().doFullTraversal(); + model.getRoot().doSafeFullTraversal(); stringItem1.setState("123"); @@ -483,7 +483,7 @@ public class RulesTest { // add StateSyncGroup as rule to root and trigger rewrite model.getRoot().addRule(group); - model.getRoot().doFullTraversal(); + model.getRoot().doSafeFullTraversal(); switchItem3.setState(false); diff --git a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/jastadd_test/core/TestConfiguration.java b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/jastadd_test/core/TestConfiguration.java index df9495aaaddac0ca310b319c07a8b614c067d493..860efad6e30f530a7e23dacc4c8c43cc7c3ab864 100644 --- a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/jastadd_test/core/TestConfiguration.java +++ b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/jastadd_test/core/TestConfiguration.java @@ -135,12 +135,10 @@ public class TestConfiguration { File[] files = dir.listFiles(); if (files == null) return; for (File file: files) { - if (!file.isDirectory()) { - file.delete(); - } else { + if (file.isDirectory()) { cleanDirectory(file); - file.delete(); } + file.delete(); } } diff --git a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/jastadd_test/core/TestProperties.java b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/jastadd_test/core/TestProperties.java index 1b8099c99948940e0c376e59b843221005471b53..5ee91322f00e961a46d4e77955c08cde8d76a638 100644 --- a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/jastadd_test/core/TestProperties.java +++ b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/jastadd_test/core/TestProperties.java @@ -136,7 +136,7 @@ public class TestProperties extends Properties { private static void addPaths(Collection<String> list, String pathList) { String[] items = pathList.split(","); for (String item : items) { - item = item.trim().replace('\\', '/'); + item = Util.platformIndependentPath(item.trim()); if (!item.isEmpty()) { list.add(item); } diff --git a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/jastadd_test/core/Util.java b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/jastadd_test/core/Util.java index 019e9da2b3c94da40e8c7b5b52c4bc16c755de3b..7fb7320f9127648a1ee2526ea5878b11360cc603 100644 --- a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/jastadd_test/core/Util.java +++ b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/jastadd_test/core/Util.java @@ -38,14 +38,18 @@ import java.util.*; */ public class Util { + public static String platformIndependentPath(String regularPath) { + return regularPath.replace('\\', '/'); + } + // public static final String TEST_ROOT = "src/test/resources/tests"; // public static final String TEST_ROOT = "tests"; /** * Find all test directories - * @param testRoot - * @param tests - * @param excludes + * @param testRoot root directory of tests + * @param tests list of test configurations to add + * @param excludes paths to exclude */ private static void addChildTestDirs(File testRoot, List<TestConfiguration> tests, Collection<String> excludes) { @@ -58,7 +62,7 @@ public class Util { return; } for (File child: files) { - addTestDir(testRoot.getPath(), child, tests, excludes); + addTestDir(platformIndependentPath(testRoot.getPath()), child, tests, excludes); } } @@ -178,7 +182,7 @@ public class Util { addTestDir(properties.getTestRoot(), new File(properties.getTestRoot()), tests, excludes); } else { for (String include: includes) { - addByPattern(new File(properties.getTestRoot()), include.replace('\\', '/'), tests, excludes); + addByPattern(new File(properties.getTestRoot()), platformIndependentPath(include), tests, excludes); } } diff --git a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/Application.java b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/Application.java index 3427804342d059baa96f933f9781d7bdf356501a..1e793fb89c91b7b5b496fa027825ae2a634d7602 100644 --- a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/Application.java +++ b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/Application.java @@ -114,7 +114,7 @@ public class Application { //--- PUT /model/items/:identifier --- Spark.put("", (request, response) -> { - SmartHomeEntityModel SmartHomeEntityModel = root.getSmartHomeEntityModel(); + SmartHomeEntityModel smartHomeEntityModel = root.getSmartHomeEntityModel(); Item item; try { item = ParserUtils.parseItem(request.body()); @@ -122,7 +122,7 @@ public class Application { logger.catching(e); return makeError(response, 400, "Could not create item. Error message: " + e.getMessage()); } - if (!SmartHomeEntityModel.resolveItem(item.getID()).isPresent()) { + if (!smartHomeEntityModel.resolveItem(item.getID()).isPresent()) { root.getSmartHomeEntityModel().addNewItem(item); response.status(201); return "OK"; @@ -242,13 +242,13 @@ public class Application { item.getLabel(), item.getTopic() != null ? item.getTopic().getTopicString() : null, item.isSendState(), - wrapMetaData(item.getMetaDataList())); + wrapMetaData(item.getMetaData())); } - private Map<String, String> wrapMetaData(JastAddList<ItemMetaData> itemMetaDataList) { + private Map<String, String> wrapMetaData(MetaData metaData) { Map<String, String> result = new HashMap<>(); - for (ItemMetaData metaData : itemMetaDataList) { - result.put(metaData.getKey(), metaData.getValue()); + for (KeyValuePair keyValuePair : metaData.getKeyValuePairList()) { + result.put(keyValuePair.getKey(), keyValuePair.getValue()); } return result; } diff --git a/feedbackloop.api/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/api/Execute.java b/feedbackloop.api/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/api/Execute.java index 3b3da24d3cf88899fec03a538198e2472f72ac1a..8e824e83a0f9b73331d9629a7aa06bb97114ea98 100644 --- a/feedbackloop.api/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/api/Execute.java +++ b/feedbackloop.api/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/api/Execute.java @@ -20,13 +20,6 @@ public interface Execute { */ void setKnowledgeBase(Root knowledgeBase); - /** - * <b>Deprecated</b>: Use {@link #updateItems(Iterable)} instead. - * @param brightnessAndRgbForItems Map, keys are item names, values are RGB and brightness values - */ - @Deprecated - void updateItems(Map<String, Tuple<Integer, ValuesRGB>> brightnessAndRgbForItems); - /** * Updates items according to given updates * @param updates tuples containing item and its new HSB value diff --git a/feedbackloop.api/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/api/Learner.java b/feedbackloop.api/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/api/Learner.java index a08a6fc2a444b4a30fd4f234acfd4449c075d444..0d92fbbd0ef22abb47cc16c2ba568a0ca02116ec 100644 --- a/feedbackloop.api/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/api/Learner.java +++ b/feedbackloop.api/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/api/Learner.java @@ -118,9 +118,6 @@ public interface Learner { * */ EncogModel getTrainedModel(int modelID); - @Deprecated - EncogModel getTrainedModel(URL url, int modelID); - /** * * Method for getting normalizer of a model for a specific column/input. diff --git a/feedbackloop.execute/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/execute/ExecuteImpl.java b/feedbackloop.execute/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/execute/ExecuteImpl.java index 2b305dfd4ffc42996e2d3f157fe24bc1b0d3bc62..fd2ab95d6792ea57ccae539c2ff6cc6f5d081d97 100644 --- a/feedbackloop.execute/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/execute/ExecuteImpl.java +++ b/feedbackloop.execute/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/execute/ExecuteImpl.java @@ -1,16 +1,8 @@ package de.tudresden.inf.st.eraser.feedbackloop.execute; -import de.tudresden.inf.st.eraser.commons.color.ColorUtils; -import de.tudresden.inf.st.eraser.commons.color.ColorUtils.ValuesIntegralHSB; -import de.tudresden.inf.st.eraser.commons.color.ColorUtils.ValuesRGB; import de.tudresden.inf.st.eraser.feedbackloop.api.Execute; -import de.tudresden.inf.st.eraser.jastadd.model.*; -import de.tudresden.inf.st.eraser.util.Tuple; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.util.*; -import java.util.function.Consumer; +import de.tudresden.inf.st.eraser.jastadd.model.ItemUpdate; +import de.tudresden.inf.st.eraser.jastadd.model.Root; /** * Reference implementation for Execute. @@ -19,38 +11,11 @@ import java.util.function.Consumer; */ public class ExecuteImpl implements Execute { - private Logger logger = LogManager.getLogger(ExecuteImpl.class); - private Root knowledgeBase; +// private Root knowledgeBase; @Override public void setKnowledgeBase(Root knowledgeBase) { - this.knowledgeBase = knowledgeBase; - } - - @Override - public void updateItems(Map<String, Tuple<Integer, ValuesRGB>> brightnessAndRgbForItems) { - List<ItemUpdate> updates = new ArrayList<>(); - for (Map.Entry<String, Tuple<Integer, ValuesRGB>> entry : brightnessAndRgbForItems.entrySet()) { - String itemId = entry.getKey(); - resolveOrLogError(itemId, item -> { - if (entry.getValue() == null) { - return; - } - Integer brightness = entry.getValue().x; - ValuesRGB rgb = entry.getValue().y; - ValuesIntegralHSB hsb; - if (rgb != null) { - // also set rgb values - hsb = ColorUtils.convertRGBtoHSB(rgb).toIntegral(); - hsb.brightness = brightness; - } else { - hsb = ValuesIntegralHSB.of(0, 100, brightness); - } - hsb.ensureBounds(); - updates.add(new ItemUpdateColor(item, TupleHSB.of(hsb.hue, hsb.saturation, hsb.brightness))); - }); - } - updateItems(updates); +// this.knowledgeBase = knowledgeBase; } @Override @@ -59,12 +24,4 @@ public class ExecuteImpl implements Execute { preference.apply(); } } - - private void resolveOrLogError(String itemId, Consumer<? super Item> consumer) { - Optional<Item> optionalItem = knowledgeBase.getSmartHomeEntityModel().resolveItem(itemId); - if (!optionalItem.isPresent()) { - logger.warn("Could not resolve '{}' as an item.", itemId); - } - optionalItem.ifPresent(consumer); - } } diff --git a/feedbackloop.learner/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/learner/LearnerImpl.java b/feedbackloop.learner/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/learner/LearnerImpl.java index 83edf6b7f195d9be6420369d4590955c42449735..5c2489a393a7aa4cefa55c1383b69327059ead75 100644 --- a/feedbackloop.learner/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/learner/LearnerImpl.java +++ b/feedbackloop.learner/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/learner/LearnerImpl.java @@ -174,11 +174,6 @@ public class LearnerImpl implements Learner { return fillModel(modelID); } - @Override - public EncogModel getTrainedModel(URL url, int modelID) { - return fillModel(modelID); - } - private EncogModel fillModel(int modelID) { EncogModel encogModel = new EncogModel("NN"); BasicNetwork nn = models.get(modelID).getNetwork(); diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Main.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Main.java index d8ff6ed7248d6e48107a5c3ecafc523cffcb984c..c1958a1255ef28b67d0ae925abea7deb73b5fae0 100644 --- a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Main.java +++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Main.java @@ -59,7 +59,7 @@ public class Main { private static Root createRootWithItemsFrom(LearnerScenarioDefinition scenarioDefinition) { Root result = Root.createEmptyRoot(); - ParserUtils.createUnknownGroup( + ParserUtils.addToUnknownGroup( result.getSmartHomeEntityModel(), scenarioDefinition.relevantItemNames.stream().map(Main::createItem).collect(Collectors.toList())); return result; diff --git a/feedbackloop.learner_backup/src/test/java/de/tudresden/inf/st/eraser/feedbackloop/learner_backup/LearnerTestUtils.java b/feedbackloop.learner_backup/src/test/java/de/tudresden/inf/st/eraser/feedbackloop/learner_backup/LearnerTestUtils.java index fe32a87d0339b3461a2c268711a22554c75b6545..50d235f4b736ea0cb2d29f951004a977f61b449f 100644 --- a/feedbackloop.learner_backup/src/test/java/de/tudresden/inf/st/eraser/feedbackloop/learner_backup/LearnerTestUtils.java +++ b/feedbackloop.learner_backup/src/test/java/de/tudresden/inf/st/eraser/feedbackloop/learner_backup/LearnerTestUtils.java @@ -46,8 +46,8 @@ public class LearnerTestUtils { itemName -> { if (itemName.equals("activity")) return; Item item = createItem(itemName); - ParserUtils.createMqttTopic(item, itemName, result); group.addItem(item); + item.setTopic(result.getMqttRoot().getOrCreateMqttTopic(itemName)); } ); // init activities