From 8667cbe3dade8976fdb992f92c8c2634613aa40f Mon Sep 17 00:00:00 2001 From: rschoene <rene.schoene@tu-dresden.de> Date: Fri, 31 Jul 2020 19:13:02 +0200 Subject: [PATCH] Begin with REST impl. - also fixed bug when using tokens with no type (must be treated implicitly as String) --- ragconnect.base/src/main/jastadd/Errors.jrag | 20 +-- .../src/main/jastadd/MustacheNodes.relast | 4 +- .../src/main/jastadd/Navigation.jrag | 31 +++-- .../src/main/jastadd/RagConnect.relast | 11 +- .../src/main/jastadd/backend/Generation.jadd | 76 +++++++---- .../src/main/jastadd/backend/Mappings.jrag | 119 ++++++++++++++++-- .../src/main/jastadd/parser/RagConnect.parser | 42 +++---- .../src/main/jastadd/scanner/Keywords.flex | 3 + .../main/resources/receiveDefinition.mustache | 4 +- .../main/resources/sendDefinition.mustache | 2 +- ragconnect.tests/build.gradle | 36 +++++- .../src/test/01-input/via/Test.connect | 28 +++++ .../src/test/01-input/via/Test.jadd | 6 + .../src/test/01-input/via/Test.relast | 4 + 14 files changed, 298 insertions(+), 88 deletions(-) create mode 100644 ragconnect.tests/src/test/01-input/via/Test.connect create mode 100644 ragconnect.tests/src/test/01-input/via/Test.jadd create mode 100644 ragconnect.tests/src/test/01-input/via/Test.relast diff --git a/ragconnect.base/src/main/jastadd/Errors.jrag b/ragconnect.base/src/main/jastadd/Errors.jrag index bfee254..cf001ac 100644 --- a/ragconnect.base/src/main/jastadd/Errors.jrag +++ b/ragconnect.base/src/main/jastadd/Errors.jrag @@ -7,32 +7,32 @@ aspect Errors { [new TreeSet<ErrorMessage>()] root RagConnect; - ReceiveFromMqttDefinition contributes error("Receive definition already defined for " + getToken().getName()) + ReceiveTokenEndpointDefinition contributes error("Receive definition already defined for " + getToken().getName()) when isAlreadyDefined() to RagConnect.errors(); - ReceiveFromMqttDefinition contributes error("Receiving target token must not be an NTA token!") + ReceiveTokenEndpointDefinition contributes error("Receiving target token must not be an NTA token!") when getToken().getNTA() to RagConnect.errors(); // if first mapping is null, then suitableDefaultMapping() == null - ReceiveFromMqttDefinition contributes error("No suitable default mapping found for type " + + ReceiveTokenEndpointDefinition contributes error("No suitable default mapping found for type " + ((getMappingList().isEmpty()) - ? getToken().getJavaTypeUse().prettyPrint() + ? getToken().effectiveJavaTypeUse().prettyPrint() : getMappingList().get(0).getFromType().prettyPrint())) when effectiveMappings().get(0) == null to RagConnect.errors(); - ReceiveFromMqttDefinition contributes error("to-type of last mapping must be type of the Token!") - when getToken().getJavaTypeUse().prettyPrint().equals( - effectiveMappings().get(effectiveMappings().size() - 1)) + ReceiveTokenEndpointDefinition contributes error("to-type of last mapping (" + effectiveMappings().get(effectiveMappings().size() - 1).getToType().prettyPrint() + ") does not match type of the Token (" + getToken().effectiveJavaTypeUse().prettyPrint() + ")!") + when !getToken().effectiveJavaTypeUse().prettyPrint().equals( + effectiveMappings().get(effectiveMappings().size() - 1).getToType().prettyPrint()) to RagConnect.errors(); - SendToMqttDefinition contributes error("Sending target token must be an NTA token!") + SendTokenEndpointDefinition contributes error("Sending target token must be an NTA token!") when !getToken().getNTA() to RagConnect.errors(); - SendToMqttDefinition contributes error("Send definition already defined for " + getToken().getName()) + SendTokenEndpointDefinition contributes error("Send definition already defined for " + getToken().getName()) when isAlreadyDefined() to RagConnect.errors(); @@ -44,7 +44,7 @@ aspect Errors { when isAlreadyDefinedAsList() to RagConnect.errors(); - DependencyDefinition contributes error("There must be a send update definition targeting " + getSource().parentTypeypeAndName() + " for dependency definition " + getID()) + DependencyDefinition contributes error("There must be a send endpoint definition targeting " + getSource().parentTypeypeAndName() + " for dependency definition " + getID()) when targetEndpointDefinition() == null to RagConnect.errors(); } diff --git a/ragconnect.base/src/main/jastadd/MustacheNodes.relast b/ragconnect.base/src/main/jastadd/MustacheNodes.relast index ce85cab..1a35853 100644 --- a/ragconnect.base/src/main/jastadd/MustacheNodes.relast +++ b/ragconnect.base/src/main/jastadd/MustacheNodes.relast @@ -13,8 +13,8 @@ MTokenComponent; rel MRagConnect.RagConnect -> RagConnect; rel MInnerMappingDefinition.MappingDefinition -> MappingDefinition; -rel MReceiveDefinition.ReceiveFromMqttDefinition -> ReceiveFromMqttDefinition; -rel MSendDefinition.SendToMqttDefinition -> SendToMqttDefinition; +rel MReceiveDefinition.ReceiveTokenEndpointDefinition -> ReceiveTokenEndpointDefinition; +rel MSendDefinition.SendTokenEndpointDefinition -> SendTokenEndpointDefinition; rel MMappingDefinition.MappingDefinition -> MappingDefinition; rel MDependencyDefinition.DependencyDefinition -> DependencyDefinition; rel MTypeComponent.TypeComponent -> TypeComponent; diff --git a/ragconnect.base/src/main/jastadd/Navigation.jrag b/ragconnect.base/src/main/jastadd/Navigation.jrag index 2314386..481de3d 100644 --- a/ragconnect.base/src/main/jastadd/Navigation.jrag +++ b/ragconnect.base/src/main/jastadd/Navigation.jrag @@ -10,7 +10,9 @@ aspect Navigation { eq MRagConnect.getChild().ragconnect() = getRagConnect(); // --- containedFile + eq Grammar.getChild().containedFile() = null; eq RagConnect.getChild().containedFile() = null; + eq MRagConnect.getChild().containedFile() = null; // --- containedFileName --- eq RagConnect.getChild().containedFileName() = getFileName(); @@ -24,30 +26,33 @@ aspect Navigation { syn TokenEndpointDefinition EndpointDefinition.asTokenEndpointDefinition() = null; eq TokenEndpointDefinition.asTokenEndpointDefinition() = this; - // --- isSendToMqttDefinition --- - syn boolean EndpointDefinition.isSendToMqttDefinition() = false; - eq SendToMqttDefinition.isSendToMqttDefinition() = true; + // --- isSendTokenEndpointDefinition --- + syn boolean EndpointDefinition.isSendTokenEndpointDefinition() = false; + eq SendTokenEndpointDefinition.isSendTokenEndpointDefinition() = true; - // --- asSendToMqttDefinition --- - syn SendToMqttDefinition EndpointDefinition.asSendToMqttDefinition() = null; - eq SendToMqttDefinition.asSendToMqttDefinition() = this; + // --- asSendTokenEndpointDefinition --- + syn SendTokenEndpointDefinition EndpointDefinition.asSendTokenEndpointDefinition() = null; + eq SendTokenEndpointDefinition.asSendTokenEndpointDefinition() = this; - // --- asReceiveFromMqttDefinition --- - syn ReceiveFromMqttDefinition EndpointDefinition.asReceiveFromMqttDefinition() = null; - eq ReceiveFromMqttDefinition.asReceiveFromMqttDefinition() = this; + // --- asReceiveTokenEndpointDefinition --- + syn ReceiveTokenEndpointDefinition EndpointDefinition.asReceiveTokenEndpointDefinition() = null; + eq ReceiveTokenEndpointDefinition.asReceiveTokenEndpointDefinition() = this; // --- targetEndpointDefinition --- - syn SendToMqttDefinition DependencyDefinition.targetEndpointDefinition() { + syn SendTokenEndpointDefinition DependencyDefinition.targetEndpointDefinition() { // resolve definition in here, as we do not need resolveMethod in any other place (yet) for (EndpointDefinition endpointDefinition : ragconnect().getEndpointDefinitionList()) { - if (endpointDefinition.isSendToMqttDefinition() && - endpointDefinition.asSendToMqttDefinition().getToken().equals(this.getTarget())) { - return endpointDefinition.asSendToMqttDefinition(); + if (endpointDefinition.isSendTokenEndpointDefinition() && + endpointDefinition.asSendTokenEndpointDefinition().getToken().equals(this.getTarget())) { + return endpointDefinition.asSendTokenEndpointDefinition(); } } return null; } + // --- effectiveJavaTypeUse (should be in preprocessor) --- + syn lazy JavaTypeUse TokenComponent.effectiveJavaTypeUse() = hasJavaTypeUse() ? getJavaTypeUse() : new SimpleJavaTypeUse("String"); + // --- isDefaultMappingDefinition --- syn boolean MappingDefinition.isDefaultMappingDefinition() = false; eq DefaultMappingDefinition.isDefaultMappingDefinition() = true; diff --git a/ragconnect.base/src/main/jastadd/RagConnect.relast b/ragconnect.base/src/main/jastadd/RagConnect.relast index d30116e..2729b85 100644 --- a/ragconnect.base/src/main/jastadd/RagConnect.relast +++ b/ragconnect.base/src/main/jastadd/RagConnect.relast @@ -2,13 +2,18 @@ RagConnect ::= EndpointDefinition* DependencyDefinition* MappingDefinition* Prog abstract EndpointDefinition ::= <AlwaysApply:boolean> ; -rel EndpointDefinition.Mapping* -> MappingDefinition; +rel EndpointDefinition.Mapping* <-> MappingDefinition.UsedAt*; abstract TokenEndpointDefinition : EndpointDefinition; rel TokenEndpointDefinition.Token -> TokenComponent; -ReceiveFromMqttDefinition : TokenEndpointDefinition; -SendToMqttDefinition : TokenEndpointDefinition; +abstract ReceiveTokenEndpointDefinition : TokenEndpointDefinition; +abstract SendTokenEndpointDefinition : TokenEndpointDefinition; + +ReceiveFromMqttDefinition : ReceiveTokenEndpointDefinition; +SendToMqttDefinition : SendTokenEndpointDefinition; +ReceiveFromRestDefinition : ReceiveTokenEndpointDefinition; +SendToRestDefinition : SendTokenEndpointDefinition; DependencyDefinition ::= <ID>; rel DependencyDefinition.Source <-> TokenComponent.DependencySourceDefinition*; diff --git a/ragconnect.base/src/main/jastadd/backend/Generation.jadd b/ragconnect.base/src/main/jastadd/backend/Generation.jadd index 067626e..512750e 100644 --- a/ragconnect.base/src/main/jastadd/backend/Generation.jadd +++ b/ragconnect.base/src/main/jastadd/backend/Generation.jadd @@ -37,6 +37,8 @@ aspect AttributesForMustache { syn String MRagConnect.mqttWaitUntilReadyMethod() = getRagConnect().mqttWaitUntilReadyMethod(); syn String MRagConnect.mqttCloseMethod() = getRagConnect().mqttCloseMethod(); + syn String MRagConnect.restHandlerAttribute() = getRagConnect().restHandlerAttribute(); + // --- MEndpointDefinition --- syn String MEndpointDefinition.preemptiveExpectedValue(); syn String MEndpointDefinition.preemptiveReturn(); @@ -49,6 +51,7 @@ aspect AttributesForMustache { inh String MEndpointDefinition.mqttHandlerAttribute(); + syn String MEndpointDefinition.handlerAttribute() = endpointDef().handlerAttribute(); syn String MEndpointDefinition.connectMethod() = endpointDef().connectMethod(); syn TokenComponent MEndpointDefinition.token() = endpointDef().getToken(); syn boolean MEndpointDefinition.alwaysApply() = endpointDef().getAlwaysApply(); @@ -82,20 +85,20 @@ aspect AttributesForMustache { // --- MReceiveDefinition --- eq MReceiveDefinition.preemptiveExpectedValue() = "get" + tokenName() + "()"; eq MReceiveDefinition.preemptiveReturn() = "return;"; - eq MReceiveDefinition.endpointDef() = getReceiveFromMqttDefinition(); + eq MReceiveDefinition.endpointDef() = getReceiveTokenEndpointDefinition(); eq MReceiveDefinition.firstInputVarName() = "message"; // --- MSendDefinition --- eq MSendDefinition.preemptiveExpectedValue() = lastValue(); eq MSendDefinition.preemptiveReturn() = "return false;"; - eq MSendDefinition.endpointDef() = getSendToMqttDefinition(); + eq MSendDefinition.endpointDef() = getSendTokenEndpointDefinition(); eq MSendDefinition.firstInputVarName() = "get" + tokenName() + "()"; - syn String MSendDefinition.sendTopic() = getSendToMqttDefinition().sendTopic(); - syn String MSendDefinition.lastValue() = getSendToMqttDefinition().lastValue(); - syn String MSendDefinition.updateMethod() = getSendToMqttDefinition().updateMethod(); - syn String MSendDefinition.writeMethod() = getSendToMqttDefinition().writeMethod(); - syn String MSendDefinition.tokenResetMethod() = getSendToMqttDefinition().tokenResetMethod(); + syn String MSendDefinition.sendTopic() = getSendTokenEndpointDefinition().sendTopic(); + syn String MSendDefinition.lastValue() = getSendTokenEndpointDefinition().lastValue(); + syn String MSendDefinition.updateMethod() = getSendTokenEndpointDefinition().updateMethod(); + syn String MSendDefinition.writeMethod() = getSendTokenEndpointDefinition().writeMethod(); + syn String MSendDefinition.tokenResetMethod() = getSendTokenEndpointDefinition().tokenResetMethod(); // --- MMappingDefinition --- syn String MMappingDefinition.toType() = getMappingDefinition().getToType().prettyPrint(); @@ -122,7 +125,7 @@ aspect AttributesForMustache { // --- MTokenComponent --- syn String MTokenComponent.parentTypeName() = getTokenComponent().containingTypeDecl().getName(); syn String MTokenComponent.name() = getTokenComponent().getName(); - syn String MTokenComponent.javaType() = getTokenComponent().getJavaTypeUse().prettyPrint(); + syn String MTokenComponent.javaType() = getTokenComponent().effectiveJavaTypeUse().prettyPrint(); syn String MTokenComponent.internalName() = getTokenComponent().internalName(); // --- toMustache --- @@ -130,10 +133,10 @@ aspect AttributesForMustache { MRagConnect result = new MRagConnect(); result.setRagConnect(this); for (EndpointDefinition def : getEndpointDefinitionList()) { - if (def.isSendToMqttDefinition()) { - result.addSendDefinition(def.asSendToMqttDefinition().toMustache()); + if (def.isSendTokenEndpointDefinition()) { + result.addSendDefinition(def.asSendTokenEndpointDefinition().toMustache()); } else { - result.addReceiveDefinition(def.asReceiveFromMqttDefinition().toMustache()); + result.addReceiveDefinition(def.asReceiveTokenEndpointDefinition().toMustache()); } } for (MappingDefinition def : allMappingDefinitions()) { @@ -163,15 +166,31 @@ aspect AttributesForMustache { addInnerMappingDefinition(inner); } } - syn lazy MReceiveDefinition ReceiveFromMqttDefinition.toMustache() { + syn lazy MReceiveDefinition ReceiveTokenEndpointDefinition.toMustache(); + eq ReceiveFromMqttDefinition.toMustache() { + MReceiveDefinition result = new MReceiveDefinition(); + result.setReceiveTokenEndpointDefinition(this); + result.addInnerMappings(); + return result; + } + eq ReceiveFromRestDefinition.toMustache() { MReceiveDefinition result = new MReceiveDefinition(); - result.setReceiveFromMqttDefinition(this); + System.err.println("REST not implemented!"); + result.setReceiveTokenEndpointDefinition(this); + result.addInnerMappings(); + return result; + } + syn lazy MSendDefinition SendTokenEndpointDefinition.toMustache(); + eq SendToMqttDefinition.toMustache() { + MSendDefinition result = new MSendDefinition(); + result.setSendTokenEndpointDefinition(this); result.addInnerMappings(); return result; } - syn lazy MSendDefinition SendToMqttDefinition.toMustache() { + eq SendToRestDefinition.toMustache() { MSendDefinition result = new MSendDefinition(); - result.setSendToMqttDefinition(this); + System.err.println("REST not implemented!"); + result.setSendTokenEndpointDefinition(this); result.addInnerMappings(); return result; } @@ -206,11 +225,11 @@ aspect AspectGeneration { syn String TokenComponent.externalName() = getName(); syn String TokenEndpointDefinition.connectMethod() = "connect" + getToken().getName(); - syn String SendToMqttDefinition.sendTopic() = "_topic_" + getToken().getName(); - syn String SendToMqttDefinition.lastValue() = "_lastValue" + getToken().getName(); - syn String SendToMqttDefinition.updateMethod() = "_update_" + getToken().getName(); - syn String SendToMqttDefinition.writeMethod() = "_writeLastValue_" + getToken().getName(); - syn String SendToMqttDefinition.tokenResetMethod() = "get" + getToken().getName() + "_reset"; + syn String SendTokenEndpointDefinition.sendTopic() = "_topic_" + getToken().getName(); + syn String SendTokenEndpointDefinition.lastValue() = "_lastValue" + getToken().getName(); + syn String SendTokenEndpointDefinition.updateMethod() = "_update_" + getToken().getName(); + syn String SendTokenEndpointDefinition.writeMethod() = "_writeLastValue_" + getToken().getName(); + syn String SendTokenEndpointDefinition.tokenResetMethod() = "get" + getToken().getName() + "_reset"; syn String MappingDefinition.methodName() = "_apply_" + getID(); syn String DependencyDefinition.dependencyMethod() = "add" + Character.toUpperCase(getID().charAt(0)) + @@ -225,13 +244,24 @@ aspect AspectGeneration { syn String RagConnect.mqttWaitUntilReadyMethod() = "MqttWaitUntilReady"; syn String RagConnect.mqttCloseMethod() = "MqttCloseConnections"; + syn String RagConnect.restHandlerAttribute() = "_restHandler"; + syn String RagConnect.restHandlerField() = "_restHandler"; + + syn String TokenEndpointDefinition.handlerAttribute(); + eq ReceiveFromMqttDefinition.handlerAttribute() = mqttHandlerAttribute(); + eq SendToMqttDefinition.handlerAttribute() = mqttHandlerAttribute(); + eq ReceiveFromRestDefinition.handlerAttribute() = restHandlerAttribute(); + eq SendToRestDefinition.handlerAttribute() = restHandlerAttribute(); + // naming copy attributes // --- mqttHandlerAttribute --- inh String EndpointDefinition.mqttHandlerAttribute(); - inh String MappingDefinition.mqttHandlerAttribute(); - inh String DependencyDefinition.mqttHandlerAttribute(); eq RagConnect.getChild().mqttHandlerAttribute() = mqttHandlerAttribute(); + // --- restHandlerAttribute --- + inh String EndpointDefinition.restHandlerAttribute(); + eq RagConnect.getChild().restHandlerAttribute() = restHandlerAttribute(); + // --- rootNodeName --- syn String ASTNode.rootNodeName() = rootNode.getName(); @@ -296,7 +326,7 @@ aspect GrammarExtension { if (!getName().equals("")) { b.append(internalName()).append(":"); } - getJavaTypeUse().generateAbstractGrammar(b); + effectiveJavaTypeUse().generateAbstractGrammar(b); b.append(">"); if (getNTA()) { b.append("/"); diff --git a/ragconnect.base/src/main/jastadd/backend/Mappings.jrag b/ragconnect.base/src/main/jastadd/backend/Mappings.jrag index 07cbf5b..d5f7904 100644 --- a/ragconnect.base/src/main/jastadd/backend/Mappings.jrag +++ b/ragconnect.base/src/main/jastadd/backend/Mappings.jrag @@ -18,6 +18,26 @@ aspect DefaultMappings { return result; } + private String RagConnect.baseDefaultMappingTypeNamePart(String typeName) { + return Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1).replace("[]", "s"); + } + + private MappingDefinitionType RagConnect.baseDefaultMappingTypeFromName(String typeName) { + return typeName.endsWith("[]") ? + new JavaArrayMappingDefinitionType(new SimpleJavaTypeUse(typeName.replace("[]", ""))) : + new JavaMappingDefinitionType(new SimpleJavaTypeUse(typeName)); + } + + private DefaultMappingDefinition RagConnect.baseDefaultMappingDefinition(String fromTypeName, String toTypeName, String content) { + DefaultMappingDefinition result = new DefaultMappingDefinition(); + result.setID("_Default" + baseDefaultMappingTypeNamePart(fromTypeName) + "To" + baseDefaultMappingTypeNamePart(toTypeName) + "Mapping"); + result.setFromType(baseDefaultMappingTypeFromName(fromTypeName)); + result.setFromVariableName("input"); + result.setToType(baseDefaultMappingTypeFromName(toTypeName)); + result.setContent(content); + return result; + } + syn nta DefaultMappingDefinition RagConnect.defaultBytesToIntMapping() { DefaultMappingDefinition result = baseDefaultMappingDefinitionFromBytes("int"); result.setContent("return java.nio.ByteBuffer.wrap(bytes).getInt();"); @@ -101,17 +121,31 @@ aspect DefaultMappings { result.setContent("return input.getBytes();"); return result; } + + syn nta DefaultMappingDefinition RagConnect.defaultStringToIntMapping() = baseDefaultMappingDefinition("String", "int", "return Integer.parseInteger(input);"); + syn nta DefaultMappingDefinition RagConnect.defaultStringToShortMapping() = baseDefaultMappingDefinition("String", "short", "return Short.parseShort(input);"); + syn nta DefaultMappingDefinition RagConnect.defaultStringToLongMapping() = baseDefaultMappingDefinition("String", "long", "return Long.parseLong(input);"); + syn nta DefaultMappingDefinition RagConnect.defaultStringToFloatMapping() = baseDefaultMappingDefinition("String", "float", "return Float.parseFloat(input);"); + syn nta DefaultMappingDefinition RagConnect.defaultStringToDoubleMapping() = baseDefaultMappingDefinition("String", "double", "return Double.parseDouble(input);"); + syn nta DefaultMappingDefinition RagConnect.defaultStringToCharMapping() = baseDefaultMappingDefinition("String", "char", "return input.charAt(0);"); + + syn nta DefaultMappingDefinition RagConnect.defaultIntToStringMapping() = baseDefaultMappingDefinition("int", "String", "return String.valueOf(input);"); + syn nta DefaultMappingDefinition RagConnect.defaultShortToStringMapping() = baseDefaultMappingDefinition("int", "String", "return String.valueOf(input);"); + syn nta DefaultMappingDefinition RagConnect.defaultLongToStringMapping() = baseDefaultMappingDefinition("int", "String", "return String.valueOf(input);"); + syn nta DefaultMappingDefinition RagConnect.defaultFloatToStringMapping() = baseDefaultMappingDefinition("int", "String", "return String.valueOf(input);"); + syn nta DefaultMappingDefinition RagConnect.defaultDoubleToStringMapping() = baseDefaultMappingDefinition("int", "String", "return String.valueOf(input);"); + syn nta DefaultMappingDefinition RagConnect.defaultCharToStringMapping() = baseDefaultMappingDefinition("int", "String", "return String.valueOf(input);"); } aspect Mappings { // --- effectiveMappings --- syn java.util.List<MappingDefinition> EndpointDefinition.effectiveMappings(); - eq ReceiveFromMqttDefinition.effectiveMappings() { - // if there is a first mapping, check if its input type is byte[]. + eq ReceiveTokenEndpointDefinition.effectiveMappings() { + // if there is a first mapping, check if it is suitable. // or if no mappings are specified. // then prepend the suitable default mapping java.util.List<MappingDefinition> result; - if (getMappingList().isEmpty() || !getMappingList().get(0).getFromType().isByteArray()) { + if (getMappingList().isEmpty() || !hasSuitableEdgeMapping()) { result = new java.util.ArrayList(); result.add(suitableDefaultMapping()); result.addAll(getMappingList()); @@ -120,13 +154,12 @@ aspect Mappings { } return result; } - eq SendToMqttDefinition.effectiveMappings() { - // if there is a mapping, check if the output type of the last mapping is byte[]. + eq SendTokenEndpointDefinition.effectiveMappings() { + // if there is a mapping, check if it is suitable. // or if no mappings are specified. // then append the suitable default mapping java.util.List<MappingDefinition> result; - int numMappings = getMappingList().size(); - if (numMappings == 0 || !getMappingList().get(numMappings - 1).getToType().isByteArray()) { + if (getMappingList().isEmpty() || !hasSuitableEdgeMapping()) { result = new java.util.ArrayList(); result.addAll(getMappingList()); result.add(suitableDefaultMapping()); @@ -136,8 +169,20 @@ aspect Mappings { return result; } + // --- hasSuitableEdgeMapping --- + syn boolean TokenEndpointDefinition.hasSuitableEdgeMapping(); + eq ReceiveTokenEndpointDefinition.hasSuitableEdgeMapping() = isSuitableEdgeMapping(getMappingList().get(0)); + eq SendTokenEndpointDefinition.hasSuitableEdgeMapping() = isSuitableEdgeMapping(getMappingList().get(getMappingList().size() - 1)); + + // --- isSuitableEdgeMapping(def) --- + syn boolean TokenEndpointDefinition.isSuitableEdgeMapping(MappingDefinition def); + eq ReceiveFromMqttDefinition.isSuitableEdgeMapping(MappingDefinition def) = def.getFromType().isByteArray(); + eq SendToMqttDefinition.isSuitableEdgeMapping(MappingDefinition def) = def.getToType().isByteArray(); + eq ReceiveFromRestDefinition.isSuitableEdgeMapping(MappingDefinition def) = def.getFromType().isString(); + eq SendToRestDefinition.isSuitableEdgeMapping(MappingDefinition def) = def.getToType().isString(); + // --- isPrimitiveType --- - syn boolean TokenComponent.isPrimitiveType() = getJavaTypeUse().isPrimitiveType(); + syn boolean TokenComponent.isPrimitiveType() = effectiveJavaTypeUse().isPrimitiveType(); syn boolean JavaTypeUse.isPrimitiveType() = false; eq SimpleJavaTypeUse.isPrimitiveType() { switch(getName()) { @@ -202,15 +247,60 @@ aspect Mappings { default: return null; } } + eq ReceiveFromRestDefinition.suitableDefaultMapping() { + String typeName = getMappingList().isEmpty() ? + getToken().getJavaTypeUse().getName() : + getMappingList().get(0).getFromType().prettyPrint(); + switch(typeName) { + case "int": + case "Integer": return ragconnect().defaultStringToIntMapping(); + case "short": + case "Short": return ragconnect().defaultStringToShortMapping(); + case "long": + case "Long": return ragconnect().defaultStringToLongMapping(); + case "float": + case "Float": return ragconnect().defaultStringToFloatMapping(); + case "double": + case "Double": return ragconnect().defaultStringToDoubleMapping(); + case "char": + case "Character": return ragconnect().defaultStringToCharMapping(); + default: return null; + } + } + eq SendToRestDefinition.suitableDefaultMapping() { + String typeName = getMappingList().isEmpty() ? + getToken().getJavaTypeUse().getName() : + getMappingList().get(getMappingList().size() - 1).getFromType().prettyPrint(); + switch(typeName) { + case "int": + case "Integer": return ragconnect().defaultIntToStringMapping(); + case "short": + case "Short": return ragconnect().defaultShortToStringMapping(); + case "long": + case "Long": return ragconnect().defaultLongToStringMapping(); + case "float": + case "Float": return ragconnect().defaultFloatToStringMapping(); + case "double": + case "Double": return ragconnect().defaultDoubleToStringMapping(); + case "char": + case "Character": return ragconnect().defaultCharToStringMapping(); + default: return null; + } + } // --- isByteArray --- syn boolean MappingDefinitionType.isByteArray() = false; eq JavaArrayMappingDefinitionType.isByteArray() = getType().getName().equals("byte"); + // --- isString --- + syn boolean MappingDefinitionType.isString() = false; + eq JavaMappingDefinitionType.isString() = getType().getName().equals("String"); + // --- allMappingDefinitions --- syn java.util.List<MappingDefinition> RagConnect.allMappingDefinitions() { java.util.List<MappingDefinition> result = new java.util.ArrayList<>(); getMappingDefinitionList().iterator().forEachRemaining(result::add); + // byte[] converstion result.add(defaultBytesToIntMapping()); result.add(defaultBytesToShortMapping()); result.add(defaultBytesToLongMapping()); @@ -225,6 +315,19 @@ aspect Mappings { result.add(defaultDoubleToBytesMapping()); result.add(defaultCharToBytesMapping()); result.add(defaultStringToBytesMapping()); + // string converstion + result.add(defaultStringToIntMapping()); + result.add(defaultStringToShortMapping()); + result.add(defaultStringToLongMapping()); + result.add(defaultStringToFloatMapping()); + result.add(defaultStringToDoubleMapping()); + result.add(defaultStringToCharMapping()); + result.add(defaultIntToStringMapping()); + result.add(defaultShortToStringMapping()); + result.add(defaultLongToStringMapping()); + result.add(defaultFloatToStringMapping()); + result.add(defaultDoubleToStringMapping()); + result.add(defaultCharToStringMapping()); return result; } } diff --git a/ragconnect.base/src/main/jastadd/parser/RagConnect.parser b/ragconnect.base/src/main/jastadd/parser/RagConnect.parser index e2685c1..0f897af 100644 --- a/ragconnect.base/src/main/jastadd/parser/RagConnect.parser +++ b/ragconnect.base/src/main/jastadd/parser/RagConnect.parser @@ -13,38 +13,32 @@ RagConnect ragconnect :} ; EndpointDefinition endpoint_definition - = RECEIVE ID.type_name DOT ID.token_name SCOL + = endpoint_definition_type.endpointDef SCOL {: - ReceiveFromMqttDefinition result = new ReceiveFromMqttDefinition(); - result.setToken(TokenComponent.createRef(type_name + "." + token_name)); - return result; - :} - | RECEIVE ID.type_name DOT ID.token_name USING string_list.mapping_defs SCOL - {: - ReceiveFromMqttDefinition result = new ReceiveFromMqttDefinition(); - result.setToken(TokenComponent.createRef(type_name + "." + token_name)); - for (String mapping_def : makeMappingDefs(mapping_defs)) { - result.addMapping(MappingDefinition.createRef(mapping_def)); - } - return result; - :} - | SEND ID.type_name DOT ID.token_name SCOL - {: - SendToMqttDefinition result = new SendToMqttDefinition(); - result.setToken(TokenComponent.createRef(type_name + "." + token_name)); - return result; + return endpointDef; :} - | SEND ID.type_name DOT ID.token_name USING string_list.mapping_defs SCOL + | endpoint_definition_type.endpointDef USING string_list.mapping_defs SCOL {: - SendToMqttDefinition result = new SendToMqttDefinition(); - result.setToken(TokenComponent.createRef(type_name + "." + token_name)); for (String mapping_def : makeMappingDefs(mapping_defs)) { - result.addMapping(MappingDefinition.createRef(mapping_def)); + endpointDef.addMapping(MappingDefinition.createRef(mapping_def)); } - return result; + return endpointDef; :} ; +EndpointDefinition endpoint_definition_type + = RECEIVE token_ref {: return new ReceiveFromMqttDefinition().setToken(token_ref); :} + | RECEIVE token_ref VIA MQTT {: return new ReceiveFromMqttDefinition().setToken(token_ref); :} + | RECEIVE token_ref VIA REST {: return new ReceiveFromRestDefinition().setToken(token_ref); :} + | SEND token_ref {: return new SendToMqttDefinition().setToken(token_ref); :} + | SEND token_ref VIA MQTT {: return new SendToMqttDefinition().setToken(token_ref); :} + | SEND token_ref VIA REST {: return new SendToRestDefinition().setToken(token_ref); :} +; + +TokenComponent token_ref + = ID.type_name DOT ID.token_name {: return TokenComponent.createRef(type_name + "." + token_name); :} +; + ArrayList string_list = ID | string_list COMMA ID diff --git a/ragconnect.base/src/main/jastadd/scanner/Keywords.flex b/ragconnect.base/src/main/jastadd/scanner/Keywords.flex index 5773118..fe8a814 100644 --- a/ragconnect.base/src/main/jastadd/scanner/Keywords.flex +++ b/ragconnect.base/src/main/jastadd/scanner/Keywords.flex @@ -5,3 +5,6 @@ "maps" { return sym(Terminals.MAPS); } "to" { return sym(Terminals.TO); } "as" { return sym(Terminals.AS); } +"via" { return sym(Terminals.VIA); } +"mqtt" { return sym(Terminals.MQTT); } +"rest" { return sym(Terminals.REST); } diff --git a/ragconnect.base/src/main/resources/receiveDefinition.mustache b/ragconnect.base/src/main/resources/receiveDefinition.mustache index e2df043..c02f5e5 100644 --- a/ragconnect.base/src/main/resources/receiveDefinition.mustache +++ b/ragconnect.base/src/main/resources/receiveDefinition.mustache @@ -1,8 +1,8 @@ public void {{parentTypeName}}.{{connectMethod}}(String topic) { - {{mqttHandlerAttribute}}().newConnection(topic, message -> { + {{handlerAttribute}}().newConnection(topic, message -> { {{> mappingApplication}} {{#loggingEnabledForReads}} - System.out.println("[Receive] " + topic + " -> {{tokenName}} = " + {{lastResult}});{{!lastResult has to be a new attribute}} + System.out.println("[Receive] " + topic + " -> {{tokenName}} = " + {{lastResult}}); {{/loggingEnabledForReads}} set{{tokenName}}({{lastResult}}); }); diff --git a/ragconnect.base/src/main/resources/sendDefinition.mustache b/ragconnect.base/src/main/resources/sendDefinition.mustache index 477dbc5..874a342 100644 --- a/ragconnect.base/src/main/resources/sendDefinition.mustache +++ b/ragconnect.base/src/main/resources/sendDefinition.mustache @@ -20,5 +20,5 @@ {{#loggingEnabledForWrites}} System.out.println("[Send] {{tokenName}} = " + get{{tokenName}}() + " -> " + {{sendTopic}}); {{/loggingEnabledForWrites}} - {{mqttHandlerAttribute}}().publish({{sendTopic}}, {{lastValue}}); + {{handlerAttribute}}().publish({{sendTopic}}, {{lastValue}}); } diff --git a/ragconnect.tests/build.gradle b/ragconnect.tests/build.gradle index d0a6997..4cb42ea 100644 --- a/ragconnect.tests/build.gradle +++ b/ragconnect.tests/build.gradle @@ -64,6 +64,10 @@ sourceSets { } } +clean { + delete 'src/test/02-after-ragconnect/*/', 'src/test/03-after-relast/*/', 'src/test/java-gen/*/' +} + // --- Test: Example --- task preprocessExampleTest(type: JavaExec, group: 'verification') { doFirst { @@ -223,6 +227,34 @@ task compileRead2Write1Test(type: RelastTest) { testClasses.dependsOn compileRead2Write1Test compileRead2Write1Test.dependsOn preprocessRead2Write1Test -clean { - delete 'src/test/02-after-ragconnect/*/', 'src/test/03-after-relast/*/', 'src/test/java-gen/*/' +// --- Test: via --- +task preprocessViaTest(type: JavaExec, group: 'verification') { + doFirst { + delete 'src/test/02-after-ragconnect/via/Test.relast', + 'src/test/02-after-ragconnect/via/MqttHandler.java', + 'src/test/02-after-ragconnect/via/RagConnect.jadd' + } + + classpath = sourceSets.main.runtimeClasspath + main = 'org.jastadd.ragconnect.compiler.Compiler' + args '--o=src/test/02-after-ragconnect/via', + 'src/test/01-input/via/Test.relast', + 'src/test/01-input/via/Test.connect', + '--rootNode=A', '--verbose', + '--logReads', '--logWrites' } + +task compileViaTest(type: RelastTest) { + useJastAddNames = true + jastAddList = 'JastAddList' + relastFiles 'src/test/02-after-ragconnect/via/Test.relast', + 'src/test/02-after-ragconnect/via/RagConnect.relast' + grammarName = 'src/test/03-after-relast/via/via' + packageName = 'via.ast' + moreInputFiles 'src/test/01-input/via/Test.jadd', + 'src/test/02-after-ragconnect/via/MqttHandler.jadd', + 'src/test/02-after-ragconnect/via/RagConnect.jadd' +} + +testClasses.dependsOn compileViaTest +compileViaTest.dependsOn preprocessViaTest diff --git a/ragconnect.tests/src/test/01-input/via/Test.connect b/ragconnect.tests/src/test/01-input/via/Test.connect new file mode 100644 index 0000000..2f39f08 --- /dev/null +++ b/ragconnect.tests/src/test/01-input/via/Test.connect @@ -0,0 +1,28 @@ +receive A.Mqtt2MqttInput via mqtt using MarkMqttInput ; +receive A.Rest2RestInput via rest using MarkRestInput ; +receive A.Mqtt2RestInput via mqtt using MarkMqttInput ; +receive A.Rest2MqttInput via rest using MarkRestInput ; + +send A.Mqtt2MqttOutput via mqtt using MarkMqttOutput ; +send A.Rest2RestOutput via rest using MarkRestOutput ; +send A.Mqtt2RestOutput via rest using MarkRestOutput ; +send A.Rest2MqttOutput via mqtt using MarkMqttOutput ; + +A.Mqtt2MqttOutput canDependOn A.Mqtt2MqttInput as dependencyMqtt2Mqtt ; +A.Rest2RestOutput canDependOn A.Rest2RestInput as dependencyRest2Rest ; +A.Mqtt2RestOutput canDependOn A.Mqtt2RestInput as dependencyMqtt2Rest ; +A.Rest2MqttOutput canDependOn A.Rest2MqttInput as dependencyRest2Mqtt ; + +MarkMqttInput maps String s to String {: + return "FromMqtt" + s; +:} +MarkRestInput maps String s to String {: + return "FromRest" + s; +:} + +MarkMqttOutput maps String s to String {: + return s + "ToMqtt"; +:} +MarkRestOutput maps String s to String {: + return s + "ToRest"; +:} diff --git a/ragconnect.tests/src/test/01-input/via/Test.jadd b/ragconnect.tests/src/test/01-input/via/Test.jadd new file mode 100644 index 0000000..3c4313f --- /dev/null +++ b/ragconnect.tests/src/test/01-input/via/Test.jadd @@ -0,0 +1,6 @@ +aspect Computation { + syn lazy String A.getMqtt2MqttOutput() = getMqtt2MqttInput() + "M2M" ; + syn lazy String A.getRest2RestOutput() = getRest2RestInput() + "R2R" ; + syn lazy String A.getMqtt2RestOutput() = getMqtt2RestInput() + "M2R" ; + syn lazy String A.getRest2MqttOutput() = getRest2MqttInput() + "R2M" ; +} diff --git a/ragconnect.tests/src/test/01-input/via/Test.relast b/ragconnect.tests/src/test/01-input/via/Test.relast new file mode 100644 index 0000000..6868ed8 --- /dev/null +++ b/ragconnect.tests/src/test/01-input/via/Test.relast @@ -0,0 +1,4 @@ +A ::= <Mqtt2MqttInput> /<Mqtt2MqttOutput>/ + <Rest2RestInput> /<Rest2RestOutput>/ + <Mqtt2RestInput> /<Mqtt2RestOutput>/ + <Rest2MqttInput> /<Rest2MqttOutput>/; -- GitLab