Copilot commented on code in PR #4304:
URL: 
https://github.com/apache/incubator-kie-kogito-runtimes/pull/4304#discussion_r3403549383


##########
addons/common/external-signals/external-signals-runtime/src/main/java/org/kie/kogito/addons/externalsignals/runtime/DefaultExternalSignalDispatcher.java:
##########
@@ -0,0 +1,337 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.kogito.addons.externalsignals.runtime;
+
+import java.net.URI;
+import java.time.OffsetDateTime;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
+
+import org.kie.kogito.addons.externalsignals.ExternalSignalConfig;
+import org.kie.kogito.addons.externalsignals.ExternalSignalDispatchException;
+import org.kie.kogito.addons.externalsignals.ExternalSignalDispatcher;
+import org.kie.kogito.addons.externalsignals.ExternalSignalEvent;
+import org.kie.kogito.event.DataEvent;
+import org.kie.kogito.event.EventEmitter;
+import org.kie.kogito.event.impl.EventFactoryUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.cloudevents.CloudEvent;
+import io.cloudevents.CloudEventData;
+import io.cloudevents.SpecVersion;
+import io.cloudevents.core.builder.CloudEventBuilder;
+
+/**
+ * Default implementation of {@link ExternalSignalDispatcher} that uses 
Kogito's
+ * {@link EventEmitter} infrastructure for transport-agnostic signal 
dispatching.
+ * 
+ * This dispatcher:
+ * <ul>
+ * <li>Resolves the target topic/trigger based on configuration</li>
+ * <li>Transforms the signal event into a CloudEvent-compatible DataEvent</li>
+ * <li>Dispatches the event using the appropriate EventEmitter</li>
+ * <li>Operates in fire-and-forget mode (Phase 1)</li>
+ * </ul>
+ * 
+ * The actual transport mechanism (Kafka, HTTP, etc.) is determined by the
+ * EventEmitter implementation available at runtime through ServiceLoader.
+ *
+ * @see ExternalSignalEvent
+ * @see ExternalSignalConfig
+ * @see EventEmitter
+ */
+public class DefaultExternalSignalDispatcher implements 
ExternalSignalDispatcher {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(DefaultExternalSignalDispatcher.class);
+
+    private static final String EVENT_TYPE_PREFIX = 
"org.kie.kogito.signal.external";
+
+    private final ExternalSignalConfig config;
+
+    public DefaultExternalSignalDispatcher() {
+        this(new ExternalSignalConfigImpl());
+    }
+
+    /**
+     * Creates a new dispatcher with the specified configuration.
+     * 
+     * @param config the configuration to use
+     * @throws IllegalArgumentException if config is null
+     */
+    public DefaultExternalSignalDispatcher(ExternalSignalConfig config) {
+        this.config = Objects.requireNonNull(config, "ExternalSignalConfig 
cannot be null");
+        LOG.info("External signal dispatcher initialized with config: {}", 
config);
+    }
+
+    @Override
+    public void dispatch(ExternalSignalEvent event) {
+        Objects.requireNonNull(event, "ExternalSignalEvent cannot be null");
+
+        if (event.getSignalName() == null || 
event.getSignalName().trim().isEmpty()) {
+            throw new IllegalArgumentException("Signal name cannot be null or 
empty");
+        }
+
+        try {
+            String trigger = resolveTrigger(event.getSignalName());
+
+            LOG.debug("Dispatching external signal '{}' to trigger '{}' from 
process instance '{}'",
+                    event.getSignalName(), trigger, 
event.getSourceProcessInstanceId());
+
+            // Get the appropriate event emitter for this trigger
+            EventEmitter emitter = EventFactoryUtils.getEventEmitter(trigger);
+
+            // Transform to DataEvent
+            DataEvent<ExternalSignalEvent> dataEvent = createDataEvent(event, 
trigger);
+
+            // Emit the event
+            emitter.emit(dataEvent);
+
+            LOG.info("Successfully dispatched external signal '{}' with 
correlation ID '{}' to trigger '{}'",
+                    event.getSignalName(), event.getCorrelationId(), trigger);
+
+        } catch (Exception e) {
+            String errorMsg = String.format(
+                    "Failed to dispatch external signal '%s' from process 
instance '%s'",
+                    event.getSignalName(), event.getSourceProcessInstanceId());
+            LOG.error(errorMsg, e);
+            throw new ExternalSignalDispatchException(errorMsg, e);
+        }
+    }
+
+    @Override
+    public String resolveTrigger(String signalName) {
+        if (signalName == null || signalName.trim().isEmpty()) {
+            throw new IllegalArgumentException("Signal name cannot be null or 
empty");
+        }
+
+        String trigger = config.resolveTrigger(signalName);
+        LOG.debug("Resolved signal '{}' to trigger '{}'", signalName, trigger);
+        return trigger;
+    }
+
+    /**
+     * Creates a CloudEvent-compatible DataEvent from an ExternalSignalEvent.
+     * 
+     * @param event the external signal event
+     * @param trigger the resolved trigger name
+     * @return the data event
+     */
+    private DataEvent<ExternalSignalEvent> createDataEvent(ExternalSignalEvent 
event, String trigger) {
+        // Create event type: org.kie.kogito.signal.external.{signalName}
+        String eventType = EVENT_TYPE_PREFIX + "." + event.getSignalName();
+
+        // Create source URI
+        URI source = event.getSource();
+
+        // Create the DataEvent using the factory
+        return new ExternalSignalDataEvent(
+                eventType,
+                source,
+                event,
+                event.getCorrelationId());
+    }
+
+    /**
+     * Simple DataEvent wrapper for external signals.
+     * This is a minimal implementation for Phase 1.
+     */
+    private static class ExternalSignalDataEvent implements 
DataEvent<ExternalSignalEvent> {
+
+        private final String type;
+        private final URI source;
+        private final ExternalSignalEvent data;
+        private final String id;
+
+        ExternalSignalDataEvent(String type, URI source, ExternalSignalEvent 
data, String id) {
+            this.type = type;
+            this.source = source;
+            this.data = data;
+            this.id = id;
+        }
+
+        @Override
+        public ExternalSignalEvent getData() {
+            return data;
+        }
+
+        @Override
+        public String getType() {
+            return type;
+        }
+
+        @Override
+        public URI getSource() {
+            return source;
+        }
+
+        @Override
+        public String getId() {
+            return id;
+        }
+
+        @Override
+        public SpecVersion getSpecVersion() {
+            return SpecVersion.V1;
+        }
+
+        @Override
+        public OffsetDateTime getTime() {
+            return data.getTimestamp() != null ? OffsetDateTime.now() : null;
+        }

Review Comment:
   `DataEvent#getTime()` should reflect the actual event timestamp. Returning 
`OffsetDateTime.now()` ignores `ExternalSignalEvent#getTimestamp()` and can 
produce incorrect CloudEvent `time` values (and makes event timestamps 
non-deterministic).



##########
addons/common/external-signals/external-signals-integration-tests/pom.xml:
##########
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <parent>
+    <groupId>org.kie</groupId>
+    <artifactId>kogito-addons-external-signals-parent</artifactId>
+    <version>999-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>kogito-addons-external-signals-integration-tests</artifactId>
+  <name>Kogito :: Add-Ons :: External Signals :: Integration Tests</name>
+  <description>External Signal Scope Integration Tests</description>
+  <packaging>pom</packaging>
+

Review Comment:
   This module declares `<packaging>pom</packaging>` but also contains 
`src/test/java` tests. With `pom` packaging, Maven won’t bind the compiler/test 
lifecycle by default, so these tests typically won’t compile/run (even if 
surefire is configured). Using `jar` packaging keeps it as a test-only module 
while still running the tests.



##########
addons/common/external-signals/README.md:
##########
@@ -0,0 +1,293 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Kogito External Signals Addon
+
+This addon provides support for external signal scope in Kogito runtimes, 
enabling BPMN processes to send signals to external systems via messaging 
infrastructure (Kafka, HTTP, etc.).
+
+## Overview
+
+The External Signals addon allows BPMN signal throw events to dispatch signals 
outside the process engine scope. When a signal throw event is marked with an 
"external" scope, instead of being processed internally by the process engine, 
the signal is sent to an external system through Kogito's event infrastructure.
+
+### Key Features
+
+- **Transport-Agnostic**: Uses Kogito's `EventEmitter` infrastructure, 
supporting any transport (Kafka, HTTP, etc.)
+- **CloudEvent Compatible**: Signal events follow CloudEvent specifications 
for interoperability
+- **Configurable Routing**: Map signal names to specific topics/triggers via 
configuration
+- **Fire-and-Forget **: Signals are dispatched asynchronously without blocking 
the process

Review Comment:
   There’s an extra space inside the bold markup (`**Fire-and-Forget **`), 
which breaks consistent Markdown formatting.



##########
addons/common/external-signals/README.md:
##########
@@ -0,0 +1,293 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Kogito External Signals Addon
+
+This addon provides support for external signal scope in Kogito runtimes, 
enabling BPMN processes to send signals to external systems via messaging 
infrastructure (Kafka, HTTP, etc.).
+
+## Overview
+
+The External Signals addon allows BPMN signal throw events to dispatch signals 
outside the process engine scope. When a signal throw event is marked with an 
"external" scope, instead of being processed internally by the process engine, 
the signal is sent to an external system through Kogito's event infrastructure.
+
+### Key Features
+
+- **Transport-Agnostic**: Uses Kogito's `EventEmitter` infrastructure, 
supporting any transport (Kafka, HTTP, etc.)
+- **CloudEvent Compatible**: Signal events follow CloudEvent specifications 
for interoperability
+- **Configurable Routing**: Map signal names to specific topics/triggers via 
configuration
+- **Fire-and-Forget **: Signals are dispatched asynchronously without blocking 
the process
+- **Extensible**: Designed for future enhancements (correlation, 
request-response patterns)
+
+## Architecture
+
+### Components
+
+1. **ExternalSignalEvent** - CloudEvent-compatible signal event model
+2. **ExternalSignalDispatcher** - Interface for signal dispatching
+3. **ExternalSignalWorkItemHandler** - Handles "External Send Task" work items
+4. **ExternalSignalConfig** - Configuration for signal-to-topic mapping
+
+### How It Works
+
+```
+BPMN Process → Signal Throw Event (external scope) 
+    → ExternalSignalWorkItemHandler 
+    → ExternalSignalDispatcher 
+    → EventEmitter 
+    → External System (Kafka/HTTP/etc.)
+```
+
+## Installation
+
+### Maven
+
+Add the runtime dependency to your project:
+
+```xml
+<dependency>
+    <groupId>org.kie</groupId>
+    <artifactId>kogito-addons-external-signals-runtime</artifactId>

Review Comment:
   The README references `kogito-addons-external-signals-runtime`, but the 
runtime module in this PR is published as 
`org.kie:kogito-addons-external-signals` (`external-signals-runtime/pom.xml`). 
As written, the dependency snippet will not resolve.



##########
addons/common/external-signals/README.md:
##########
@@ -0,0 +1,293 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Kogito External Signals Addon
+
+This addon provides support for external signal scope in Kogito runtimes, 
enabling BPMN processes to send signals to external systems via messaging 
infrastructure (Kafka, HTTP, etc.).
+
+## Overview
+
+The External Signals addon allows BPMN signal throw events to dispatch signals 
outside the process engine scope. When a signal throw event is marked with an 
"external" scope, instead of being processed internally by the process engine, 
the signal is sent to an external system through Kogito's event infrastructure.
+
+### Key Features
+
+- **Transport-Agnostic**: Uses Kogito's `EventEmitter` infrastructure, 
supporting any transport (Kafka, HTTP, etc.)
+- **CloudEvent Compatible**: Signal events follow CloudEvent specifications 
for interoperability
+- **Configurable Routing**: Map signal names to specific topics/triggers via 
configuration
+- **Fire-and-Forget **: Signals are dispatched asynchronously without blocking 
the process
+- **Extensible**: Designed for future enhancements (correlation, 
request-response patterns)
+
+## Architecture
+
+### Components
+
+1. **ExternalSignalEvent** - CloudEvent-compatible signal event model
+2. **ExternalSignalDispatcher** - Interface for signal dispatching
+3. **ExternalSignalWorkItemHandler** - Handles "External Send Task" work items
+4. **ExternalSignalConfig** - Configuration for signal-to-topic mapping
+
+### How It Works
+
+```
+BPMN Process → Signal Throw Event (external scope) 
+    → ExternalSignalWorkItemHandler 
+    → ExternalSignalDispatcher 
+    → EventEmitter 
+    → External System (Kafka/HTTP/etc.)
+```
+
+## Installation
+
+### Maven
+
+Add the runtime dependency to your project:
+
+```xml
+<dependency>
+    <groupId>org.kie</groupId>
+    <artifactId>kogito-addons-external-signals-runtime</artifactId>
+</dependency>
+```
+
+The addon is automatically discovered via ServiceLoader and registers the work 
item handler.
+
+## Configuration
+
+Configure signal-to-topic mappings using application properties:
+
+### Properties
+
+```properties
+# Map specific signals to topics/triggers
+kogito.external-signals.mapping.OrderCreated=order-events
+kogito.external-signals.mapping.PaymentProcessed=payment-topic
+kogito.external-signals.mapping.InventoryUpdated=inventory-updates
+
+# Set custom default prefix for unmapped signals (default: 
"kogito-external-signal")
+kogito.external-signals.default-prefix=my-app-signal
+```
+
+### Topic Resolution
+
+The addon resolves topics using this priority:
+
+1. **Explicit Mapping**: If `kogito.external-signals.mapping.{signalName}` is 
configured, use that value
+2. **Default Convention**: Otherwise, use `{prefix}-{signalName}` where prefix 
defaults to `kogito-external-signal`
+
+**Examples:**
+
+| Signal Name | Configuration | Resolved Topic |
+|------------|---------------|----------------|
+| OrderCreated | `kogito.external-signals.mapping.OrderCreated=order-events` | 
`order-events` |
+| PaymentProcessed | (no mapping) | `kogito-external-signal-PaymentProcessed` |
+| InventoryUpdated | (custom prefix: `my-app`) | `my-app-InventoryUpdated` |
+
+## Usage
+
+### BPMN Process Definition
+
+Create a BPMN process with a signal throw event marked with external scope:
+
+```xml
+<?xml version="1.0" encoding="UTF-8"?>
+<bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL";
+                   targetNamespace="http://www.kogito.org/bpmn";>
+  
+  <bpmn2:signal id="OrderApprovalSignal" name="OrderApproval"/>
+  
+  <bpmn2:process id="order-process" name="Order Process">
+    
+    <bpmn2:startEvent id="start" name="Start"/>
+    
+    <!-- External Signal Throw Event -->
+    <bpmn2:intermediateThrowEvent id="sendApproval" name="Send Approval 
Request">
+      <bpmn2:signalEventDefinition signalRef="OrderApprovalSignal">
+        <bpmn2:extensionElements>
+          <customScope>external</customScope>
+        </bpmn2:extensionElements>
+      </bpmn2:signalEventDefinition>
+    </bpmn2:intermediateThrowEvent>

Review Comment:
   The BPMN snippet shows `<customScope>external</customScope>` inside 
`<bpmn2:signalEventDefinition>`, but jBPM reads the scope from node metadata 
(`getMetaData("customScope")`) populated via `drools:metaData` on the throw 
event. As-is, the example is unlikely to work if copied into a jBPM/Kogito 
project.



##########
addons/common/external-signals/external-signals-runtime/src/main/java/org/kie/kogito/addons/externalsignals/runtime/DefaultExternalSignalDispatcher.java:
##########
@@ -0,0 +1,337 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.kogito.addons.externalsignals.runtime;
+
+import java.net.URI;
+import java.time.OffsetDateTime;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
+
+import org.kie.kogito.addons.externalsignals.ExternalSignalConfig;
+import org.kie.kogito.addons.externalsignals.ExternalSignalDispatchException;
+import org.kie.kogito.addons.externalsignals.ExternalSignalDispatcher;
+import org.kie.kogito.addons.externalsignals.ExternalSignalEvent;
+import org.kie.kogito.event.DataEvent;
+import org.kie.kogito.event.EventEmitter;
+import org.kie.kogito.event.impl.EventFactoryUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.cloudevents.CloudEvent;
+import io.cloudevents.CloudEventData;
+import io.cloudevents.SpecVersion;
+import io.cloudevents.core.builder.CloudEventBuilder;
+
+/**
+ * Default implementation of {@link ExternalSignalDispatcher} that uses 
Kogito's
+ * {@link EventEmitter} infrastructure for transport-agnostic signal 
dispatching.
+ * 
+ * This dispatcher:
+ * <ul>
+ * <li>Resolves the target topic/trigger based on configuration</li>
+ * <li>Transforms the signal event into a CloudEvent-compatible DataEvent</li>
+ * <li>Dispatches the event using the appropriate EventEmitter</li>
+ * <li>Operates in fire-and-forget mode (Phase 1)</li>
+ * </ul>
+ * 
+ * The actual transport mechanism (Kafka, HTTP, etc.) is determined by the
+ * EventEmitter implementation available at runtime through ServiceLoader.
+ *
+ * @see ExternalSignalEvent
+ * @see ExternalSignalConfig
+ * @see EventEmitter
+ */
+public class DefaultExternalSignalDispatcher implements 
ExternalSignalDispatcher {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(DefaultExternalSignalDispatcher.class);
+
+    private static final String EVENT_TYPE_PREFIX = 
"org.kie.kogito.signal.external";
+
+    private final ExternalSignalConfig config;
+
+    public DefaultExternalSignalDispatcher() {
+        this(new ExternalSignalConfigImpl());
+    }
+
+    /**
+     * Creates a new dispatcher with the specified configuration.
+     * 
+     * @param config the configuration to use
+     * @throws IllegalArgumentException if config is null
+     */

Review Comment:
   The constructor Javadoc says it throws `IllegalArgumentException` when 
`config` is null, but the implementation uses `Objects.requireNonNull`, which 
throws `NullPointerException`. The Javadoc should match the actual behavior (or 
the code should throw `IllegalArgumentException`).



##########
addons/common/external-signals/README.md:
##########
@@ -0,0 +1,293 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Kogito External Signals Addon
+
+This addon provides support for external signal scope in Kogito runtimes, 
enabling BPMN processes to send signals to external systems via messaging 
infrastructure (Kafka, HTTP, etc.).
+
+## Overview
+
+The External Signals addon allows BPMN signal throw events to dispatch signals 
outside the process engine scope. When a signal throw event is marked with an 
"external" scope, instead of being processed internally by the process engine, 
the signal is sent to an external system through Kogito's event infrastructure.
+
+### Key Features
+
+- **Transport-Agnostic**: Uses Kogito's `EventEmitter` infrastructure, 
supporting any transport (Kafka, HTTP, etc.)
+- **CloudEvent Compatible**: Signal events follow CloudEvent specifications 
for interoperability
+- **Configurable Routing**: Map signal names to specific topics/triggers via 
configuration
+- **Fire-and-Forget **: Signals are dispatched asynchronously without blocking 
the process
+- **Extensible**: Designed for future enhancements (correlation, 
request-response patterns)
+
+## Architecture
+
+### Components
+
+1. **ExternalSignalEvent** - CloudEvent-compatible signal event model
+2. **ExternalSignalDispatcher** - Interface for signal dispatching
+3. **ExternalSignalWorkItemHandler** - Handles "External Send Task" work items
+4. **ExternalSignalConfig** - Configuration for signal-to-topic mapping
+
+### How It Works
+
+```
+BPMN Process → Signal Throw Event (external scope) 
+    → ExternalSignalWorkItemHandler 
+    → ExternalSignalDispatcher 
+    → EventEmitter 
+    → External System (Kafka/HTTP/etc.)
+```
+
+## Installation
+
+### Maven
+
+Add the runtime dependency to your project:
+
+```xml
+<dependency>
+    <groupId>org.kie</groupId>
+    <artifactId>kogito-addons-external-signals-runtime</artifactId>
+</dependency>
+```
+
+The addon is automatically discovered via ServiceLoader and registers the work 
item handler.
+
+## Configuration
+
+Configure signal-to-topic mappings using application properties:
+
+### Properties
+
+```properties
+# Map specific signals to topics/triggers
+kogito.external-signals.mapping.OrderCreated=order-events
+kogito.external-signals.mapping.PaymentProcessed=payment-topic
+kogito.external-signals.mapping.InventoryUpdated=inventory-updates
+
+# Set custom default prefix for unmapped signals (default: 
"kogito-external-signal")
+kogito.external-signals.default-prefix=my-app-signal
+```
+
+### Topic Resolution
+
+The addon resolves topics using this priority:
+
+1. **Explicit Mapping**: If `kogito.external-signals.mapping.{signalName}` is 
configured, use that value
+2. **Default Convention**: Otherwise, use `{prefix}-{signalName}` where prefix 
defaults to `kogito-external-signal`
+
+**Examples:**
+
+| Signal Name | Configuration | Resolved Topic |
+|------------|---------------|----------------|
+| OrderCreated | `kogito.external-signals.mapping.OrderCreated=order-events` | 
`order-events` |
+| PaymentProcessed | (no mapping) | `kogito-external-signal-PaymentProcessed` |
+| InventoryUpdated | (custom prefix: `my-app`) | `my-app-InventoryUpdated` |
+
+## Usage
+
+### BPMN Process Definition
+
+Create a BPMN process with a signal throw event marked with external scope:
+
+```xml
+<?xml version="1.0" encoding="UTF-8"?>
+<bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL";
+                   targetNamespace="http://www.kogito.org/bpmn";>
+  
+  <bpmn2:signal id="OrderApprovalSignal" name="OrderApproval"/>
+  
+  <bpmn2:process id="order-process" name="Order Process">
+    
+    <bpmn2:startEvent id="start" name="Start"/>
+    
+    <!-- External Signal Throw Event -->
+    <bpmn2:intermediateThrowEvent id="sendApproval" name="Send Approval 
Request">
+      <bpmn2:signalEventDefinition signalRef="OrderApprovalSignal">
+        <bpmn2:extensionElements>
+          <customScope>external</customScope>
+        </bpmn2:extensionElements>
+      </bpmn2:signalEventDefinition>
+    </bpmn2:intermediateThrowEvent>
+    
+    <bpmn2:endEvent id="end" name="End"/>
+    
+    <bpmn2:sequenceFlow sourceRef="start" targetRef="sendApproval"/>
+    <bpmn2:sequenceFlow sourceRef="sendApproval" targetRef="end"/>
+    
+  </bpmn2:process>
+</bpmn2:definitions>
+```
+
+### Work Item Parameters
+
+The external signal work item supports these parameters:
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| Signal | String | Yes | Name of the signal to send |
+| Data | Object | No | Data payload to send with the signal |
+| SignalProcessInstanceId | String | No | Target process instance ID (for 
future correlation) |
+| SignalWorkItemId | String | No | Target work item ID (for future 
correlation) |
+| SignalDeploymentId | String | No | Target deployment ID (for future 
correlation) |
+
+### Event Structure
+
+External signals are dispatched as CloudEvent-compatible events:
+
+```json
+{
+  "specversion": "1.0",
+  "type": "org.kie.kogito.signal.external.OrderApproval",
+  "source": "kogito://process/order-123",
+  "id": "signal-correlation-id",
+  "time": "2024-01-15T10:30:00Z",
+  "data": {
+    "signalName": "OrderApproval",
+    "signalData": {
+      "orderId": "12345",
+      "amount": 1000.00
+    },
+    "sourceProcessInstanceId": "order-123",
+    "correlationId": "signal-correlation-id",
+    "timestamp": "2024-01-15T10:30:00Z",
+    "metadata": {
+      "workItemId": "wi-456",
+      "nodeInstanceId": "ni-789"
+    }
+  }
+}
+```
+
+## Integration with Messaging
+
+### Kafka
+
+When using with Kafka, ensure you have the Kafka addon:
+
+```xml
+<dependency>
+    <groupId>org.kie.kogito</groupId>
+    <artifactId>kogito-addons-quarkus-messaging</artifactId>
+</dependency>
+```
+
+Configure Kafka topics in `application.properties`:
+
+```properties
+# Map signals to Kafka topics
+kogito.external-signals.mapping.OrderCreated=orders
+kogito.external-signals.mapping.PaymentProcessed=payments
+
+# Kafka configuration
+mp.messaging.outgoing.orders.connector=smallrye-kafka
+mp.messaging.outgoing.orders.topic=order-events
+mp.messaging.outgoing.orders.value.serializer=org.apache.kafka.common.serialization.StringSerializer
+
+mp.messaging.outgoing.payments.connector=smallrye-kafka
+mp.messaging.outgoing.payments.topic=payment-events
+mp.messaging.outgoing.payments.value.serializer=org.apache.kafka.common.serialization.StringSerializer
+```
+
+### HTTP
+
+For HTTP-based event emission, configure the HTTP addon accordingly.
+
+## Current Limitations
+
+The current implementation has these characteristics:
+
+- **Fire-and-Forget**: Signals are dispatched asynchronously without waiting 
for responses
+- **No Correlation**: Response correlation is not yet implemented
+- **No Retry Logic**: Failed dispatches abort the work item (can be enhanced 
in future)
+
+## Future Enhancements (Roadmap)
+
+## Troubleshooting
+
+### Signal Not Dispatched
+
+**Problem**: External signal is not being sent to the external system.
+
+**Solutions**:
+1. Verify the addon is on the classpath
+2. Check that the signal throw event has `<customScope>external</customScope>`

Review Comment:
   This troubleshooting step references `<customScope>external</customScope>`, 
which doesn’t match how jBPM/Kogito reads the scope (it uses node metaData 
`customScope` via `drools:metaData`). Updating this avoids misleading users 
during debugging.



##########
kogito-bom/pom.xml:
##########
@@ -176,6 +176,17 @@
         <version>${project.version}</version>
         <classifier>sources</classifier>
       </dependency>
+      <!-- External signals Add-on-->
+      <dependency>
+        <groupId>org.kie</groupId>
+        <artifactId>kogito-addons-external-signals-api</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.kie</groupId>
+        <artifactId>kogito-addons-external-signals</artifactId>
+        <version>${project.version}</version>
+      </dependency>

Review Comment:
   In `kogito-bom`, add-ons are typically listed both as the main artifact and 
with a `sources` classifier (e.g., `kogito-addons-jobs-api`, 
`kie-addons-flyway`). The external-signals entries are missing the `sources` 
dependencies, which makes the BOM inconsistent and prevents consumers from 
resolving sources via dependencyManagement.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to