This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-26185-asterisk-event-actions
in repository https://gitbox.apache.org/repos/asf/camel.git

commit c0c730f855b081580bc5d24cf34d6528de3a61cd
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Nov 2 23:46:48 2026 +0100

    CAMEL-26185: camel-asterisk - QUEUE_STATUS and SIP_PEERS return the events 
of the list
    
    QUEUE_STATUS and SIP_PEERS are event generating actions: Asterisk answers 
with a
    "will follow" response and sends the data as events. The producer sent every
    action with sendAction, so the body was only that response and the queue and
    peer events were lost. The producer now sends an EventGeneratingAction with
    sendEventGeneratingAction and sets the ResponseEvents (response and events) 
as
    the body. EXTENSION_STATE still gives the ManagerResponse.
    
    Adds a test against a fake AMI server, updates the body types, the component
    doc and the upgrade guide.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../apache/camel/catalog/components/asterisk.json  |   2 +-
 .../camel/catalog/docs/asterisk-component.adoc     |   9 +
 .../apache/camel/component/asterisk/asterisk.json  |   2 +-
 .../src/main/docs/asterisk-component.adoc          |   9 +
 .../component/asterisk/AsteriskConnection.java     |  16 ++
 .../camel/component/asterisk/AsteriskEndpoint.java |  19 +-
 .../camel/component/asterisk/AsteriskProducer.java |  20 +-
 .../asterisk/AsteriskProducerFakeServerTest.java   | 251 +++++++++++++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    |   8 +
 9 files changed, 326 insertions(+), 10 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/asterisk.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/asterisk.json
