diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index fb3a5ccb5f43a8339f349324f764d3648b58f1e7..453d9297e35aaedfbc03b908516840b535e6a061 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -3,7 +3,7 @@ variables:
 
 stages:
 - build
-- publish
+# - publish
 
 before_script:
   - export GRADLE_USER_HOME=`pwd`/.gradle
@@ -22,22 +22,22 @@ build:
     paths:
       - "/builds/jastadd/ragconnect/build/libs/ragconnect-*.jar"
 
-publish:
-  image: openjdk:11
-  stage: publish
-  script:
-    - "./gradlew publish"
-  only:
-    - master
+#publish:
+#  image: openjdk:11
+#  stage: publish
+#  script:
+#    - "./gradlew publish"
+#  only:
+#    - master
 
-pages:
-  image: python:3.7-alpine
-  stage: publish
-  script:
-  - pip install -U sphinx sphinx-rtd-theme recommonmark sphinxemoji sphinx-markdown-tables
-  - sphinx-build -b html pages/ public
-  artifacts:
-    paths:
-    - public
-  only:
-  - master
+#pages:
+#  image: python:3.7-alpine
+#  stage: publish
+#  script:
+#  - pip install -U sphinx sphinx-rtd-theme recommonmark sphinxemoji sphinx-markdown-tables
+#  - sphinx-build -b html pages/ public
+#  artifacts:
+#    paths:
+#    - public
+#  only:
+#  - master
diff --git a/ragconnect.base/src/main/jastadd/Configuration.jadd b/ragconnect.base/src/main/jastadd/Configuration.jadd
index 8d3b16c3f99014408c6aefa5655201d222c3d892..32f13d45b54541d43af1a5417d2daf9082bb5711 100644
--- a/ragconnect.base/src/main/jastadd/Configuration.jadd
+++ b/ragconnect.base/src/main/jastadd/Configuration.jadd
@@ -4,4 +4,5 @@ aspect Configuration {
   public static TypeDecl ASTNode.rootNode;
   public static boolean ASTNode.usesMqtt;
   public static boolean ASTNode.usesRest;
+  public static boolean ASTNode.usesJava;
 }
