diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 70f955c066941e1f22918595675270a4c5570ae2..898917dc6d63e885dc03d9801253bcafe665a365 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,11 +3,11 @@ variables: GIT_DEPTH: 1000 stages: - - build - - test - - ragdoc_build - - ragdoc_view - - publish +- build +- test +#- ragdoc_build +#- ragdoc_view +#- publish before_script: - export GRADLE_USER_HOME=`pwd`/.gradle @@ -44,64 +44,64 @@ test: junit: "ragconnect.tests/build/test-results/**/TEST-*.xml" expire_in: 1 week -publish: - image: openjdk:11 - stage: publish - needs: - - test - script: - - "./gradlew publish" - only: - - dev - - master +#publish: +# image: openjdk:11 +# stage: publish +# needs: +# - test +# script: +# - "./gradlew publish" +# only: +# - dev +# - master -ragdoc_build: - image: - name: "git-st.inf.tu-dresden.de:4567/jastadd/ragdoc-builder" - entrypoint: [""] - stage: ragdoc_build - needs: - - build - script: - - JAVA_FILES=$(find ragconnect.base/src/ -name '*.java') - - /ragdoc-builder/start-builder.sh -excludeGenerated -d data/ $JAVA_FILES - artifacts: - paths: - - "data/" +#ragdoc_build: +# image: +# name: "git-st.inf.tu-dresden.de:4567/jastadd/ragdoc-builder" +# entrypoint: [""] +# stage: ragdoc_build +# needs: +# - build +# script: +# - JAVA_FILES=$(find ragconnect.base/src/ -name '*.java') +# - /ragdoc-builder/start-builder.sh -excludeGenerated -d data/ $JAVA_FILES +# artifacts: +# paths: +# - "data/" -ragdoc_view: - image: - name: "git-st.inf.tu-dresden.de:4567/jastadd/ragdoc-view:relations" - entrypoint: [""] - stage: ragdoc_view - needs: - - ragdoc_build - script: - - DATA_DIR=$(pwd -P)/data - - mkdir -p pages/docs/ragdoc - - OUTPUT_DIR=$(pwd -P)/pages/docs/ragdoc - - cd /ragdoc-view/src/ && rm -rf data && ln -s $DATA_DIR - - /ragdoc-view/build-view.sh --output-path=$OUTPUT_DIR - only: - - dev - - master - artifacts: - paths: - - "pages/docs/ragdoc" +#ragdoc_view: +# image: +# name: "git-st.inf.tu-dresden.de:4567/jastadd/ragdoc-view:relations" +# entrypoint: [""] +# stage: ragdoc_view +# needs: +# - ragdoc_build +# script: +# - DATA_DIR=$(pwd -P)/data +# - mkdir -p pages/docs/ragdoc +# - OUTPUT_DIR=$(pwd -P)/pages/docs/ragdoc +# - cd /ragdoc-view/src/ && rm -rf data && ln -s $DATA_DIR +# - /ragdoc-view/build-view.sh --output-path=$OUTPUT_DIR +# only: +# - dev +# - master +# artifacts: +# paths: +# - "pages/docs/ragdoc" -pages: - image: python:3.8-buster - stage: publish - needs: - - ragdoc_view - - test - before_script: - - pip install -U mkdocs mkdocs-macros-plugin mkdocs-git-revision-date-localized-plugin - script: - - cd pages && mkdocs build - only: - - dev - - master - artifacts: - paths: - - public +#pages: +# image: python:3.8-buster +# stage: publish +# needs: +# - ragdoc_view +# - test +# before_script: +# - pip install -U mkdocs mkdocs-macros-plugin mkdocs-git-revision-date-localized-plugin +# script: +# - cd pages && mkdocs build +#only: +# - dev +# - master +#artifacts: +# paths: +# - public diff --git a/.gitmodules b/.gitmodules index 58efd108e858ae06dde5f626286bd3d73f9dde4e..14c250a57ed1d3278b5d6ce961c8fae45e9266cb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,6 @@ path = relast-preprocessor url = ../relast-preprocessor.git branch = develop +[submodule "ragconnect.base/src/main/jastadd/mustache"] + path = ragconnect.base/src/main/jastadd/mustache + url = git@git-st.inf.tu-dresden.de:jastadd/jastadd-ceti/mustache.git diff --git a/ragconnect.base/build.gradle b/ragconnect.base/build.gradle index 671556c463b40a4224cc70df5ad1db0340858ee5..753814f384186d096929fd2794ac6a19129bfb1f 100644 --- a/ragconnect.base/build.gradle +++ b/ragconnect.base/build.gradle @@ -28,6 +28,9 @@ repositories { dependencies { implementation project(':relast-preprocessor') implementation group: 'com.github.spullara.mustache.java', name: 'compiler', version: "${mustache_java_version}" + // https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 + api group: 'org.apache.commons', name: 'commons-lang3', version: '3.0' + runtimeOnly group: 'org.jastadd', name: 'jastadd', version: '2.3.4' // runtimeOnly group: 'org.jastadd', name: 'jastadd', version: '2.3.5' runtimeOnly fileTree(include: ['jastadd2.jar'], dir: '../libs') api group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11' diff --git a/ragconnect.base/src/main/jastadd/Configuration.jadd b/ragconnect.base/src/main/jastadd/Configuration.jadd index 8fd0e64b14bbd9a05c7cbf9b7de59ed0cd216d78..8c7213850afc5471c70c215d5462442b7da32326 100644 --- a/ragconnect.base/src/main/jastadd/Configuration.jadd +++ b/ragconnect.base/src/main/jastadd/Configuration.jadd @@ -6,6 +6,7 @@ aspect Configuration { public static String ASTNode.JastAddList = "List"; public static boolean ASTNode.usesMqtt; public static boolean ASTNode.usesRest; + public static boolean ASTNode.usesJava; public static boolean ASTNode.incrementalOptionActive; public static boolean ASTNode.experimentalJastAdd329; } diff --git a/ragconnect.base/src/main/jastadd/intermediate/Generation.jadd b/ragconnect.base/src/main/jastadd/intermediate/Generation.jadd index 7e4bde916d565d16bdef34598d638d2080f2f5fa..7a09e6547c1ce7c635e2d2f37f9d7db77248ae68 100644 --- a/ragconnect.base/src/main/jastadd/intermediate/Generation.jadd +++ b/ragconnect.base/src/main/jastadd/intermediate/Generation.jadd @@ -18,6 +18,9 @@ aspect AttributesForMustache { syn String MRagConnect.restHandlerAttribute() = "_restHandler"; syn String MRagConnect.restHandlerField() = "_restHandler"; + syn String MRagConnect.javaHandlerAttribute() = "_javaHandler"; + syn String MRagConnect.javaHandlerField() = "_javaHandler"; + syn boolean MRagConnect.hasTreeListEndpoints() = !sendingTreeListEndpoints().isEmpty() || !receivingTreeListEndpoints().isEmpty(); syn List<MTypeEndpointDefinition> MRagConnect.sendingTreeListEndpoints() { List<MTypeEndpointDefinition> result = new ArrayList<>(); @@ -254,6 +257,8 @@ aspect AttributesForMustache { result.mqttHandlerAttribute(), result.mqttHandlerField(), usesMqtt)); result.addHandler(new MHandler("RestServerHandler", "new RestServerHandler(\"RagConnectREST\")", result.restHandlerAttribute(), result.restHandlerField(), usesRest)); + result.addHandler(new MHandler("JavaHandler", "JavaHandler.getInstance()", + result.javaHandlerAttribute(), result.javaHandlerField(), usesJava)); return result; } diff --git a/ragconnect.base/src/main/jastadd/intermediate2mustache/MustacheNodesToYAML.jrag b/ragconnect.base/src/main/jastadd/intermediate2mustache/MustacheNodesToYAML.jrag index 04b9cf89c248c39740677c88835b56c5325493bf..bd3afcd607a3be9757ec920251d48080fccd1901 100644 --- a/ragconnect.base/src/main/jastadd/intermediate2mustache/MustacheNodesToYAML.jrag +++ b/ragconnect.base/src/main/jastadd/intermediate2mustache/MustacheNodesToYAML.jrag @@ -6,11 +6,17 @@ aspect MustacheNodesToYAML { root.put("closeMethod", closeMethod()); root.put("usesMqtt", usesMqtt); root.put("usesRest", usesRest); + root.put("usesJava", usesJava); + // mqtt root.put("mqttHandlerField", mqttHandlerField()); root.put("mqttHandlerAttribute", mqttHandlerAttribute()); root.put("mqttSetupWaitUntilReadyMethod", mqttSetupWaitUntilReadyMethod()); + // java + root.put("javaHandlerField", javaHandlerField()); + root.put("javaHandlerAttribute", javaHandlerAttribute()); + // rootTypeComponents ListElement rootTypeComponents = new ListElement(); for (MTypeComponent comp : getRootTypeComponentList()) { diff --git a/ragconnect.base/src/main/jastadd/mustache b/ragconnect.base/src/main/jastadd/mustache new file mode 160000 index 0000000000000000000000000000000000000000..c10bed0d03e3fa18b8133ce1de48de7646899615 --- /dev/null +++ b/ragconnect.base/src/main/jastadd/mustache @@ -0,0 +1 @@ +Subproject commit c10bed0d03e3fa18b8133ce1de48de7646899615 diff --git a/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java b/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java index 915d9f92d49cf3a847f05d0b23393bce1832fc1a..c16c6261b688eb6e784c9c8954578d81f0b8cd24 100644 --- a/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java +++ b/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java @@ -32,6 +32,7 @@ public class Compiler extends AbstractCompiler { private static final String OPTION_PROTOCOL_MQTT = "mqtt"; private static final String OPTION_PROTOCOL_REST = "rest"; + private static final String OPTION_PROTOCOL_JAVA = "java"; private final static Logger LOGGER = Logger.getLogger(Compiler.class.getName()); @@ -69,6 +70,18 @@ public class Compiler extends AbstractCompiler { RagConnect ragConnect = parseProgram(getConfiguration().getFiles()); + // lets inspect ragconnects tree + /* + for(EndpointDefinition ed : ragConnect.getEndpointDefinitionList()){ + if(ed.isReceiveTokenEndpointDefinition()){ + for(MappingDefinition md : ed.asReceiveTokenEndpointDefinition().effectiveMappings()){ + // if (!effectiveMappings().get(effectiveMappings().size() - 1).getToType().assignableTo( + // getToken().effectiveJavaTypeUse())) { + System.out.println("gtt: " + md.getToType()); + } + } + } + */ if (!ragConnect.errors().isEmpty()) { StringBuilder sb = new StringBuilder("Errors:\n"); for (ErrorMessage e : ragConnect.errors()) { @@ -91,6 +104,9 @@ public class Compiler extends AbstractCompiler { if (ASTNode.usesMqtt) { handlers.add("MqttHandler.jadd"); } + if (ASTNode.usesJava) { + handlers.add("JavaHandler.jadd"); + } if (ASTNode.usesRest) { handlers.add("RestHandler.jadd"); } @@ -163,8 +179,9 @@ public class Compiler extends AbstractCompiler { optionProtocols = addOption( new ValueOption("protocols", "Protocols to enable") .acceptMultipleValues(true) - .addDefaultValue(OPTION_PROTOCOL_MQTT, "Enable MQTT") + .addDefaultValue(OPTION_PROTOCOL_JAVA, "Enable Java") .addAcceptedValue(OPTION_PROTOCOL_REST, "Enable REST") + .addAcceptedValue(OPTION_PROTOCOL_MQTT, "Enable MQTT") ); optionPrintYaml = addOption( new BooleanOption("printYaml", "Print out YAML instead of generating files") @@ -246,6 +263,7 @@ public class Compiler extends AbstractCompiler { ASTNode.JastAddList = getConfiguration().listType(); ASTNode.usesMqtt = optionProtocols.hasValue(OPTION_PROTOCOL_MQTT); + ASTNode.usesJava = optionProtocols.hasValue(OPTION_PROTOCOL_JAVA); ASTNode.usesRest = optionProtocols.hasValue(OPTION_PROTOCOL_REST); return ragConnect; } diff --git a/ragconnect.base/src/main/resources/JavaHandler.jadd b/ragconnect.base/src/main/resources/JavaHandler.jadd new file mode 100644 index 0000000000000000000000000000000000000000..5849b61fb221752c21e00795cb5494c43f18ef51 --- /dev/null +++ b/ragconnect.base/src/main/resources/JavaHandler.jadd @@ -0,0 +1,101 @@ +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; + +aspect JavaHandler { + + /** + * Singleton class providing routing functionality for byte[] based message calls. + */ + public class JavaHandler { + + public static JavaHandler JAVA_HANDLER_INSTANCE = null; + + private final org.apache.logging.log4j.Logger logger = org.apache.logging.log4j.LogManager.getLogger(JavaHandler.class); + + private Map<String, List<org.apache.commons.lang3.tuple.Pair<String, Consumer<byte[]>>>> callbackList = new ConcurrentHashMap<>(); + + private JavaHandler() { + + } + + public synchronized static JavaHandler getInstance() { + if(JAVA_HANDLER_INSTANCE == null) { + JAVA_HANDLER_INSTANCE = new JavaHandler(); + } + return JAVA_HANDLER_INSTANCE; + } + + public String registerCallback(String topic, Consumer<byte[]> callback) { + + logger.debug("[JAVA_HANDLER] Registering new callback."); + + String callbackUUID = java.util.UUID.randomUUID().toString(); + + List<org.apache.commons.lang3.tuple.Pair<String, Consumer<byte[]>>> registeredCallbacks = getAllCallbacks().get(topic); + + if(registeredCallbacks == null){ + List<org.apache.commons.lang3.tuple.Pair<String, Consumer<byte[]>>> newCallbackList = Collections.synchronizedList(new ArrayList<>()); + newCallbackList.add(new org.apache.commons.lang3.tuple.MutablePair<>(callbackUUID, callback)); + callbackList.put(topic, newCallbackList); + } else { + registeredCallbacks.add(new org.apache.commons.lang3.tuple.MutablePair<>(callbackUUID, callback)); + } + + return callbackUUID; + } + + public boolean unregisterCallback(String path, String uuid){ + + logger.debug("[JAVA_HANDLER] Unregistering callback with uuid: " + uuid + " on path: " + path); + + List<org.apache.commons.lang3.tuple.Pair<String, Consumer<byte[]>>> callbacks = getAllCallbacks().get(path); + + int count = 0; + + if(callbacks != null){ + for(org.apache.commons.lang3.tuple.Pair<String, Consumer<byte[]>> callbackPair : callbacks){ + if(callbackPair.getLeft().equals(uuid)){ + callbacks.remove(count); + return true; + }else{ + count++; + } + } + } + return false; + } + + public void close(){}; + + public boolean push(String topic, byte[] data) { + + logger.info("[JAVA_HANDLER] Pushing a message."); + + String dataString = new String(data); + + logger.info("[JAVA_HANDLER] Data: " + dataString); + + List<org.apache.commons.lang3.tuple.Pair<String, Consumer<byte[]>>> callbacks = getAllCallbacks().get(topic); + + if(callbacks == null){ + logger.error("[JAVA_HANDLER] Could not publish message. No callback registered for topic " + topic); + return false; + } + + for(org.apache.commons.lang3.tuple.Pair<String, Consumer<byte[]>> callbackPair : callbacks){ + logger.debug("[JAVA_HANDLER] Calling callback: " + callbackPair.getLeft()); + callbackPair.getRight().accept(data); + } + + return true; + } + + public Map<String, List<org.apache.commons.lang3.tuple.Pair<String, Consumer<byte[]>>>> getAllCallbacks() { + return callbackList; + } + } +} \ No newline at end of file diff --git a/ragconnect.base/src/main/resources/handler.mustache b/ragconnect.base/src/main/resources/handler.mustache index 41e42387f69239f054b8ddaafa80680b13ca7591..896f6ac8dd7befc02d67ce3a2863c45f0822e0c1 100644 --- a/ragconnect.base/src/main/resources/handler.mustache +++ b/ragconnect.base/src/main/resources/handler.mustache @@ -1,3 +1,4 @@ + aspect RagConnectHandler { {{#Handlers}} {{#InUse}} @@ -15,14 +16,19 @@ aspect RagConnectHandler { {{/Handlers}} } class ConnectToken { - static java.util.concurrent.atomic.AtomicLong counter = new java.util.concurrent.atomic.AtomicLong(0); - final long id; + //static java.util.concurrent.atomic.AtomicLong counter = new java.util.concurrent.atomic.AtomicLong(0); + final String id; final java.net.URI uri; + public ConnectToken(java.net.URI uri) { - this.id = counter.incrementAndGet(); + this.id = java.util.UUID.randomUUID().toString(); // counter.incrementAndGet(); this.uri = uri; } + public ConnectToken(java.net.URI uri, String uuid) { + this.id = uuid; // counter.incrementAndGet(); + this.uri = uri; + } } static java.util.Map<ASTNode, java.util.Map<java.net.URI, ConnectToken>> ASTNode.connectTokens = new java.util.HashMap<>(); } diff --git a/ragconnect.base/src/main/resources/receiveDefinition.mustache b/ragconnect.base/src/main/resources/receiveDefinition.mustache index 4ae8a05c6f97e03f5522160a487f33a710186a2c..9a8e309964319ee768879aa9f0c4b6a6b9d316a4 100644 --- a/ragconnect.base/src/main/resources/receiveDefinition.mustache +++ b/ragconnect.base/src/main/resources/receiveDefinition.mustache @@ -109,6 +109,15 @@ private boolean {{parentTypeName}}.{{internalConnectMethod}}(String {{connectPar } break; {{/usesMqtt}} + {{#usesJava}} + case "java": + String uuid = {{javaHandlerAttribute}}().registerCallback(path, consumer); + connectToken = new ConnectToken(uri, uuid); + if (uuid == null) { + return false; + } + break; + {{/usesJava}} {{#usesRest}} case "rest": connectToken = {{restHandlerAttribute}}().newPUTConnection(uri, input -> { @@ -135,6 +144,9 @@ public boolean {{parentTypeName}}.{{disconnectMethod}}(String {{connectParameter {{#usesMqtt}} case "mqtt": return {{mqttHandlerAttribute}}().disconnect(connectTokens.get(this).get(uri)); {{/usesMqtt}} + {{#usesJava}} + case "java": return {{javaHandlerAttribute}}().unregisterCallback(uri.getPath(), connectTokens.get(this).get(uri).id); + {{/usesJava}} {{#usesRest}} case "rest": return {{restHandlerAttribute}}().disconnect(connectTokens.get(this).get(uri)); {{/usesRest}} diff --git a/ragconnect.base/src/main/resources/sendDefinition.mustache b/ragconnect.base/src/main/resources/sendDefinition.mustache index 6fd97bf2cc7154cd0d053311f95166347cbccc6a..bf05fadf4c4c8281aea696425b2982617eec2029 100644 --- a/ragconnect.base/src/main/resources/sendDefinition.mustache +++ b/ragconnect.base/src/main/resources/sendDefinition.mustache @@ -27,6 +27,19 @@ public boolean {{parentTypeName}}.{{connectMethod}}(String {{connectParameterNam connectToken = new ConnectToken(uri); break; {{/usesMqtt}} + {{#usesJava}} + case "java": + final JavaHandler handler = {{javaHandlerAttribute}}().getInstance(); + + {{sender}} = () -> { + handler.push(path, {{lastValue}}); + }; + {{updateMethod}}(); + if (writeCurrentValue) { + {{writeMethod}}(); + } + break; + {{/usesJava}} {{#usesRest}} case "rest": connectToken = {{restHandlerAttribute}}().newGETConnection(uri, () -> { @@ -70,6 +83,11 @@ public boolean {{parentTypeName}}.{{disconnectMethod}}(String {{connectParameter {{lastValue}} = null; break; {{/usesMqtt}} + {{#usesJava}} + case "java": + // nothing todo, because senders are not registered (just callbacks) + break; + {{/usesJava}} {{#usesRest}} case "rest": {{restHandlerAttribute}}().disconnect(connectToken); diff --git a/ragconnect.tests/build.gradle b/ragconnect.tests/build.gradle index 61470f5292531d0ec7ca5d3691a3b248bcff1588..c43e47044c47358624b646fec196634ac28786bf 100644 --- a/ragconnect.tests/build.gradle +++ b/ragconnect.tests/build.gradle @@ -562,3 +562,4 @@ task compileSingleListVariantIncremental(type: RagConnectTest, dependsOn: ':ragc //} //compileSingleListVariantManual.dependsOn cleanCurrentManualTest //compileSingleListVariantIncremental.dependsOn cleanCurrentIncrementalTest + diff --git a/relast-preprocessor b/relast-preprocessor index 02f8e35993dc3f62ab49e94f69a6dc27170660da..c00441c03dc6723a08de0fcb041254a99497774f 160000 --- a/relast-preprocessor +++ b/relast-preprocessor @@ -1 +1 @@ -Subproject commit 02f8e35993dc3f62ab49e94f69a6dc27170660da +Subproject commit c00441c03dc6723a08de0fcb041254a99497774f