index 473fa1f31d1d..aa4a08e4aa59 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/asterisk.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/asterisk.json
@@ -37,7 +37,7 @@
   "bodyTypes": {
     "consumerOut": { "carriers": [ "pojo" ], "javaType": 
"org.asteriskjava.manager.event.ManagerEvent", "description": "The AMI event: a 
subclass of ManagerEvent such as NewChannelEvent or HangupEvent, with its 
simple class name in the CamelAsteriskEventName header. The ConnectEvent of the 
login comes first" },
     "producerIn": { "carriers": [ "any" ], "description": "The body is not 
read: the action comes from the action option or the CamelAsteriskAction 
header, and the extension and context of EXTENSION_STATE from the 
CamelAsteriskExtension and CamelAsteriskContext headers" },
-    "producerOut": { "carriers": [ "pojo" ], "javaType": 
"org.asteriskjava.manager.response.ManagerResponse", "description": "The 
ManagerResponse of the action, such as an ExtensionStateResponse; a 
ManagerError when Asterisk answers with an error. QUEUE_STATUS and SIP_PEERS 
give only the first response, not the events of the list" }
+    "producerOut": { "carriers": [ "pojo" ], "byOption": [ { "option": 
"action", "value": "QUEUE_STATUS", "carriers": [ "pojo" ], "javaType": 
"org.asteriskjava.manager.ResponseEvents" }, { "option": "action", "value": 
"SIP_PEERS", "carriers": [ "pojo" ], "javaType": 
"org.asteriskjava.manager.ResponseEvents" }, { "option": "action", "value": 
"EXTENSION_STATE", "carriers": [ "pojo" ], "javaType": 
"org.asteriskjava.manager.response.ManagerResponse" } ], "description": 
"QUEUE_STATUS and SIP_ [...]
   },
   "properties": {
     "name": { "index": 0, "kind": "path", "displayName": "Name", "group": 
"common", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Name of component" },
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/asterisk-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/asterisk-component.adoc
index 5bb9ae53215f..fbfd1c6669a6 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/asterisk-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/asterisk-component.adoc
@@ -49,6 +49,15 @@ Supported actions are:
 * SIP_PEERS: List SIP peers
 * EXTENSION_STATE: Check extension status
 
+QUEUE_STATUS and SIP_PEERS are answered with a list of events. The producer 
waits for the whole list and sets
+the `org.asteriskjava.manager.ResponseEvents` as the message body: 
`getResponse()` is the response of Asterisk,
+and `getEvents()` the events of the list, such as `QueueParamsEvent` and 
`QueueMemberEvent` for QUEUE_STATUS or
+`PeerEntryEvent` for SIP_PEERS, ending with the complete event 
(`QueueStatusCompleteEvent` or
+`PeerlistCompleteEvent`). To route each event on its own, split on 
`${body.events}`.
+
+EXTENSION_STATE sets the `ManagerResponse` (an `ExtensionStateResponse`) as 
the message body.
+When Asterisk answers with an error, the response is a `ManagerError`.
+
 == Examples
 
 === Producer Example
diff --git 
a/components/camel-asterisk/src/generated/resources/META-INF/org/apache/camel/component/asterisk/asterisk.json
 
b/components/camel-asterisk/src/generated/resources/META-INF/org/apache/camel/component/asterisk/asterisk.json
index 473fa1f31d1d..aa4a08e4aa59 100644
--- 
a/components/camel-asterisk/src/generated/resources/META-INF/org/apache/camel/component/asterisk/asterisk.json
+++ 
b/components/camel-asterisk/src/generated/resources/META-INF/org/apache/camel/component/asterisk/asterisk.json
@@ -37,7 +37,7 @@
   "bodyTypes": {
     "consumerOut": { "carriers": [ "pojo" ], "javaType": 
"org.asteriskjava.manager.event.ManagerEvent", "description": "The AMI event: a 
subclass of ManagerEvent such as NewChannelEvent or HangupEvent, with its 
simple class name in the CamelAsteriskEventName header. The ConnectEvent of the 
login comes first" },
     "producerIn": { "carriers": [ "any" ], "description": "The body is not 
read: the action comes from the action option or the CamelAsteriskAction 
header, and the extension and context of EXTENSION_STATE from the 
CamelAsteriskExtension and CamelAsteriskContext headers" },
-    "producerOut": { "carriers": [ "pojo" ], "javaType": 
"org.asteriskjava.manager.response.ManagerResponse", "description": "The 
ManagerResponse of the action, such as an ExtensionStateResponse; a 
ManagerError when Asterisk answers with an error. QUEUE_STATUS and SIP_PEERS 
give only the first response, not the events of the list" }
+    "producerOut": { "carriers": [ "pojo" ], "byOption": [ { "option": 
"action", "value": "QUEUE_STATUS", "carriers": [ "pojo" ], "javaType": 
"org.asteriskjava.manager.ResponseEvents" }, { "option": "action", "value": 
"SIP_PEERS", "carriers": [ "pojo" ], "javaType": 
"org.asteriskjava.manager.ResponseEvents" }, { "option": "action", "value": 
"EXTENSION_STATE", "carriers": [ "pojo" ], "javaType": 
"org.asteriskjava.manager.response.ManagerResponse" } ], "description": 
"QUEUE_STATUS and SIP_ [...]
   },
   "properties": {
     "name": { "index": 0, "kind": "path", "displayName": "Name", "group": 
"common", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Name of component" },
diff --git a/components/camel-asterisk/src/main/docs/asterisk-component.adoc 
b/components/camel-asterisk/src/main/docs/asterisk-component.adoc
index 5bb9ae53215f..fbfd1c6669a6 100644
--- a/components/camel-asterisk/src/main/docs/asterisk-component.adoc
+++ b/components/camel-asterisk/src/main/docs/asterisk-component.adoc
@@ -49,6 +49,15 @@ Supported actions are:
 * SIP_PEERS: List SIP peers
 * EXTENSION_STATE: Check extension status
 
+QUEUE_STATUS and SIP_PEERS are answered with a list of events. The producer 
waits for the whole list and sets
+the `org.asteriskjava.manager.ResponseEvents` as the message body: 
`getResponse()` is the response of Asterisk,
+and `getEvents()` the events of the list, such as `QueueParamsEvent` and 
`QueueMemberEvent` for QUEUE_STATUS or
+`PeerEntryEvent` for SIP_PEERS, ending with the complete event 
(`QueueStatusCompleteEvent` or
+`PeerlistCompleteEvent`). To route each event on its own, split on 
`${body.events}`.
+
+EXTENSION_STATE sets the `ManagerResponse` (an `ExtensionStateResponse`) as 
the message body.
+When Asterisk answers with an error, the response is a `ManagerError`.
+
 == Examples
 
 === Producer Example
diff --git 
a/components/camel-asterisk/src/main/java/org/apache/camel/component/asterisk/AsteriskConnection.java
 
b/components/camel-asterisk/src/main/java/org/apache/camel/component/asterisk/AsteriskConnection.java
index 81a57513e12f..b099aec5d061 100644
--- 
a/components/camel-asterisk/src/main/java/org/apache/camel/component/asterisk/AsteriskConnection.java
+++ 
b/components/camel-asterisk/src/main/java/org/apache/camel/component/asterisk/AsteriskConnection.java
@@ -19,11 +19,14 @@ package org.apache.camel.component.asterisk;
 import java.io.IOException;
 
 import org.asteriskjava.manager.AuthenticationFailedException;
+import org.asteriskjava.manager.EventTimeoutException;
 import org.asteriskjava.manager.ManagerConnection;
 import org.asteriskjava.manager.ManagerConnectionFactory;
 import org.asteriskjava.manager.ManagerConnectionState;
 import org.asteriskjava.manager.ManagerEventListener;
+import org.asteriskjava.manager.ResponseEvents;
 import org.asteriskjava.manager.TimeoutException;
+import org.asteriskjava.manager.action.EventGeneratingAction;
 import org.asteriskjava.manager.action.ManagerAction;
 import org.asteriskjava.manager.response.ManagerResponse;
 import org.slf4j.Logger;
@@ -43,6 +46,13 @@ public final class AsteriskConnection {
         this.password = password;
     }
 
+    AsteriskConnection(ManagerConnection managerConnection) {
+        this.host = managerConnection.getHostname();
+        this.username = managerConnection.getUsername();
+        this.password = managerConnection.getPassword();
+        this.managerConnection = managerConnection;
+    }
+
     public void connect() {
         if (managerConnection == null) {
             LOG.debug("asterisk connection attempt to {} username: {}", host, 
username);
@@ -104,4 +114,10 @@ public final class AsteriskConnection {
 
         return managerConnection.sendAction(action);
     }
+
+    public ResponseEvents sendEventGeneratingAction(EventGeneratingAction 
action)
+            throws IllegalArgumentException, IllegalStateException, 
IOException, EventTimeoutException {
+
+        return managerConnection.sendEventGeneratingAction(action);
+    }
 }
diff --git 
a/components/camel-asterisk/src/main/java/org/apache/camel/component/asterisk/AsteriskEndpoint.java
 
b/components/camel-asterisk/src/main/java/org/apache/camel/component/asterisk/AsteriskEndpoint.java
index 88d35537b63d..97740ea38bd1 100644
--- 
a/components/camel-asterisk/src/main/java/org/apache/camel/component/asterisk/AsteriskEndpoint.java
+++ 
b/components/camel-asterisk/src/main/java/org/apache/camel/component/asterisk/AsteriskEndpoint.java
@@ -47,10 +47,21 @@ import org.apache.camel.util.ObjectHelper;
                                                 + " CamelAsteriskAction 
header, and the extension and context of"
                                                 + " EXTENSION_STATE from the 
CamelAsteriskExtension and"
                                                 + " CamelAsteriskContext 
headers"),
-           producerOut = @BodyType(value = Carrier.POJO, javaType = 
"org.asteriskjava.manager.response.ManagerResponse",
-                                   description = "The ManagerResponse of the 
action, such as an ExtensionStateResponse; a"
-                                                 + " ManagerError when 
Asterisk answers with an error. QUEUE_STATUS and"
-                                                 + " SIP_PEERS give only the 
first response, not the events of the list"))
+           producerOut = @BodyType(value = Carrier.POJO,
+                                   byOption = {
+                                           @BodyType.When(option = "action", 
value = "QUEUE_STATUS", carriers = Carrier.POJO,
+                                                          javaType = 
"org.asteriskjava.manager.ResponseEvents"),
+                                           @BodyType.When(option = "action", 
value = "SIP_PEERS", carriers = Carrier.POJO,
+                                                          javaType = 
"org.asteriskjava.manager.ResponseEvents"),
+                                           @BodyType.When(option = "action", 
value = "EXTENSION_STATE",
+                                                          carriers = 
Carrier.POJO,
+                                                          javaType = 
"org.asteriskjava.manager.response.ManagerResponse") },
+                                   description = "QUEUE_STATUS and SIP_PEERS 
give the ResponseEvents of asterisk-java: the"
+                                                 + " ManagerResponse in 
getResponse() and the events of the list in"
+                                                 + " getEvents(), such as 
QueueParamsEvent and QueueMemberEvent or"
+                                                 + " PeerEntryEvent, ending 
with the complete event. EXTENSION_STATE gives"
+                                                 + " the ManagerResponse, an 
ExtensionStateResponse. A ManagerError is the"
+                                                 + " response when Asterisk 
answers with an error"))
 public class AsteriskEndpoint extends DefaultEndpoint implements 
EndpointServiceLocation {
     @UriPath(description = "Name of component")
     @Metadata(required = true)
diff --git 
a/components/camel-asterisk/src/main/java/org/apache/camel/component/asterisk/AsteriskProducer.java
 
b/components/camel-asterisk/src/main/java/org/apache/camel/component/asterisk/AsteriskProducer.java
index 0e85e34a3ba2..db1b1e5c7215 100644
--- 
a/components/camel-asterisk/src/main/java/org/apache/camel/component/asterisk/AsteriskProducer.java
+++ 
b/components/camel-asterisk/src/main/java/org/apache/camel/component/asterisk/AsteriskProducer.java
@@ -19,6 +19,8 @@ package org.apache.camel.component.asterisk;
 import org.apache.camel.Exchange;
 import org.apache.camel.support.DefaultProducer;
 import org.apache.camel.util.ObjectHelper;
+import org.asteriskjava.manager.ResponseEvents;
+import org.asteriskjava.manager.action.EventGeneratingAction;
 import org.asteriskjava.manager.action.ManagerAction;
 import org.asteriskjava.manager.response.ManagerResponse;
 import org.slf4j.Logger;
@@ -35,10 +37,14 @@ public class AsteriskProducer extends DefaultProducer {
     private final AsteriskConnection connection;
 
     public AsteriskProducer(AsteriskEndpoint endpoint) {
+        this(endpoint, new AsteriskConnection(endpoint.getHostname(), 
endpoint.getUsername(), endpoint.getPassword()));
+    }
+
+    AsteriskProducer(AsteriskEndpoint endpoint, AsteriskConnection connection) 
{
         super(endpoint);
 
         this.endpoint = endpoint;
-        this.connection = new AsteriskConnection(endpoint.getHostname(), 
endpoint.getUsername(), endpoint.getPassword());
+        this.connection = connection;
     }
 
     @Override
@@ -70,9 +76,15 @@ public class AsteriskProducer extends DefaultProducer {
         LOG.debug("Send action {}", action);
 
         ManagerAction managerAction = action.apply(exchange);
-        ManagerResponse managerResponse = connection.sendAction(managerAction);
-
-        exchange.getIn().setBody(managerResponse);
+        if (managerAction instanceof EventGeneratingAction 
eventGeneratingAction) {
+            // such as QUEUE_STATUS and SIP_PEERS: the response only says that 
the
+            // list will follow, the data comes as events until the complete 
event
+            ResponseEvents responseEvents = 
connection.sendEventGeneratingAction(eventGeneratingAction);
+            exchange.getIn().setBody(responseEvents);
+        } else {
+            ManagerResponse managerResponse = 
connection.sendAction(managerAction);
+            exchange.getIn().setBody(managerResponse);
+        }
     }
 
 }
diff --git 
a/components/camel-asterisk/src/test/java/org/apache/camel/component/asterisk/AsteriskProducerFakeServerTest.java
 
b/components/camel-asterisk/src/test/java/org/apache/camel/component/asterisk/AsteriskProducerFakeServerTest.java
new file mode 100644
index 000000000000..a73478d8a5ec
--- /dev/null
+++ 
b/components/camel-asterisk/src/test/java/org/apache/camel/component/asterisk/AsteriskProducerFakeServerTest.java
@@ -0,0 +1,251 @@
+/*
+ * 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.apache.camel.component.asterisk;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.asteriskjava.manager.ResponseEvents;
+import org.asteriskjava.manager.event.PeerEntryEvent;
+import org.asteriskjava.manager.event.PeerlistCompleteEvent;
+import org.asteriskjava.manager.event.QueueMemberEvent;
+import org.asteriskjava.manager.event.QueueParamsEvent;
+import org.asteriskjava.manager.event.QueueStatusCompleteEvent;
+import org.asteriskjava.manager.event.ResponseEvent;
+import org.asteriskjava.manager.internal.ManagerConnectionImpl;
+import org.asteriskjava.manager.response.ExtensionStateResponse;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+
+/**
+ * Runs the producer against a fake Asterisk Manager Interface (AMI) server on 
a random port.
+ */
+public class AsteriskProducerFakeServerTest extends CamelTestSupport {
+
+    private FakeAmiServer server;
+    private AsteriskProducer producer;
+
+    @BeforeEach
+    void startFakeServer() throws Exception {
+        server = new FakeAmiServer();
+        server.start();
+
+        AsteriskEndpoint endpoint = context.getEndpoint(
+                
"asterisk:fake?hostname=localhost&username=admin&password=secret&action=EXTENSION_STATE",
+                AsteriskEndpoint.class);
+
+        ManagerConnectionImpl managerConnection = new ManagerConnectionImpl();
+        
managerConnection.setHostname(InetAddress.getLoopbackAddress().getHostAddress());
+        managerConnection.setPort(server.getPort());
+        managerConnection.setUsername("admin");
+        managerConnection.setPassword("secret");
+
+        producer = new AsteriskProducer(endpoint, new 
AsteriskConnection(managerConnection));
+        producer.start();
+    }
+
+    @AfterEach
+    void stopFakeServer() throws Exception {
+        if (producer != null) {
+            producer.stop();
+        }
+        if (server != null) {
+            server.close();
+        }
+    }
+
+    @Test
+    void testQueueStatusReturnsTheEvents() throws Exception {
+        Exchange exchange = send(AsteriskAction.QUEUE_STATUS);
+
+        ResponseEvents responseEvents = assertInstanceOf(ResponseEvents.class, 
exchange.getMessage().getBody());
+        assertEquals("Success", responseEvents.getResponse().getResponse());
+
+        List<ResponseEvent> events = new 
ArrayList<>(responseEvents.getEvents());
+        assertEquals(3, events.size());
+        QueueParamsEvent params = assertInstanceOf(QueueParamsEvent.class, 
events.get(0));
+        assertEquals("support", params.getQueue());
+        assertEquals(2, params.getCalls());
+        QueueMemberEvent member = assertInstanceOf(QueueMemberEvent.class, 
events.get(1));
+        assertEquals("SIP/1001", member.getLocation());
+        assertInstanceOf(QueueStatusCompleteEvent.class, events.get(2));
+    }
+
+    @Test
+    void testSipPeersReturnsTheEvents() throws Exception {
+        Exchange exchange = send(AsteriskAction.SIP_PEERS);
+
+        ResponseEvents responseEvents = assertInstanceOf(ResponseEvents.class, 
exchange.getMessage().getBody());
+        assertEquals("Success", responseEvents.getResponse().getResponse());
+
+        List<ResponseEvent> events = new 
ArrayList<>(responseEvents.getEvents());
+        assertEquals(3, events.size());
+        assertEquals("1001", assertInstanceOf(PeerEntryEvent.class, 
events.get(0)).getObjectName());
+        assertEquals("1002", assertInstanceOf(PeerEntryEvent.class, 
events.get(1)).getObjectName());
+        assertInstanceOf(PeerlistCompleteEvent.class, events.get(2));
+    }
+
+    @Test
+    void testExtensionStateReturnsTheResponse() throws Exception {
+        Exchange exchange = producer.getEndpoint().createExchange();
+        exchange.getMessage().setHeader(AsteriskConstants.EXTENSION, "1001");
+        exchange.getMessage().setHeader(AsteriskConstants.CONTEXT, "default");
+        producer.process(exchange);
+
+        ExtensionStateResponse response
+                = assertInstanceOf(ExtensionStateResponse.class, 
exchange.getMessage().getBody());
+        assertEquals("1001", response.getExten());
+        assertEquals(0, response.getStatus());
+    }
+
+    private Exchange send(AsteriskAction action) throws Exception {
+        Exchange exchange = producer.getEndpoint().createExchange();
+        exchange.getMessage().setHeader(AsteriskConstants.ACTION, action);
+        producer.process(exchange);
+        return exchange;
+    }
+
+    /**
+     * Answers the AMI actions of asterisk-java: the login, the version lookup 
and the actions of the producer.
+     */
+    private static final class FakeAmiServer implements AutoCloseable {
+
+        private final ServerSocket serverSocket;
+        private final List<Socket> sockets = new ArrayList<>();
+
+        FakeAmiServer() throws IOException {
+            serverSocket = new ServerSocket(0, 50, 
InetAddress.getLoopbackAddress());
+        }
+
+        int getPort() {
+            return serverSocket.getLocalPort();
+        }
+
+        void start() {
+            Thread thread = new Thread(this::acceptLoop, "FakeAmiServer");
+            thread.setDaemon(true);
+            thread.start();
+        }
+
+        private void acceptLoop() {
+            while (!serverSocket.isClosed()) {
+                try {
+                    Socket socket = serverSocket.accept();
+                    synchronized (sockets) {
+                        sockets.add(socket);
+                    }
+                    Thread thread = new Thread(() -> serve(socket), 
"FakeAmiServer-connection");
+                    thread.setDaemon(true);
+                    thread.start();
+                } catch (IOException e) {
+                    // closed
+                    return;
+                }
+            }
+        }
+
+        private void serve(Socket socket) {
+            try (socket;
+                 BufferedReader reader
+                         = new BufferedReader(new 
InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8))) {
+                OutputStream out = socket.getOutputStream();
+                write(out, "Asterisk Call Manager/5.0.1\r\n");
+
+                Map<String, String> packet = new HashMap<>();
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    if (!line.isEmpty()) {
+                        int pos = line.indexOf(':');
+                        if (pos > 0) {
+                            packet.put(line.substring(0, 
pos).trim().toLowerCase(), line.substring(pos + 1).trim());
+                        }
+                        continue;
+                    }
+                    if (!packet.isEmpty()) {
+                        write(out, answer(packet.get("action"), 
packet.get("actionid")));
+                        packet.clear();
+                    }
+                }
+            } catch (IOException e) {
+                // the client logged off or the server is closed
+            }
+        }
+
+        private static String answer(String action, String actionId) {
+            String id = "ActionID: " + actionId + "\r\n";
+            switch (action == null ? "" : action.toLowerCase()) {
+                case "challenge":
+                    return "Response: Success\r\n" + id + "Challenge: 
123456789\r\n\r\n";
+                case "login":
+                    return "Response: Success\r\n" + id + "Message: 
Authentication accepted\r\n\r\n";
+                case "coresettings":
+                    return "Response: Success\r\n" + id + "AMIversion: 
5.0.1\r\nAsteriskVersion: 18.20.0\r\n\r\n";
+                case "queuestatus":
+                    return "Response: Success\r\n" + id + "EventList: 
start\r\nMessage: Queue status will follow\r\n\r\n"
+                           + "Event: QueueParams\r\nQueue: support\r\nMax: 
0\r\nStrategy: ringall\r\nCalls: 2\r\n" + id
+                           + "\r\n"
+                           + "Event: QueueMember\r\nQueue: support\r\nName: 
Alice\r\nLocation: SIP/1001\r\n"
+                           + "StateInterface: SIP/1001\r\nMembership: 
static\r\nPenalty: 0\r\nCallsTaken: 0\r\n"
+                           + "Status: 1\r\nPaused: 0\r\n" + id + "\r\n"
+                           + "Event: QueueStatusComplete\r\n" + id + 
"EventList: Complete\r\nListItems: 2\r\n\r\n";
+                case "sippeers":
+                    return "Response: Success\r\n" + id + "EventList: 
start\r\nMessage: Peer status list will follow\r\n\r\n"
+                           + "Event: PeerEntry\r\n" + id + "Channeltype: 
SIP\r\nObjectName: 1001\r\nStatus: OK (5 ms)\r\n\r\n"
+                           + "Event: PeerEntry\r\n" + id + "Channeltype: 
SIP\r\nObjectName: 1002\r\nStatus: UNKNOWN\r\n\r\n"
+                           + "Event: PeerlistComplete\r\n" + id + "EventList: 
Complete\r\nListItems: 2\r\n\r\n";
+                case "extensionstate":
+                    return "Response: Success\r\n" + id + "Message: Extension 
Status\r\nExten: 1001\r\nContext: default\r\n"
+                           + "Hint: SIP/1001\r\nStatus: 0\r\n\r\n";
+                case "logoff":
+                    return "Response: Goodbye\r\n" + id + "Message: Thanks for 
all the fish.\r\n\r\n";
+                default:
+                    return "Response: Success\r\n" + id + "\r\n";
+            }
+        }
+
+        private static void write(OutputStream out, String text) throws 
IOException {
+            out.write(text.getBytes(StandardCharsets.UTF_8));
+            out.flush();
+        }
+
+        @Override
+        public void close() throws IOException {
+            serverSocket.close();
+            synchronized (sockets) {
+                for (Socket socket : sockets) {
+                    socket.close();
+                }
+            }
+        }
+    }
+}
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index 10f5a47c1b89..5a5fcb003cb9 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -903,6 +903,14 @@ explicitly (for example `partner.example:8443`).
 
 A deployment that lists a bare host and receives asynchronous MDNs on a 
non-default port must add the port to the entry.
 
+=== camel-asterisk - QUEUE_STATUS and SIP_PEERS return the events of the list
+
+The `QUEUE_STATUS` and `SIP_PEERS` actions of the `asterisk` producer now wait 
for the whole list and set the
+`org.asteriskjava.manager.ResponseEvents` as the body: `getResponse()` is the 
response and `getEvents()` the
+events, such as `QueueParamsEvent`, `QueueMemberEvent` and `PeerEntryEvent`. 
Before, the body was only the
+`ManagerResponse` saying that the list will follow, and the events were lost. 
A route that read that response from
+the body now finds it in `${body.response}`. `EXTENSION_STATE` still sets the 
`ManagerResponse` as the body.
+
 === camel-jbang - camel validate and camel overview report the same endpoints 
no route consumes
 
 `camel validate source` and `camel overview` now use the same rules for a 
`direct:`, `seda:` or `disruptor:` endpoint

Reply via email to