diff --git a/ragconnect.base/src/main/jastadd/intermediate/Generation.jadd b/ragconnect.base/src/main/jastadd/intermediate/Generation.jadd
index 607f96066832b1f788d0d1d6e5d0a18552f11337..06d223ee1f4a3fd0cc78beeaa2a8cedf0a2bbd45 100644
--- a/ragconnect.base/src/main/jastadd/intermediate/Generation.jadd
+++ b/ragconnect.base/src/main/jastadd/intermediate/Generation.jadd
@@ -15,6 +15,9 @@ aspect AttributesForMustache {
   syn String MRagConnect.restHandlerAttribute() = "_restHandler";
   syn String MRagConnect.restHandlerField() = "_restHandler";
 
+  syn String MRagConnect.javaHandlerAttribute() = "_javaHandler";
+  syn String MRagConnect.javaHandlerField() = "_javaHandler";
+
   // --- MEndpointDefinition ---
   syn String MEndpointDefinition.preemptiveExpectedValue();
   syn String MEndpointDefinition.preemptiveReturn();
@@ -141,6 +144,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 337527db4b44261a30c6768450ded30ad99446db..4688e9915ddb04a97c7d53b637977f54e1c9b803 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/java/org/jastadd/ragconnect/compiler/Compiler.java b/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java
index 28a3f209ecf5ee4bf436251fe2cff9e71d091bc8..8c649c4fb47be4f7824f26b93758d4a7d58a1028 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
@@ -28,6 +28,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";
 
   public Compiler() {
     super("ragconnect", true);
@@ -81,6 +82,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");
     }
@@ -158,8 +162,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")
diff --git a/ragconnect.base/src/main/resources/JavaHandler.jadd b/ragconnect.base/src/main/resources/JavaHandler.jadd
new file mode 100644
index 0000000000000000000000000000000000000000..217ae63bce14a4cfe64e97aa3d5212fc82d783cb
--- /dev/null
+++ b/ragconnect.base/src/main/resources/JavaHandler.jadd
@@ -0,0 +1,70 @@
+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<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 void registerCallback(String topic, Consumer<byte[]> callback) {
+
+            logger.debug("[JAVA_HANDLER] Registering new callback.");
+
+            List<Consumer<byte[]>> registeredCallbacks = getAllCallbacks().get(topic);
+
+            if(registeredCallbacks == null){
+                List<Consumer<byte[]>> newCallbackList = Collections.synchronizedList(new ArrayList<>());
+                newCallbackList.add(callback);
+                callbackList.put(topic, newCallbackList);
+            } else {
+                registeredCallbacks.add(callback);
+            }
+        }
+
+        public boolean push(String topic, byte[] data) {
+
+            logger.debug("[JAVA_HANDLER] Pushing a message.");
+
+            List<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(Consumer<byte[]> callback : callbacks){
+                logger.debug("[JAVA_HANDLER] Calling callback: " + callback.toString());
+                callback.accept(data);
+            }
+
+            return true;
+        }
+
+        public Map<String, List<Consumer<byte[]>>> getAllCallbacks() {
+            return callbackList;
+        }
+    }
+}
\ No newline at end of file
diff --git a/ragconnect.base/src/main/resources/receiveDefinition.mustache b/ragconnect.base/src/main/resources/receiveDefinition.mustache
index 1dd0e0ddbfbfd2acf03536ff41a2d740043eb34b..86523f5c74a03f009c98ae5abb796af42e1823af 100644
--- a/ragconnect.base/src/main/resources/receiveDefinition.mustache
+++ b/ragconnect.base/src/main/resources/receiveDefinition.mustache
@@ -11,8 +11,11 @@ public boolean {{parentTypeName}}.{{connectMethod}}(String {{connectParameterNam
   {{#usesMqtt}}
     case "mqtt": return {{mqttHandlerAttribute}}().newConnection(uri, consumer);
   {{/usesMqtt}}
+  {{#usesJava}}
+    case "mqtt": return {{javaHandlerAttribute}}().registerCallback(uri, consumer);
+  {{/usesJava}}
   {{#usesRest}}
-    case "rest": return {{restHandlerAttribute}}().newPUTConnection(uri, input -> {
+    case "java": return {{restHandlerAttribute}}().newPUTConnection(uri, input -> {
       consumer.accept(input.getBytes());
     });
   {{/usesRest}}
diff --git a/ragconnect.base/src/main/resources/sendDefinition.mustache b/ragconnect.base/src/main/resources/sendDefinition.mustache
index 60f5efcca8f3333d41fc8cc4706a736946a42ab7..a91371020903b8f146bb3453d39abec877855e6a 100644
--- a/ragconnect.base/src/main/resources/sendDefinition.mustache
+++ b/ragconnect.base/src/main/resources/sendDefinition.mustache
@@ -20,6 +20,22 @@ public boolean {{parentTypeName}}.{{connectMethod}}(String {{connectParameterNam
       }
       break;
   {{/usesMqtt}}
+  {{#usesJava}}
+      case "java":
+      final JavaHandler handler = {{javaHandlerAttribute}}().resolveHandler(uri);
+      final String topic = {{javaHandlerAttribute}}().extractTopic(uri);
+      {{sender}} = () -> {
+        {{#loggingEnabledForWrites}}
+        System.out.println("[Send] {{tokenName}} = " + get{{tokenName}}() + " -> " + {{connectParameterName}});
+        {{/loggingEnabledForWrites}}
+        handler.publish(topic, {{lastValue}});
+      };
+    {{updateMethod}}();
+    if (writeCurrentValue) {
+      {{writeMethod}}();
+    }
+    break;
+  {{/usesJava}}
   {{#usesRest}}
     case "rest":
       {{restHandlerAttribute}}().newGETConnection(uri, () -> {