Skip to content
Snippets Groups Projects
Commit 61c612f3 authored by René Schöne's avatar René Schöne
Browse files

Merge branch 'rest' into 'master'

Rest

Closes #24

See merge request jastadd/ros2rag!5
parents 2b5156d5 29847fd7
No related branches found
No related tags found
No related merge requests found
Pipeline #7593 passed
Showing
with 948 additions and 472 deletions
...@@ -5,3 +5,4 @@ ...@@ -5,3 +5,4 @@
.classpath .classpath
.idea/ .idea/
.gradle/ .gradle/
build/
...@@ -69,19 +69,12 @@ task relast(type: JavaExec) { ...@@ -69,19 +69,12 @@ task relast(type: JavaExec) {
group = 'Build' group = 'Build'
main = "-jar" main = "-jar"
doFirst {
delete "src/gen/jastadd/*.ast"
delete "src/gen/jastadd/RagConnect.jadd"
delete "src/gen/jastadd/RagConnectRefResolver.jadd"
delete "src/gen/jastadd/RagConnectResolverStubs.jrag"
mkdir "src/gen/jastadd/"
}
args = [ args = [
"../libs/relast.jar", "../libs/relast.jar",
"../relast.preprocessor/src/main/jastadd/RelAst.relast", "../relast.preprocessor/src/main/jastadd/RelAst.relast",
"./src/main/jastadd/RagConnect.relast", "./src/main/jastadd/RagConnect.relast",
"./src/main/jastadd/MustacheNodes.relast", "./src/main/jastadd/MustacheNodes.relast",
"./src/main/jastadd/YAML.relast",
"--listClass=java.util.ArrayList", "--listClass=java.util.ArrayList",
"--jastAddList=JastAddList", "--jastAddList=JastAddList",
"--useJastAddNames", "--useJastAddNames",
...@@ -90,14 +83,15 @@ task relast(type: JavaExec) { ...@@ -90,14 +83,15 @@ task relast(type: JavaExec) {
"--grammarName=./src/gen/jastadd/RagConnect" "--grammarName=./src/gen/jastadd/RagConnect"
] ]
inputs.files file("../libs/relast.jar"), inputs.files("../libs/relast.jar",
file("../relast.preprocessor/src/main/jastadd/RelAST.relast"), "../relast.preprocessor/src/main/jastadd/RelAst.relast",
file("./src/main/jastadd/RagConnect.relast") "./src/main/jastadd/RagConnect.relast",
file("./src/main/jastadd/MustacheNodes.relast") "./src/main/jastadd/MustacheNodes.relast",
outputs.files file("./src/gen/jastadd/RagConnect.ast"), "./src/main/jastadd/YAML.relast")
file("./src/gen/jastadd/RagConnect.jadd"), outputs.files("./src/gen/jastadd/RagConnect.ast",
file("./src/gen/jastadd/RagConnectRefResolver.jadd"), "./src/gen/jastadd/RagConnect.jadd",
file('./src/gen/jastadd/RagConnectResolverStubs.jrag') "./src/gen/jastadd/RagConnectRefResolver.jadd",
'./src/gen/jastadd/RagConnectResolverStubs.jrag')
} }
jastadd { jastadd {
......
aspect Analysis { aspect Analysis {
// --- lookupTokenEndpointDefinition --- // --- lookupTokenEndpointDefinition ---
inh TokenEndpointDefinition TokenEndpointDefinition.lookupTokenEndpointDefinition(TokenComponent token); inh java.util.List<TokenEndpointDefinition> TokenEndpointDefinition.lookupTokenEndpointDefinitions(TokenComponent token);
eq RagConnect.getEndpointDefinition().lookupTokenEndpointDefinition(TokenComponent token) { eq RagConnect.getEndpointDefinition().lookupTokenEndpointDefinitions(TokenComponent token) = lookupTokenEndpointDefinitions(token);
syn java.util.List<TokenEndpointDefinition> RagConnect.lookupTokenEndpointDefinitions(TokenComponent token) {
java.util.List<TokenEndpointDefinition> result = new java.util.ArrayList<>();
for (EndpointDefinition def : getEndpointDefinitionList()) { for (EndpointDefinition def : getEndpointDefinitionList()) {
if (def.isTokenEndpointDefinition() && def.asTokenEndpointDefinition().getToken().equals(token)) { if (def.isTokenEndpointDefinition() && def.asTokenEndpointDefinition().getToken().equals(token)) {
return def.asTokenEndpointDefinition(); result.add(def.asTokenEndpointDefinition());
} }
} }
return null; return result;
} }
// --- lookupDependencyDefinition --- // --- lookupDependencyDefinition ---
...@@ -22,6 +24,34 @@ aspect Analysis { ...@@ -22,6 +24,34 @@ aspect Analysis {
} }
// --- isAlreadyDefined --- // --- isAlreadyDefined ---
syn boolean TokenEndpointDefinition.isAlreadyDefined() = lookupTokenEndpointDefinition(getToken()) != this; syn boolean TokenEndpointDefinition.isAlreadyDefined() = lookupTokenEndpointDefinitions(getToken()).size() > 1;
syn boolean DependencyDefinition.isAlreadyDefined() = lookupDependencyDefinition(getSource().containingTypeDecl(), getID()) != this; syn boolean DependencyDefinition.isAlreadyDefined() = lookupDependencyDefinition(getSource().containingTypeDecl(), getID()) != this;
syn boolean MappingDefinitionType.assignableTo(JavaTypeUse target);
eq JavaMappingDefinitionType.assignableTo(JavaTypeUse target) = getType().assignableTo(target);
eq JavaArrayMappingDefinitionType.assignableTo(JavaTypeUse target) {
if (!target.getName().endsWith("[]")) { return false; }
return getType().assignableTo(new SimpleJavaTypeUse(target.getName().replace("[]", "")));
}
syn boolean JavaTypeUse.assignableTo(JavaTypeUse target) {
// target var = this;
return target.primitivePrettyPrint().equals(this.primitivePrettyPrint());
}
syn String JavaTypeUse.primitivePrettyPrint() {
switch(getName()) {
case "int":
case "Integer": return "int";
case "short":
case "Short": return "short";
case "long":
case "Long": return "long";
case "float":
case "Float": return "float";
case "double":
case "Double": return "double";
case "char":
case "Character": return "char";
default: return getName();
}
}
} }
...@@ -7,32 +7,32 @@ aspect Errors { ...@@ -7,32 +7,32 @@ aspect Errors {
[new TreeSet<ErrorMessage>()] [new TreeSet<ErrorMessage>()]
root RagConnect; root RagConnect;
ReceiveFromMqttDefinition contributes error("Receive definition already defined for " + getToken().getName()) ReceiveTokenEndpointDefinition contributes error("Receive definition already defined for " + getToken().getName())
when isAlreadyDefined() when isAlreadyDefined()
to RagConnect.errors(); 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() when getToken().getNTA()
to RagConnect.errors(); to RagConnect.errors();
// if first mapping is null, then suitableDefaultMapping() == null // 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()) ((getMappingList().isEmpty())
? getToken().getJavaTypeUse().prettyPrint() ? getToken().effectiveJavaTypeUse().prettyPrint()
: getMappingList().get(0).getFromType().prettyPrint())) : getMappingList().get(0).getFromType().prettyPrint()))
when effectiveMappings().get(0) == null when effectiveMappings().get(0) == null
to RagConnect.errors(); to RagConnect.errors();
ReceiveFromMqttDefinition contributes error("to-type of last mapping must be type of the Token!") ReceiveTokenEndpointDefinition contributes error("to-type of last mapping (" + effectiveMappings().get(effectiveMappings().size() - 1).getToType().prettyPrint() + ") not assignable to type of the Token (" + getToken().effectiveJavaTypeUse().prettyPrint() + ")!")
when getToken().getJavaTypeUse().prettyPrint().equals( when !effectiveMappings().get(effectiveMappings().size() - 1).getToType().assignableTo(
effectiveMappings().get(effectiveMappings().size() - 1)) getToken().effectiveJavaTypeUse())
to RagConnect.errors(); 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() when !getToken().getNTA()
to RagConnect.errors(); 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() when isAlreadyDefined()
to RagConnect.errors(); to RagConnect.errors();
...@@ -44,7 +44,7 @@ aspect Errors { ...@@ -44,7 +44,7 @@ aspect Errors {
when isAlreadyDefinedAsList() when isAlreadyDefinedAsList()
to RagConnect.errors(); 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 when targetEndpointDefinition() == null
to RagConnect.errors(); to RagConnect.errors();
} }
......
//TypeComponentMustache ;
//rel TypeComponentMustache.TypeComponent -> TypeComponent ;
MRagConnect ::= ReceiveDefinition:MReceiveDefinition* SendDefinition:MSendDefinition* MappingDefinition:MMappingDefinition* DependencyDefinition:MDependencyDefinition* RootTypeComponent:MTypeComponent* TokenComponent:MTokenComponent*; MRagConnect ::= ReceiveDefinition:MReceiveDefinition* SendDefinition:MSendDefinition* MappingDefinition:MMappingDefinition* DependencyDefinition:MDependencyDefinition* RootTypeComponent:MTypeComponent* TokenComponent:MTokenComponent*;
abstract MEndpointDefinition ::= InnerMappingDefinition:MInnerMappingDefinition*; abstract MEndpointDefinition ::= InnerMappingDefinition:MInnerMappingDefinition*;
MReceiveDefinition : MEndpointDefinition; MReceiveDefinition : MEndpointDefinition;
...@@ -12,9 +9,9 @@ MTypeComponent; ...@@ -12,9 +9,9 @@ MTypeComponent;
MTokenComponent; MTokenComponent;
rel MRagConnect.RagConnect -> RagConnect; rel MRagConnect.RagConnect -> RagConnect;
rel MInnerMappingDefinition.MappingDefinition -> MappingDefinition; rel MInnerMappingDefinition.MMappingDefinition -> MMappingDefinition;
rel MReceiveDefinition.ReceiveFromMqttDefinition -> ReceiveFromMqttDefinition; rel MReceiveDefinition.ReceiveTokenEndpointDefinition -> ReceiveTokenEndpointDefinition;
rel MSendDefinition.SendToMqttDefinition -> SendToMqttDefinition; rel MSendDefinition.SendTokenEndpointDefinition -> SendTokenEndpointDefinition;
rel MMappingDefinition.MappingDefinition -> MappingDefinition; rel MMappingDefinition.MappingDefinition -> MappingDefinition;
rel MDependencyDefinition.DependencyDefinition -> DependencyDefinition; rel MDependencyDefinition.DependencyDefinition -> DependencyDefinition;
rel MTypeComponent.TypeComponent -> TypeComponent; rel MTypeComponent.TypeComponent -> TypeComponent;
......
...@@ -10,9 +10,12 @@ aspect Navigation { ...@@ -10,9 +10,12 @@ aspect Navigation {
eq MRagConnect.getChild().ragconnect() = getRagConnect(); eq MRagConnect.getChild().ragconnect() = getRagConnect();
// --- containedFile // --- containedFile
eq Grammar.getChild().containedFile() = null;
eq RagConnect.getChild().containedFile() = null; eq RagConnect.getChild().containedFile() = null;
eq MRagConnect.getChild().containedFile() = null;
// --- containedFileName --- // --- containedFileName ---
eq Grammar.getChild().containedFileName() = null; // should be in PP
eq RagConnect.getChild().containedFileName() = getFileName(); eq RagConnect.getChild().containedFileName() = getFileName();
eq MRagConnect.getChild().containedFileName() = null; eq MRagConnect.getChild().containedFileName() = null;
...@@ -24,30 +27,33 @@ aspect Navigation { ...@@ -24,30 +27,33 @@ aspect Navigation {
syn TokenEndpointDefinition EndpointDefinition.asTokenEndpointDefinition() = null; syn TokenEndpointDefinition EndpointDefinition.asTokenEndpointDefinition() = null;
eq TokenEndpointDefinition.asTokenEndpointDefinition() = this; eq TokenEndpointDefinition.asTokenEndpointDefinition() = this;
// --- isSendToMqttDefinition --- // --- isSendTokenEndpointDefinition ---
syn boolean EndpointDefinition.isSendToMqttDefinition() = false; syn boolean EndpointDefinition.isSendTokenEndpointDefinition() = false;
eq SendToMqttDefinition.isSendToMqttDefinition() = true; eq SendTokenEndpointDefinition.isSendTokenEndpointDefinition() = true;
// --- asSendToMqttDefinition --- // --- asSendTokenEndpointDefinition ---
syn SendToMqttDefinition EndpointDefinition.asSendToMqttDefinition() = null; syn SendTokenEndpointDefinition EndpointDefinition.asSendTokenEndpointDefinition() = null;
eq SendToMqttDefinition.asSendToMqttDefinition() = this; eq SendTokenEndpointDefinition.asSendTokenEndpointDefinition() = this;
// --- asReceiveFromMqttDefinition --- // --- asReceiveTokenEndpointDefinition ---
syn ReceiveFromMqttDefinition EndpointDefinition.asReceiveFromMqttDefinition() = null; syn ReceiveTokenEndpointDefinition EndpointDefinition.asReceiveTokenEndpointDefinition() = null;
eq ReceiveFromMqttDefinition.asReceiveFromMqttDefinition() = this; eq ReceiveTokenEndpointDefinition.asReceiveTokenEndpointDefinition() = this;
// --- targetEndpointDefinition --- // --- targetEndpointDefinition ---
syn SendToMqttDefinition DependencyDefinition.targetEndpointDefinition() { syn SendTokenEndpointDefinition DependencyDefinition.targetEndpointDefinition() {
// resolve definition in here, as we do not need resolveMethod in any other place (yet) // resolve definition in here, as we do not need resolveMethod in any other place (yet)
for (EndpointDefinition endpointDefinition : ragconnect().getEndpointDefinitionList()) { for (EndpointDefinition endpointDefinition : ragconnect().getEndpointDefinitionList()) {
if (endpointDefinition.isSendToMqttDefinition() && if (endpointDefinition.isSendTokenEndpointDefinition() &&
endpointDefinition.asSendToMqttDefinition().getToken().equals(this.getTarget())) { endpointDefinition.asSendTokenEndpointDefinition().getToken().equals(this.getTarget())) {
return endpointDefinition.asSendToMqttDefinition(); return endpointDefinition.asSendTokenEndpointDefinition();
} }
} }
return null; return null;
} }
// --- effectiveJavaTypeUse (should be in preprocessor) ---
syn lazy JavaTypeUse TokenComponent.effectiveJavaTypeUse() = hasJavaTypeUse() ? getJavaTypeUse() : new SimpleJavaTypeUse("String");
// --- isDefaultMappingDefinition --- // --- isDefaultMappingDefinition ---
syn boolean MappingDefinition.isDefaultMappingDefinition() = false; syn boolean MappingDefinition.isDefaultMappingDefinition() = false;
eq DefaultMappingDefinition.isDefaultMappingDefinition() = true; eq DefaultMappingDefinition.isDefaultMappingDefinition() = true;
......
aspect Printing {
String ASTNode.PRINT_INDENT = " ";
syn String MappingDefinitionType.prettyPrint();
eq JavaMappingDefinitionType.prettyPrint() = getType().getName();
eq JavaArrayMappingDefinitionType.prettyPrint() = getType().getName() + "[]";
syn String JavaTypeUse.prettyPrint() {
StringBuilder sb = new StringBuilder();
generateAbstractGrammar(sb);
return sb.toString();
}
syn String Document.prettyPrint() {
StringBuilder sb = new StringBuilder();
sb.append("# RagConnect created at ").append(java.time.Instant.now()).append("\n");
for (ComplexElement element : getComplexElementList()) {
element.prettyPrint(sb, false, "");
}
if (sb.charAt(sb.length() - 1) != '\n') {
sb.append("\n");
}
return sb.toString();
}
syn StringBuilder Element.prettyPrint(StringBuilder sb, boolean printIndent, String indent);
eq ValueElement.prettyPrint(StringBuilder sb, boolean printIndent, String indent) {
sb.append(getValue());
return sb;
}
eq StringElement.prettyPrint(StringBuilder sb, boolean printIndent, String indent) {
sb.append("\"").append(getValue()).append("\"");
return sb;
}
eq ListElement.prettyPrint(StringBuilder sb, boolean printIndent, String indent) {
if (isEmpty()) {
sb.append("[]");
} else {
for (Element element : getElementList()) {
sb.append(indent).append("- ");
element.prettyPrint(sb, false, indent + PRINT_INDENT);
sb.append("\n");
}
// delete last newline
sb.deleteCharAt(sb.length() - 1);
}
return sb;
}
eq KeyValuePair.prettyPrint(StringBuilder sb, boolean printIndent, String indent) {
if (printIndent) sb.append(indent);
sb.append(getKey()).append(": ");
if (getValue().isComplex() && !getValue().isEmpty()) {
sb.append("\n");
getValue().prettyPrint(sb, true, indent + PRINT_INDENT); //);
} else {
getValue().prettyPrint(sb, false, indent);
}
return sb;
}
eq MappingElement.prettyPrint(StringBuilder sb, boolean printIndent, String indent) {
if (isEmpty()) {
sb.append("{}");
} else {
boolean first = true;
for (KeyValuePair pair : getKeyValuePairList()) {
if (!first || printIndent) sb.append(indent);
first = false;
pair.prettyPrint(sb, false, indent); // + PRINT_INDENT
sb.append("\n");
}
// delete last newline
sb.deleteCharAt(sb.length() - 1);
}
return sb;
}
}
...@@ -2,13 +2,13 @@ RagConnect ::= EndpointDefinition* DependencyDefinition* MappingDefinition* Prog ...@@ -2,13 +2,13 @@ RagConnect ::= EndpointDefinition* DependencyDefinition* MappingDefinition* Prog
abstract EndpointDefinition ::= <AlwaysApply:boolean> ; abstract EndpointDefinition ::= <AlwaysApply:boolean> ;
rel EndpointDefinition.Mapping* -> MappingDefinition; rel EndpointDefinition.Mapping* <-> MappingDefinition.UsedAt*;
abstract TokenEndpointDefinition : EndpointDefinition; abstract TokenEndpointDefinition : EndpointDefinition;
rel TokenEndpointDefinition.Token -> TokenComponent; rel TokenEndpointDefinition.Token -> TokenComponent;
ReceiveFromMqttDefinition : TokenEndpointDefinition; ReceiveTokenEndpointDefinition : TokenEndpointDefinition;
SendToMqttDefinition : TokenEndpointDefinition; SendTokenEndpointDefinition : TokenEndpointDefinition;
DependencyDefinition ::= <ID>; DependencyDefinition ::= <ID>;
rel DependencyDefinition.Source <-> TokenComponent.DependencySourceDefinition*; rel DependencyDefinition.Source <-> TokenComponent.DependencySourceDefinition*;
......
aspect Util {
static String ASTNode.capitalize(String s) {
return Character.toUpperCase(s.charAt(0)) + s.substring(1);
}
}
aspect Navigation {
eq Document.getChild().program() = null;
eq Document.getChild().ragconnect() = null;
eq Document.getChild().containedFile() = null;
eq Document.getChild().containedFileName() = getFileName();
syn boolean Element.isComplex() = false;
eq ComplexElement.isComplex() = true;
syn boolean Element.isEmpty() = false;
eq MappingElement.isEmpty() = getNumKeyValuePair() == 0;
eq ListElement.isEmpty() = getNumElement() == 0;
}
aspect Helper {
public static ValueElement ValueElement.of(int value) {
return new ValueElement(String.valueOf(value));
}
public static ValueElement ValueElement.of(boolean value) {
return new ValueElement(String.valueOf(value));
}
public static ValueElement ValueElement.of(String value) {
return new ValueElement(value);
}
public static StringElement StringElement.of(String value) {
return new StringElement(value);
}
public void MappingElement.addKeyValuePair(String key, Element value) {
addKeyValuePair(new KeyValuePair(key, value));
}
}
Document ::= <FileName> ComplexElement* ;
abstract Element ;
abstract ComplexElement : Element ;
MappingElement : ComplexElement ::= KeyValuePair* ;
KeyValuePair : ComplexElement ::= <Key> Value:Element ;
ListElement : ComplexElement ::= Element* ;
abstract SimpleElement : Element ;
ValueElement : SimpleElement ::= <Value> ;
StringElement : SimpleElement ::= <Value> ;
...@@ -2,4 +2,6 @@ aspect Configuration { ...@@ -2,4 +2,6 @@ aspect Configuration {
public static boolean ASTNode.loggingEnabledForReads = false; public static boolean ASTNode.loggingEnabledForReads = false;
public static boolean ASTNode.loggingEnabledForWrites = false; public static boolean ASTNode.loggingEnabledForWrites = false;
public static TypeDecl ASTNode.rootNode; public static TypeDecl ASTNode.rootNode;
public static boolean ASTNode.usesMqtt;
public static boolean ASTNode.usesRest;
} }
aspect GenerationUtils { /*
public static final String ASTNode.aspectIndent = " "; Design considerations
- InnerMappingDefinition needed for iteration attribute (first, last) - not easily possible with list-relation
public String ASTNode.ind(int n) {
StringBuilder s = new StringBuilder();
for (int i = 0; i < n; i++) {
s.append(aspectIndent);
}
return s.toString();
}
// --- prettyPrint ---
syn String MappingDefinitionType.prettyPrint();
eq JavaMappingDefinitionType.prettyPrint() = getType().getName();
eq JavaArrayMappingDefinitionType.prettyPrint() = getType().getName() + "[]";
syn String JavaTypeUse.prettyPrint() {
StringBuilder sb = new StringBuilder();
generateAbstractGrammar(sb);
return sb.toString();
}
}
/* Open questions
- Should all string constants be defined on the normal AST, or on the special mustache AST?
*/ */
aspect AttributesForMustache { aspect AttributesForMustache {
// --- MRagConnect --- // --- MRagConnect ---
eq MRagConnect.getChild().mqttHandlerAttribute() = mqttHandlerAttribute();
eq MRagConnect.getChild().mqttHandlerField() = mqttHandlerField();
eq MRagConnect.getRootTypeComponent(int i).isFirst() = i == 0; eq MRagConnect.getRootTypeComponent(int i).isFirst() = i == 0;
syn String MRagConnect.mqttHandlerAttribute() = getRagConnect().mqttHandlerAttribute(); syn String MRagConnect.closeMethod() = "ragconnectCloseConnections";
syn String MRagConnect.mqttHandlerField() = getRagConnect().mqttHandlerField(); syn String MRagConnect.mqttHandlerAttribute() = "_mqttHandler";
syn String MRagConnect.mqttSetHostMethod() = getRagConnect().mqttSetHostMethod(); syn String MRagConnect.mqttHandlerField() = "_mqttHandler";
syn String MRagConnect.mqttWaitUntilReadyMethod() = getRagConnect().mqttWaitUntilReadyMethod(); syn String MRagConnect.mqttSetupWaitUntilReadyMethod() = "ragconnectSetupMqttWaitUntilReady";
syn String MRagConnect.mqttCloseMethod() = getRagConnect().mqttCloseMethod();
syn String MRagConnect.restHandlerAttribute() = "_restHandler";
syn String MRagConnect.restHandlerField() = "_restHandler";
// --- MEndpointDefinition --- // --- MEndpointDefinition ---
syn String MEndpointDefinition.preemptiveExpectedValue(); syn String MEndpointDefinition.preemptiveExpectedValue();
...@@ -44,29 +22,25 @@ aspect AttributesForMustache { ...@@ -44,29 +22,25 @@ aspect AttributesForMustache {
syn String MEndpointDefinition.firstInputVarName(); syn String MEndpointDefinition.firstInputVarName();
eq MEndpointDefinition.getInnerMappingDefinition(int i).isLast() = i == getNumInnerMappingDefinition() - 1; eq MEndpointDefinition.getInnerMappingDefinition(int i).isLast() = i == getNumInnerMappingDefinition() - 1;
eq MEndpointDefinition.getInnerMappingDefinition().resultVarPrefix() = resultVarPrefix(); eq MEndpointDefinition.getInnerMappingDefinition(int i).inputVarName() = i == 0 ? firstInputVarName() : getInnerMappingDefinition(i - 1).outputVarName();
eq MEndpointDefinition.getInnerMappingDefinition(int i).inputVarName() = i == 0 ? firstInputVarName() : resultVarPrefix() + getInnerMappingDefinition(i - 1).getMappingDefinition().methodName();
inh String MEndpointDefinition.mqttHandlerAttribute();
syn String MEndpointDefinition.connectMethod() = endpointDef().connectMethod(); syn String MEndpointDefinition.connectParameterName() = "uriString";
syn String MEndpointDefinition.connectMethod() = "connect" + tokenName();
syn TokenComponent MEndpointDefinition.token() = endpointDef().getToken(); syn TokenComponent MEndpointDefinition.token() = endpointDef().getToken();
syn boolean MEndpointDefinition.alwaysApply() = endpointDef().getAlwaysApply(); syn boolean MEndpointDefinition.alwaysApply() = endpointDef().getAlwaysApply();
syn String MEndpointDefinition.resultVarPrefix() = "result"; // we do not need "_" here, because methodName begins with one
syn String MEndpointDefinition.parentTypeName() = token().containingTypeDecl().getName(); syn String MEndpointDefinition.parentTypeName() = token().containingTypeDecl().getName();
syn String MEndpointDefinition.tokenName() = token().getName(); syn String MEndpointDefinition.tokenName() = token().getName();
syn MInnerMappingDefinition MEndpointDefinition.lastDefinition() = getInnerMappingDefinition(getNumInnerMappingDefinition() - 1); syn MInnerMappingDefinition MEndpointDefinition.lastDefinition() = getInnerMappingDefinition(getNumInnerMappingDefinition() - 1);
syn String MEndpointDefinition.lastDefinitionToType() = lastDefinition().ToType(); syn String MEndpointDefinition.lastDefinitionToType() = lastDefinition().toType();
syn String MEndpointDefinition.lastDefinitionName() = lastDefinition().methodName(); syn String MEndpointDefinition.lastResult() = lastDefinition().outputVarName();
syn String MEndpointDefinition.lastResult() = resultVarPrefix() + lastDefinitionName();
syn String MEndpointDefinition.condition() { syn String MEndpointDefinition.condition() {
if (lastDefinition().getMappingDefinition().getToType().isArray()) { if (lastDefinition().mappingDef().getToType().isArray()) {
return "java.util.Arrays.equals(" + preemptiveExpectedValue() + ", " + lastResult() + ")"; return "java.util.Arrays.equals(" + preemptiveExpectedValue() + ", " + lastResult() + ")";
} }
if (token().isPrimitiveType() && lastDefinition().getMappingDefinition().getToType().isPrimitiveType()) { if (token().isPrimitiveType() && lastDefinition().mappingDef().getToType().isPrimitiveType()) {
return preemptiveExpectedValue() + " == " + lastResult(); return preemptiveExpectedValue() + " == " + lastResult();
} }
if (lastDefinition().getMappingDefinition().isDefaultMappingDefinition()) { if (lastDefinition().mappingDef().isDefaultMappingDefinition()) {
return preemptiveExpectedValue() + " != null && " + preemptiveExpectedValue() + ".equals(" + lastResult() + ")"; return preemptiveExpectedValue() + " != null && " + preemptiveExpectedValue() + ".equals(" + lastResult() + ")";
} }
return preemptiveExpectedValue() + " != null ? " + preemptiveExpectedValue() + ".equals(" + lastResult() + ") : " + lastResult() + " == null"; return preemptiveExpectedValue() + " != null ? " + preemptiveExpectedValue() + ".equals(" + lastResult() + ") : " + lastResult() + " == null";
...@@ -74,66 +48,67 @@ aspect AttributesForMustache { ...@@ -74,66 +48,67 @@ aspect AttributesForMustache {
// --- MInnerMappingDefinition --- // --- MInnerMappingDefinition ---
inh boolean MInnerMappingDefinition.isLast(); inh boolean MInnerMappingDefinition.isLast();
inh String MInnerMappingDefinition.resultVarPrefix();
syn String MInnerMappingDefinition.ToType() = getMappingDefinition().getToType().prettyPrint();
syn String MInnerMappingDefinition.methodName() = getMappingDefinition().methodName();
inh String MInnerMappingDefinition.inputVarName(); inh String MInnerMappingDefinition.inputVarName();
syn String MInnerMappingDefinition.toType() = mappingDef().getToType().prettyPrint();
syn String MInnerMappingDefinition.methodName() = getMMappingDefinition().methodName();
syn MappingDefinition MInnerMappingDefinition.mappingDef() = getMMappingDefinition().getMappingDefinition();
syn String MInnerMappingDefinition.outputVarName() = "result" + methodName(); // we do not need "_" in between here, because methodName begins with one
// --- MReceiveDefinition --- // --- MReceiveDefinition ---
eq MReceiveDefinition.preemptiveExpectedValue() = "get" + tokenName() + "()"; eq MReceiveDefinition.preemptiveExpectedValue() = "get" + tokenName() + "()";
eq MReceiveDefinition.preemptiveReturn() = "return;"; eq MReceiveDefinition.preemptiveReturn() = "return;";
eq MReceiveDefinition.endpointDef() = getReceiveFromMqttDefinition(); eq MReceiveDefinition.endpointDef() = getReceiveTokenEndpointDefinition();
eq MReceiveDefinition.firstInputVarName() = "message"; eq MReceiveDefinition.firstInputVarName() = "message";
// --- MSendDefinition --- // --- MSendDefinition ---
eq MSendDefinition.preemptiveExpectedValue() = lastValue(); eq MSendDefinition.preemptiveExpectedValue() = lastValue();
eq MSendDefinition.preemptiveReturn() = "return false;"; eq MSendDefinition.preemptiveReturn() = "return false;";
eq MSendDefinition.endpointDef() = getSendToMqttDefinition(); eq MSendDefinition.endpointDef() = getSendTokenEndpointDefinition();
eq MSendDefinition.firstInputVarName() = "get" + tokenName() + "()"; eq MSendDefinition.firstInputVarName() = "get" + tokenName() + "()";
syn String MSendDefinition.sendTopic() = getSendToMqttDefinition().sendTopic(); syn String MSendDefinition.sender() = "_sender_" + tokenName();
syn String MSendDefinition.lastValue() = getSendToMqttDefinition().lastValue(); syn String MSendDefinition.lastValue() = "_lastValue" + tokenName();
syn String MSendDefinition.updateMethod() = getSendToMqttDefinition().updateMethod(); syn String MSendDefinition.updateMethod() = "_update_" + tokenName();
syn String MSendDefinition.writeMethod() = getSendToMqttDefinition().writeMethod(); syn String MSendDefinition.writeMethod() = "_writeLastValue_" + tokenName();
syn String MSendDefinition.tokenResetMethod() = getSendToMqttDefinition().tokenResetMethod(); syn String MSendDefinition.tokenResetMethod() = "get" + tokenName() + "_reset";
// --- MMappingDefinition --- // --- MMappingDefinition ---
syn String MMappingDefinition.toType() = getMappingDefinition().getToType().prettyPrint(); syn String MMappingDefinition.toType() = getMappingDefinition().getToType().prettyPrint();
syn String MMappingDefinition.methodName() = getMappingDefinition().methodName(); syn String MMappingDefinition.methodName() = "_apply_" + getMappingDefinition().getID();
syn String MMappingDefinition.fromType() = getMappingDefinition().getFromType().prettyPrint(); syn String MMappingDefinition.fromType() = getMappingDefinition().getFromType().prettyPrint();
syn String MMappingDefinition.fromVariableName() = getMappingDefinition().getFromVariableName(); syn String MMappingDefinition.fromVariableName() = getMappingDefinition().getFromVariableName();
syn String MMappingDefinition.content() = getMappingDefinition().getContent(); syn String MMappingDefinition.content() = getMappingDefinition().getContent();
// --- MDependencyDefinition --- // --- MDependencyDefinition ---
syn String MDependencyDefinition.targetParentTypeName() = getDependencyDefinition().getTarget().containingTypeDecl().getName(); syn String MDependencyDefinition.targetParentTypeName() = getDependencyDefinition().getTarget().containingTypeDecl().getName();
syn String MDependencyDefinition.dependencyMethod() = getDependencyDefinition().dependencyMethod(); syn String MDependencyDefinition.dependencyMethod() = "add" + capitalize(getDependencyDefinition().getID());
syn String MDependencyDefinition.sourceParentTypeName() = getDependencyDefinition().getSource().containingTypeDecl().getName(); syn String MDependencyDefinition.sourceParentTypeName() = getDependencyDefinition().getSource().containingTypeDecl().getName();
syn String MDependencyDefinition.internalRelationPrefix() = getDependencyDefinition().internalRelationPrefix(); syn String MDependencyDefinition.internalRelationPrefix() = "_internal_" + getDependencyDefinition().getID();
syn nta MEndpointDefinition MDependencyDefinition.targetEndpointDefinition() { syn nta MSendDefinition MDependencyDefinition.targetEndpointDefinition() {
return getDependencyDefinition().targetEndpointDefinition().toMustache(); return getDependencyDefinition().targetEndpointDefinition().toMustache();
} }
// --- MTypeComponent --- // --- MTypeComponent ---
syn String MTypeComponent.name() = getTypeComponent().getName(); syn String MTypeComponent.name() = getTypeComponent().getName();
inh String MTypeComponent.mqttHandlerAttribute();
inh String MTypeComponent.mqttHandlerField();
inh boolean MTypeComponent.isFirst(); inh boolean MTypeComponent.isFirst();
// --- MTokenComponent --- // --- MTokenComponent ---
syn String MTokenComponent.parentTypeName() = getTokenComponent().containingTypeDecl().getName(); syn String MTokenComponent.parentTypeName() = getTokenComponent().containingTypeDecl().getName();
syn String MTokenComponent.name() = getTokenComponent().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(); syn String MTokenComponent.internalName() = getTokenComponent().getDependencySourceDefinitionList().isEmpty() ? externalName() : "_internal_" + name();
syn String MTokenComponent.externalName() = name();
// --- toMustache --- // --- toMustache ---
syn lazy MRagConnect RagConnect.toMustache() { syn lazy MRagConnect RagConnect.toMustache() {
MRagConnect result = new MRagConnect(); MRagConnect result = new MRagConnect();
result.setRagConnect(this); result.setRagConnect(this);
for (EndpointDefinition def : getEndpointDefinitionList()) { for (EndpointDefinition def : getEndpointDefinitionList()) {
if (def.isSendToMqttDefinition()) { if (def.isSendTokenEndpointDefinition()) {
result.addSendDefinition(def.asSendToMqttDefinition().toMustache()); SendTokenEndpointDefinition sendDef = def.asSendTokenEndpointDefinition();
result.addSendDefinition(sendDef.toMustache());
} else { } else {
result.addReceiveDefinition(def.asReceiveFromMqttDefinition().toMustache()); result.addReceiveDefinition(def.asReceiveTokenEndpointDefinition().toMustache());
} }
} }
for (MappingDefinition def : allMappingDefinitions()) { for (MappingDefinition def : allMappingDefinitions()) {
...@@ -155,41 +130,46 @@ aspect AttributesForMustache { ...@@ -155,41 +130,46 @@ aspect AttributesForMustache {
return result; return result;
} }
//MInnerMappingDefinition.MappingDefinition -> MappingDefinition;
protected void MEndpointDefinition.addInnerMappings() { protected void MEndpointDefinition.addInnerMappings() {
for (MappingDefinition def : endpointDef().effectiveMappings()) { for (MappingDefinition def : endpointDef().effectiveMappings()) {
MInnerMappingDefinition inner = new MInnerMappingDefinition(); MInnerMappingDefinition inner = new MInnerMappingDefinition();
inner.setMappingDefinition(def); inner.setMMappingDefinition(def.toMustache());
addInnerMappingDefinition(inner); addInnerMappingDefinition(inner);
} }
} }
syn lazy MReceiveDefinition ReceiveFromMqttDefinition.toMustache() {
syn lazy MReceiveDefinition ReceiveTokenEndpointDefinition.toMustache() {
MReceiveDefinition result = new MReceiveDefinition(); MReceiveDefinition result = new MReceiveDefinition();
result.setReceiveFromMqttDefinition(this); result.setReceiveTokenEndpointDefinition(this);
result.addInnerMappings(); result.addInnerMappings();
return result; return result;
} }
syn lazy MSendDefinition SendToMqttDefinition.toMustache() {
syn lazy MSendDefinition SendTokenEndpointDefinition.toMustache() {
MSendDefinition result = new MSendDefinition(); MSendDefinition result = new MSendDefinition();
result.setSendToMqttDefinition(this); result.setSendTokenEndpointDefinition(this);
result.addInnerMappings(); result.addInnerMappings();
return result; return result;
} }
syn lazy MMappingDefinition MappingDefinition.toMustache() { syn lazy MMappingDefinition MappingDefinition.toMustache() {
MMappingDefinition result = new MMappingDefinition(); MMappingDefinition result = new MMappingDefinition();
result.setMappingDefinition(this); result.setMappingDefinition(this);
return result; return result;
} }
syn lazy MDependencyDefinition DependencyDefinition.toMustache() { syn lazy MDependencyDefinition DependencyDefinition.toMustache() {
MDependencyDefinition result = new MDependencyDefinition(); MDependencyDefinition result = new MDependencyDefinition();
result.setDependencyDefinition(this); result.setDependencyDefinition(this);
return result; return result;
} }
syn lazy MTypeComponent TypeComponent.toMustache() { syn lazy MTypeComponent TypeComponent.toMustache() {
MTypeComponent result = new MTypeComponent(); MTypeComponent result = new MTypeComponent();
result.setTypeComponent(this); result.setTypeComponent(this);
return result; return result;
} }
syn lazy MTokenComponent TokenComponent.toMustache() { syn lazy MTokenComponent TokenComponent.toMustache() {
MTokenComponent result = new MTokenComponent(); MTokenComponent result = new MTokenComponent();
result.setTokenComponent(this); result.setTokenComponent(this);
...@@ -201,37 +181,6 @@ aspect AttributesForMustache { ...@@ -201,37 +181,6 @@ aspect AttributesForMustache {
} }
aspect AspectGeneration { aspect AspectGeneration {
// naming convention attributes
syn String TokenComponent.internalName() = getDependencySourceDefinitionList().isEmpty() ? externalName() : "_internal_" + getName();
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 MappingDefinition.methodName() = "_apply_" + getID();
syn String DependencyDefinition.dependencyMethod() = "add" +
Character.toUpperCase(getID().charAt(0)) +
getID().substring(1);
syn String DependencyDefinition.internalRelationPrefix() = "_internal_" + getID();
syn String DependencyDefinition.internalTokenName() = getSource().internalName();
syn String RagConnect.mqttHandlerAttribute() = "_mqttHandler";
syn String RagConnect.mqttHandlerField() = "_mqttHandler";
syn String RagConnect.mqttSetHostMethod() = "MqttSetHost";
syn String RagConnect.mqttWaitUntilReadyMethod() = "MqttWaitUntilReady";
syn String RagConnect.mqttCloseMethod() = "MqttCloseConnections";
// naming copy attributes
// --- mqttHandlerAttribute ---
inh String EndpointDefinition.mqttHandlerAttribute();
inh String MappingDefinition.mqttHandlerAttribute();
inh String DependencyDefinition.mqttHandlerAttribute();
eq RagConnect.getChild().mqttHandlerAttribute() = mqttHandlerAttribute();
// --- rootNodeName --- // --- rootNodeName ---
syn String ASTNode.rootNodeName() = rootNode.getName(); syn String ASTNode.rootNodeName() = rootNode.getName();
...@@ -275,10 +224,11 @@ aspect RelationGeneration { ...@@ -275,10 +224,11 @@ aspect RelationGeneration {
} }
syn nta Relation DependencyDefinition.getRelationToCreate() { syn nta Relation DependencyDefinition.getRelationToCreate() {
String internalRelationPrefix = toMustache().internalRelationPrefix();
BidirectionalRelation result = new BidirectionalRelation(); BidirectionalRelation result = new BidirectionalRelation();
NavigableRole left = new ListRole(internalRelationPrefix() + "Source"); NavigableRole left = new ListRole(internalRelationPrefix + "Source");
left.setType(getTarget().containingTypeDecl()); left.setType(getTarget().containingTypeDecl());
NavigableRole right = new ListRole(internalRelationPrefix() + "Target"); NavigableRole right = new ListRole(internalRelationPrefix + "Target");
right.setType(getSource().containingTypeDecl()); right.setType(getSource().containingTypeDecl());
result.setLeft(left); result.setLeft(left);
result.setRight(right); result.setRight(right);
...@@ -294,9 +244,9 @@ aspect GrammarExtension { ...@@ -294,9 +244,9 @@ aspect GrammarExtension {
} }
b.append("<"); b.append("<");
if (!getName().equals("")) { if (!getName().equals("")) {
b.append(internalName()).append(":"); b.append(toMustache().internalName()).append(":");
} }
getJavaTypeUse().generateAbstractGrammar(b); effectiveJavaTypeUse().generateAbstractGrammar(b);
b.append(">"); b.append(">");
if (getNTA()) { if (getNTA()) {
b.append("/"); b.append("/");
......
aspect DefaultMappings { aspect DefaultMappings {
private DefaultMappingDefinition RagConnect.baseDefaultMappingDefinitionFromBytes(String typeName) { private String RagConnect.baseDefaultMappingTypeNamePart(String typeName) {
DefaultMappingDefinition result = new DefaultMappingDefinition(); return capitalize(typeName).replace("[]", "s");
result.setID("_DefaultBytesTo" + Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1) + "Mapping");
result.setFromType(new JavaArrayMappingDefinitionType(new SimpleJavaTypeUse("byte")));
result.setFromVariableName("bytes");
result.setToType(new JavaMappingDefinitionType(new SimpleJavaTypeUse(typeName)));
return result;
}
private DefaultMappingDefinition RagConnect.baseDefaultMappingDefinitionToBytes(String typeName) {
DefaultMappingDefinition result = new DefaultMappingDefinition();
result.setID("_Default" + Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1) + "ToBytesMapping");
result.setFromType(new JavaMappingDefinitionType(new SimpleJavaTypeUse(typeName)));
result.setFromVariableName("input");
result.setToType(new JavaArrayMappingDefinitionType(new SimpleJavaTypeUse("byte")));
return result;
}
syn nta DefaultMappingDefinition RagConnect.defaultBytesToIntMapping() {
DefaultMappingDefinition result = baseDefaultMappingDefinitionFromBytes("int");
result.setContent("return java.nio.ByteBuffer.wrap(bytes).getInt();");
return result;
}
syn nta DefaultMappingDefinition RagConnect.defaultBytesToShortMapping() {
DefaultMappingDefinition result = baseDefaultMappingDefinitionFromBytes("short");
result.setContent("return java.nio.ByteBuffer.wrap(bytes).getShort();");
return result;
}
syn nta DefaultMappingDefinition RagConnect.defaultBytesToLongMapping() {
DefaultMappingDefinition result = baseDefaultMappingDefinitionFromBytes("long");
result.setContent("return java.nio.ByteBuffer.wrap(bytes).getLong();");
return result;
}
syn nta DefaultMappingDefinition RagConnect.defaultBytesToFloatMapping() {
DefaultMappingDefinition result = baseDefaultMappingDefinitionFromBytes("float");
result.setContent("return java.nio.ByteBuffer.wrap(bytes).getFloat();");
return result;
}
syn nta DefaultMappingDefinition RagConnect.defaultBytesToDoubleMapping() {
DefaultMappingDefinition result = baseDefaultMappingDefinitionFromBytes("double");
result.setContent("return java.nio.ByteBuffer.wrap(bytes).getDouble();");
return result;
} }
syn nta DefaultMappingDefinition RagConnect.defaultBytesToCharMapping() { private MappingDefinitionType RagConnect.baseDefaultMappingTypeFromName(String typeName) {
DefaultMappingDefinition result = baseDefaultMappingDefinitionFromBytes("char"); return typeName.endsWith("[]") ?
result.setContent("return java.nio.ByteBuffer.wrap(bytes).getChar();"); new JavaArrayMappingDefinitionType(new SimpleJavaTypeUse(typeName.replace("[]", ""))) :
return result; new JavaMappingDefinitionType(new SimpleJavaTypeUse(typeName));
} }
syn nta DefaultMappingDefinition RagConnect.defaultBytesToStringMapping() { private DefaultMappingDefinition RagConnect.baseDefaultMappingDefinition(String fromTypeName, String toTypeName, String content) {
DefaultMappingDefinition result = baseDefaultMappingDefinitionFromBytes("String"); DefaultMappingDefinition result = new DefaultMappingDefinition();
result.setContent("return new String(bytes);"); result.setID("_Default" + baseDefaultMappingTypeNamePart(fromTypeName) + "To" + baseDefaultMappingTypeNamePart(toTypeName) + "Mapping");
return result; result.setFromType(baseDefaultMappingTypeFromName(fromTypeName));
} result.setFromVariableName("input");
result.setToType(baseDefaultMappingTypeFromName(toTypeName));
syn nta DefaultMappingDefinition RagConnect.defaultIntToBytesMapping() { result.setContent(content);
DefaultMappingDefinition result = baseDefaultMappingDefinitionToBytes("int");
result.setContent("return java.nio.ByteBuffer.allocate(4).putInt(input).array();");
return result; return result;
} }
syn nta DefaultMappingDefinition RagConnect.defaultShortToBytesMapping() { syn nta DefaultMappingDefinition RagConnect.defaultBytesToIntMapping() = baseDefaultMappingDefinition(
DefaultMappingDefinition result = baseDefaultMappingDefinitionToBytes("short"); "byte[]", "int", "return java.nio.ByteBuffer.wrap(input).getInt();");
result.setContent("return java.nio.ByteBuffer.allocate(2).putShort(input).array();"); syn nta DefaultMappingDefinition RagConnect.defaultBytesToShortMapping() = baseDefaultMappingDefinition(
return result; "byte[]", "short", "return java.nio.ByteBuffer.wrap(input).getShort();");
} syn nta DefaultMappingDefinition RagConnect.defaultBytesToLongMapping() = baseDefaultMappingDefinition(
"byte[]", "long", "return java.nio.ByteBuffer.wrap(input).getLong();");
syn nta DefaultMappingDefinition RagConnect.defaultBytesToFloatMapping() = baseDefaultMappingDefinition(
"byte[]", "float", "return java.nio.ByteBuffer.wrap(input).getFloat();");
syn nta DefaultMappingDefinition RagConnect.defaultBytesToDoubleMapping() = baseDefaultMappingDefinition(
"byte[]", "double", "return java.nio.ByteBuffer.wrap(input).getDouble();");
syn nta DefaultMappingDefinition RagConnect.defaultBytesToCharMapping() = baseDefaultMappingDefinition(
"byte[]", "char", "return java.nio.ByteBuffer.wrap(input).getChar();");
syn nta DefaultMappingDefinition RagConnect.defaultBytesToStringMapping() = baseDefaultMappingDefinition(
"byte[]", "String", "return new String(input);");
syn nta DefaultMappingDefinition RagConnect.defaultLongToBytesMapping() { syn nta DefaultMappingDefinition RagConnect.defaultIntToBytesMapping() = baseDefaultMappingDefinition(
DefaultMappingDefinition result = baseDefaultMappingDefinitionToBytes("long"); "int", "byte[]", "return java.nio.ByteBuffer.allocate(Integer.BYTES).putInt(input).array();");
result.setContent("return java.nio.ByteBuffer.allocate(8).putLong(input).array();"); syn nta DefaultMappingDefinition RagConnect.defaultShortToBytesMapping() = baseDefaultMappingDefinition(
return result; "short", "byte[]", "return java.nio.ByteBuffer.allocate(Short.BYTES).putShort(input).array();");
} syn nta DefaultMappingDefinition RagConnect.defaultLongToBytesMapping() = baseDefaultMappingDefinition(
"long", "byte[]", "return java.nio.ByteBuffer.allocate(Long.BYTES).putLong(input).array();");
syn nta DefaultMappingDefinition RagConnect.defaultFloatToBytesMapping() = baseDefaultMappingDefinition(
"float", "byte[]", "return java.nio.ByteBuffer.allocate(Float.BYTES).putFloat(input).array();");
syn nta DefaultMappingDefinition RagConnect.defaultDoubleToBytesMapping() = baseDefaultMappingDefinition(
"double", "byte[]", "return java.nio.ByteBuffer.allocate(Double.BYTES).putDouble(input).array();");
syn nta DefaultMappingDefinition RagConnect.defaultCharToBytesMapping() = baseDefaultMappingDefinition(
"char", "byte[]", "return java.nio.ByteBuffer.allocate(Character.BYTES).putChar(input).array();");
syn nta DefaultMappingDefinition RagConnect.defaultStringToBytesMapping() = baseDefaultMappingDefinition(
"String", "byte[]", "return input.getBytes();");
syn nta DefaultMappingDefinition RagConnect.defaultFloatToBytesMapping() { syn nta DefaultMappingDefinition RagConnect.defaultStringToIntMapping() = baseDefaultMappingDefinition(
DefaultMappingDefinition result = baseDefaultMappingDefinitionToBytes("float"); "String", "int", "return Integer.parseInt(input);");
result.setContent("return java.nio.ByteBuffer.allocate(4).putFloat(input).array();"); syn nta DefaultMappingDefinition RagConnect.defaultStringToShortMapping() = baseDefaultMappingDefinition(
return result; "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.defaultDoubleToBytesMapping() { syn nta DefaultMappingDefinition RagConnect.defaultIntToStringMapping() = baseDefaultMappingDefinition(
DefaultMappingDefinition result = baseDefaultMappingDefinitionToBytes("double"); "int", "String", "return String.valueOf(input);");
result.setContent("return java.nio.ByteBuffer.allocate(8).putDouble(input).array();"); syn nta DefaultMappingDefinition RagConnect.defaultShortToStringMapping() = baseDefaultMappingDefinition(
return result; "short", "String", "return String.valueOf(input);");
} syn nta DefaultMappingDefinition RagConnect.defaultLongToStringMapping() = baseDefaultMappingDefinition(
"long", "String", "return String.valueOf(input);");
syn nta DefaultMappingDefinition RagConnect.defaultCharToBytesMapping() { syn nta DefaultMappingDefinition RagConnect.defaultFloatToStringMapping() = baseDefaultMappingDefinition(
DefaultMappingDefinition result = baseDefaultMappingDefinitionToBytes("char"); "float", "String", "return String.valueOf(input);");
result.setContent("return java.nio.ByteBuffer.allocate(2).putChar(input).array();"); syn nta DefaultMappingDefinition RagConnect.defaultDoubleToStringMapping() = baseDefaultMappingDefinition(
return result; "double", "String", "return String.valueOf(input);");
} syn nta DefaultMappingDefinition RagConnect.defaultCharToStringMapping() = baseDefaultMappingDefinition(
"char", "String", "return String.valueOf(input);");
syn nta DefaultMappingDefinition RagConnect.defaultStringToBytesMapping() {
DefaultMappingDefinition result = baseDefaultMappingDefinitionToBytes("String");
result.setContent("return input.getBytes();");
return result;
}
} }
aspect Mappings { aspect Mappings {
// --- effectiveMappings --- // --- effectiveMappings ---
syn java.util.List<MappingDefinition> EndpointDefinition.effectiveMappings(); syn java.util.List<MappingDefinition> EndpointDefinition.effectiveMappings();
eq ReceiveFromMqttDefinition.effectiveMappings() { eq ReceiveTokenEndpointDefinition.effectiveMappings() {
// if there is a first mapping, check if its input type is byte[]. // if there is a first mapping, check if it is suitable.
// or if no mappings are specified. // or if no mappings are specified.
// then prepend the suitable default mapping // then prepend the suitable default mapping
java.util.List<MappingDefinition> result; java.util.List<MappingDefinition> result;
if (getMappingList().isEmpty() || !getMappingList().get(0).getFromType().isByteArray()) { if (getMappingList().isEmpty() || !hasSuitableEdgeMapping()) {
result = new java.util.ArrayList(); result = new java.util.ArrayList();
result.add(suitableDefaultMapping()); result.add(suitableDefaultMapping());
result.addAll(getMappingList()); result.addAll(getMappingList());
...@@ -120,15 +94,13 @@ aspect Mappings { ...@@ -120,15 +94,13 @@ aspect Mappings {
} }
return result; return result;
} }
eq SendToMqttDefinition.effectiveMappings() { eq SendTokenEndpointDefinition.effectiveMappings() {
// if there is a mapping, check if the output type of the last mapping is byte[]. // if there is a mapping, check if it is suitable.
// or if no mappings are specified. // or if no mappings are specified.
// then append the suitable default mapping // then append the suitable default mapping
java.util.List<MappingDefinition> result; java.util.List<MappingDefinition> result;
int numMappings = getMappingList().size(); if (getMappingList().isEmpty() || !hasSuitableEdgeMapping()) {
if (numMappings == 0 || !getMappingList().get(numMappings - 1).getToType().isByteArray()) { result = new java.util.ArrayList(getMappingList());
result = new java.util.ArrayList();
result.addAll(getMappingList());
result.add(suitableDefaultMapping()); result.add(suitableDefaultMapping());
} else { } else {
result = getMappingList(); result = getMappingList();
...@@ -136,8 +108,18 @@ aspect Mappings { ...@@ -136,8 +108,18 @@ aspect Mappings {
return result; 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 ReceiveTokenEndpointDefinition.isSuitableEdgeMapping(MappingDefinition def) = def.getFromType().isByteArray();
eq SendTokenEndpointDefinition.isSuitableEdgeMapping(MappingDefinition def) = def.getToType().isByteArray();
// --- isPrimitiveType --- // --- isPrimitiveType ---
syn boolean TokenComponent.isPrimitiveType() = getJavaTypeUse().isPrimitiveType(); syn boolean TokenComponent.isPrimitiveType() = effectiveJavaTypeUse().isPrimitiveType();
syn boolean JavaTypeUse.isPrimitiveType() = false; syn boolean JavaTypeUse.isPrimitiveType() = false;
eq SimpleJavaTypeUse.isPrimitiveType() { eq SimpleJavaTypeUse.isPrimitiveType() {
switch(getName()) { switch(getName()) {
...@@ -160,9 +142,9 @@ aspect Mappings { ...@@ -160,9 +142,9 @@ aspect Mappings {
// --- suitableDefaultMapping --- // --- suitableDefaultMapping ---
syn DefaultMappingDefinition EndpointDefinition.suitableDefaultMapping(); syn DefaultMappingDefinition EndpointDefinition.suitableDefaultMapping();
eq ReceiveFromMqttDefinition.suitableDefaultMapping() { eq ReceiveTokenEndpointDefinition.suitableDefaultMapping() {
String typeName = getMappingList().isEmpty() ? String typeName = getMappingList().isEmpty() ?
getToken().getJavaTypeUse().getName() : getToken().effectiveJavaTypeUse().getName() :
getMappingList().get(0).getFromType().prettyPrint(); getMappingList().get(0).getFromType().prettyPrint();
switch(typeName) { switch(typeName) {
case "int": case "int":
...@@ -181,9 +163,9 @@ aspect Mappings { ...@@ -181,9 +163,9 @@ aspect Mappings {
default: return null; default: return null;
} }
} }
eq SendToMqttDefinition.suitableDefaultMapping() { eq SendTokenEndpointDefinition.suitableDefaultMapping() {
String typeName = getMappingList().isEmpty() ? String typeName = getMappingList().isEmpty() ?
getToken().getJavaTypeUse().getName() : getToken().effectiveJavaTypeUse().getName() :
getMappingList().get(getMappingList().size() - 1).getFromType().prettyPrint(); getMappingList().get(getMappingList().size() - 1).getFromType().prettyPrint();
switch(typeName) { switch(typeName) {
case "int": case "int":
...@@ -202,15 +184,60 @@ aspect Mappings { ...@@ -202,15 +184,60 @@ aspect Mappings {
default: return null; 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 --- // --- isByteArray ---
syn boolean MappingDefinitionType.isByteArray() = false; syn boolean MappingDefinitionType.isByteArray() = false;
eq JavaArrayMappingDefinitionType.isByteArray() = getType().getName().equals("byte"); eq JavaArrayMappingDefinitionType.isByteArray() = getType().getName().equals("byte");
// // --- isString ---
// syn boolean MappingDefinitionType.isString() = false;
// eq JavaMappingDefinitionType.isString() = getType().getName().equals("String");
// --- allMappingDefinitions --- // --- allMappingDefinitions ---
syn java.util.List<MappingDefinition> RagConnect.allMappingDefinitions() { syn java.util.List<MappingDefinition> RagConnect.allMappingDefinitions() {
java.util.List<MappingDefinition> result = new java.util.ArrayList<>(); java.util.List<MappingDefinition> result = new java.util.ArrayList<>();
getMappingDefinitionList().iterator().forEachRemaining(result::add); getMappingDefinitionList().iterator().forEachRemaining(result::add);
// byte[] conversion
result.add(defaultBytesToIntMapping()); result.add(defaultBytesToIntMapping());
result.add(defaultBytesToShortMapping()); result.add(defaultBytesToShortMapping());
result.add(defaultBytesToLongMapping()); result.add(defaultBytesToLongMapping());
...@@ -225,6 +252,19 @@ aspect Mappings { ...@@ -225,6 +252,19 @@ aspect Mappings {
result.add(defaultDoubleToBytesMapping()); result.add(defaultDoubleToBytesMapping());
result.add(defaultCharToBytesMapping()); result.add(defaultCharToBytesMapping());
result.add(defaultStringToBytesMapping()); result.add(defaultStringToBytesMapping());
// // string conversion
// 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; return result;
} }
} }
aspect MustacheNodesToYAML {
syn Document MRagConnect.toYAML() {
Document doc = new Document();
MappingElement root = new MappingElement();
root.addKeyValuePair("rootNodeName", StringElement.of(rootNodeName()));
root.addKeyValuePair("closeMethod", StringElement.of(closeMethod()));
root.addKeyValuePair("usesMqtt", ValueElement.of(usesMqtt));
root.addKeyValuePair("usesRest", ValueElement.of(usesRest));
// mqtt
root.addKeyValuePair("mqttHandlerField", StringElement.of(mqttHandlerField()));
root.addKeyValuePair("mqttHandlerAttribute", StringElement.of(mqttHandlerAttribute()));
root.addKeyValuePair("mqttSetupWaitUntilReadyMethod", StringElement.of(mqttSetupWaitUntilReadyMethod()));
// rootTypeComponents
ListElement rootTypeComponents = new ListElement();
for (MTypeComponent comp : getRootTypeComponentList()) {
MappingElement inner = new MappingElement();
inner.addKeyValuePair("first", ValueElement.of(comp.isFirst()));
inner.addKeyValuePair("name", StringElement.of(comp.name()));
rootTypeComponents.addElement(inner);
}
root.addKeyValuePair("RootTypeComponents", rootTypeComponents);
// rest
root.addKeyValuePair("restHandlerField", StringElement.of(restHandlerField()));
root.addKeyValuePair("restHandlerAttribute", StringElement.of(restHandlerAttribute()));
// ReceiveDefinitions
ListElement receiveDefinitions = new ListElement();
for (MReceiveDefinition def : getReceiveDefinitionList()) {
receiveDefinitions.addElement(def.toYAML());
}
root.addKeyValuePair("ReceiveDefinitions", receiveDefinitions);
// SendDefinitions
ListElement sendDefinitions = new ListElement();
for (MSendDefinition def : getSendDefinitionList()) {
sendDefinitions.addElement(def.toYAML());
}
root.addKeyValuePair("SendDefinitions", sendDefinitions);
// MappingDefinitions
ListElement mappingDefinitions = new ListElement();
for (MMappingDefinition def : getMappingDefinitionList()) {
mappingDefinitions.addElement(def.toYAML());
}
root.addKeyValuePair("MappingDefinitions", mappingDefinitions);
// DependencyDefinitions
ListElement dependencyDefinitions = new ListElement();
for (MDependencyDefinition def : getDependencyDefinitionList()) {
dependencyDefinitions.addElement(def.toYAML());
}
root.addKeyValuePair("DependencyDefinitions", dependencyDefinitions);
// TokenComponents
ListElement tokenComponents = new ListElement();
for (MTokenComponent comp : getTokenComponentList()) {
tokenComponents.addElement(comp.toYAML());
}
root.addKeyValuePair("TokenComponents", tokenComponents);
doc.addComplexElement(root);
return doc;
}
syn MappingElement MEndpointDefinition.toYAML() {
MappingElement result = new MappingElement();
result.addKeyValuePair("parentTypeName", StringElement.of(parentTypeName()));
result.addKeyValuePair("connectMethod", StringElement.of(connectMethod()));
result.addKeyValuePair("connectParameterName", StringElement.of(connectParameterName()));
result.addKeyValuePair("lastDefinitionToType", StringElement.of(lastDefinitionToType()));
result.addKeyValuePair("preemptiveReturn", StringElement.of(preemptiveReturn()));
result.addKeyValuePair("alwaysApply", ValueElement.of(alwaysApply()));
result.addKeyValuePair("condition", StringElement.of(
condition().replace("\"", "\\\"").replace("\n", "\\n")));
result.addKeyValuePair("lastResult", StringElement.of(lastResult()));
result.addKeyValuePair("tokenName", StringElement.of(tokenName()));
result.addKeyValuePair("InnerMappingDefinitions", innerMappingDefinitionsAsListElement());
return result;
}
syn MappingElement MReceiveDefinition.toYAML() {
MappingElement result = super.toYAML();
result.addKeyValuePair("loggingEnabledForReads", ValueElement.of(loggingEnabledForReads));
return result;
}
syn MappingElement MSendDefinition.toYAML() {
MappingElement result = super.toYAML();
result.addKeyValuePair("sender", StringElement.of(sender()));
result.addKeyValuePair("lastValue", StringElement.of(lastValue()));
result.addKeyValuePair("loggingEnabledForWrites", ValueElement.of(loggingEnabledForWrites));
result.addKeyValuePair("updateMethod", StringElement.of(updateMethod()));
result.addKeyValuePair("writeMethod", StringElement.of(writeMethod()));
result.addKeyValuePair("tokenResetMethod", StringElement.of(tokenResetMethod()));
return result;
}
syn Element MMappingDefinition.toYAML() {
MappingElement result = new MappingElement();
result.addKeyValuePair("toType", StringElement.of(toType()));
result.addKeyValuePair("methodName", StringElement.of(methodName()));
result.addKeyValuePair("fromType", StringElement.of(fromType()));
result.addKeyValuePair("fromVariableName", StringElement.of(fromVariableName()));
result.addKeyValuePair("content", StringElement.of(
content().replace("\"", "\\\"").replace("\n", "\\n")));
return result;
}
syn Element MDependencyDefinition.toYAML() {
MappingElement result = new MappingElement();
result.addKeyValuePair("targetParentTypeName", StringElement.of(targetParentTypeName()));
result.addKeyValuePair("dependencyMethod", StringElement.of(dependencyMethod()));
result.addKeyValuePair("sourceParentTypeName", StringElement.of(sourceParentTypeName()));
result.addKeyValuePair("internalRelationPrefix", StringElement.of(internalRelationPrefix()));
return result;
}
syn Element MTokenComponent.toYAML() {
MappingElement result = new MappingElement();
result.addKeyValuePair("parentTypeName", StringElement.of(parentTypeName()));
result.addKeyValuePair("name", StringElement.of(name()));
result.addKeyValuePair("javaType", StringElement.of(javaType()));
result.addKeyValuePair("internalName", StringElement.of(internalName()));
ListElement dependencyDefinitions = new ListElement();
for (MDependencyDefinition def : getDependencyDefinitionList()) {
MappingElement inner = new MappingElement();
inner.addKeyValuePair("targetParentTypeName", StringElement.of(def.targetParentTypeName()));
inner.addKeyValuePair("internalRelationPrefix", StringElement.of(def.internalRelationPrefix()));
MappingElement targetEndpointDefinition = new MappingElement();
targetEndpointDefinition.addKeyValuePair("updateMethod", StringElement.of(def.targetEndpointDefinition().updateMethod()));
targetEndpointDefinition.addKeyValuePair("writeMethod", StringElement.of(def.targetEndpointDefinition().writeMethod()));
inner.addKeyValuePair("targetEndpointDefinition", targetEndpointDefinition);
dependencyDefinitions.addElement(inner);
}
result.addKeyValuePair("DependencyDefinitions", dependencyDefinitions);
return result;
}
ListElement MEndpointDefinition.innerMappingDefinitionsAsListElement() {
ListElement innerMappingDefinitions = new ListElement();
for (MInnerMappingDefinition def : getInnerMappingDefinitionList()) {
MappingElement inner = new MappingElement();
inner.addKeyValuePair("toType", StringElement.of(def.toType()));
inner.addKeyValuePair("methodName", StringElement.of(def.methodName()));
inner.addKeyValuePair("inputVarName", StringElement.of(def.inputVarName()));
inner.addKeyValuePair("outputVarName", StringElement.of(def.outputVarName()));
inner.addKeyValuePair("last", ValueElement.of(def.isLast()));
innerMappingDefinitions.addElement(inner);
}
return innerMappingDefinitions;
}
}
...@@ -10,41 +10,35 @@ RagConnect ragconnect ...@@ -10,41 +10,35 @@ RagConnect ragconnect
private Iterable<String> makeMappingDefs(ArrayList<?> raw_mapping_defs) { private Iterable<String> makeMappingDefs(ArrayList<?> raw_mapping_defs) {
return () -> raw_mapping_defs.stream().map(raw -> ((Symbol) raw).value.toString()).iterator(); return () -> raw_mapping_defs.stream().map(raw -> ((Symbol) raw).value.toString()).iterator();
} }
private TokenEndpointDefinition enableAlwaysApply(TokenEndpointDefinition def) {
def.setAlwaysApply(true);
return def;
}
:} ; :} ;
EndpointDefinition endpoint_definition EndpointDefinition endpoint_definition
= RECEIVE ID.type_name DOT ID.token_name SCOL = endpoint_definition_type.endpointDef SCOL
{: {:
ReceiveFromMqttDefinition result = new ReceiveFromMqttDefinition(); return endpointDef;
result.setToken(TokenComponent.createRef(type_name + "." + token_name));
return result;
:} :}
| RECEIVE ID.type_name DOT ID.token_name USING string_list.mapping_defs SCOL | endpoint_definition_type.endpointDef 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)) { for (String mapping_def : makeMappingDefs(mapping_defs)) {
result.addMapping(MappingDefinition.createRef(mapping_def)); endpointDef.addMapping(MappingDefinition.createRef(mapping_def));
} }
return result; return endpointDef;
:}
| SEND ID.type_name DOT ID.token_name SCOL
{:
SendToMqttDefinition result = new SendToMqttDefinition();
result.setToken(TokenComponent.createRef(type_name + "." + token_name));
return result;
:}
| SEND ID.type_name DOT ID.token_name 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));
}
return result;
:} :}
; ;
EndpointDefinition endpoint_definition_type
= RECEIVE token_ref {: return new ReceiveTokenEndpointDefinition().setToken(token_ref); :}
| SEND token_ref {: return new SendTokenEndpointDefinition().setToken(token_ref); :}
;
TokenComponent token_ref
= ID.type_name DOT ID.token_name {: return TokenComponent.createRef(type_name + "." + token_name); :}
;
ArrayList string_list ArrayList string_list
= ID = ID
| string_list COMMA ID | string_list COMMA ID
......
...@@ -14,18 +14,21 @@ import java.nio.file.Files; ...@@ -14,18 +14,21 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.Collection; import java.util.*;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
public class Compiler extends AbstractCompiler { public class Compiler extends AbstractCompiler {
// private ValueOption optionOutputDir; // private ValueOption optionOutputDir;
private ValueOption optionRootNode; private ValueOption optionRootNode;
private ValueOption optionProtocols;
private BooleanOption optionPrintYaml;
private BooleanOption optionVerbose; private BooleanOption optionVerbose;
private BooleanOption optionLogReads; private BooleanOption optionLogReads;
private BooleanOption optionLogWrites; private BooleanOption optionLogWrites;
private static final String OPTION_PROTOCOL_MQTT = "mqtt";
private static final String OPTION_PROTOCOL_REST = "rest";
public Compiler() { public Compiler() {
super("ragconnect", true); super("ragconnect", true);
} }
...@@ -51,6 +54,10 @@ public class Compiler extends AbstractCompiler { ...@@ -51,6 +54,10 @@ public class Compiler extends AbstractCompiler {
} }
} }
if (!optionRootNode.isMatched()) {
return error("Root node not specified");
}
RagConnect ragConnect = parseProgram(getConfiguration().getFiles()); RagConnect ragConnect = parseProgram(getConfiguration().getFiles());
if (!ragConnect.errors().isEmpty()) { if (!ragConnect.errors().isEmpty()) {
...@@ -61,25 +68,41 @@ public class Compiler extends AbstractCompiler { ...@@ -61,25 +68,41 @@ public class Compiler extends AbstractCompiler {
System.exit(1); System.exit(1);
} }
if (optionPrintYaml.value()) {
ASTNode.rootNode = ragConnect.getProgram().resolveTypeDecl(optionRootNode.value());
String yamlContent = ragConnect.toMustache().toYAML().prettyPrint();
System.out.println(yamlContent);
writeToFile(getConfiguration().outputDir().toPath().resolve("RagConnect.yml"), yamlContent);
return 0;
}
printMessage("Writing output files"); printMessage("Writing output files");
// copy MqttHandler into outputDir final List<String> handlers = new ArrayList<>();
final String mqttHandlerFileName = "MqttHandler.jadd"; if (ASTNode.usesMqtt) {
handlers.add("MqttHandler.jadd");
}
if (ASTNode.usesRest) {
handlers.add("RestHandler.jadd");
}
// copy handlers into outputDir
for (String handlerFileName : handlers) {
try { try {
InputStream inputStream = Compiler.class.getClassLoader().getResourceAsStream(mqttHandlerFileName); InputStream inputStream = Compiler.class.getClassLoader().getResourceAsStream(handlerFileName);
if (inputStream == null) { if (inputStream == null) {
throw new CompilerException("Could not open " + mqttHandlerFileName); throw new CompilerException("Could not open " + handlerFileName);
} }
Files.copy(inputStream, Files.copy(inputStream,
getConfiguration().outputDir().toPath().resolve(mqttHandlerFileName), getConfiguration().outputDir().toPath().resolve(handlerFileName),
StandardCopyOption.REPLACE_EXISTING); StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) { } catch (IOException e) {
throw new CompilerException("Could not copy " + mqttHandlerFileName, e); throw new CompilerException("Could not copy " + handlerFileName, e);
}
} }
for (GrammarFile grammarFile : ragConnect.getProgram().getGrammarFileList()) { for (GrammarFile grammarFile : ragConnect.getProgram().getGrammarFileList()) {
Path outputFile = getConfiguration().outputDir().toPath().resolve(grammarFile.getFileName()); Path outputFile = getConfiguration().outputDir().toPath().resolve(grammarFile.getFileName());
sendToFile(outputFile, grammarFile.generateAbstractGrammar()); writeToFile(outputFile, grammarFile.generateAbstractGrammar());
} }
sendToFile(getConfiguration().outputDir().toPath().resolve("RagConnect.jadd"), ragConnect.generateAspect(optionRootNode.value())); writeToFile(getConfiguration().outputDir().toPath().resolve("RagConnect.jadd"), ragConnect.generateAspect(optionRootNode.value()));
return 0; return 0;
} }
...@@ -89,8 +112,8 @@ public class Compiler extends AbstractCompiler { ...@@ -89,8 +112,8 @@ public class Compiler extends AbstractCompiler {
try { try {
new Compiler().run(args); new Compiler().run(args);
} catch (CompilerException e) { } catch (CompilerException e) {
System.err.println(e.getMessage()); e.printStackTrace();
System.exit(-1); System.exit(1);
} }
} }
...@@ -118,7 +141,7 @@ public class Compiler extends AbstractCompiler { ...@@ -118,7 +141,7 @@ public class Compiler extends AbstractCompiler {
System.out.println(message); System.out.println(message);
} }
private void sendToFile(Path path, String str) throws CompilerException { private void writeToFile(Path path, String str) throws CompilerException {
try (BufferedWriter writer = Files.newBufferedWriter(path)) { try (BufferedWriter writer = Files.newBufferedWriter(path)) {
writer.append(str); writer.append(str);
} catch (Exception e) { } catch (Exception e) {
...@@ -132,6 +155,15 @@ public class Compiler extends AbstractCompiler { ...@@ -132,6 +155,15 @@ public class Compiler extends AbstractCompiler {
new ValueOption("rootNode", "root node in the base grammar.") new ValueOption("rootNode", "root node in the base grammar.")
.acceptAnyValue() .acceptAnyValue()
.needsValue(true)); .needsValue(true));
optionProtocols = addOption(
new ValueOption("protocols", "Protocols to enable")
.acceptMultipleValues(true)
.addDefaultValue(OPTION_PROTOCOL_MQTT, "Enable MQTT")
.addAcceptedValue(OPTION_PROTOCOL_REST, "Enable REST")
);
optionPrintYaml = addOption(
new BooleanOption("printYaml", "Print out YAML instead of generating files")
.defaultValue(false));
optionVerbose = addOption( optionVerbose = addOption(
new BooleanOption("verbose", "Print more messages while compiling.") new BooleanOption("verbose", "Print more messages while compiling.")
.defaultValue(false)); .defaultValue(false));
...@@ -145,6 +177,8 @@ public class Compiler extends AbstractCompiler { ...@@ -145,6 +177,8 @@ public class Compiler extends AbstractCompiler {
private RagConnect parseProgram(Collection<String> files) throws CompilerException { private RagConnect parseProgram(Collection<String> files) throws CompilerException {
Program program = new Program(); Program program = new Program();
boolean atLeastOneGrammar = false;
boolean atLeastOneRagConnect = false;
RagConnect ragConnect = new RagConnect(); RagConnect ragConnect = new RagConnect();
ragConnect.setProgram(program); ragConnect.setProgram(program);
...@@ -160,20 +194,34 @@ public class Compiler extends AbstractCompiler { ...@@ -160,20 +194,34 @@ public class Compiler extends AbstractCompiler {
case "relast": case "relast":
// processGrammar // processGrammar
parseGrammar(program, filename); parseGrammar(program, filename);
atLeastOneGrammar = true;
break; break;
case "connect": case "connect":
case "ragconnect":
// process ragConnect // process ragConnect
RagConnect parsedRagConnect = parseRagConnect(program, filename); RagConnect parsedRagConnect = parseRagConnect(program, filename);
mergeRagConnectDefinitions(ragConnect, parsedRagConnect); mergeRagConnectDefinitions(ragConnect, parsedRagConnect);
atLeastOneRagConnect = true;
break; break;
default: default:
throw new CompilerException("Unknown file extension in " + filename); throw new CompilerException("Unknown file extension in " + filename);
} }
} }
if (!atLeastOneGrammar) {
System.err.println("No grammar file specified! (*.ast, *.relast)");
}
if (!atLeastOneRagConnect) {
System.err.println("No ragconnect file specified! (*.connect, *.ragconnect)");
}
if (!atLeastOneGrammar && !atLeastOneRagConnect) {
System.exit(1);
}
ragConnect.treeResolveAll(); ragConnect.treeResolveAll();
ragConnect.additionalRelations().forEach(ragConnectGrammarPart::addDeclaration); ragConnect.additionalRelations().forEach(ragConnectGrammarPart::addDeclaration);
ASTNode.loggingEnabledForReads = optionLogReads.value(); ASTNode.loggingEnabledForReads = optionLogReads.value();
ASTNode.loggingEnabledForWrites = optionLogWrites.value(); ASTNode.loggingEnabledForWrites = optionLogWrites.value();
ASTNode.usesMqtt = optionProtocols.hasValue(OPTION_PROTOCOL_MQTT);
ASTNode.usesRest = optionProtocols.hasValue(OPTION_PROTOCOL_REST);
return ragConnect; return ragConnect;
} }
......
package org.jastadd.ragconnect.compiler; package org.jastadd.ragconnect.compiler;
import beaver.Parser;
import org.jastadd.ragconnect.ast.*; import org.jastadd.ragconnect.ast.*;
import org.jastadd.ragconnect.parser.RagConnectParser; import org.jastadd.ragconnect.parser.RagConnectParser;
import org.jastadd.ragconnect.scanner.RagConnectScanner; import org.jastadd.ragconnect.scanner.RagConnectScanner;
import java.io.BufferedReader; import java.io.Reader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
/** /**
...@@ -19,141 +15,87 @@ import java.nio.file.Paths; ...@@ -19,141 +15,87 @@ import java.nio.file.Paths;
*/ */
public class SimpleMain { public class SimpleMain {
// --- just testing byte[] conversion --- private static void printManualYAML() {
public static void testing() { Document doc = new Document();
byte[] bytes; KeyValuePair root = new KeyValuePair();
int i = 1; root.setKey("panda_mqtt_connector");
double d = 2.3d; MappingElement firstLevel = new MappingElement();
float f = 4.2f; firstLevel.addKeyValuePair(new KeyValuePair("server", new StringElement("tcp://localhost:1883")));
short sh = 13; firstLevel.addKeyValuePair(new KeyValuePair("robot_speed_factor", new ValueElement(".7")));
long l = 7L;
String s = "Hello"; KeyValuePair topics = new KeyValuePair();
char c = 'a'; topics.setKey("topics");
MappingElement theTopics = new MappingElement();
Integer ii = Integer.valueOf(1); theTopics.addKeyValuePair(new KeyValuePair("robotConfig", new StringElement("robotconfig")));
if (!ii.equals(i)) throw new AssertionError("Ints not equal"); theTopics.addKeyValuePair(new KeyValuePair("trajectory", new StringElement("trajectory")));
theTopics.addKeyValuePair(new KeyValuePair("nextStep", new StringElement("ros2rag/nextStep")));
// int to byte topics.setValue(theTopics);
ByteBuffer i2b = ByteBuffer.allocate(4); firstLevel.addKeyValuePair(topics);
i2b.putInt(i);
bytes = i2b.array(); firstLevel.addKeyValuePair(new KeyValuePair("zone_size", new ValueElement("0.5")));
// byte to int KeyValuePair zones = new KeyValuePair();
ByteBuffer b2i = ByteBuffer.wrap(bytes); zones.setKey("zones");
int actual_i = b2i.getInt(); ListElement theZones = new ListElement();
if (i != actual_i) throw new AssertionError("Ints not equal"); theZones.addElement(new StringElement("1 1"));
theZones.addElement(new StringElement("0 1"));
// double to byte theZones.addElement(new StringElement("-1 1"));
ByteBuffer d2b = ByteBuffer.allocate(8); zones.setValue(theZones);
d2b.putDouble(d); firstLevel.addKeyValuePair(zones);
bytes = d2b.array();
KeyValuePair parts = new KeyValuePair();
// byte to double parts.setKey("end_effectors");
ByteBuffer b2d = ByteBuffer.wrap(bytes); KeyValuePair pandaParts = new KeyValuePair();
double actual_d = b2d.getDouble(); pandaParts.setKey("panda");
if (d != actual_d) throw new AssertionError("Doubles not equal"); MappingElement thePanda = new MappingElement();
thePanda.addKeyValuePair(new KeyValuePair("Link0", new StringElement("panda_link0")));
// float to byte thePanda.addKeyValuePair(new KeyValuePair("Link1", new StringElement("panda_link1")));
ByteBuffer f2b = ByteBuffer.allocate(4); thePanda.addKeyValuePair(new KeyValuePair("Link2", new StringElement("panda_link2")));
f2b.putFloat(f); thePanda.addKeyValuePair(new KeyValuePair("Link3", new StringElement("panda_link3")));
bytes = f2b.array(); thePanda.addKeyValuePair(new KeyValuePair("Link4", new StringElement("panda_link4")));
thePanda.addKeyValuePair(new KeyValuePair("Link5", new StringElement("panda_link5")));
// byte to float thePanda.addKeyValuePair(new KeyValuePair("Link6", new StringElement("panda_link6")));
ByteBuffer b2f = ByteBuffer.wrap(bytes); thePanda.addKeyValuePair(new KeyValuePair("RightFinger", new StringElement("panda_rightfinger")));
float actual_f = b2f.getFloat(); thePanda.addKeyValuePair(new KeyValuePair("LeftFinger", new StringElement("panda_leftfinger")));
if (f != actual_f) throw new AssertionError("Floats not equal"); pandaParts.setValue(thePanda);
parts.setValue(pandaParts);
// short to byte firstLevel.addKeyValuePair(parts);
ByteBuffer sh2b = ByteBuffer.allocate(2);
sh2b.putShort(sh); KeyValuePair end_effectors = new KeyValuePair();
bytes = sh2b.array(); end_effectors.setKey("end_effectors");
KeyValuePair endEffectorParts = new KeyValuePair();
// byte to short endEffectorParts.setKey("panda");
ByteBuffer b2sh = ByteBuffer.wrap(bytes); endEffectorParts.setValue(new KeyValuePair("EndEffector", new StringElement("panda_hand")));
short actual_sh = b2sh.getShort(); end_effectors.setValue(endEffectorParts);
if (sh != actual_sh) throw new AssertionError("Shorts not equal"); firstLevel.addKeyValuePair(end_effectors);
// long to byte KeyValuePair goalPoses = new KeyValuePair();
ByteBuffer l2b = ByteBuffer.allocate(8); goalPoses.setKey("goal_poses");
l2b.putLong(l); ListElement theGoalPoses = new ListElement();
bytes = l2b.array(); addPose(theGoalPoses, "0.4 0.4 0.3");
addPose(theGoalPoses, "-0.4 0.4 0.3");
// byte to long addPose(theGoalPoses, "-0.4 -0.4 0.3");
ByteBuffer b2l = ByteBuffer.wrap(bytes); addPose(theGoalPoses, "0.4 0.4 0.3");
long actual_l = b2l.getLong(); addPose(theGoalPoses, "-0.4 0.4 0.3");
if (l != actual_l) throw new AssertionError("Longs not equal"); addPose(theGoalPoses, "0.4 0.4 0.3");
goalPoses.setValue(theGoalPoses);
// String to byte firstLevel.addKeyValuePair(goalPoses);
bytes = s.getBytes();
root.setValue(firstLevel);
// byte to String doc.addComplexElement(root);
String actual_s = new String(bytes);
if (!s.equals(actual_s)) throw new AssertionError("Strings not equal"); System.out.println(doc.prettyPrint());
// char to byte
ByteBuffer c2b = ByteBuffer.allocate(2);
c2b.putChar(c);
bytes = c2b.array();
// byte to char
ByteBuffer b2c = ByteBuffer.wrap(bytes);
char actual_c = b2c.getChar();
if (c != actual_c) throw new AssertionError("Floats not equal");
}
public static void main(String[] args) {
// testing();
createManualAST();
} }
private static void createManualAST() { private static void addPose(ListElement theGoalPoses, String position) {
RagConnect model = new RagConnect(); MappingElement goalPose1 = new MappingElement();
Program program = parseProgram(Paths.get("ros2rag.starter","src", "main", "jastadd", "RobotModel.relast")); goalPose1.addKeyValuePair(new KeyValuePair("position", new StringElement(position)));
model.setProgram(program); goalPose1.addKeyValuePair(new KeyValuePair("orientation", new StringElement("1 1 0 0")));
goalPose1.addKeyValuePair(new KeyValuePair("work", new StringElement("20000")));
MappingDefinition mappingDefinition = new MappingDefinition(); theGoalPoses.addElement(goalPose1);
mappingDefinition.setID("PoseToPosition");
mappingDefinition.setFromType(makeMappingDefinitionType("int"));
mappingDefinition.setFromVariableName("x");
mappingDefinition.setToType(makeMappingDefinitionType("Position"));
mappingDefinition.setContent(" pose.position.x += sqrt(.5 * size.x)\n" +
" MAP round(2)\n" +
" x = x / 100\n" +
" IGNORE_IF_SAME\n" +
" ;");
model.addMappingDefinition(mappingDefinition);
ReceiveFromMqttDefinition receiveFromMqttDefinition = new ReceiveFromMqttDefinition();
receiveFromMqttDefinition.setAlwaysApply(false);
receiveFromMqttDefinition.setToken(TokenComponent.createRef("Link.CurrentPosition"));
receiveFromMqttDefinition.addMapping(mappingDefinition);
model.addEndpointDefinition(receiveFromMqttDefinition);
model.treeResolveAll();
for (ErrorMessage error : model.errors()) {
System.err.println(error);
} }
System.out.println(model.generateAspect("Model")); public static void main(String[] args) {
} printManualYAML();
private static MappingDefinitionType makeMappingDefinitionType(String type) {
JavaMappingDefinitionType result = new JavaMappingDefinitionType();
result.setType(new SimpleJavaTypeUse(type));
return result;
}
private static Program parseProgram(Path path) {
try (BufferedReader reader = Files.newBufferedReader(path)) {
RagConnectScanner scanner = new RagConnectScanner(reader);
RagConnectParser parser = new RagConnectParser();
GrammarFile grammarFile = (GrammarFile) parser.parse(scanner);
Program program = new Program();
program.addGrammarFile(grammarFile);
return program;
} catch (IOException | Parser.Exception e) {
e.printStackTrace();
}
return null;
} }
} }
aspect MqttHandler { import java.io.IOException;
import java.util.concurrent.TimeUnit;aspect MqttHandler {
public class MqttServerHandler {
private final java.util.Map<String, MqttHandler> handlers = new java.util.HashMap<>();
private long time;
private java.util.concurrent.TimeUnit unit;
private String name;
public MqttServerHandler() {
this("RagConnect");
}
public MqttServerHandler(String name) {
this.name = name;
setupWaitUntilReady(1, TimeUnit.SECONDS);
}
public void setupWaitUntilReady(long time, java.util.concurrent.TimeUnit unit) {
this.time = time;
this.unit = unit;
}
public MqttHandler resolveHandler(java.net.URI uri) throws IOException {
MqttHandler handler = handlers.get(uri.getHost());
if (handler == null) {
// first connect to that server
handler = new MqttHandler();
if (uri.getPort() == -1) {
handler.setHost(uri.getHost());
} else {
handler.setHost(uri.getHost(), uri.getPort());
}
handlers.put(uri.getHost(), handler);
}
handler.waitUntilReady(this.time, this.unit);
return handler;
}
public boolean newConnection(java.net.URI uri, java.util.function.Consumer<byte[]> callback) throws IOException {
return resolveHandler(uri).newConnection(extractTopic(uri), callback);
}
public void publish(java.net.URI uri, byte[] bytes) throws IOException {
resolveHandler(uri).publish(extractTopic(uri), bytes);
}
public void publish(java.net.URI uri, byte[] bytes, boolean retain) throws IOException {
resolveHandler(uri).publish(extractTopic(uri), bytes, retain);
}
public void publish(java.net.URI uri, byte[] bytes,
org.fusesource.mqtt.client.QoS qos, boolean retain) throws IOException {
resolveHandler(uri).publish(extractTopic(uri), bytes, qos, retain);
}
private String extractTopic(java.net.URI uri) {
String path = uri.getPath();
if (path.charAt(0) == '/') {
path = path.substring(1);
}
return path;
}
public void close() {
for (MqttHandler handler : handlers.values()) {
handler.close();
}
}
}
/** /**
* Helper class to receive updates via MQTT and use callbacks to handle those messages. * Helper class to receive updates via MQTT and use callbacks to handle those messages.
* *
...@@ -14,10 +83,8 @@ public class MqttHandler { ...@@ -14,10 +83,8 @@ public class MqttHandler {
private java.net.URI host; private java.net.URI host;
/** The connection to the MQTT broker. */ /** The connection to the MQTT broker. */
private org.fusesource.mqtt.client.CallbackConnection connection; private org.fusesource.mqtt.client.CallbackConnection connection;
/** Whether we are subscribed to the topics yet */ /** Whether we are connected yet */
private final java.util.concurrent.locks.Condition readyCondition; private final java.util.concurrent.CountDownLatch readyLatch;
private final java.util.concurrent.locks.Lock readyLock;
private boolean ready;
private boolean sendWelcomeMessage = true; private boolean sendWelcomeMessage = true;
private org.fusesource.mqtt.client.QoS qos; private org.fusesource.mqtt.client.QoS qos;
/** Dispatch knowledge */ /** Dispatch knowledge */
...@@ -31,9 +98,7 @@ public class MqttHandler { ...@@ -31,9 +98,7 @@ public class MqttHandler {
this.name = java.util.Objects.requireNonNull(name, "Name must be set"); this.name = java.util.Objects.requireNonNull(name, "Name must be set");
this.logger = org.apache.logging.log4j.LogManager.getLogger(MqttHandler.class); this.logger = org.apache.logging.log4j.LogManager.getLogger(MqttHandler.class);
this.callbacks = new java.util.HashMap<>(); this.callbacks = new java.util.HashMap<>();
this.readyLock = new java.util.concurrent.locks.ReentrantLock(); this.readyLatch = new java.util.concurrent.CountDownLatch(1);
this.readyCondition = readyLock.newCondition();
this.ready = false;
this.qos = org.fusesource.mqtt.client.QoS.AT_LEAST_ONCE; this.qos = org.fusesource.mqtt.client.QoS.AT_LEAST_ONCE;
} }
...@@ -83,7 +148,7 @@ public class MqttHandler { ...@@ -83,7 +148,7 @@ public class MqttHandler {
String topicString = topic.toString(); String topicString = topic.toString();
java.util.List<java.util.function.Consumer<byte[]>> callbackList = callbacks.get(topicString); java.util.List<java.util.function.Consumer<byte[]>> callbackList = callbacks.get(topicString);
if (callbackList == null || callbackList.isEmpty()) { if (callbackList == null || callbackList.isEmpty()) {
logger.debug("Got a message, but no callback to call. Forgot to unsubscribe?"); logger.debug("Got a message, but no callback to call. Forgot to subscribe?");
} else { } else {
byte[] message = body.toByteArray(); byte[] message = body.toByteArray();
// System.out.println("message = " + Arrays.toString(message)); // System.out.println("message = " + Arrays.toString(message));
...@@ -144,13 +209,7 @@ public class MqttHandler { ...@@ -144,13 +209,7 @@ public class MqttHandler {
} }
private void setReady() { private void setReady() {
try { readyLatch.countDown();
readyLock.lock();
ready = true;
readyCondition.signalAll();
} finally {
readyLock.unlock();
}
} }
private void throwIf(java.util.concurrent.atomic.AtomicReference<Throwable> error) throws java.io.IOException { private void throwIf(java.util.concurrent.atomic.AtomicReference<Throwable> error) throws java.io.IOException {
...@@ -163,12 +222,15 @@ public class MqttHandler { ...@@ -163,12 +222,15 @@ public class MqttHandler {
this.qos = qos; this.qos = qos;
} }
public void newConnection(String topic, java.util.function.Consumer<byte[]> callback) { public boolean newConnection(String topic, java.util.function.Consumer<byte[]> callback) {
if (!ready) { if (readyLatch.getCount() > 0) {
// should maybe be something more kind than throwing an exception here System.err.println("Handler not ready");
throw new IllegalStateException("Updater not ready"); return false;
// // should maybe be something more kind than throwing an exception here
// throw new IllegalStateException("Updater not ready");
} }
// register callback // register callback
logger.debug("new connection for {}", topic);
if (callbacks.get(topic) == null) { if (callbacks.get(topic) == null) {
callbacks.put(topic, new java.util.ArrayList<>()); callbacks.put(topic, new java.util.ArrayList<>());
...@@ -189,6 +251,7 @@ public class MqttHandler { ...@@ -189,6 +251,7 @@ public class MqttHandler {
}); });
} }
callbacks.get(topic).add(callback); callbacks.get(topic).add(callback);
return true;
} }
/** /**
...@@ -202,15 +265,9 @@ public class MqttHandler { ...@@ -202,15 +265,9 @@ public class MqttHandler {
*/ */
public boolean waitUntilReady(long time, java.util.concurrent.TimeUnit unit) { public boolean waitUntilReady(long time, java.util.concurrent.TimeUnit unit) {
try { try {
readyLock.lock(); return readyLatch.await(time, unit);
if (ready) {
return true;
}
return readyCondition.await(time, unit);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} finally {
readyLock.unlock();
} }
return false; return false;
} }
...@@ -253,7 +310,7 @@ public class MqttHandler { ...@@ -253,7 +310,7 @@ public class MqttHandler {
@Override @Override
public void onFailure(Throwable value) { public void onFailure(Throwable value) {
logger.warn("Could not publish on topic '{}'", topic); logger.warn("Could not publish on topic '{}'", topic, value);
} }
}); });
}); });
......
import java.util.concurrent.TimeUnit;aspect RestHandler {
public class RestServerHandler {
private static final int DEFAULT_PORT = 4567;
private final java.util.Map<Integer, RestHandler> handlers = new java.util.HashMap<>();
private String name;
public RestServerHandler() {
this("RagConnect");
}
public RestServerHandler(String name) {
this.name = name;
}
private RestHandler resolveHandler(java.net.URI uri) {
int port = uri.getPort() != -1 ? uri.getPort() : DEFAULT_PORT;
RestHandler handler = handlers.get(port);
if (handler == null) {
// first connect to that server
handler = new RestHandler();
handler.setPort(port);
handlers.put(port, handler);
}
return handler;
}
public boolean newPUTConnection(java.net.URI uri, java.util.function.Consumer<String> callback) {
resolveHandler(uri).newPUTConnection(uri.getPath(), callback);
return true;
}
public boolean newGETConnection(java.net.URI uri, SupplierWithException<String> supplier) {
resolveHandler(uri).newGETConnection(uri.getPath(), supplier);
return true;
}
public void close() {
for (RestHandler handler : handlers.values()) {
handler.close();
}
}
}
/**
* Helper class to receive updates and publishes information via REST.
* @author rschoene - Initial contribution
*/
public class RestHandler {
private static final int DEFAULT_PORT = 4567;
private final org.apache.logging.log4j.Logger logger;
private final String name;
private int port;
private final java.util.concurrent.CountDownLatch exitCondition;
/** Dispatch knowledge */
private final java.util.Map<String, java.util.List<java.util.function.Consumer<String>>> callbacks;
private final java.util.Map<String, SupplierWithException<String>> suppliers;
public RestHandler() {
this("RagConnect");
}
public RestHandler(String name) {
this.logger = org.apache.logging.log4j.LogManager.getLogger(RestHandler.class);
this.name = name;
this.port = DEFAULT_PORT;
this.exitCondition = new java.util.concurrent.CountDownLatch(1);
this.callbacks = new java.util.HashMap<>();
this.suppliers = new java.util.HashMap<>();
}
public RestHandler setPort(int port) {
this.port = port;
start();
return this;
}
public void newPUTConnection(String path, java.util.function.Consumer<String> callback) {
if (callbacks.containsKey(path)) {
callbacks.get(path).add(callback);
} else {
// setup path
java.util.List<java.util.function.Consumer<String>> callbackList = new java.util.ArrayList<>();
callbackList.add(callback);
callbacks.put(path, callbackList);
spark.Spark.put(path, (request, response) -> {
String content = request.body();
java.util.Set<String> errors = new java.util.HashSet<>();
for (java.util.function.Consumer<String> f : callbackList) {
try {
f.accept(content);
} catch (Exception e) {
errors.add(e.getMessage());
}
}
if (errors.isEmpty()) {
return "OK";
} else {
return makeError(response, 500, errors.stream().collect(java.util.stream.Collectors.joining("\n", "The following error(s) happened: [", "]")));
}
});
}
}
public void newGETConnection(String path, SupplierWithException<String> supplier) {
if (suppliers.get(path) != null) {
logger.warn("Overriding existing supplier for '{}'", path);
}
suppliers.put(path, supplier);
spark.Spark.get(path, (request, response) -> {
try {
return supplier.get();
} catch (Exception e) {
return makeError(response, 500, e.getMessage());
}
});
}
private String makeError(spark.Response response, int statusCode, String message) {
response.status(statusCode);
return message;
}
private void start() {
logger.info("Starting REST server at {}", this.port);
spark.Spark.port(this.port);
spark.Spark.init();
spark.Spark.awaitInitialization();
}
public void close() {
spark.Spark.stop();
spark.Spark.awaitStop();
}
}
@FunctionalInterface
public interface SupplierWithException<T> {
public T get() throws Exception;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment