This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new e6ae7a3dad08 CAMEL-26185: camel-asterisk - QUEUE_STATUS and SIP_PEERS
return the events of the list (#29009)
e6ae7a3dad08 is described below
commit e6ae7a3dad087636e587b4d373a753c5fe3a3da6
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Nov 3 11:41:27 2026 +0100
CAMEL-26185: camel-asterisk - QUEUE_STATUS and SIP_PEERS return the events
of the list (#29009)
…vents 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 d78d31699e19..cbe623761a39 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
@@ -1030,6 +1030,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