diff --git a/data-plane/THIRD-PARTY.txt b/data-plane/THIRD-PARTY.txt
index 300cf412ce..39d5e5436c 100644
--- a/data-plane/THIRD-PARTY.txt
+++ b/data-plane/THIRD-PARTY.txt
@@ -1,5 +1,5 @@
-Lists of 231 third-party dependencies.
+Lists of 232 third-party dependencies.
(Eclipse Public License - v 1.0) (GNU Lesser General Public License) Logback Classic Module (ch.qos.logback:logback-classic:1.2.11 - http://logback.qos.ch/logback-classic)
(Eclipse Public License - v 1.0) (GNU Lesser General Public License) Logback Core Module (ch.qos.logback:logback-core:1.2.11 - http://logback.qos.ch/logback-core)
(Apache License 2.0) brotli4j (com.aayushatharva.brotli4j:brotli4j:1.12.0 - https://github.com/hyperxpro/Brotli4j/brotli4j)
@@ -34,6 +34,7 @@ Lists of 231 third-party dependencies.
(Unknown license) contract (dev.knative.eventing.kafka.broker:contract:1.0-SNAPSHOT - no url defined)
(Unknown license) core (dev.knative.eventing.kafka.broker:core:1.0-SNAPSHOT - no url defined)
(Unknown license) dispatcher (dev.knative.eventing.kafka.broker:dispatcher:1.0-SNAPSHOT - no url defined)
+ (Unknown license) dispatcher-loom (dev.knative.eventing.kafka.broker:dispatcher-loom:1.0-SNAPSHOT - no url defined)
(Unknown license) dispatcher-vertx (dev.knative.eventing.kafka.broker:dispatcher-vertx:1.0-SNAPSHOT - no url defined)
(Unknown license) receiver (dev.knative.eventing.kafka.broker:receiver:1.0-SNAPSHOT - no url defined)
(Unknown license) receiver-loom (dev.knative.eventing.kafka.broker:receiver-loom:1.0-SNAPSHOT - no url defined)
diff --git a/data-plane/dispatcher-loom/pom.xml b/data-plane/dispatcher-loom/pom.xml
index a6b0ea5b97..2546ba55f0 100644
--- a/data-plane/dispatcher-loom/pom.xml
+++ b/data-plane/dispatcher-loom/pom.xml
@@ -30,6 +30,7 @@
20
+ --enable-preview
@@ -39,6 +40,32 @@
dispatcher
${project.version}
+
+ dev.knative.eventing.kafka.broker
+ receiver-loom
+ ${project.version}
+
+
+
+ io.vertx
+ vertx-junit5
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
+ test
+
diff --git a/data-plane/dispatcher-loom/src/main/java/dev/knative/eventing/kafka/broker/dispatcherloom/LoomConsumerFactory.java b/data-plane/dispatcher-loom/src/main/java/dev/knative/eventing/kafka/broker/dispatcherloom/LoomConsumerFactory.java
index 58106e03e7..cbbda41d92 100644
--- a/data-plane/dispatcher-loom/src/main/java/dev/knative/eventing/kafka/broker/dispatcherloom/LoomConsumerFactory.java
+++ b/data-plane/dispatcher-loom/src/main/java/dev/knative/eventing/kafka/broker/dispatcherloom/LoomConsumerFactory.java
@@ -15,6 +15,16 @@
*/
package dev.knative.eventing.kafka.broker.dispatcherloom;
-public class LoomConsumerFactory {
- // TODO implement
+import dev.knative.eventing.kafka.broker.core.ReactiveConsumerFactory;
+import dev.knative.eventing.kafka.broker.core.ReactiveKafkaConsumer;
+import io.vertx.core.Vertx;
+import java.util.Map;
+import org.apache.kafka.clients.consumer.KafkaConsumer;
+
+public class LoomConsumerFactory implements ReactiveConsumerFactory {
+
+ @Override
+ public ReactiveKafkaConsumer create(Vertx vertx, Map configs) {
+ return new LoomKafkaConsumer<>(vertx, new KafkaConsumer<>(configs));
+ }
}
diff --git a/data-plane/dispatcher-loom/src/main/java/dev/knative/eventing/kafka/broker/dispatcherloom/LoomKafkaConsumer.java b/data-plane/dispatcher-loom/src/main/java/dev/knative/eventing/kafka/broker/dispatcherloom/LoomKafkaConsumer.java
index bdf09b8884..aac391373f 100644
--- a/data-plane/dispatcher-loom/src/main/java/dev/knative/eventing/kafka/broker/dispatcherloom/LoomKafkaConsumer.java
+++ b/data-plane/dispatcher-loom/src/main/java/dev/knative/eventing/kafka/broker/dispatcherloom/LoomKafkaConsumer.java
@@ -15,6 +15,202 @@
*/
package dev.knative.eventing.kafka.broker.dispatcherloom;
-public class LoomKafkaConsumer {
- // TODO implement
+import dev.knative.eventing.kafka.broker.core.ReactiveKafkaConsumer;
+import io.vertx.core.Future;
+import io.vertx.core.Handler;
+import io.vertx.core.Promise;
+import io.vertx.core.Vertx;
+import java.time.Duration;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.kafka.clients.consumer.Consumer;
+import org.apache.kafka.clients.consumer.ConsumerRebalanceListener;
+import org.apache.kafka.clients.consumer.ConsumerRecords;
+import org.apache.kafka.clients.consumer.OffsetAndMetadata;
+import org.apache.kafka.common.TopicPartition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class LoomKafkaConsumer implements ReactiveKafkaConsumer {
+
+ private static final Logger logger = LoggerFactory.getLogger(LoomKafkaConsumer.class);
+
+ private final Consumer consumer;
+ private final BlockingQueue taskQueue;
+ private final AtomicBoolean isClosed;
+ private final Thread taskRunnerThread;
+ private Handler exceptionHandler;
+
+ public LoomKafkaConsumer(Vertx vertx, Consumer consumer) {
+ this.consumer = consumer;
+ this.taskQueue = new LinkedBlockingQueue<>();
+ this.isClosed = new AtomicBoolean(false);
+
+ taskRunnerThread = Thread.ofVirtual().start(this::processTaskQueue);
+ }
+
+ private void addTask(Runnable task, Promise> promise) {
+ if (isClosed.get()) {
+ promise.fail("Consumer is closed");
+ }
+ taskQueue.add(task);
+ }
+
+ private void processTaskQueue() {
+ while (!isClosed.get() || !taskQueue.isEmpty()) {
+ try {
+ taskQueue.take().run();
+ } catch (InterruptedException e) {
+ logger.debug("Interrupted while waiting for task", e);
+ }
+ }
+ }
+
+ @Override
+ public Future