diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/azure-servicebus.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/azure-servicebus.json index 81dbd9b326dcb..a2937fdd266ee 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/azure-servicebus.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/azure-servicebus.json @@ -31,28 +31,25 @@ "proxyOptions": { "index": 5, "kind": "property", "displayName": "Proxy Options", "group": "common", "label": "common", "required": false, "type": "object", "javaType": "com.azure.core.amqp.ProxyOptions", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the proxy configuration to use for ServiceBusSenderAsyncClient. When a proxy is configured, AMQP_WEB_SOCKETS must be used for the transport type." }, "serviceBusType": { "index": 6, "kind": "property", "displayName": "Service Bus Type", "group": "common", "label": "common", "required": true, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.ServiceBusType", "enum": [ "queue", "topic" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "queue", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "The service bus type of connection to execute. Queue is for typical queue option and topic for subscription based model." }, "bridgeErrorHandler": { "index": 7, "kind": "property", "displayName": "Bridge Error Handler", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, - "consumerOperation": { "index": 8, "kind": "property", "displayName": "Consumer Operation", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.ServiceBusConsumerOperationDefinition", "enum": [ "receiveMessages", "peekMessages" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "receiveMessages", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the desired operation to be used in the consumer" }, - "disableAutoComplete": { "index": 9, "kind": "property", "displayName": "Disable Auto Complete", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Disables auto-complete and auto-abandon of received messages. By default, a successfully processed message is completed. If an error happens when the message is abandoned." }, - "enableDeadLettering": { "index": 10, "kind": "property", "displayName": "Enable Dead Lettering", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Enable application level deadlettering to the subscription deadletter subqueue if deadletter related headers are set." }, - "maxAutoLockRenewDuration": { "index": 11, "kind": "property", "displayName": "Max Auto Lock Renew Duration", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "java.time.Duration", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "5m", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the amount of time to continue auto-renewing the lock. Setting ZERO disables auto-renewal. For ServiceBus receive mode (RECEIVE_AND_DELETE RECEIVE_AND_DELETE), auto-renewal is disabled." }, - "peekNumMaxMessages": { "index": 12, "kind": "property", "displayName": "Peek Num Max Messages", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Set the max number of messages to be peeked during the peek operation." }, - "prefetchCount": { "index": 13, "kind": "property", "displayName": "Prefetch Count", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the prefetch count of the receiver. For both PEEK_LOCK PEEK_LOCK and RECEIVE_AND_DELETE RECEIVE_AND_DELETE receive modes the default value is 1. Prefetch speeds up the message flow by aiming to have a message readily available for local retrieval when and before the application asks for one using receive message. Setting a non-zero value will prefetch that number of messages. Setting the value to zero turns prefetch off." }, - "receiverAsyncClient": { "index": 14, "kind": "property", "displayName": "Receiver Async Client", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the receiverAsyncClient in order to consume messages by the consumer" }, - "serviceBusReceiveMode": { "index": 15, "kind": "property", "displayName": "Service Bus Receive Mode", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.models.ServiceBusReceiveMode", "enum": [ "PEEK_LOCK", "RECEIVE_AND_DELETE" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "PEEK_LOCK", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the receive mode for the receiver." }, - "subQueue": { "index": 16, "kind": "property", "displayName": "Sub Queue", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.models.SubQueue", "enum": [ "NONE", "DEAD_LETTER_QUEUE", "TRANSFER_DEAD_LETTER_QUEUE" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the type of the SubQueue to connect to." }, - "subscriptionName": { "index": 17, "kind": "property", "displayName": "Subscription Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the name of the subscription in the topic to listen to. topicOrQueueName and serviceBusType=topic must also be set. This property is required if serviceBusType=topic and the consumer is in use." }, - "reconnectDelay": { "index": 18, "kind": "property", "displayName": "Reconnect Delay", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "If the consumer has connection failure to Azure ServiceBus, then delay (millis) some time before re-connecting." }, - "binary": { "index": 19, "kind": "property", "displayName": "Binary", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Set binary mode. If true, message body will be sent as byte. By default, it is false." }, - "lazyStartProducer": { "index": 20, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, - "producerOperation": { "index": 21, "kind": "property", "displayName": "Producer Operation", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.ServiceBusProducerOperationDefinition", "enum": [ "sendMessages", "scheduleMessages" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "sendMessages", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the desired operation to be used in the producer" }, - "scheduledEnqueueTime": { "index": 22, "kind": "property", "displayName": "Scheduled Enqueue Time", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "java.time.OffsetDateTime", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets OffsetDateTime at which the message should appear in the Service Bus queue or topic." }, - "senderAsyncClient": { "index": 23, "kind": "property", "displayName": "Sender Async Client", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusSenderAsyncClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets SenderAsyncClient to be used in the producer." }, - "serviceBusTransactionContext": { "index": 24, "kind": "property", "displayName": "Service Bus Transaction Context", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusTransactionContext", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Represents transaction in service. This object just contains transaction id." }, - "autowiredEnabled": { "index": 25, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." }, - "connectionString": { "index": 26, "kind": "property", "displayName": "Connection String", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the connection string for a Service Bus namespace or a specific Service Bus resource." }, - "credentialType": { "index": 27, "kind": "property", "displayName": "Credential Type", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.CredentialType", "enum": [ "AZURE_IDENTITY", "CONNECTION_STRING", "TOKEN_CREDENTIAL" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "CONNECTION_STRING", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Determines the credential strategy to adopt" }, - "fullyQualifiedNamespace": { "index": 28, "kind": "property", "displayName": "Fully Qualified Namespace", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Fully Qualified Namespace of the service bus" }, - "tokenCredential": { "index": 29, "kind": "property", "displayName": "Token Credential", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "com.azure.core.credential.TokenCredential", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "A TokenCredential for Azure AD authentication." } + "enableDeadLettering": { "index": 8, "kind": "property", "displayName": "Enable Dead Lettering", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Enable application level deadlettering to the subscription deadletter subqueue if deadletter related headers are set." }, + "maxAutoLockRenewDuration": { "index": 9, "kind": "property", "displayName": "Max Auto Lock Renew Duration", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "java.time.Duration", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "5m", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the amount of time to continue auto-renewing the lock. Setting ZERO disables auto-renewal. For ServiceBus receive mode (RECEIVE_AND_DELETE RECEIVE_AND_DELETE), auto-renewal is disabled." }, + "maxConcurrentCalls": { "index": 10, "kind": "property", "displayName": "Max Concurrent Calls", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets maximum number of concurrent calls" }, + "prefetchCount": { "index": 11, "kind": "property", "displayName": "Prefetch Count", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the prefetch count of the receiver. For both PEEK_LOCK PEEK_LOCK and RECEIVE_AND_DELETE RECEIVE_AND_DELETE receive modes the default value is 1. Prefetch speeds up the message flow by aiming to have a message readily available for local retrieval when and before the application asks for one using receive message. Setting a non-zero value will prefetch that number of messages. Setting the value to zero turns prefetch off." }, + "processorClient": { "index": 12, "kind": "property", "displayName": "Processor Client", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusProcessorClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the processorClient in order to consume messages by the consumer" }, + "serviceBusReceiveMode": { "index": 13, "kind": "property", "displayName": "Service Bus Receive Mode", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.models.ServiceBusReceiveMode", "enum": [ "PEEK_LOCK", "RECEIVE_AND_DELETE" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "PEEK_LOCK", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the receive mode for the receiver." }, + "subQueue": { "index": 14, "kind": "property", "displayName": "Sub Queue", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.models.SubQueue", "enum": [ "NONE", "DEAD_LETTER_QUEUE", "TRANSFER_DEAD_LETTER_QUEUE" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the type of the SubQueue to connect to." }, + "subscriptionName": { "index": 15, "kind": "property", "displayName": "Subscription Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the name of the subscription in the topic to listen to. topicOrQueueName and serviceBusType=topic must also be set. This property is required if serviceBusType=topic and the consumer is in use." }, + "binary": { "index": 16, "kind": "property", "displayName": "Binary", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Set binary mode. If true, message body will be sent as byte. By default, it is false." }, + "lazyStartProducer": { "index": 17, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "producerOperation": { "index": 18, "kind": "property", "displayName": "Producer Operation", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.ServiceBusProducerOperationDefinition", "enum": [ "sendMessages", "scheduleMessages" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "sendMessages", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the desired operation to be used in the producer" }, + "scheduledEnqueueTime": { "index": 19, "kind": "property", "displayName": "Scheduled Enqueue Time", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "java.time.OffsetDateTime", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets OffsetDateTime at which the message should appear in the Service Bus queue or topic." }, + "senderAsyncClient": { "index": 20, "kind": "property", "displayName": "Sender Async Client", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusSenderAsyncClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets SenderAsyncClient to be used in the producer." }, + "serviceBusTransactionContext": { "index": 21, "kind": "property", "displayName": "Service Bus Transaction Context", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusTransactionContext", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Represents transaction in service. This object just contains transaction id." }, + "autowiredEnabled": { "index": 22, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." }, + "connectionString": { "index": 23, "kind": "property", "displayName": "Connection String", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the connection string for a Service Bus namespace or a specific Service Bus resource." }, + "credentialType": { "index": 24, "kind": "property", "displayName": "Credential Type", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.CredentialType", "enum": [ "AZURE_IDENTITY", "CONNECTION_STRING", "TOKEN_CREDENTIAL" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "CONNECTION_STRING", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Determines the credential strategy to adopt" }, + "fullyQualifiedNamespace": { "index": 25, "kind": "property", "displayName": "Fully Qualified Namespace", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Fully Qualified Namespace of the service bus" }, + "tokenCredential": { "index": 26, "kind": "property", "displayName": "Token Credential", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "com.azure.core.credential.TokenCredential", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "A TokenCredential for Azure AD authentication." } }, "headers": { "CamelAzureServiceBusApplicationProperties": { "index": 0, "kind": "header", "displayName": "", "group": "common", "label": "common", "required": false, "javaType": "Map", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The application properties (also known as custom properties) on messages sent and received by the producer and consumer, respectively.", "constantName": "org.apache.camel.component.azure.servicebus.ServiceBusConstants#APPLICATION_PROPERTIES" }, @@ -89,29 +86,26 @@ "headerFilterStrategy": { "index": 4, "kind": "parameter", "displayName": "Header Filter Strategy", "group": "common", "label": "common", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "To use a custom HeaderFilterStrategy to filter Service Bus application properties to and from Camel message headers." }, "proxyOptions": { "index": 5, "kind": "parameter", "displayName": "Proxy Options", "group": "common", "label": "common", "required": false, "type": "object", "javaType": "com.azure.core.amqp.ProxyOptions", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the proxy configuration to use for ServiceBusSenderAsyncClient. When a proxy is configured, AMQP_WEB_SOCKETS must be used for the transport type." }, "serviceBusType": { "index": 6, "kind": "parameter", "displayName": "Service Bus Type", "group": "common", "label": "common", "required": true, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.ServiceBusType", "enum": [ "queue", "topic" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "queue", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "The service bus type of connection to execute. Queue is for typical queue option and topic for subscription based model." }, - "consumerOperation": { "index": 7, "kind": "parameter", "displayName": "Consumer Operation", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.ServiceBusConsumerOperationDefinition", "enum": [ "receiveMessages", "peekMessages" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "receiveMessages", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the desired operation to be used in the consumer" }, - "disableAutoComplete": { "index": 8, "kind": "parameter", "displayName": "Disable Auto Complete", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Disables auto-complete and auto-abandon of received messages. By default, a successfully processed message is completed. If an error happens when the message is abandoned." }, - "enableDeadLettering": { "index": 9, "kind": "parameter", "displayName": "Enable Dead Lettering", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Enable application level deadlettering to the subscription deadletter subqueue if deadletter related headers are set." }, - "maxAutoLockRenewDuration": { "index": 10, "kind": "parameter", "displayName": "Max Auto Lock Renew Duration", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "java.time.Duration", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "5m", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the amount of time to continue auto-renewing the lock. Setting ZERO disables auto-renewal. For ServiceBus receive mode (RECEIVE_AND_DELETE RECEIVE_AND_DELETE), auto-renewal is disabled." }, - "peekNumMaxMessages": { "index": 11, "kind": "parameter", "displayName": "Peek Num Max Messages", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Set the max number of messages to be peeked during the peek operation." }, - "prefetchCount": { "index": 12, "kind": "parameter", "displayName": "Prefetch Count", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the prefetch count of the receiver. For both PEEK_LOCK PEEK_LOCK and RECEIVE_AND_DELETE RECEIVE_AND_DELETE receive modes the default value is 1. Prefetch speeds up the message flow by aiming to have a message readily available for local retrieval when and before the application asks for one using receive message. Setting a non-zero value will prefetch that number of messages. Setting the value to zero turns prefetch off." }, - "receiverAsyncClient": { "index": 13, "kind": "parameter", "displayName": "Receiver Async Client", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the receiverAsyncClient in order to consume messages by the consumer" }, - "serviceBusReceiveMode": { "index": 14, "kind": "parameter", "displayName": "Service Bus Receive Mode", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.models.ServiceBusReceiveMode", "enum": [ "PEEK_LOCK", "RECEIVE_AND_DELETE" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "PEEK_LOCK", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the receive mode for the receiver." }, - "subQueue": { "index": 15, "kind": "parameter", "displayName": "Sub Queue", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.models.SubQueue", "enum": [ "NONE", "DEAD_LETTER_QUEUE", "TRANSFER_DEAD_LETTER_QUEUE" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the type of the SubQueue to connect to." }, - "subscriptionName": { "index": 16, "kind": "parameter", "displayName": "Subscription Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the name of the subscription in the topic to listen to. topicOrQueueName and serviceBusType=topic must also be set. This property is required if serviceBusType=topic and the consumer is in use." }, - "bridgeErrorHandler": { "index": 17, "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, - "exceptionHandler": { "index": 18, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, - "exchangePattern": { "index": 19, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." }, - "reconnectDelay": { "index": 20, "kind": "parameter", "displayName": "Reconnect Delay", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "If the consumer has connection failure to Azure ServiceBus, then delay (millis) some time before re-connecting." }, - "binary": { "index": 21, "kind": "parameter", "displayName": "Binary", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Set binary mode. If true, message body will be sent as byte. By default, it is false." }, - "producerOperation": { "index": 22, "kind": "parameter", "displayName": "Producer Operation", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.ServiceBusProducerOperationDefinition", "enum": [ "sendMessages", "scheduleMessages" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "sendMessages", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the desired operation to be used in the producer" }, - "scheduledEnqueueTime": { "index": 23, "kind": "parameter", "displayName": "Scheduled Enqueue Time", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "java.time.OffsetDateTime", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets OffsetDateTime at which the message should appear in the Service Bus queue or topic." }, - "senderAsyncClient": { "index": 24, "kind": "parameter", "displayName": "Sender Async Client", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusSenderAsyncClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets SenderAsyncClient to be used in the producer." }, - "serviceBusTransactionContext": { "index": 25, "kind": "parameter", "displayName": "Service Bus Transaction Context", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusTransactionContext", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Represents transaction in service. This object just contains transaction id." }, - "lazyStartProducer": { "index": 26, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, - "connectionString": { "index": 27, "kind": "parameter", "displayName": "Connection String", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the connection string for a Service Bus namespace or a specific Service Bus resource." }, - "credentialType": { "index": 28, "kind": "parameter", "displayName": "Credential Type", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.CredentialType", "enum": [ "AZURE_IDENTITY", "CONNECTION_STRING", "TOKEN_CREDENTIAL" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "CONNECTION_STRING", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Determines the credential strategy to adopt" }, - "fullyQualifiedNamespace": { "index": 29, "kind": "parameter", "displayName": "Fully Qualified Namespace", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Fully Qualified Namespace of the service bus" }, - "tokenCredential": { "index": 30, "kind": "parameter", "displayName": "Token Credential", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "com.azure.core.credential.TokenCredential", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "A TokenCredential for Azure AD authentication." } + "enableDeadLettering": { "index": 7, "kind": "parameter", "displayName": "Enable Dead Lettering", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Enable application level deadlettering to the subscription deadletter subqueue if deadletter related headers are set." }, + "maxAutoLockRenewDuration": { "index": 8, "kind": "parameter", "displayName": "Max Auto Lock Renew Duration", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "java.time.Duration", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "5m", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the amount of time to continue auto-renewing the lock. Setting ZERO disables auto-renewal. For ServiceBus receive mode (RECEIVE_AND_DELETE RECEIVE_AND_DELETE), auto-renewal is disabled." }, + "maxConcurrentCalls": { "index": 9, "kind": "parameter", "displayName": "Max Concurrent Calls", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets maximum number of concurrent calls" }, + "prefetchCount": { "index": 10, "kind": "parameter", "displayName": "Prefetch Count", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the prefetch count of the receiver. For both PEEK_LOCK PEEK_LOCK and RECEIVE_AND_DELETE RECEIVE_AND_DELETE receive modes the default value is 1. Prefetch speeds up the message flow by aiming to have a message readily available for local retrieval when and before the application asks for one using receive message. Setting a non-zero value will prefetch that number of messages. Setting the value to zero turns prefetch off." }, + "processorClient": { "index": 11, "kind": "parameter", "displayName": "Processor Client", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusProcessorClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the processorClient in order to consume messages by the consumer" }, + "serviceBusReceiveMode": { "index": 12, "kind": "parameter", "displayName": "Service Bus Receive Mode", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.models.ServiceBusReceiveMode", "enum": [ "PEEK_LOCK", "RECEIVE_AND_DELETE" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "PEEK_LOCK", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the receive mode for the receiver." }, + "subQueue": { "index": 13, "kind": "parameter", "displayName": "Sub Queue", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.models.SubQueue", "enum": [ "NONE", "DEAD_LETTER_QUEUE", "TRANSFER_DEAD_LETTER_QUEUE" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the type of the SubQueue to connect to." }, + "subscriptionName": { "index": 14, "kind": "parameter", "displayName": "Subscription Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the name of the subscription in the topic to listen to. topicOrQueueName and serviceBusType=topic must also be set. This property is required if serviceBusType=topic and the consumer is in use." }, + "bridgeErrorHandler": { "index": 15, "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "exceptionHandler": { "index": 16, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "exchangePattern": { "index": 17, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." }, + "binary": { "index": 18, "kind": "parameter", "displayName": "Binary", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Set binary mode. If true, message body will be sent as byte. By default, it is false." }, + "producerOperation": { "index": 19, "kind": "parameter", "displayName": "Producer Operation", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.ServiceBusProducerOperationDefinition", "enum": [ "sendMessages", "scheduleMessages" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "sendMessages", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the desired operation to be used in the producer" }, + "scheduledEnqueueTime": { "index": 20, "kind": "parameter", "displayName": "Scheduled Enqueue Time", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "java.time.OffsetDateTime", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets OffsetDateTime at which the message should appear in the Service Bus queue or topic." }, + "senderAsyncClient": { "index": 21, "kind": "parameter", "displayName": "Sender Async Client", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusSenderAsyncClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets SenderAsyncClient to be used in the producer." }, + "serviceBusTransactionContext": { "index": 22, "kind": "parameter", "displayName": "Service Bus Transaction Context", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusTransactionContext", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Represents transaction in service. This object just contains transaction id." }, + "lazyStartProducer": { "index": 23, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "connectionString": { "index": 24, "kind": "parameter", "displayName": "Connection String", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the connection string for a Service Bus namespace or a specific Service Bus resource." }, + "credentialType": { "index": 25, "kind": "parameter", "displayName": "Credential Type", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.CredentialType", "enum": [ "AZURE_IDENTITY", "CONNECTION_STRING", "TOKEN_CREDENTIAL" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "CONNECTION_STRING", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Determines the credential strategy to adopt" }, + "fullyQualifiedNamespace": { "index": 26, "kind": "parameter", "displayName": "Fully Qualified Namespace", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Fully Qualified Namespace of the service bus" }, + "tokenCredential": { "index": 27, "kind": "parameter", "displayName": "Token Credential", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "com.azure.core.credential.TokenCredential", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "A TokenCredential for Azure AD authentication." } } } diff --git a/components/camel-azure/camel-azure-servicebus/pom.xml b/components/camel-azure/camel-azure-servicebus/pom.xml index 85aa07ea4b261..53ed69bd136b8 100644 --- a/components/camel-azure/camel-azure-servicebus/pom.xml +++ b/components/camel-azure/camel-azure-servicebus/pom.xml @@ -72,6 +72,12 @@ camel-test-junit5 test + + org.assertj + assertj-core + ${assertj-version} + test + org.mockito mockito-core @@ -84,5 +90,12 @@ ${awaitility-version} test + + org.apache.camel + camel-test-infra-core + ${project.version} + test + test-jar + diff --git a/components/camel-azure/camel-azure-servicebus/src/generated/java/org/apache/camel/component/azure/servicebus/ServiceBusComponentConfigurer.java b/components/camel-azure/camel-azure-servicebus/src/generated/java/org/apache/camel/component/azure/servicebus/ServiceBusComponentConfigurer.java index f7e3d9e89e0d6..7d47146496355 100644 --- a/components/camel-azure/camel-azure-servicebus/src/generated/java/org/apache/camel/component/azure/servicebus/ServiceBusComponentConfigurer.java +++ b/components/camel-azure/camel-azure-servicebus/src/generated/java/org/apache/camel/component/azure/servicebus/ServiceBusComponentConfigurer.java @@ -44,12 +44,8 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "configuration": target.setConfiguration(property(camelContext, org.apache.camel.component.azure.servicebus.ServiceBusConfiguration.class, value)); return true; case "connectionstring": case "connectionString": getOrCreateConfiguration(target).setConnectionString(property(camelContext, java.lang.String.class, value)); return true; - case "consumeroperation": - case "consumerOperation": getOrCreateConfiguration(target).setConsumerOperation(property(camelContext, org.apache.camel.component.azure.servicebus.ServiceBusConsumerOperationDefinition.class, value)); return true; case "credentialtype": case "credentialType": getOrCreateConfiguration(target).setCredentialType(property(camelContext, org.apache.camel.component.azure.servicebus.CredentialType.class, value)); return true; - case "disableautocomplete": - case "disableAutoComplete": getOrCreateConfiguration(target).setDisableAutoComplete(property(camelContext, boolean.class, value)); return true; case "enabledeadlettering": case "enableDeadLettering": getOrCreateConfiguration(target).setEnableDeadLettering(property(camelContext, boolean.class, value)); return true; case "fullyqualifiednamespace": @@ -60,18 +56,16 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; case "maxautolockrenewduration": case "maxAutoLockRenewDuration": getOrCreateConfiguration(target).setMaxAutoLockRenewDuration(property(camelContext, java.time.Duration.class, value)); return true; - case "peeknummaxmessages": - case "peekNumMaxMessages": getOrCreateConfiguration(target).setPeekNumMaxMessages(property(camelContext, java.lang.Integer.class, value)); return true; + case "maxconcurrentcalls": + case "maxConcurrentCalls": getOrCreateConfiguration(target).setMaxConcurrentCalls(property(camelContext, int.class, value)); return true; case "prefetchcount": case "prefetchCount": getOrCreateConfiguration(target).setPrefetchCount(property(camelContext, int.class, value)); return true; + case "processorclient": + case "processorClient": getOrCreateConfiguration(target).setProcessorClient(property(camelContext, com.azure.messaging.servicebus.ServiceBusProcessorClient.class, value)); return true; case "produceroperation": case "producerOperation": getOrCreateConfiguration(target).setProducerOperation(property(camelContext, org.apache.camel.component.azure.servicebus.ServiceBusProducerOperationDefinition.class, value)); return true; case "proxyoptions": case "proxyOptions": getOrCreateConfiguration(target).setProxyOptions(property(camelContext, com.azure.core.amqp.ProxyOptions.class, value)); return true; - case "receiverasyncclient": - case "receiverAsyncClient": getOrCreateConfiguration(target).setReceiverAsyncClient(property(camelContext, com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient.class, value)); return true; - case "reconnectdelay": - case "reconnectDelay": getOrCreateConfiguration(target).setReconnectDelay(property(camelContext, int.class, value)); return true; case "scheduledenqueuetime": case "scheduledEnqueueTime": getOrCreateConfiguration(target).setScheduledEnqueueTime(property(camelContext, java.time.OffsetDateTime.class, value)); return true; case "senderasyncclient": @@ -94,7 +88,7 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj @Override public String[] getAutowiredNames() { - return new String[]{"receiverAsyncClient", "senderAsyncClient"}; + return new String[]{"processorClient", "senderAsyncClient"}; } @Override @@ -114,12 +108,8 @@ public Class getOptionType(String name, boolean ignoreCase) { case "configuration": return org.apache.camel.component.azure.servicebus.ServiceBusConfiguration.class; case "connectionstring": case "connectionString": return java.lang.String.class; - case "consumeroperation": - case "consumerOperation": return org.apache.camel.component.azure.servicebus.ServiceBusConsumerOperationDefinition.class; case "credentialtype": case "credentialType": return org.apache.camel.component.azure.servicebus.CredentialType.class; - case "disableautocomplete": - case "disableAutoComplete": return boolean.class; case "enabledeadlettering": case "enableDeadLettering": return boolean.class; case "fullyqualifiednamespace": @@ -130,18 +120,16 @@ public Class getOptionType(String name, boolean ignoreCase) { case "lazyStartProducer": return boolean.class; case "maxautolockrenewduration": case "maxAutoLockRenewDuration": return java.time.Duration.class; - case "peeknummaxmessages": - case "peekNumMaxMessages": return java.lang.Integer.class; + case "maxconcurrentcalls": + case "maxConcurrentCalls": return int.class; case "prefetchcount": case "prefetchCount": return int.class; + case "processorclient": + case "processorClient": return com.azure.messaging.servicebus.ServiceBusProcessorClient.class; case "produceroperation": case "producerOperation": return org.apache.camel.component.azure.servicebus.ServiceBusProducerOperationDefinition.class; case "proxyoptions": case "proxyOptions": return com.azure.core.amqp.ProxyOptions.class; - case "receiverasyncclient": - case "receiverAsyncClient": return com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient.class; - case "reconnectdelay": - case "reconnectDelay": return int.class; case "scheduledenqueuetime": case "scheduledEnqueueTime": return java.time.OffsetDateTime.class; case "senderasyncclient": @@ -180,12 +168,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "configuration": return target.getConfiguration(); case "connectionstring": case "connectionString": return getOrCreateConfiguration(target).getConnectionString(); - case "consumeroperation": - case "consumerOperation": return getOrCreateConfiguration(target).getConsumerOperation(); case "credentialtype": case "credentialType": return getOrCreateConfiguration(target).getCredentialType(); - case "disableautocomplete": - case "disableAutoComplete": return getOrCreateConfiguration(target).isDisableAutoComplete(); case "enabledeadlettering": case "enableDeadLettering": return getOrCreateConfiguration(target).isEnableDeadLettering(); case "fullyqualifiednamespace": @@ -196,18 +180,16 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "lazyStartProducer": return target.isLazyStartProducer(); case "maxautolockrenewduration": case "maxAutoLockRenewDuration": return getOrCreateConfiguration(target).getMaxAutoLockRenewDuration(); - case "peeknummaxmessages": - case "peekNumMaxMessages": return getOrCreateConfiguration(target).getPeekNumMaxMessages(); + case "maxconcurrentcalls": + case "maxConcurrentCalls": return getOrCreateConfiguration(target).getMaxConcurrentCalls(); case "prefetchcount": case "prefetchCount": return getOrCreateConfiguration(target).getPrefetchCount(); + case "processorclient": + case "processorClient": return getOrCreateConfiguration(target).getProcessorClient(); case "produceroperation": case "producerOperation": return getOrCreateConfiguration(target).getProducerOperation(); case "proxyoptions": case "proxyOptions": return getOrCreateConfiguration(target).getProxyOptions(); - case "receiverasyncclient": - case "receiverAsyncClient": return getOrCreateConfiguration(target).getReceiverAsyncClient(); - case "reconnectdelay": - case "reconnectDelay": return getOrCreateConfiguration(target).getReconnectDelay(); case "scheduledenqueuetime": case "scheduledEnqueueTime": return getOrCreateConfiguration(target).getScheduledEnqueueTime(); case "senderasyncclient": diff --git a/components/camel-azure/camel-azure-servicebus/src/generated/java/org/apache/camel/component/azure/servicebus/ServiceBusEndpointConfigurer.java b/components/camel-azure/camel-azure-servicebus/src/generated/java/org/apache/camel/component/azure/servicebus/ServiceBusEndpointConfigurer.java index 44b1f0d0cbc8f..66958cf64c8a7 100644 --- a/components/camel-azure/camel-azure-servicebus/src/generated/java/org/apache/camel/component/azure/servicebus/ServiceBusEndpointConfigurer.java +++ b/components/camel-azure/camel-azure-servicebus/src/generated/java/org/apache/camel/component/azure/servicebus/ServiceBusEndpointConfigurer.java @@ -34,12 +34,8 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "clientOptions": target.getConfiguration().setClientOptions(property(camelContext, com.azure.core.util.ClientOptions.class, value)); return true; case "connectionstring": case "connectionString": target.getConfiguration().setConnectionString(property(camelContext, java.lang.String.class, value)); return true; - case "consumeroperation": - case "consumerOperation": target.getConfiguration().setConsumerOperation(property(camelContext, org.apache.camel.component.azure.servicebus.ServiceBusConsumerOperationDefinition.class, value)); return true; case "credentialtype": case "credentialType": target.getConfiguration().setCredentialType(property(camelContext, org.apache.camel.component.azure.servicebus.CredentialType.class, value)); return true; - case "disableautocomplete": - case "disableAutoComplete": target.getConfiguration().setDisableAutoComplete(property(camelContext, boolean.class, value)); return true; case "enabledeadlettering": case "enableDeadLettering": target.getConfiguration().setEnableDeadLettering(property(camelContext, boolean.class, value)); return true; case "exceptionhandler": @@ -54,18 +50,16 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; case "maxautolockrenewduration": case "maxAutoLockRenewDuration": target.getConfiguration().setMaxAutoLockRenewDuration(property(camelContext, java.time.Duration.class, value)); return true; - case "peeknummaxmessages": - case "peekNumMaxMessages": target.getConfiguration().setPeekNumMaxMessages(property(camelContext, java.lang.Integer.class, value)); return true; + case "maxconcurrentcalls": + case "maxConcurrentCalls": target.getConfiguration().setMaxConcurrentCalls(property(camelContext, int.class, value)); return true; case "prefetchcount": case "prefetchCount": target.getConfiguration().setPrefetchCount(property(camelContext, int.class, value)); return true; + case "processorclient": + case "processorClient": target.getConfiguration().setProcessorClient(property(camelContext, com.azure.messaging.servicebus.ServiceBusProcessorClient.class, value)); return true; case "produceroperation": case "producerOperation": target.getConfiguration().setProducerOperation(property(camelContext, org.apache.camel.component.azure.servicebus.ServiceBusProducerOperationDefinition.class, value)); return true; case "proxyoptions": case "proxyOptions": target.getConfiguration().setProxyOptions(property(camelContext, com.azure.core.amqp.ProxyOptions.class, value)); return true; - case "receiverasyncclient": - case "receiverAsyncClient": target.getConfiguration().setReceiverAsyncClient(property(camelContext, com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient.class, value)); return true; - case "reconnectdelay": - case "reconnectDelay": target.getConfiguration().setReconnectDelay(property(camelContext, int.class, value)); return true; case "scheduledenqueuetime": case "scheduledEnqueueTime": target.getConfiguration().setScheduledEnqueueTime(property(camelContext, java.time.OffsetDateTime.class, value)); return true; case "senderasyncclient": @@ -88,7 +82,7 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj @Override public String[] getAutowiredNames() { - return new String[]{"receiverAsyncClient", "senderAsyncClient"}; + return new String[]{"processorClient", "senderAsyncClient"}; } @Override @@ -105,12 +99,8 @@ public Class getOptionType(String name, boolean ignoreCase) { case "clientOptions": return com.azure.core.util.ClientOptions.class; case "connectionstring": case "connectionString": return java.lang.String.class; - case "consumeroperation": - case "consumerOperation": return org.apache.camel.component.azure.servicebus.ServiceBusConsumerOperationDefinition.class; case "credentialtype": case "credentialType": return org.apache.camel.component.azure.servicebus.CredentialType.class; - case "disableautocomplete": - case "disableAutoComplete": return boolean.class; case "enabledeadlettering": case "enableDeadLettering": return boolean.class; case "exceptionhandler": @@ -125,18 +115,16 @@ public Class getOptionType(String name, boolean ignoreCase) { case "lazyStartProducer": return boolean.class; case "maxautolockrenewduration": case "maxAutoLockRenewDuration": return java.time.Duration.class; - case "peeknummaxmessages": - case "peekNumMaxMessages": return java.lang.Integer.class; + case "maxconcurrentcalls": + case "maxConcurrentCalls": return int.class; case "prefetchcount": case "prefetchCount": return int.class; + case "processorclient": + case "processorClient": return com.azure.messaging.servicebus.ServiceBusProcessorClient.class; case "produceroperation": case "producerOperation": return org.apache.camel.component.azure.servicebus.ServiceBusProducerOperationDefinition.class; case "proxyoptions": case "proxyOptions": return com.azure.core.amqp.ProxyOptions.class; - case "receiverasyncclient": - case "receiverAsyncClient": return com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient.class; - case "reconnectdelay": - case "reconnectDelay": return int.class; case "scheduledenqueuetime": case "scheduledEnqueueTime": return java.time.OffsetDateTime.class; case "senderasyncclient": @@ -172,12 +160,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "clientOptions": return target.getConfiguration().getClientOptions(); case "connectionstring": case "connectionString": return target.getConfiguration().getConnectionString(); - case "consumeroperation": - case "consumerOperation": return target.getConfiguration().getConsumerOperation(); case "credentialtype": case "credentialType": return target.getConfiguration().getCredentialType(); - case "disableautocomplete": - case "disableAutoComplete": return target.getConfiguration().isDisableAutoComplete(); case "enabledeadlettering": case "enableDeadLettering": return target.getConfiguration().isEnableDeadLettering(); case "exceptionhandler": @@ -192,18 +176,16 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "lazyStartProducer": return target.isLazyStartProducer(); case "maxautolockrenewduration": case "maxAutoLockRenewDuration": return target.getConfiguration().getMaxAutoLockRenewDuration(); - case "peeknummaxmessages": - case "peekNumMaxMessages": return target.getConfiguration().getPeekNumMaxMessages(); + case "maxconcurrentcalls": + case "maxConcurrentCalls": return target.getConfiguration().getMaxConcurrentCalls(); case "prefetchcount": case "prefetchCount": return target.getConfiguration().getPrefetchCount(); + case "processorclient": + case "processorClient": return target.getConfiguration().getProcessorClient(); case "produceroperation": case "producerOperation": return target.getConfiguration().getProducerOperation(); case "proxyoptions": case "proxyOptions": return target.getConfiguration().getProxyOptions(); - case "receiverasyncclient": - case "receiverAsyncClient": return target.getConfiguration().getReceiverAsyncClient(); - case "reconnectdelay": - case "reconnectDelay": return target.getConfiguration().getReconnectDelay(); case "scheduledenqueuetime": case "scheduledEnqueueTime": return target.getConfiguration().getScheduledEnqueueTime(); case "senderasyncclient": diff --git a/components/camel-azure/camel-azure-servicebus/src/generated/java/org/apache/camel/component/azure/servicebus/ServiceBusEndpointUriFactory.java b/components/camel-azure/camel-azure-servicebus/src/generated/java/org/apache/camel/component/azure/servicebus/ServiceBusEndpointUriFactory.java index 4775a77f32a69..d3a6b51d89ba3 100644 --- a/components/camel-azure/camel-azure-servicebus/src/generated/java/org/apache/camel/component/azure/servicebus/ServiceBusEndpointUriFactory.java +++ b/components/camel-azure/camel-azure-servicebus/src/generated/java/org/apache/camel/component/azure/servicebus/ServiceBusEndpointUriFactory.java @@ -23,16 +23,14 @@ public class ServiceBusEndpointUriFactory extends org.apache.camel.support.compo private static final Set SECRET_PROPERTY_NAMES; private static final Set MULTI_VALUE_PREFIXES; static { - Set props = new HashSet<>(31); + Set props = new HashSet<>(28); props.add("amqpRetryOptions"); props.add("amqpTransportType"); props.add("binary"); props.add("bridgeErrorHandler"); props.add("clientOptions"); props.add("connectionString"); - props.add("consumerOperation"); props.add("credentialType"); - props.add("disableAutoComplete"); props.add("enableDeadLettering"); props.add("exceptionHandler"); props.add("exchangePattern"); @@ -40,12 +38,11 @@ public class ServiceBusEndpointUriFactory extends org.apache.camel.support.compo props.add("headerFilterStrategy"); props.add("lazyStartProducer"); props.add("maxAutoLockRenewDuration"); - props.add("peekNumMaxMessages"); + props.add("maxConcurrentCalls"); props.add("prefetchCount"); + props.add("processorClient"); props.add("producerOperation"); props.add("proxyOptions"); - props.add("receiverAsyncClient"); - props.add("reconnectDelay"); props.add("scheduledEnqueueTime"); props.add("senderAsyncClient"); props.add("serviceBusReceiveMode"); diff --git a/components/camel-azure/camel-azure-servicebus/src/generated/resources/META-INF/org/apache/camel/component/azure/servicebus/azure-servicebus.json b/components/camel-azure/camel-azure-servicebus/src/generated/resources/META-INF/org/apache/camel/component/azure/servicebus/azure-servicebus.json index 81dbd9b326dcb..a2937fdd266ee 100644 --- a/components/camel-azure/camel-azure-servicebus/src/generated/resources/META-INF/org/apache/camel/component/azure/servicebus/azure-servicebus.json +++ b/components/camel-azure/camel-azure-servicebus/src/generated/resources/META-INF/org/apache/camel/component/azure/servicebus/azure-servicebus.json @@ -31,28 +31,25 @@ "proxyOptions": { "index": 5, "kind": "property", "displayName": "Proxy Options", "group": "common", "label": "common", "required": false, "type": "object", "javaType": "com.azure.core.amqp.ProxyOptions", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the proxy configuration to use for ServiceBusSenderAsyncClient. When a proxy is configured, AMQP_WEB_SOCKETS must be used for the transport type." }, "serviceBusType": { "index": 6, "kind": "property", "displayName": "Service Bus Type", "group": "common", "label": "common", "required": true, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.ServiceBusType", "enum": [ "queue", "topic" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "queue", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "The service bus type of connection to execute. Queue is for typical queue option and topic for subscription based model." }, "bridgeErrorHandler": { "index": 7, "kind": "property", "displayName": "Bridge Error Handler", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, - "consumerOperation": { "index": 8, "kind": "property", "displayName": "Consumer Operation", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.ServiceBusConsumerOperationDefinition", "enum": [ "receiveMessages", "peekMessages" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "receiveMessages", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the desired operation to be used in the consumer" }, - "disableAutoComplete": { "index": 9, "kind": "property", "displayName": "Disable Auto Complete", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Disables auto-complete and auto-abandon of received messages. By default, a successfully processed message is completed. If an error happens when the message is abandoned." }, - "enableDeadLettering": { "index": 10, "kind": "property", "displayName": "Enable Dead Lettering", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Enable application level deadlettering to the subscription deadletter subqueue if deadletter related headers are set." }, - "maxAutoLockRenewDuration": { "index": 11, "kind": "property", "displayName": "Max Auto Lock Renew Duration", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "java.time.Duration", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "5m", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the amount of time to continue auto-renewing the lock. Setting ZERO disables auto-renewal. For ServiceBus receive mode (RECEIVE_AND_DELETE RECEIVE_AND_DELETE), auto-renewal is disabled." }, - "peekNumMaxMessages": { "index": 12, "kind": "property", "displayName": "Peek Num Max Messages", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Set the max number of messages to be peeked during the peek operation." }, - "prefetchCount": { "index": 13, "kind": "property", "displayName": "Prefetch Count", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the prefetch count of the receiver. For both PEEK_LOCK PEEK_LOCK and RECEIVE_AND_DELETE RECEIVE_AND_DELETE receive modes the default value is 1. Prefetch speeds up the message flow by aiming to have a message readily available for local retrieval when and before the application asks for one using receive message. Setting a non-zero value will prefetch that number of messages. Setting the value to zero turns prefetch off." }, - "receiverAsyncClient": { "index": 14, "kind": "property", "displayName": "Receiver Async Client", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the receiverAsyncClient in order to consume messages by the consumer" }, - "serviceBusReceiveMode": { "index": 15, "kind": "property", "displayName": "Service Bus Receive Mode", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.models.ServiceBusReceiveMode", "enum": [ "PEEK_LOCK", "RECEIVE_AND_DELETE" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "PEEK_LOCK", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the receive mode for the receiver." }, - "subQueue": { "index": 16, "kind": "property", "displayName": "Sub Queue", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.models.SubQueue", "enum": [ "NONE", "DEAD_LETTER_QUEUE", "TRANSFER_DEAD_LETTER_QUEUE" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the type of the SubQueue to connect to." }, - "subscriptionName": { "index": 17, "kind": "property", "displayName": "Subscription Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the name of the subscription in the topic to listen to. topicOrQueueName and serviceBusType=topic must also be set. This property is required if serviceBusType=topic and the consumer is in use." }, - "reconnectDelay": { "index": 18, "kind": "property", "displayName": "Reconnect Delay", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "If the consumer has connection failure to Azure ServiceBus, then delay (millis) some time before re-connecting." }, - "binary": { "index": 19, "kind": "property", "displayName": "Binary", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Set binary mode. If true, message body will be sent as byte. By default, it is false." }, - "lazyStartProducer": { "index": 20, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, - "producerOperation": { "index": 21, "kind": "property", "displayName": "Producer Operation", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.ServiceBusProducerOperationDefinition", "enum": [ "sendMessages", "scheduleMessages" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "sendMessages", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the desired operation to be used in the producer" }, - "scheduledEnqueueTime": { "index": 22, "kind": "property", "displayName": "Scheduled Enqueue Time", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "java.time.OffsetDateTime", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets OffsetDateTime at which the message should appear in the Service Bus queue or topic." }, - "senderAsyncClient": { "index": 23, "kind": "property", "displayName": "Sender Async Client", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusSenderAsyncClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets SenderAsyncClient to be used in the producer." }, - "serviceBusTransactionContext": { "index": 24, "kind": "property", "displayName": "Service Bus Transaction Context", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusTransactionContext", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Represents transaction in service. This object just contains transaction id." }, - "autowiredEnabled": { "index": 25, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." }, - "connectionString": { "index": 26, "kind": "property", "displayName": "Connection String", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the connection string for a Service Bus namespace or a specific Service Bus resource." }, - "credentialType": { "index": 27, "kind": "property", "displayName": "Credential Type", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.CredentialType", "enum": [ "AZURE_IDENTITY", "CONNECTION_STRING", "TOKEN_CREDENTIAL" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "CONNECTION_STRING", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Determines the credential strategy to adopt" }, - "fullyQualifiedNamespace": { "index": 28, "kind": "property", "displayName": "Fully Qualified Namespace", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Fully Qualified Namespace of the service bus" }, - "tokenCredential": { "index": 29, "kind": "property", "displayName": "Token Credential", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "com.azure.core.credential.TokenCredential", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "A TokenCredential for Azure AD authentication." } + "enableDeadLettering": { "index": 8, "kind": "property", "displayName": "Enable Dead Lettering", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Enable application level deadlettering to the subscription deadletter subqueue if deadletter related headers are set." }, + "maxAutoLockRenewDuration": { "index": 9, "kind": "property", "displayName": "Max Auto Lock Renew Duration", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "java.time.Duration", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "5m", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the amount of time to continue auto-renewing the lock. Setting ZERO disables auto-renewal. For ServiceBus receive mode (RECEIVE_AND_DELETE RECEIVE_AND_DELETE), auto-renewal is disabled." }, + "maxConcurrentCalls": { "index": 10, "kind": "property", "displayName": "Max Concurrent Calls", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets maximum number of concurrent calls" }, + "prefetchCount": { "index": 11, "kind": "property", "displayName": "Prefetch Count", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the prefetch count of the receiver. For both PEEK_LOCK PEEK_LOCK and RECEIVE_AND_DELETE RECEIVE_AND_DELETE receive modes the default value is 1. Prefetch speeds up the message flow by aiming to have a message readily available for local retrieval when and before the application asks for one using receive message. Setting a non-zero value will prefetch that number of messages. Setting the value to zero turns prefetch off." }, + "processorClient": { "index": 12, "kind": "property", "displayName": "Processor Client", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusProcessorClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the processorClient in order to consume messages by the consumer" }, + "serviceBusReceiveMode": { "index": 13, "kind": "property", "displayName": "Service Bus Receive Mode", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.models.ServiceBusReceiveMode", "enum": [ "PEEK_LOCK", "RECEIVE_AND_DELETE" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "PEEK_LOCK", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the receive mode for the receiver." }, + "subQueue": { "index": 14, "kind": "property", "displayName": "Sub Queue", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.models.SubQueue", "enum": [ "NONE", "DEAD_LETTER_QUEUE", "TRANSFER_DEAD_LETTER_QUEUE" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the type of the SubQueue to connect to." }, + "subscriptionName": { "index": 15, "kind": "property", "displayName": "Subscription Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the name of the subscription in the topic to listen to. topicOrQueueName and serviceBusType=topic must also be set. This property is required if serviceBusType=topic and the consumer is in use." }, + "binary": { "index": 16, "kind": "property", "displayName": "Binary", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Set binary mode. If true, message body will be sent as byte. By default, it is false." }, + "lazyStartProducer": { "index": 17, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "producerOperation": { "index": 18, "kind": "property", "displayName": "Producer Operation", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.ServiceBusProducerOperationDefinition", "enum": [ "sendMessages", "scheduleMessages" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "sendMessages", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the desired operation to be used in the producer" }, + "scheduledEnqueueTime": { "index": 19, "kind": "property", "displayName": "Scheduled Enqueue Time", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "java.time.OffsetDateTime", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets OffsetDateTime at which the message should appear in the Service Bus queue or topic." }, + "senderAsyncClient": { "index": 20, "kind": "property", "displayName": "Sender Async Client", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusSenderAsyncClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets SenderAsyncClient to be used in the producer." }, + "serviceBusTransactionContext": { "index": 21, "kind": "property", "displayName": "Service Bus Transaction Context", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusTransactionContext", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Represents transaction in service. This object just contains transaction id." }, + "autowiredEnabled": { "index": 22, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." }, + "connectionString": { "index": 23, "kind": "property", "displayName": "Connection String", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the connection string for a Service Bus namespace or a specific Service Bus resource." }, + "credentialType": { "index": 24, "kind": "property", "displayName": "Credential Type", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.CredentialType", "enum": [ "AZURE_IDENTITY", "CONNECTION_STRING", "TOKEN_CREDENTIAL" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "CONNECTION_STRING", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Determines the credential strategy to adopt" }, + "fullyQualifiedNamespace": { "index": 25, "kind": "property", "displayName": "Fully Qualified Namespace", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Fully Qualified Namespace of the service bus" }, + "tokenCredential": { "index": 26, "kind": "property", "displayName": "Token Credential", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "com.azure.core.credential.TokenCredential", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "A TokenCredential for Azure AD authentication." } }, "headers": { "CamelAzureServiceBusApplicationProperties": { "index": 0, "kind": "header", "displayName": "", "group": "common", "label": "common", "required": false, "javaType": "Map", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The application properties (also known as custom properties) on messages sent and received by the producer and consumer, respectively.", "constantName": "org.apache.camel.component.azure.servicebus.ServiceBusConstants#APPLICATION_PROPERTIES" }, @@ -89,29 +86,26 @@ "headerFilterStrategy": { "index": 4, "kind": "parameter", "displayName": "Header Filter Strategy", "group": "common", "label": "common", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "To use a custom HeaderFilterStrategy to filter Service Bus application properties to and from Camel message headers." }, "proxyOptions": { "index": 5, "kind": "parameter", "displayName": "Proxy Options", "group": "common", "label": "common", "required": false, "type": "object", "javaType": "com.azure.core.amqp.ProxyOptions", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the proxy configuration to use for ServiceBusSenderAsyncClient. When a proxy is configured, AMQP_WEB_SOCKETS must be used for the transport type." }, "serviceBusType": { "index": 6, "kind": "parameter", "displayName": "Service Bus Type", "group": "common", "label": "common", "required": true, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.ServiceBusType", "enum": [ "queue", "topic" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "queue", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "The service bus type of connection to execute. Queue is for typical queue option and topic for subscription based model." }, - "consumerOperation": { "index": 7, "kind": "parameter", "displayName": "Consumer Operation", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.ServiceBusConsumerOperationDefinition", "enum": [ "receiveMessages", "peekMessages" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "receiveMessages", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the desired operation to be used in the consumer" }, - "disableAutoComplete": { "index": 8, "kind": "parameter", "displayName": "Disable Auto Complete", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Disables auto-complete and auto-abandon of received messages. By default, a successfully processed message is completed. If an error happens when the message is abandoned." }, - "enableDeadLettering": { "index": 9, "kind": "parameter", "displayName": "Enable Dead Lettering", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Enable application level deadlettering to the subscription deadletter subqueue if deadletter related headers are set." }, - "maxAutoLockRenewDuration": { "index": 10, "kind": "parameter", "displayName": "Max Auto Lock Renew Duration", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "java.time.Duration", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "5m", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the amount of time to continue auto-renewing the lock. Setting ZERO disables auto-renewal. For ServiceBus receive mode (RECEIVE_AND_DELETE RECEIVE_AND_DELETE), auto-renewal is disabled." }, - "peekNumMaxMessages": { "index": 11, "kind": "parameter", "displayName": "Peek Num Max Messages", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Set the max number of messages to be peeked during the peek operation." }, - "prefetchCount": { "index": 12, "kind": "parameter", "displayName": "Prefetch Count", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the prefetch count of the receiver. For both PEEK_LOCK PEEK_LOCK and RECEIVE_AND_DELETE RECEIVE_AND_DELETE receive modes the default value is 1. Prefetch speeds up the message flow by aiming to have a message readily available for local retrieval when and before the application asks for one using receive message. Setting a non-zero value will prefetch that number of messages. Setting the value to zero turns prefetch off." }, - "receiverAsyncClient": { "index": 13, "kind": "parameter", "displayName": "Receiver Async Client", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the receiverAsyncClient in order to consume messages by the consumer" }, - "serviceBusReceiveMode": { "index": 14, "kind": "parameter", "displayName": "Service Bus Receive Mode", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.models.ServiceBusReceiveMode", "enum": [ "PEEK_LOCK", "RECEIVE_AND_DELETE" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "PEEK_LOCK", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the receive mode for the receiver." }, - "subQueue": { "index": 15, "kind": "parameter", "displayName": "Sub Queue", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.models.SubQueue", "enum": [ "NONE", "DEAD_LETTER_QUEUE", "TRANSFER_DEAD_LETTER_QUEUE" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the type of the SubQueue to connect to." }, - "subscriptionName": { "index": 16, "kind": "parameter", "displayName": "Subscription Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the name of the subscription in the topic to listen to. topicOrQueueName and serviceBusType=topic must also be set. This property is required if serviceBusType=topic and the consumer is in use." }, - "bridgeErrorHandler": { "index": 17, "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, - "exceptionHandler": { "index": 18, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, - "exchangePattern": { "index": 19, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." }, - "reconnectDelay": { "index": 20, "kind": "parameter", "displayName": "Reconnect Delay", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "If the consumer has connection failure to Azure ServiceBus, then delay (millis) some time before re-connecting." }, - "binary": { "index": 21, "kind": "parameter", "displayName": "Binary", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Set binary mode. If true, message body will be sent as byte. By default, it is false." }, - "producerOperation": { "index": 22, "kind": "parameter", "displayName": "Producer Operation", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.ServiceBusProducerOperationDefinition", "enum": [ "sendMessages", "scheduleMessages" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "sendMessages", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the desired operation to be used in the producer" }, - "scheduledEnqueueTime": { "index": 23, "kind": "parameter", "displayName": "Scheduled Enqueue Time", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "java.time.OffsetDateTime", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets OffsetDateTime at which the message should appear in the Service Bus queue or topic." }, - "senderAsyncClient": { "index": 24, "kind": "parameter", "displayName": "Sender Async Client", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusSenderAsyncClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets SenderAsyncClient to be used in the producer." }, - "serviceBusTransactionContext": { "index": 25, "kind": "parameter", "displayName": "Service Bus Transaction Context", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusTransactionContext", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Represents transaction in service. This object just contains transaction id." }, - "lazyStartProducer": { "index": 26, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, - "connectionString": { "index": 27, "kind": "parameter", "displayName": "Connection String", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the connection string for a Service Bus namespace or a specific Service Bus resource." }, - "credentialType": { "index": 28, "kind": "parameter", "displayName": "Credential Type", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.CredentialType", "enum": [ "AZURE_IDENTITY", "CONNECTION_STRING", "TOKEN_CREDENTIAL" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "CONNECTION_STRING", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Determines the credential strategy to adopt" }, - "fullyQualifiedNamespace": { "index": 29, "kind": "parameter", "displayName": "Fully Qualified Namespace", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Fully Qualified Namespace of the service bus" }, - "tokenCredential": { "index": 30, "kind": "parameter", "displayName": "Token Credential", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "com.azure.core.credential.TokenCredential", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "A TokenCredential for Azure AD authentication." } + "enableDeadLettering": { "index": 7, "kind": "parameter", "displayName": "Enable Dead Lettering", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Enable application level deadlettering to the subscription deadletter subqueue if deadletter related headers are set." }, + "maxAutoLockRenewDuration": { "index": 8, "kind": "parameter", "displayName": "Max Auto Lock Renew Duration", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "java.time.Duration", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "5m", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the amount of time to continue auto-renewing the lock. Setting ZERO disables auto-renewal. For ServiceBus receive mode (RECEIVE_AND_DELETE RECEIVE_AND_DELETE), auto-renewal is disabled." }, + "maxConcurrentCalls": { "index": 9, "kind": "parameter", "displayName": "Max Concurrent Calls", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets maximum number of concurrent calls" }, + "prefetchCount": { "index": 10, "kind": "parameter", "displayName": "Prefetch Count", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the prefetch count of the receiver. For both PEEK_LOCK PEEK_LOCK and RECEIVE_AND_DELETE RECEIVE_AND_DELETE receive modes the default value is 1. Prefetch speeds up the message flow by aiming to have a message readily available for local retrieval when and before the application asks for one using receive message. Setting a non-zero value will prefetch that number of messages. Setting the value to zero turns prefetch off." }, + "processorClient": { "index": 11, "kind": "parameter", "displayName": "Processor Client", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusProcessorClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the processorClient in order to consume messages by the consumer" }, + "serviceBusReceiveMode": { "index": 12, "kind": "parameter", "displayName": "Service Bus Receive Mode", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.models.ServiceBusReceiveMode", "enum": [ "PEEK_LOCK", "RECEIVE_AND_DELETE" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "PEEK_LOCK", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the receive mode for the receiver." }, + "subQueue": { "index": 13, "kind": "parameter", "displayName": "Sub Queue", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.models.SubQueue", "enum": [ "NONE", "DEAD_LETTER_QUEUE", "TRANSFER_DEAD_LETTER_QUEUE" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the type of the SubQueue to connect to." }, + "subscriptionName": { "index": 14, "kind": "parameter", "displayName": "Subscription Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the name of the subscription in the topic to listen to. topicOrQueueName and serviceBusType=topic must also be set. This property is required if serviceBusType=topic and the consumer is in use." }, + "bridgeErrorHandler": { "index": 15, "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "exceptionHandler": { "index": 16, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "exchangePattern": { "index": 17, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." }, + "binary": { "index": 18, "kind": "parameter", "displayName": "Binary", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Set binary mode. If true, message body will be sent as byte. By default, it is false." }, + "producerOperation": { "index": 19, "kind": "parameter", "displayName": "Producer Operation", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.ServiceBusProducerOperationDefinition", "enum": [ "sendMessages", "scheduleMessages" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "sendMessages", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the desired operation to be used in the producer" }, + "scheduledEnqueueTime": { "index": 20, "kind": "parameter", "displayName": "Scheduled Enqueue Time", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "java.time.OffsetDateTime", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets OffsetDateTime at which the message should appear in the Service Bus queue or topic." }, + "senderAsyncClient": { "index": 21, "kind": "parameter", "displayName": "Sender Async Client", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusSenderAsyncClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets SenderAsyncClient to be used in the producer." }, + "serviceBusTransactionContext": { "index": 22, "kind": "parameter", "displayName": "Service Bus Transaction Context", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "com.azure.messaging.servicebus.ServiceBusTransactionContext", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Represents transaction in service. This object just contains transaction id." }, + "lazyStartProducer": { "index": 23, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "connectionString": { "index": 24, "kind": "parameter", "displayName": "Connection String", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Sets the connection string for a Service Bus namespace or a specific Service Bus resource." }, + "credentialType": { "index": 25, "kind": "parameter", "displayName": "Credential Type", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.component.azure.servicebus.CredentialType", "enum": [ "AZURE_IDENTITY", "CONNECTION_STRING", "TOKEN_CREDENTIAL" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "CONNECTION_STRING", "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Determines the credential strategy to adopt" }, + "fullyQualifiedNamespace": { "index": 26, "kind": "parameter", "displayName": "Fully Qualified Namespace", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "Fully Qualified Namespace of the service bus" }, + "tokenCredential": { "index": 27, "kind": "parameter", "displayName": "Token Credential", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "com.azure.core.credential.TokenCredential", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.azure.servicebus.ServiceBusConfiguration", "configurationField": "configuration", "description": "A TokenCredential for Azure AD authentication." } } } diff --git a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusComponent.java b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusComponent.java index 5e314007743e9..b7d161bd8a451 100644 --- a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusComponent.java +++ b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusComponent.java @@ -88,7 +88,7 @@ public void setConfiguration(ServiceBusConfiguration configuration) { } private void validateConfigurations(final ServiceBusConfiguration configuration) { - if (configuration.getReceiverAsyncClient() == null || configuration.getSenderAsyncClient() == null) { + if (configuration.getProcessorClient() == null || configuration.getSenderAsyncClient() == null) { if (ObjectHelper.isEmpty(configuration.getConnectionString()) && ObjectHelper.isEmpty(configuration.getFullyQualifiedNamespace())) { throw new IllegalArgumentException( diff --git a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConfiguration.java b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConfiguration.java index 55f2840134b8c..b25bcebf9edcc 100644 --- a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConfiguration.java +++ b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConfiguration.java @@ -24,7 +24,7 @@ import com.azure.core.amqp.ProxyOptions; import com.azure.core.credential.TokenCredential; import com.azure.core.util.ClientOptions; -import com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient; +import com.azure.messaging.servicebus.ServiceBusProcessorClient; import com.azure.messaging.servicebus.ServiceBusSenderAsyncClient; import com.azure.messaging.servicebus.ServiceBusTransactionContext; import com.azure.messaging.servicebus.models.ServiceBusReceiveMode; @@ -59,16 +59,12 @@ public class ServiceBusConfiguration implements Cloneable, HeaderFilterStrategyA @UriParam(label = "common", description = "To use a custom HeaderFilterStrategy to filter Service Bus application properties to and from Camel message headers.") private HeaderFilterStrategy headerFilterStrategy = new ServiceBusHeaderFilterStrategy(); - @UriParam(label = "consumer", defaultValue = "receiveMessages") - private ServiceBusConsumerOperationDefinition consumerOperation = ServiceBusConsumerOperationDefinition.receiveMessages; @UriParam(label = "consumer") @Metadata(autowired = true) - private ServiceBusReceiverAsyncClient receiverAsyncClient; + private ServiceBusProcessorClient processorClient; @UriParam(label = "consumer") private String subscriptionName; @UriParam(label = "consumer") - private boolean disableAutoComplete; - @UriParam(label = "consumer") private boolean enableDeadLettering; @UriParam(label = "consumer", defaultValue = "PEEK_LOCK") private ServiceBusReceiveMode serviceBusReceiveMode = ServiceBusReceiveMode.PEEK_LOCK; @@ -78,8 +74,8 @@ public class ServiceBusConfiguration implements Cloneable, HeaderFilterStrategyA private int prefetchCount; @UriParam(label = "consumer") private SubQueue subQueue; - @UriParam(label = "consumer") - private Integer peekNumMaxMessages; + @UriParam(label = "consumer", defaultValue = "1") + private int maxConcurrentCalls = 1; @UriParam(label = "producer", defaultValue = "sendMessages") private ServiceBusProducerOperationDefinition producerOperation = ServiceBusProducerOperationDefinition.sendMessages; @UriParam(label = "producer") @@ -94,8 +90,6 @@ public class ServiceBusConfiguration implements Cloneable, HeaderFilterStrategyA @UriParam(label = "security", enums = "AZURE_IDENTITY,CONNECTION_STRING,TOKEN_CREDENTIAL", defaultValue = "CONNECTION_STRING") private CredentialType credentialType = CONNECTION_STRING; - @UriParam(label = "consumer,advanced", defaultValue = "5000") - private int reconnectDelay = 5000; /** * Selected topic name or the queue name, that is depending on serviceBusType config. For example if @@ -202,26 +196,14 @@ public void setHeaderFilterStrategy(HeaderFilterStrategy headerFilterStrategy) { } /** - * Sets the receiverAsyncClient in order to consume messages by the consumer - */ - public ServiceBusReceiverAsyncClient getReceiverAsyncClient() { - return receiverAsyncClient; - } - - public void setReceiverAsyncClient(ServiceBusReceiverAsyncClient receiverAsyncClient) { - this.receiverAsyncClient = receiverAsyncClient; - } - - /** - * Disables auto-complete and auto-abandon of received messages. By default, a successfully processed message is - * completed. If an error happens when the message is abandoned. + * Sets the processorClient in order to consume messages by the consumer */ - public boolean isDisableAutoComplete() { - return disableAutoComplete; + public ServiceBusProcessorClient getProcessorClient() { + return processorClient; } - public void setDisableAutoComplete(boolean disableAutoComplete) { - this.disableAutoComplete = disableAutoComplete; + public void setProcessorClient(ServiceBusProcessorClient processorClient) { + this.processorClient = processorClient; } /** @@ -262,7 +244,7 @@ public void setMaxAutoLockRenewDuration(Duration maxAutoLockRenewDuration) { /** * Sets the prefetch count of the receiver. For both PEEK_LOCK PEEK_LOCK and RECEIVE_AND_DELETE RECEIVE_AND_DELETE * receive modes the default value is 1. - * + *

* Prefetch speeds up the message flow by aiming to have a message readily available for local retrieval when and * before the application asks for one using receive message. Setting a non-zero value will prefetch that number of * messages. Setting the value to zero turns prefetch off. @@ -286,6 +268,17 @@ public void setSubQueue(SubQueue subQueue) { this.subQueue = subQueue; } + /** + * Sets maximum number of concurrent calls + */ + public int getMaxConcurrentCalls() { + return maxConcurrentCalls; + } + + public void setMaxConcurrentCalls(int maxConcurrentCalls) { + this.maxConcurrentCalls = maxConcurrentCalls; + } + /** * Sets SenderAsyncClient to be used in the producer. */ @@ -319,17 +312,6 @@ public void setTokenCredential(TokenCredential tokenCredential) { this.tokenCredential = tokenCredential; } - /** - * Sets the desired operation to be used in the consumer - */ - public ServiceBusConsumerOperationDefinition getConsumerOperation() { - return consumerOperation; - } - - public void setConsumerOperation(ServiceBusConsumerOperationDefinition consumerOperation) { - this.consumerOperation = consumerOperation; - } - /** * Sets the desired operation to be used in the producer */ @@ -363,17 +345,6 @@ public void setScheduledEnqueueTime(OffsetDateTime scheduledEnqueueTime) { this.scheduledEnqueueTime = scheduledEnqueueTime; } - /** - * Set the max number of messages to be peeked during the peek operation. - */ - public Integer getPeekNumMaxMessages() { - return peekNumMaxMessages; - } - - public void setPeekNumMaxMessages(Integer peekNumMaxMessages) { - this.peekNumMaxMessages = peekNumMaxMessages; - } - /** * Set binary mode. If true, message body will be sent as byte[]. By default, it is false. */ @@ -396,17 +367,6 @@ public void setCredentialType(CredentialType credentialType) { this.credentialType = credentialType; } - public int getReconnectDelay() { - return reconnectDelay; - } - - /** - * If the consumer has connection failure to Azure ServiceBus, then delay (millis) some time before re-connecting. - */ - public void setReconnectDelay(int reconnectDelay) { - this.reconnectDelay = reconnectDelay; - } - // ************************************************* // // ************************************************* diff --git a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumer.java b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumer.java index 17551243b185f..a34a055a2a3b8 100644 --- a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumer.java +++ b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumer.java @@ -17,44 +17,30 @@ package org.apache.camel.component.azure.servicebus; import java.util.Arrays; -import java.util.EnumMap; import java.util.Map; import java.util.stream.Collectors; +import com.azure.messaging.servicebus.ServiceBusErrorContext; +import com.azure.messaging.servicebus.ServiceBusProcessorClient; import com.azure.messaging.servicebus.ServiceBusReceivedMessage; -import com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient; +import com.azure.messaging.servicebus.ServiceBusReceivedMessageContext; import com.azure.messaging.servicebus.models.DeadLetterOptions; import com.azure.messaging.servicebus.models.SubQueue; import org.apache.camel.AsyncCallback; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.Processor; -import org.apache.camel.RuntimeCamelException; -import org.apache.camel.component.azure.servicebus.client.ServiceBusClientFactory; -import org.apache.camel.component.azure.servicebus.client.ServiceBusReceiverAsyncClientWrapper; -import org.apache.camel.component.azure.servicebus.operations.ServiceBusReceiverOperations; import org.apache.camel.spi.HeaderFilterStrategy; import org.apache.camel.support.DefaultConsumer; import org.apache.camel.support.SynchronizationAdapter; import org.apache.camel.util.ObjectHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import reactor.core.scheduler.Schedulers; public class ServiceBusConsumer extends DefaultConsumer { private static final Logger LOG = LoggerFactory.getLogger(ServiceBusConsumer.class); - - private ServiceBusReceiverAsyncClientWrapper clientWrapper; - private ServiceBusReceiverOperations operations; - - private final Map operationsToExecute - = new EnumMap<>(ServiceBusConsumerOperationDefinition.class); - - { - bind(ServiceBusConsumerOperationDefinition.peekMessages, this::peekMessages); - bind(ServiceBusConsumerOperationDefinition.receiveMessages, this::receiveMessages); - } + private ServiceBusProcessorClient client; public ServiceBusConsumer(final ServiceBusEndpoint endpoint, final Processor processor) { super(endpoint, processor); @@ -64,35 +50,32 @@ public ServiceBusConsumer(final ServiceBusEndpoint endpoint, final Processor pro protected void doStart() throws Exception { super.doStart(); - createAndConnectClient(); - } - - protected void createAndConnectClient() { LOG.debug("Creating connection to Azure ServiceBus"); + client = getEndpoint().getServiceBusClientFactory().createServiceBusProcessorClient(getConfiguration(), + this::processMessage, this::processError); + client.start(); + } - // create the client - final ServiceBusReceiverAsyncClient client = getConfiguration().getReceiverAsyncClient() != null - ? getConfiguration().getReceiverAsyncClient() - : ServiceBusClientFactory.createServiceBusReceiverAsyncClient(getConfiguration()); - - // create the wrapper - clientWrapper = new ServiceBusReceiverAsyncClientWrapper(client); - - // create the operations - operations = new ServiceBusReceiverOperations(clientWrapper); - - // get the operation that we want to invoke - final ServiceBusConsumerOperationDefinition chosenOperation = getConfiguration().getConsumerOperation(); + private void processMessage(ServiceBusReceivedMessageContext messageContext) { + final ServiceBusReceivedMessage message = messageContext.getMessage(); + final Exchange exchange = createServiceBusExchange(message); + final ConsumerOnCompletion onCompletion = new ConsumerOnCompletion(messageContext); + // add exchange callback + exchange.getExchangeExtension().addOnCompletion(onCompletion); + // use default consumer callback + AsyncCallback cb = defaultConsumerCallback(exchange, true); + getAsyncProcessor().process(exchange, cb); + } - // invoke the operation and run it - invokeOperation(chosenOperation); + private void processError(ServiceBusErrorContext errorContext) { + LOG.error("Error from Service Bus client: {}", errorContext.getErrorSource(), errorContext.getException()); } @Override protected void doStop() throws Exception { - if (clientWrapper != null) { + if (client != null) { // shutdown the client - clientWrapper.close(); + client.close(); } // shutdown camel consumer @@ -108,53 +91,6 @@ public ServiceBusEndpoint getEndpoint() { return (ServiceBusEndpoint) super.getEndpoint(); } - private void bind(final ServiceBusConsumerOperationDefinition operation, Runnable fn) { - operationsToExecute.put(operation, fn); - } - - /** - * Entry method that selects the appropriate operation and executes it - */ - private void invokeOperation(final ServiceBusConsumerOperationDefinition operation) { - final ServiceBusConsumerOperationDefinition operationsToInvoke; - - if (ObjectHelper.isEmpty(operation)) { - operationsToInvoke = ServiceBusConsumerOperationDefinition.receiveMessages; - } else { - operationsToInvoke = operation; - } - - final Runnable fnToInvoke = operationsToExecute.get(operationsToInvoke); - - if (fnToInvoke != null) { - fnToInvoke.run(); - } else { - throw new RuntimeCamelException("Operation not supported. Value: " + operationsToInvoke); - } - } - - private void receiveMessages() { - operations.receiveMessages() - .subscribe(this::onEventListener, this::onErrorListener, () -> { - }); - } - - private void peekMessages() { - operations.peekMessages(getConfiguration().getPeekNumMaxMessages()) - .subscribe(this::onEventListener, this::onErrorListener, () -> { - }); - } - - private void onEventListener(final ServiceBusReceivedMessage message) { - final Exchange exchange = createServiceBusExchange(message); - final ConsumerOnCompletion onCompletion = new ConsumerOnCompletion(message); - // add exchange callback - exchange.getExchangeExtension().addOnCompletion(onCompletion); - // use default consumer callback - AsyncCallback cb = defaultConsumerCallback(exchange, true); - getAsyncProcessor().process(exchange, cb); - } - private Exchange createServiceBusExchange(final ServiceBusReceivedMessage receivedMessage) { final Exchange exchange = createExchange(true); final Message message = exchange.getIn(); @@ -196,41 +132,17 @@ private Exchange createServiceBusExchange(final ServiceBusReceivedMessage receiv return exchange; } - private void onErrorListener(final Throwable errorContext) { - LOG.warn("Error from Azure ServiceBus due to {} - Reconnecting in {} seconds", errorContext.getMessage(), - getConfiguration().getReconnectDelay()); - if (LOG.isDebugEnabled()) { - LOG.warn("Error from Azure ServiceBus (incl stacktrace)", errorContext); - } - if (getConfiguration().getReconnectDelay() > 0) { - try { - Thread.sleep(getConfiguration().getReconnectDelay()); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - - try { - clientWrapper.close(); - } catch (Exception e) { - // ignore - } - createAndConnectClient(); - } - private class ConsumerOnCompletion extends SynchronizationAdapter { - private final ServiceBusReceivedMessage message; + private final ServiceBusReceivedMessageContext messageContext; - public ConsumerOnCompletion(ServiceBusReceivedMessage message) { - this.message = message; + private ConsumerOnCompletion(ServiceBusReceivedMessageContext messageContext) { + this.messageContext = messageContext; } @Override public void onComplete(Exchange exchange) { super.onComplete(exchange); - if (!getConfiguration().isDisableAutoComplete()) { - clientWrapper.complete(message).subscribeOn(Schedulers.boundedElastic()).subscribe(); - } + messageContext.complete(); } @Override @@ -240,22 +152,21 @@ public void onFailure(Exchange exchange) { getExceptionHandler().handleException("Error during processing exchange.", exchange, cause); } - if (!getConfiguration().isDisableAutoComplete()) { - if (getConfiguration().isEnableDeadLettering() && (ObjectHelper.isEmpty(getConfiguration().getSubQueue()) || - ObjectHelper.equal(getConfiguration().getSubQueue(), SubQueue.NONE))) { - DeadLetterOptions deadLetterOptions = new DeadLetterOptions(); - if (cause != null) { - deadLetterOptions - .setDeadLetterReason(String.format("%s: %s", cause.getClass().getName(), cause.getMessage())); - deadLetterOptions.setDeadLetterErrorDescription(Arrays.stream(cause.getStackTrace()) - .map(StackTraceElement::toString) - .collect(Collectors.joining("\n"))); - } - clientWrapper.deadLetter(message, deadLetterOptions).subscribeOn(Schedulers.boundedElastic()).subscribe(); + if (getConfiguration().isEnableDeadLettering() && (ObjectHelper.isEmpty(getConfiguration().getSubQueue()) || + ObjectHelper.equal(getConfiguration().getSubQueue(), SubQueue.NONE))) { + DeadLetterOptions deadLetterOptions = new DeadLetterOptions(); + if (cause != null) { + deadLetterOptions + .setDeadLetterReason(String.format("%s: %s", cause.getClass().getName(), cause.getMessage())); + deadLetterOptions.setDeadLetterErrorDescription(Arrays.stream(cause.getStackTrace()) + .map(StackTraceElement::toString) + .collect(Collectors.joining("\n"))); + messageContext.deadLetter(deadLetterOptions); } else { - clientWrapper.abandon(message).subscribeOn(Schedulers.boundedElastic()).subscribe(); + messageContext.deadLetter(); } - + } else { + messageContext.abandon(); } } } diff --git a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumerOperationDefinition.java b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumerOperationDefinition.java deleted file mode 100644 index 89946fa2b65cf..0000000000000 --- a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumerOperationDefinition.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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.azure.servicebus; - -public enum ServiceBusConsumerOperationDefinition { - receiveMessages, - peekMessages -} diff --git a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusEndpoint.java b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusEndpoint.java index 64546cfb6bfc6..066dc6d2445b8 100644 --- a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusEndpoint.java +++ b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusEndpoint.java @@ -21,6 +21,7 @@ import org.apache.camel.Consumer; import org.apache.camel.Processor; import org.apache.camel.Producer; +import org.apache.camel.component.azure.servicebus.client.ServiceBusClientFactory; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.spi.UriParam; import org.apache.camel.support.DefaultEndpoint; @@ -36,6 +37,7 @@ public class ServiceBusEndpoint extends DefaultEndpoint { @UriParam private ServiceBusConfiguration configuration; + private ServiceBusClientFactory serviceBusClientFactory = new ServiceBusClientFactory(); public ServiceBusEndpoint(final String uri, final Component component, final ServiceBusConfiguration configuration) { super(uri, component); @@ -65,4 +67,15 @@ public ServiceBusConfiguration getConfiguration() { public void setConfiguration(ServiceBusConfiguration configuration) { this.configuration = configuration; } + + /** + * Set to use a custom client factory + */ + public ServiceBusClientFactory getServiceBusClientFactory() { + return serviceBusClientFactory; + } + + public void setServiceBusClientFactory(ServiceBusClientFactory serviceBusClientFactory) { + this.serviceBusClientFactory = serviceBusClientFactory; + } } diff --git a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusProducer.java b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusProducer.java index f13ff00abbf3e..3c2d2912ccd38 100644 --- a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusProducer.java +++ b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusProducer.java @@ -19,7 +19,10 @@ import java.io.File; import java.io.InputStream; import java.nio.file.Path; -import java.util.*; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -27,12 +30,7 @@ import com.azure.core.util.BinaryData; import com.azure.messaging.servicebus.ServiceBusSenderAsyncClient; -import org.apache.camel.AsyncCallback; -import org.apache.camel.Endpoint; -import org.apache.camel.Exchange; -import org.apache.camel.RuntimeCamelException; -import org.apache.camel.TypeConverter; -import org.apache.camel.component.azure.servicebus.client.ServiceBusClientFactory; +import org.apache.camel.*; import org.apache.camel.component.azure.servicebus.client.ServiceBusSenderAsyncClientWrapper; import org.apache.camel.component.azure.servicebus.operations.ServiceBusSenderOperations; import org.apache.camel.spi.HeaderFilterStrategy; @@ -45,14 +43,12 @@ public class ServiceBusProducer extends DefaultAsyncProducer { private static final Logger LOG = LoggerFactory.getLogger(ServiceBusProducer.class); - + private final Map> operationsToExecute + = new EnumMap<>(ServiceBusProducerOperationDefinition.class); private ServiceBusSenderAsyncClientWrapper senderClientWrapper; private ServiceBusConfigurationOptionsProxy configurationOptionsProxy; private ServiceBusSenderOperations serviceBusSenderOperations; - private final Map> operationsToExecute - = new EnumMap<>(ServiceBusProducerOperationDefinition.class); - { bind(ServiceBusProducerOperationDefinition.sendMessages, sendMessages()); bind(ServiceBusProducerOperationDefinition.scheduleMessages, scheduleMessages()); @@ -75,7 +71,7 @@ protected void doStart() throws Exception { // create the senderClient final ServiceBusSenderAsyncClient senderClient = getConfiguration().getSenderAsyncClient() != null ? getConfiguration().getSenderAsyncClient() - : ServiceBusClientFactory.createServiceBusSenderAsyncClient(getConfiguration()); + : getEndpoint().getServiceBusClientFactory().createServiceBusSenderAsyncClient(getConfiguration()); // create the wrapper senderClientWrapper = new ServiceBusSenderAsyncClientWrapper(senderClient); diff --git a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/client/ServiceBusClientFactory.java b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/client/ServiceBusClientFactory.java index 225f61da1c048..81bd3947319fc 100644 --- a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/client/ServiceBusClientFactory.java +++ b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/client/ServiceBusClientFactory.java @@ -16,11 +16,11 @@ */ package org.apache.camel.component.azure.servicebus.client; +import java.util.function.Consumer; + import com.azure.core.credential.TokenCredential; import com.azure.identity.DefaultAzureCredentialBuilder; -import com.azure.messaging.servicebus.ServiceBusClientBuilder; -import com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient; -import com.azure.messaging.servicebus.ServiceBusSenderAsyncClient; +import com.azure.messaging.servicebus.*; import org.apache.camel.component.azure.servicebus.CredentialType; import org.apache.camel.component.azure.servicebus.ServiceBusConfiguration; import org.apache.camel.component.azure.servicebus.ServiceBusType; @@ -28,25 +28,6 @@ public final class ServiceBusClientFactory { - private ServiceBusClientFactory() { - } - - public static ServiceBusSenderAsyncClient createServiceBusSenderAsyncClient(final ServiceBusConfiguration configuration) { - return createBaseServiceBusSenderClient(createBaseServiceBusClient(configuration), configuration) - .buildAsyncClient(); - } - - public static ServiceBusReceiverAsyncClient createServiceBusReceiverAsyncClient( - final ServiceBusConfiguration configuration) { - return createBaseServiceBusReceiverClient(createBaseServiceBusClient(configuration), configuration) - .prefetchCount(configuration.getPrefetchCount()) - .receiveMode(configuration.getServiceBusReceiveMode()) - .subQueue(configuration.getSubQueue()) - .maxAutoLockRenewDuration(configuration.getMaxAutoLockRenewDuration()) - .subscriptionName(configuration.getSubscriptionName()) - .buildAsyncClient(); - } - private static ServiceBusClientBuilder createBaseServiceBusClient(final ServiceBusConfiguration configuration) { ServiceBusClientBuilder builder = new ServiceBusClientBuilder() .transportType(configuration.getAmqpTransportType()) @@ -81,19 +62,44 @@ private static ServiceBusClientBuilder.ServiceBusSenderClientBuilder createBaseS } } - private static ServiceBusClientBuilder.ServiceBusReceiverClientBuilder createBaseServiceBusReceiverClient( + private static ServiceBusClientBuilder.ServiceBusProcessorClientBuilder createBaseServiceBusProcessorClient( final ServiceBusClientBuilder busClientBuilder, final ServiceBusConfiguration configuration) { - final ServiceBusClientBuilder.ServiceBusReceiverClientBuilder receiverClientBuilder = busClientBuilder.receiver(); + final ServiceBusClientBuilder.ServiceBusProcessorClientBuilder processorClientBuilder = busClientBuilder.processor(); // We handle auto-complete in the consumer, since we have no way to propagate errors back to the reactive // pipeline messages are published on so the message would be completed even if an error occurs during Exchange // processing. - receiverClientBuilder.disableAutoComplete(); + processorClientBuilder.disableAutoComplete(); - if (configuration.getServiceBusType() == ServiceBusType.queue) { - return receiverClientBuilder.queueName(configuration.getTopicOrQueueName()); - } else { - return receiverClientBuilder.topicName(configuration.getTopicOrQueueName()); + switch (configuration.getServiceBusType()) { + case queue -> processorClientBuilder.queueName(configuration.getTopicOrQueueName()); + case topic -> processorClientBuilder.topicName(configuration.getTopicOrQueueName()); } + + return processorClientBuilder; + } + + public ServiceBusSenderAsyncClient createServiceBusSenderAsyncClient(final ServiceBusConfiguration configuration) { + return createBaseServiceBusSenderClient(createBaseServiceBusClient(configuration), configuration) + .buildAsyncClient(); + } + + public ServiceBusProcessorClient createServiceBusProcessorClient( + ServiceBusConfiguration configuration, Consumer processMessage, + Consumer processError) { + ServiceBusClientBuilder.ServiceBusProcessorClientBuilder clientBuilder + = createBaseServiceBusProcessorClient(createBaseServiceBusClient(configuration), configuration); + + clientBuilder + .subscriptionName(configuration.getSubscriptionName()) + .receiveMode(configuration.getServiceBusReceiveMode()) + .maxAutoLockRenewDuration(configuration.getMaxAutoLockRenewDuration()) + .prefetchCount(configuration.getPrefetchCount()) + .subQueue(configuration.getSubQueue()) + .maxConcurrentCalls(configuration.getMaxConcurrentCalls()) + .processMessage(processMessage) + .processError(processError); + + return clientBuilder.buildProcessorClient(); } } diff --git a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/client/ServiceBusReceiverAsyncClientWrapper.java b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/client/ServiceBusReceiverAsyncClientWrapper.java deleted file mode 100644 index 4261ecb06c7f4..0000000000000 --- a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/client/ServiceBusReceiverAsyncClientWrapper.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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.azure.servicebus.client; - -import java.time.Duration; -import java.time.OffsetDateTime; - -import com.azure.messaging.servicebus.ServiceBusReceivedMessage; -import com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient; -import com.azure.messaging.servicebus.ServiceBusTransactionContext; -import com.azure.messaging.servicebus.models.AbandonOptions; -import com.azure.messaging.servicebus.models.CompleteOptions; -import com.azure.messaging.servicebus.models.DeadLetterOptions; -import com.azure.messaging.servicebus.models.DeferOptions; -import org.apache.camel.util.ObjectHelper; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -public class ServiceBusReceiverAsyncClientWrapper { - - private ServiceBusReceiverAsyncClient client; - - public ServiceBusReceiverAsyncClientWrapper(final ServiceBusReceiverAsyncClient client) { - ObjectHelper.isNotEmpty(client); - - this.client = client; - } - - public String getFullyQualifiedNamespace() { - return client.getFullyQualifiedNamespace(); - } - - public String getEntityPath() { - return client.getEntityPath(); - } - - public Mono abandon(ServiceBusReceivedMessage message) { - return client.abandon(message); - } - - public Mono abandon( - ServiceBusReceivedMessage message, - AbandonOptions options) { - return client.abandon(message, options); - } - - public Mono complete(ServiceBusReceivedMessage message) { - return client.complete(message); - } - - public Mono complete( - ServiceBusReceivedMessage message, - CompleteOptions options) { - return client.complete(message, options); - } - - public Mono defer(ServiceBusReceivedMessage message) { - return client.defer(message); - } - - public Mono defer( - ServiceBusReceivedMessage message, - DeferOptions options) { - return client.defer(message, options); - } - - public Mono deadLetter(ServiceBusReceivedMessage message) { - return client.deadLetter(message); - } - - public Mono deadLetter( - ServiceBusReceivedMessage message, - DeadLetterOptions options) { - return client.deadLetter(message, options); - } - - public Mono getSessionState() { - return client.getSessionState(); - } - - public Mono peekMessage() { - return client.peekMessage(); - } - - public Mono peekMessage(long sequenceNumber) { - return client.peekMessage(sequenceNumber); - } - - public Flux peekMessages(int maxMessages) { - return client.peekMessages(maxMessages); - } - - public Flux peekMessages(int maxMessages, long sequenceNumber) { - return client.peekMessages(maxMessages, sequenceNumber); - } - - public Flux receiveMessages() { - return client.receiveMessages(); - } - - public Mono receiveDeferredMessage(long sequenceNumber) { - return client.receiveDeferredMessage(sequenceNumber); - } - - public Flux receiveDeferredMessages(Iterable sequenceNumbers) { - return client.receiveDeferredMessages(sequenceNumbers); - } - - public Mono renewMessageLock(ServiceBusReceivedMessage message) { - return client.renewMessageLock(message); - } - - public Mono renewMessageLock(ServiceBusReceivedMessage message, Duration maxLockRenewalDuration) { - return client.renewMessageLock(message, maxLockRenewalDuration); - } - - public Mono renewSessionLock() { - return client.renewSessionLock(); - } - - public Mono renewSessionLock(Duration maxLockRenewalDuration) { - return client.renewSessionLock(maxLockRenewalDuration); - } - - public Mono setSessionState(byte[] sessionState) { - return client.setSessionState(sessionState); - } - - public Mono createTransaction() { - return client.createTransaction(); - } - - public Mono commitTransaction(ServiceBusTransactionContext transactionContext) { - return client.commitTransaction(transactionContext); - } - - public Mono rollbackTransaction(ServiceBusTransactionContext transactionContext) { - return client.rollbackTransaction(transactionContext); - } - - public void close() { - client.close(); - } -} diff --git a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/operations/ServiceBusReceiverOperations.java b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/operations/ServiceBusReceiverOperations.java deleted file mode 100644 index 27c8741170971..0000000000000 --- a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/operations/ServiceBusReceiverOperations.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.azure.servicebus.operations; - -import com.azure.messaging.servicebus.ServiceBusReceivedMessage; -import org.apache.camel.component.azure.servicebus.client.ServiceBusReceiverAsyncClientWrapper; -import org.apache.camel.util.ObjectHelper; -import reactor.core.publisher.Flux; - -public class ServiceBusReceiverOperations { - - private final ServiceBusReceiverAsyncClientWrapper client; - - public ServiceBusReceiverOperations(final ServiceBusReceiverAsyncClientWrapper client) { - ObjectHelper.notNull(client, "client"); - - this.client = client; - } - - public Flux receiveMessages() { - return client.receiveMessages(); - } - - public Flux peekMessages(final Integer numMaxMessages) { - if (ObjectHelper.isEmpty(numMaxMessages)) { - return client.peekMessage() - .flux(); - } - - return client.peekMessages(numMaxMessages); - } -} diff --git a/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumerTest.java b/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumerTest.java new file mode 100644 index 0000000000000..3d282bcc6c1cd --- /dev/null +++ b/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumerTest.java @@ -0,0 +1,466 @@ +/* + * 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.azure.servicebus; + +import java.time.Duration; +import java.time.OffsetDateTime; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +import com.azure.core.amqp.models.AmqpAnnotatedMessage; +import com.azure.core.util.BinaryData; +import com.azure.messaging.servicebus.*; +import com.azure.messaging.servicebus.models.DeadLetterOptions; +import com.azure.messaging.servicebus.models.ServiceBusMessageState; +import com.azure.messaging.servicebus.models.SubQueue; +import org.apache.camel.*; +import org.apache.camel.component.azure.servicebus.client.ServiceBusClientFactory; +import org.apache.camel.spi.ExceptionHandler; +import org.apache.camel.spi.ExchangeFactory; +import org.apache.camel.spi.HeaderFilterStrategy; +import org.apache.camel.spi.Synchronization; +import org.apache.camel.support.DefaultExchange; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.mockito.ArgumentCaptor; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +public class ServiceBusConsumerTest { + private static final String MESSAGE_BODY = "bodyValue"; + private static final String MESSAGE_CONTENT_TYPE = "text/plain"; + private static final String MESSAGE_CORRELATION_ID = "correlationIdValue"; + private static final long MESSAGE_DELIVERY_COUNT_VALUE = 1; + private static final long MESSAGE_ENQUEUED_SEQUENCE_NUMBER_VALUE = 2; + private static final OffsetDateTime MESSAGE_ENQUEUED_TIME = OffsetDateTime.now(); + private static final OffsetDateTime MESSAGE_EXPIRES_AT = MESSAGE_ENQUEUED_TIME.plusMinutes(5); + private static final String MESSAGE_LOCK_TOKEN = "lockTokenValue"; + private static final OffsetDateTime MESSAGE_LOCKED_UNTIL = MESSAGE_ENQUEUED_TIME.plusMinutes(1); + private static final String MESSAGE_ID = "messageIdValue"; + private static final String MESSAGE_PARTITION_KEY = "partitionKeyValue"; + private static final String MESSAGE_REPLY_TO = "replyToValue"; + private static final String MESSAGE_REPLY_TO_SESSION_ID = "replyToSessionIdValue"; + private static final OffsetDateTime MESSAGE_SCHEDULED_ENQUEUE_TIME = OffsetDateTime.now(); + private static final long MESSAGE_SEQUENCE_NUMBER = 3; + private static final String MESSAGE_SESSION_ID = "sessionIdValue"; + private static final ServiceBusMessageState MESSAGE_STATE = ServiceBusMessageState.ACTIVE; + private static final String MESSAGE_SUBJECT = "subjectValue"; + private static final Duration MESSAGE_TIME_TO_LIVE = Duration.ofMinutes(5); + private static final String MESSAGE_TO = "toValue"; + private static final String MESSAGE_DEAD_LETTER_ERROR_DESCRIPTION = "deadLetterErrorDescriptionValue"; + private static final String MESSAGE_DEAD_LETTER_REASON = "deadLetterReasonValue"; + private static final String MESSAGE_DEAD_LETTER_SOURCE = "deadLetterSourceValue"; + private static final String PROPAGATED_HEADER_KEY = "propagatedHeaderKey"; + private static final String PROPAGATED_HEADER_VALUE = "propagatedHeaderValue"; + + private final ServiceBusConfiguration configuration = mock(); + private final ServiceBusClientFactory clientFactory = mock(); + private final ServiceBusProcessorClient client = mock(); + private final ServiceBusComponent component = mock(); + private final ServiceBusEndpoint endpoint = mock(); + private final ServiceBusReceivedMessageContext messageContext = mock(); + private final ServiceBusReceivedMessage message = mock(); + private final AmqpAnnotatedMessage rawAmqpAnnotatedMessage = mock(); + private final AsyncProcessor processor = mock(); + private final CamelContext context = mock(); + private final ExtendedCamelContext ecc = mock(); + private final ExchangeFactory ef = mock(); + private final HeaderFilterStrategy headerFilterStrategy = mock(); + private final ExceptionHandler exceptionHandler = mock(); + private final ArgumentCaptor> processMessageCaptor = ArgumentCaptor.captor(); + private final ArgumentCaptor> processErrorCaptor = ArgumentCaptor.captor(); + private final ArgumentCaptor exchangeCaptor = ArgumentCaptor.captor(); + private final ArgumentCaptor asyncCallbackCaptor = ArgumentCaptor.captor(); + + @BeforeEach + void beforeEach() { + when(endpoint.getCamelContext()).thenReturn(context); + when(context.getCamelContextExtension()).thenReturn(ecc); + when(ecc.getExchangeFactory()).thenReturn(ef); + when(ef.newExchangeFactory(any())).thenReturn(ef); + when(ef.create(any(Endpoint.class), anyBoolean())).thenAnswer(invocationOnMock -> DefaultExchange.newFromEndpoint(invocationOnMock.getArgument(0))); + when(endpoint.getComponent()).thenReturn(component); + when(endpoint.getConfiguration()).thenReturn(configuration); + when(endpoint.getServiceBusClientFactory()).thenReturn(clientFactory); + when(clientFactory.createServiceBusProcessorClient(any(), processMessageCaptor.capture(), processErrorCaptor.capture())).thenReturn(client); + when(processor.process(exchangeCaptor.capture(), asyncCallbackCaptor.capture())).thenReturn(true); + when(configuration.getHeaderFilterStrategy()).thenReturn(headerFilterStrategy); + } + + @Test + void consumerSubmitsExchangeToProcessor() throws Exception { + try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, processor)) { + consumer.doStart(); + verify(client).start(); + verify(clientFactory).createServiceBusProcessorClient(any(), any(), any()); + + when(messageContext.getMessage()).thenReturn(message); + configureMockMessage(); + + processMessageCaptor.getValue().accept(messageContext); + + verify(processor).process(any(Exchange.class), any(AsyncCallback.class)); + Exchange exchange = exchangeCaptor.getValue(); + assertThat(exchange).isNotNull(); + + Message inMessage = exchange.getIn(); + assertThat(inMessage).isNotNull(); + assertThat(inMessage.getBody()).isInstanceOf(BinaryData.class); + assertThat(inMessage.getBody(BinaryData.class).toString()).isEqualTo(MESSAGE_BODY); + assertThat(inMessage.getHeaders()).isEqualTo(createExpectedMessageHeaders()); + } + } + + @Test + void consumerSubmitsDeadLetterExchangeToProcessor() throws Exception { + try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, processor)) { + consumer.doStart(); + verify(client).start(); + verify(clientFactory).createServiceBusProcessorClient(any(), any(), any()); + + when(messageContext.getMessage()).thenReturn(message); + configureMockDeadLetterMessage(); + + processMessageCaptor.getValue().accept(messageContext); + + verify(processor).process(any(Exchange.class), any(AsyncCallback.class)); + Exchange exchange = exchangeCaptor.getValue(); + assertThat(exchange).isNotNull(); + + Message inMessage = exchange.getIn(); + assertThat(inMessage).isNotNull(); + assertThat(inMessage.getBody()).isInstanceOf(BinaryData.class); + assertThat(inMessage.getBody(BinaryData.class).toString()).isEqualTo(MESSAGE_BODY); + assertThat(inMessage.getHeaders()).isEqualTo(createExpectedDeadLetterMessageHeaders()); + } + } + + @Test + void consumerPropagatesApplicationPropertiesToMessageHeaders() throws Exception { + try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, processor)) { + consumer.doStart(); + verify(client).start(); + verify(clientFactory).createServiceBusProcessorClient(any(), any(), any()); + + when(messageContext.getMessage()).thenReturn(message); + configureMockMessage(); + message.getApplicationProperties().put(PROPAGATED_HEADER_KEY, PROPAGATED_HEADER_VALUE); + when(headerFilterStrategy.applyFilterToExternalHeaders(anyString(), any(), any())).thenReturn(false); + + processMessageCaptor.getValue().accept(messageContext); + + verify(headerFilterStrategy, atLeastOnce()).applyFilterToExternalHeaders(anyString(), any(), any(Exchange.class)); + verifyNoMoreInteractions(headerFilterStrategy); + + verify(processor).process(any(Exchange.class), any(AsyncCallback.class)); + Exchange exchange = exchangeCaptor.getValue(); + assertThat(exchange).isNotNull(); + + Message inMessage = exchange.getIn(); + assertThat(inMessage).isNotNull(); + assertThat(inMessage.getHeaders()).containsEntry(PROPAGATED_HEADER_KEY, PROPAGATED_HEADER_VALUE); + } + } + + @Test + void consumerFiltersApplicationPropertiesFromMessageHeaders() throws Exception { + try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, processor)) { + consumer.doStart(); + verify(client).start(); + verify(clientFactory).createServiceBusProcessorClient(any(), any(), any()); + + when(messageContext.getMessage()).thenReturn(message); + configureMockMessage(); + message.getApplicationProperties().put(PROPAGATED_HEADER_KEY, PROPAGATED_HEADER_VALUE); + when(headerFilterStrategy.applyFilterToExternalHeaders(anyString(), any(), any(Exchange.class))).thenReturn(true); + + processMessageCaptor.getValue().accept(messageContext); + + verify(headerFilterStrategy, atLeastOnce()).applyFilterToExternalHeaders(anyString(), any(), any(Exchange.class)); + verifyNoMoreInteractions(headerFilterStrategy); + + verify(processor).process(any(Exchange.class), any(AsyncCallback.class)); + Exchange exchange = exchangeCaptor.getValue(); + assertThat(exchange).isNotNull(); + + Message inMessage = exchange.getIn(); + assertThat(inMessage).isNotNull(); + assertThat(inMessage.getHeaders()).doesNotContainKey(PROPAGATED_HEADER_KEY); + } + } + + @Test + void consumerHandlesClientError() throws Exception { + try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, processor)) { + consumer.doStart(); + verify(client).start(); + verify(clientFactory).createServiceBusProcessorClient(any(), any(), any()); + + ServiceBusErrorContext errorContext = mock(); + when(errorContext.getErrorSource()).thenReturn(ServiceBusErrorSource.UNKNOWN); + when(errorContext.getException()).thenReturn(new Exception("Test exception")); + + processErrorCaptor.getValue().accept(errorContext); + + verifyNoInteractions(processor); + } + } + + @Test + void synchronizationCompletesMessageOnSuccess() throws Exception { + try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, processor)) { + consumer.doStart(); + verify(client).start(); + verify(clientFactory).createServiceBusProcessorClient(any(), any(), any()); + + when(messageContext.getMessage()).thenReturn(message); + + processMessageCaptor.getValue().accept(messageContext); + + verify(messageContext).getMessage(); + + Exchange exchange = exchangeCaptor.getValue(); + assertThat(exchange).isNotNull(); + + Synchronization synchronization = exchange.getExchangeExtension().handoverCompletions().get(0); + synchronization.onComplete(exchange); + verify(messageContext).complete(); + + verifyNoMoreInteractions(messageContext); + } + } + + @Test + void synchronizationAbandonsMessageOnFailure() throws Exception { + try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, processor)) { + consumer.doStart(); + verify(client).start(); + verify(clientFactory).createServiceBusProcessorClient(any(), any(), any()); + + when(messageContext.getMessage()).thenReturn(message); + processMessageCaptor.getValue().accept(messageContext); + + verify(messageContext).getMessage(); + + verify(processor).process(any(Exchange.class), any(AsyncCallback.class)); + Exchange exchange = exchangeCaptor.getValue(); + assertThat(exchange).isNotNull(); + + Synchronization synchronization = exchange.getExchangeExtension().handoverCompletions().get(0); + synchronization.onFailure(exchange); + verify(messageContext).abandon(); + + verifyNoMoreInteractions(messageContext); + } + } + + @Test + void synchronizationCallsExceptionHandlerOnFailure() throws Exception { + try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, processor)) { + consumer.setExceptionHandler(exceptionHandler); + consumer.doStart(); + verify(client).start(); + verify(clientFactory).createServiceBusProcessorClient(any(), any(), any()); + + when(messageContext.getMessage()).thenReturn(message); + + processMessageCaptor.getValue().accept(messageContext); + + verify(processor).process(any(Exchange.class), any(AsyncCallback.class)); + Exchange exchange = exchangeCaptor.getValue(); + assertThat(exchange).isNotNull(); + + final Exception testException = new Exception("Test exception"); + exchange.setException(testException); + Synchronization synchronization = exchange.getExchangeExtension().handoverCompletions().get(0); + synchronization.onFailure(exchange); + verify(exceptionHandler).handleException(anyString(), eq(exchange), eq(testException)); + } + } + + @Test + void synchronizationDeadLettersMessageOnFailureWhenSubQueueIsNull() throws Exception { + synchronizationDeadLettersMessageWithOptionsWhenExceptionPresent(null); + } + + @Test + void synchronizationDeadLettersMessageOnFailureWhenSubQueueIsNone() throws Exception { + synchronizationDeadLettersMessageWithOptionsWhenExceptionPresent(SubQueue.NONE); + } + + private void synchronizationDeadLettersMessageWithOptionsWhenExceptionPresent(SubQueue subQueue) throws Exception { + try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, processor)) { + when(configuration.isEnableDeadLettering()).thenReturn(true); + when(configuration.getSubQueue()).thenReturn(subQueue); + + consumer.doStart(); + verify(client).start(); + verify(clientFactory).createServiceBusProcessorClient(any(), any(), any()); + + when(messageContext.getMessage()).thenReturn(message); + + processMessageCaptor.getValue().accept(messageContext); + + verify(messageContext).getMessage(); + + verify(processor).process(any(Exchange.class), any(AsyncCallback.class)); + Exchange exchange = exchangeCaptor.getValue(); + assertThat(exchange).isNotNull(); + exchange.setException(new Exception("Test exception")); + + Synchronization synchronization = exchange.getExchangeExtension().handoverCompletions().get(0); + synchronization.onFailure(exchange); + + ArgumentCaptor deadLetterOptionsCaptor = ArgumentCaptor.captor(); + verify(messageContext).deadLetter(deadLetterOptionsCaptor.capture()); + DeadLetterOptions deadLetterOptions = deadLetterOptionsCaptor.getValue(); + assertThat(deadLetterOptions.getDeadLetterReason()).contains(Exception.class.getName()); + assertThat(deadLetterOptions.getDeadLetterReason()).contains("Test exception"); + assertThat(deadLetterOptions.getDeadLetterErrorDescription()).contains(getClass().getName()); + + verifyNoMoreInteractions(messageContext); + } + } + + @Test + void synchronizationDeadLettersMessageWithoutOptionsWhenExceptionNotPresent() throws Exception { + try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, processor)) { + when(configuration.isEnableDeadLettering()).thenReturn(true); + consumer.doStart(); + verify(client).start(); + verify(clientFactory).createServiceBusProcessorClient(any(), any(), any()); + + when(messageContext.getMessage()).thenReturn(message); + + processMessageCaptor.getValue().accept(messageContext); + + verify(messageContext).getMessage(); + + verify(processor).process(any(Exchange.class), any(AsyncCallback.class)); + Exchange exchange = exchangeCaptor.getValue(); + assertThat(exchange).isNotNull(); + + Synchronization synchronization = exchange.getExchangeExtension().handoverCompletions().get(0); + synchronization.onFailure(exchange); + verify(messageContext).deadLetter(); + + verifyNoMoreInteractions(messageContext); + } + } + + @ParameterizedTest + @EnumSource(value = SubQueue.class, names = "NONE", mode = EnumSource.Mode.EXCLUDE) + void synchronizationAbandonsMessageOnFailureWhenProcessingDeadLetterQueue(SubQueue subQueue) throws Exception { + try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, processor)) { + when(configuration.isEnableDeadLettering()).thenReturn(true); + when(configuration.getSubQueue()).thenReturn(subQueue); + consumer.doStart(); + verify(client).start(); + verify(clientFactory).createServiceBusProcessorClient(any(), any(), any()); + + when(messageContext.getMessage()).thenReturn(message); + + processMessageCaptor.getValue().accept(messageContext); + + verify(messageContext).getMessage(); + + verify(processor).process(any(Exchange.class), any(AsyncCallback.class)); + Exchange exchange = exchangeCaptor.getValue(); + assertThat(exchange).isNotNull(); + exchange.setException(new Exception("Test exception")); + + Synchronization synchronization = exchange.getExchangeExtension().handoverCompletions().get(0); + synchronization.onFailure(exchange); + verify(messageContext).abandon(); + + verifyNoMoreInteractions(messageContext); + } + } + + private void configureMockMessage() { + when(message.getApplicationProperties()).thenReturn(new HashMap<>()); + when(message.getBody()).thenReturn(BinaryData.fromBytes(MESSAGE_BODY.getBytes())); + when(message.getContentType()).thenReturn(MESSAGE_CONTENT_TYPE); + when(message.getCorrelationId()).thenReturn(MESSAGE_CORRELATION_ID); + when(message.getDeliveryCount()).thenReturn(MESSAGE_DELIVERY_COUNT_VALUE); + when(message.getEnqueuedSequenceNumber()).thenReturn(MESSAGE_ENQUEUED_SEQUENCE_NUMBER_VALUE); + when(message.getEnqueuedTime()).thenReturn(MESSAGE_ENQUEUED_TIME); + when(message.getExpiresAt()).thenReturn(MESSAGE_EXPIRES_AT); + when(message.getLockToken()).thenReturn(MESSAGE_LOCK_TOKEN); + when(message.getLockedUntil()).thenReturn(MESSAGE_LOCKED_UNTIL); + when(message.getMessageId()).thenReturn(MESSAGE_ID); + when(message.getPartitionKey()).thenReturn(MESSAGE_PARTITION_KEY); + when(message.getRawAmqpMessage()).thenReturn(rawAmqpAnnotatedMessage); + when(message.getReplyTo()).thenReturn(MESSAGE_REPLY_TO); + when(message.getReplyToSessionId()).thenReturn(MESSAGE_REPLY_TO_SESSION_ID); + when(message.getScheduledEnqueueTime()).thenReturn(MESSAGE_SCHEDULED_ENQUEUE_TIME); + when(message.getSequenceNumber()).thenReturn(MESSAGE_SEQUENCE_NUMBER); + when(message.getSessionId()).thenReturn(MESSAGE_SESSION_ID); + when(message.getState()).thenReturn(MESSAGE_STATE); + when(message.getSubject()).thenReturn(MESSAGE_SUBJECT); + when(message.getTimeToLive()).thenReturn(MESSAGE_TIME_TO_LIVE); + when(message.getTo()).thenReturn(MESSAGE_TO); + } + + private void configureMockDeadLetterMessage() { + configureMockMessage(); + when(message.getDeadLetterErrorDescription()).thenReturn(MESSAGE_DEAD_LETTER_ERROR_DESCRIPTION); + when(message.getDeadLetterReason()).thenReturn(MESSAGE_DEAD_LETTER_REASON); + when(message.getDeadLetterSource()).thenReturn(MESSAGE_DEAD_LETTER_SOURCE); + } + + private Map createExpectedMessageHeaders() { + Map expectedMessageHeaders = new HashMap<>(); + expectedMessageHeaders.put(ServiceBusConstants.APPLICATION_PROPERTIES, message.getApplicationProperties()); + expectedMessageHeaders.put(ServiceBusConstants.CONTENT_TYPE, MESSAGE_CONTENT_TYPE); + expectedMessageHeaders.put(ServiceBusConstants.MESSAGE_ID, MESSAGE_ID); + expectedMessageHeaders.put(ServiceBusConstants.CORRELATION_ID, MESSAGE_CORRELATION_ID); + expectedMessageHeaders.put(ServiceBusConstants.DEAD_LETTER_ERROR_DESCRIPTION, null); + expectedMessageHeaders.put(ServiceBusConstants.DEAD_LETTER_REASON, null); + expectedMessageHeaders.put(ServiceBusConstants.DEAD_LETTER_SOURCE, null); + expectedMessageHeaders.put(ServiceBusConstants.DELIVERY_COUNT, MESSAGE_DELIVERY_COUNT_VALUE); + expectedMessageHeaders.put(ServiceBusConstants.SCHEDULED_ENQUEUE_TIME, MESSAGE_SCHEDULED_ENQUEUE_TIME); + expectedMessageHeaders.put(ServiceBusConstants.ENQUEUED_SEQUENCE_NUMBER, MESSAGE_ENQUEUED_SEQUENCE_NUMBER_VALUE); + expectedMessageHeaders.put(ServiceBusConstants.ENQUEUED_TIME, MESSAGE_ENQUEUED_TIME); + expectedMessageHeaders.put(ServiceBusConstants.EXPIRES_AT, MESSAGE_EXPIRES_AT); + expectedMessageHeaders.put(ServiceBusConstants.LOCK_TOKEN, MESSAGE_LOCK_TOKEN); + expectedMessageHeaders.put(ServiceBusConstants.LOCKED_UNTIL, MESSAGE_LOCKED_UNTIL); + expectedMessageHeaders.put(ServiceBusConstants.PARTITION_KEY, MESSAGE_PARTITION_KEY); + expectedMessageHeaders.put(ServiceBusConstants.RAW_AMQP_MESSAGE, rawAmqpAnnotatedMessage); + expectedMessageHeaders.put(ServiceBusConstants.REPLY_TO, MESSAGE_REPLY_TO); + expectedMessageHeaders.put(ServiceBusConstants.REPLY_TO_SESSION_ID, MESSAGE_REPLY_TO_SESSION_ID); + expectedMessageHeaders.put(ServiceBusConstants.SEQUENCE_NUMBER, MESSAGE_SEQUENCE_NUMBER); + expectedMessageHeaders.put(ServiceBusConstants.SESSION_ID, MESSAGE_SESSION_ID); + expectedMessageHeaders.put(ServiceBusConstants.SUBJECT, MESSAGE_SUBJECT); + expectedMessageHeaders.put(ServiceBusConstants.TIME_TO_LIVE, MESSAGE_TIME_TO_LIVE); + expectedMessageHeaders.put(ServiceBusConstants.TO, MESSAGE_TO); + return expectedMessageHeaders; + } + + private Map createExpectedDeadLetterMessageHeaders() { + Map expectedMessageHeaders = createExpectedMessageHeaders(); + expectedMessageHeaders.put(ServiceBusConstants.DEAD_LETTER_ERROR_DESCRIPTION, MESSAGE_DEAD_LETTER_ERROR_DESCRIPTION); + expectedMessageHeaders.put(ServiceBusConstants.DEAD_LETTER_REASON, MESSAGE_DEAD_LETTER_REASON); + expectedMessageHeaders.put(ServiceBusConstants.DEAD_LETTER_SOURCE, MESSAGE_DEAD_LETTER_SOURCE); + return expectedMessageHeaders; + } +} diff --git a/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/ServiceBusTestUtils.java b/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/ServiceBusTestUtils.java deleted file mode 100644 index 8c129b0c44915..0000000000000 --- a/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/ServiceBusTestUtils.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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.azure.servicebus; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Objects; -import java.util.Properties; - -import com.azure.messaging.servicebus.ServiceBusClientBuilder; -import com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient; -import com.azure.messaging.servicebus.ServiceBusSenderAsyncClient; - -public final class ServiceBusTestUtils { - - public static final String CONNECTION_STRING = "connectionString"; - public static final String TOPIC_NAME = "topicName"; - public static final String SUBSCRIPTION_NAME = "subscriptionName"; - public static final String QUEUE_NAME = "queueName"; - - private ServiceBusTestUtils() { - } - - public static Properties loadAzurePropertiesFile() throws IOException { - final Properties properties = new Properties(); - final String fileName = "azure_key.properties"; - - final InputStream inputStream - = Objects.requireNonNull(ServiceBusTestUtils.class.getClassLoader().getResourceAsStream(fileName)); - - properties.load(inputStream); - - return properties; - } - - public static Properties loadAzureAccessFromJvmEnv() throws Exception { - final Properties properties = new Properties(); - if (System.getProperty(CONNECTION_STRING) == null) { - throw new Exception( - "Make sure to supply azure servicebus connectionString, e.g: mvn verify -DconnectionString=string"); - } - properties.setProperty(CONNECTION_STRING, System.getProperty(CONNECTION_STRING)); - properties.setProperty(TOPIC_NAME, System.getProperty(TOPIC_NAME)); - properties.setProperty(SUBSCRIPTION_NAME, System.getProperty(SUBSCRIPTION_NAME)); - //properties.setProperty(QUEUE_NAME, System.getProperty(QUEUE_NAME)); - - return properties; - } - - public static ServiceBusReceiverAsyncClient createServiceBusReceiverAsyncClient(final ServiceBusType type) - throws Exception { - final Properties properties = loadAzureAccessFromJvmEnv(); - - final ServiceBusClientBuilder.ServiceBusReceiverClientBuilder clientBuilder = new ServiceBusClientBuilder() - .connectionString(properties.getProperty(CONNECTION_STRING)) - .receiver() - .subscriptionName(properties.getProperty(SUBSCRIPTION_NAME)); - - if (type == ServiceBusType.queue) { - clientBuilder.queueName(properties.getProperty(QUEUE_NAME)); - } else { - clientBuilder.topicName(properties.getProperty(TOPIC_NAME)); - } - - return clientBuilder.buildAsyncClient(); - } - - public static ServiceBusSenderAsyncClient createServiceBusSenderAsyncClient(final ServiceBusType type) throws Exception { - final Properties properties = loadAzureAccessFromJvmEnv(); - - final ServiceBusClientBuilder.ServiceBusSenderClientBuilder clientBuilder = new ServiceBusClientBuilder() - .connectionString(properties.getProperty(CONNECTION_STRING)) - .sender(); - - if (type == ServiceBusType.queue) { - clientBuilder.queueName(properties.getProperty(QUEUE_NAME)); - } else { - clientBuilder.topicName(properties.getProperty(TOPIC_NAME)); - } - - return clientBuilder.buildAsyncClient(); - } - -} diff --git a/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/BaseCamelServiceBusTestSupport.java b/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/BaseCamelServiceBusTestSupport.java deleted file mode 100644 index 5e84c474805e8..0000000000000 --- a/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/BaseCamelServiceBusTestSupport.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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.azure.servicebus.integration; - -import com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient; -import com.azure.messaging.servicebus.ServiceBusSenderAsyncClient; -import org.apache.camel.CamelContext; -import org.apache.camel.component.azure.servicebus.ServiceBusComponent; -import org.apache.camel.component.azure.servicebus.ServiceBusTestUtils; -import org.apache.camel.component.azure.servicebus.ServiceBusType; -import org.apache.camel.test.junit5.CamelTestSupport; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; - -public class BaseCamelServiceBusTestSupport extends CamelTestSupport { - - protected ServiceBusSenderAsyncClient senderAsyncClient; - protected ServiceBusReceiverAsyncClient receiverAsyncClient; - - @BeforeEach - void prepareClient() throws Exception { - senderAsyncClient = ServiceBusTestUtils.createServiceBusSenderAsyncClient(ServiceBusType.topic); - receiverAsyncClient = ServiceBusTestUtils.createServiceBusReceiverAsyncClient(ServiceBusType.topic); - } - - @AfterEach - void closeClient() { - senderAsyncClient.close(); - receiverAsyncClient.close(); - } - - @Override - protected CamelContext createCamelContext() throws Exception { - final ServiceBusSenderAsyncClient injectedSenderAsyncClient - = ServiceBusTestUtils.createServiceBusSenderAsyncClient(ServiceBusType.topic); - final ServiceBusReceiverAsyncClient injectedReceiverAsyncClient - = ServiceBusTestUtils.createServiceBusReceiverAsyncClient(ServiceBusType.topic); - - final CamelContext context = super.createCamelContext(); - final ServiceBusComponent component = new ServiceBusComponent(context); - - component.init(); - component.getConfiguration().setReceiverAsyncClient(injectedReceiverAsyncClient); - component.getConfiguration().setSenderAsyncClient(injectedSenderAsyncClient); - context.addComponent("azure-servicebus", component); - - return context; - } -} diff --git a/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/BaseServiceBusTestSupport.java b/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/BaseServiceBusTestSupport.java new file mode 100644 index 0000000000000..5eac391015ede --- /dev/null +++ b/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/BaseServiceBusTestSupport.java @@ -0,0 +1,129 @@ +/* + * 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.azure.servicebus.integration; + +import java.util.List; +import java.util.concurrent.CountDownLatch; + +import com.azure.core.exception.ResourceExistsException; +import com.azure.messaging.servicebus.ServiceBusClientBuilder; +import com.azure.messaging.servicebus.ServiceBusProcessorClient; +import com.azure.messaging.servicebus.ServiceBusReceivedMessageContext; +import com.azure.messaging.servicebus.administration.ServiceBusAdministrationClient; +import com.azure.messaging.servicebus.administration.ServiceBusAdministrationClientBuilder; +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.azure.servicebus.ServiceBusComponent; +import org.apache.camel.test.infra.core.CamelContextExtension; +import org.apache.camel.test.infra.core.DefaultCamelContextExtension; +import org.apache.camel.test.infra.core.annotations.ContextFixture; +import org.apache.camel.test.infra.core.annotations.RouteFixture; +import org.apache.camel.test.infra.core.api.ConfigurableRoute; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static java.lang.System.getProperty; + +public abstract class BaseServiceBusTestSupport implements ConfigurableRoute { + public static final String CONNECTION_STRING_PROPERTY_NAME = "camel.component.azure-servicebus.connection-string"; + protected static final String CONNECTION_STRING = getProperty(CONNECTION_STRING_PROPERTY_NAME); + protected static final String QUEUE_NAME = "camelTestQueue"; + protected static final String TOPIC_NAME = "camelTestTopic"; + protected static final String SUBSCRIPTION_NAME = "camelTestSubscription"; + protected static final String MOCK_RESULT = "mock:result"; + private static final Logger LOGGER = LoggerFactory.getLogger(BaseServiceBusTestSupport.class); + @RegisterExtension + protected static CamelContextExtension contextExtension = new DefaultCamelContextExtension(); + protected static ServiceBusAdministrationClient serviceBusAdminClient; + protected CountDownLatch messageLatch; + protected List receivedMessageContexts; + + @BeforeAll + static void baseBeforeAll() { + serviceBusAdminClient = new ServiceBusAdministrationClientBuilder() + .connectionString(CONNECTION_STRING) + .buildClient(); + try { + serviceBusAdminClient.createQueue(QUEUE_NAME); + } catch (ResourceExistsException e) { + LOGGER.warn("Test queue already existed", e); + } + try { + serviceBusAdminClient.createTopic(TOPIC_NAME); + } catch (ResourceExistsException e) { + LOGGER.warn("Test topic already existed", e); + } + try { + serviceBusAdminClient.createSubscription(TOPIC_NAME, SUBSCRIPTION_NAME); + } catch (ResourceExistsException e) { + LOGGER.warn("Test subscription already existed", e); + } + } + + @AfterAll + static void baseAfterAll() { + serviceBusAdminClient.deleteSubscription(TOPIC_NAME, SUBSCRIPTION_NAME); + serviceBusAdminClient.deleteTopic(TOPIC_NAME); + serviceBusAdminClient.deleteQueue(QUEUE_NAME); + } + + @ContextFixture + public void configureServiceBus(CamelContext context) { + ServiceBusComponent serviceBusComponent = new ServiceBusComponent(context); + serviceBusComponent.init(); + serviceBusComponent.getConfiguration().setConnectionString(CONNECTION_STRING); + context.addComponent("azure-servicebus", serviceBusComponent); + } + + @RouteFixture + public void createRouteBuilder(CamelContext context) throws Exception { + context.addRoutes(createRouteBuilder()); + } + + protected abstract RouteBuilder createRouteBuilder(); + + protected ServiceBusProcessorClient createQueueProcessorClient() { + return new ServiceBusClientBuilder() + .connectionString(CONNECTION_STRING) + .processor() + .queueName(QUEUE_NAME) + .processMessage(this::processMessage) + .processError(serviceBusErrorContext -> LOGGER.error("Service Bus client error", + serviceBusErrorContext.getException())) + .buildProcessorClient(); + } + + protected ServiceBusProcessorClient createTopicProcessorClient() { + return new ServiceBusClientBuilder() + .connectionString(CONNECTION_STRING) + .processor() + .topicName(TOPIC_NAME) + .subscriptionName(SUBSCRIPTION_NAME) + .processMessage(this::processMessage) + .processError(serviceBusErrorContext -> LOGGER.error("Service Bus client error", + serviceBusErrorContext.getException())) + .buildProcessorClient(); + } + + private void processMessage(ServiceBusReceivedMessageContext messageContext) { + receivedMessageContexts.add(messageContext); + messageLatch.countDown(); + } +} diff --git a/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/ServiceBusConsumerIT.java b/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/ServiceBusConsumerIT.java new file mode 100644 index 0000000000000..0a2f302710f3e --- /dev/null +++ b/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/ServiceBusConsumerIT.java @@ -0,0 +1,153 @@ +/* + * 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.azure.servicebus.integration; + +import java.time.Duration; +import java.time.OffsetDateTime; +import java.util.Map; + +import com.azure.core.amqp.models.AmqpAnnotatedMessage; +import com.azure.messaging.servicebus.ServiceBusClientBuilder; +import com.azure.messaging.servicebus.ServiceBusMessage; +import com.azure.messaging.servicebus.ServiceBusSenderClient; +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.azure.servicebus.ServiceBusConstants; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.infra.core.annotations.RouteFixture; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@EnabledIfSystemProperty(named = BaseServiceBusTestSupport.CONNECTION_STRING_PROPERTY_NAME, matches = ".*", + disabledReason = "Service Bus connection string must be supplied to run this test, e.g: mvn verify -D" + + BaseServiceBusTestSupport.CONNECTION_STRING_PROPERTY_NAME + "=connectionString") +public class ServiceBusConsumerIT extends BaseServiceBusTestSupport { + + private final ServiceBusSenderClient queueSenderClient = new ServiceBusClientBuilder() + .connectionString(CONNECTION_STRING) + .sender() + .queueName(QUEUE_NAME) + .buildClient(); + + private final ServiceBusSenderClient topicSenderClient = new ServiceBusClientBuilder() + .connectionString(CONNECTION_STRING) + .sender() + .topicName(TOPIC_NAME) + .buildClient(); + + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("azure-servicebus:" + QUEUE_NAME) + .to(MOCK_RESULT); + + from("azure-servicebus:" + TOPIC_NAME + "?serviceBusType=topic&subscriptionName=" + SUBSCRIPTION_NAME) + .to(MOCK_RESULT); + } + }; + } + + @RouteFixture + public void createRouteBuilder(CamelContext context) throws Exception { + context.addRoutes(createRouteBuilder()); + } + + @Test + public void serviceBusQueueIsConsumedByCamel() throws InterruptedException { + String propagatedHeaderKey = "PropagatedCustomHeader"; + String propagatedHeaderValue = "propagated header value"; + + MockEndpoint to = contextExtension.getMockEndpoint(MOCK_RESULT); + + to.expectedMessageCount(5); + to.expectedBodiesReceivedInAnyOrder("message-0", "message-1", "message-2", "message-3", "message-4"); + to.expectedHeaderReceived(propagatedHeaderKey, propagatedHeaderValue); + + for (int k = 0; k < 5; k++) { + String msg = "message-" + k; + ServiceBusMessage serviceBusMessage = new ServiceBusMessage(msg); + serviceBusMessage.getApplicationProperties().put(propagatedHeaderKey, propagatedHeaderValue); + queueSenderClient.sendMessage(serviceBusMessage); + } + + to.assertIsSatisfied(3000); + + Map headers = to.getExchanges().get(0).getIn().getHeaders(); + assertTrue(headers.containsKey(propagatedHeaderKey), "Should receive propagated header"); + assertBrokerPropertyHeadersPropagated(headers); + } + + @Test + public void serviceBusTopicIsConsumedByCamel() throws InterruptedException { + String propagatedHeaderKey = "PropagatedCustomHeader"; + String propagatedHeaderValue = "propagated header value"; + + MockEndpoint to = contextExtension.getMockEndpoint(MOCK_RESULT); + + to.expectedMessageCount(5); + to.expectedBodiesReceivedInAnyOrder("message-0", "message-1", "message-2", "message-3", "message-4"); + to.expectedHeaderReceived(propagatedHeaderKey, propagatedHeaderValue); + + for (int k = 0; k < 5; k++) { + String msg = "message-" + k; + ServiceBusMessage serviceBusMessage = new ServiceBusMessage(msg); + serviceBusMessage.getApplicationProperties().put(propagatedHeaderKey, propagatedHeaderValue); + topicSenderClient.sendMessage(serviceBusMessage); + } + + to.assertIsSatisfied(3000); + + Map headers = to.getExchanges().get(0).getIn().getHeaders(); + assertTrue(headers.containsKey(propagatedHeaderKey), "Should receive propagated header"); + assertBrokerPropertyHeadersPropagated(headers); + } + + private void assertBrokerPropertyHeadersPropagated(Map headers) { + assertInstanceOf(Map.class, headers.get(ServiceBusConstants.APPLICATION_PROPERTIES), + "Should receive application properties"); + assertTrue(headers.containsKey(ServiceBusConstants.CONTENT_TYPE), "Should receive content type"); + assertInstanceOf(String.class, headers.get(ServiceBusConstants.MESSAGE_ID), "Should receive message ID"); + assertTrue(headers.containsKey(ServiceBusConstants.CORRELATION_ID), "Should receive correlation ID"); + assertTrue(headers.containsKey(ServiceBusConstants.DEAD_LETTER_ERROR_DESCRIPTION), + "Should receive dead letter error description"); + assertTrue(headers.containsKey(ServiceBusConstants.DEAD_LETTER_REASON), "Should receive dead letter reason"); + assertTrue(headers.containsKey(ServiceBusConstants.DEAD_LETTER_SOURCE), "Should receive dead letter source"); + assertInstanceOf(Long.class, headers.get(ServiceBusConstants.DELIVERY_COUNT), "Should receive delivery count"); + assertTrue(headers.containsKey(ServiceBusConstants.SCHEDULED_ENQUEUE_TIME), "Should receive scheduled enqueue time"); + assertInstanceOf(Long.class, headers.get(ServiceBusConstants.ENQUEUED_SEQUENCE_NUMBER), + "Should receive enqueued sequence number"); + assertInstanceOf(OffsetDateTime.class, headers.get(ServiceBusConstants.ENQUEUED_TIME), "Should receive enqueued time"); + assertInstanceOf(OffsetDateTime.class, headers.get(ServiceBusConstants.EXPIRES_AT), "Should receive expiry time"); + assertInstanceOf(String.class, headers.get(ServiceBusConstants.LOCK_TOKEN), "Should receive lock token"); + assertInstanceOf(OffsetDateTime.class, headers.get(ServiceBusConstants.LOCKED_UNTIL), + "Should receive locked until time"); + assertTrue(headers.containsKey(ServiceBusConstants.PARTITION_KEY), "Should receive partition key"); + assertInstanceOf(AmqpAnnotatedMessage.class, headers.get(ServiceBusConstants.RAW_AMQP_MESSAGE), + "Should receive raw AMQP message"); + assertTrue(headers.containsKey(ServiceBusConstants.REPLY_TO), "Should receive reply to property"); + assertTrue(headers.containsKey(ServiceBusConstants.REPLY_TO_SESSION_ID), "Should receive reply to session ID"); + assertInstanceOf(Long.class, headers.get(ServiceBusConstants.SEQUENCE_NUMBER), "Should receive sequence number"); + assertTrue(headers.containsKey(ServiceBusConstants.SESSION_ID), "Should receive session ID"); + assertTrue(headers.containsKey(ServiceBusConstants.SUBJECT), "Should receive subject"); + assertInstanceOf(Duration.class, headers.get(ServiceBusConstants.TIME_TO_LIVE), "Should receive time to live"); + assertTrue(headers.containsKey(ServiceBusConstants.TO), "Should receive to property"); + } +} diff --git a/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/ServiceBusConsumerTest.java b/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/ServiceBusConsumerTest.java deleted file mode 100644 index 9ff5ebb89ef39..0000000000000 --- a/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/ServiceBusConsumerTest.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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.azure.servicebus.integration; - -import java.util.LinkedList; -import java.util.List; - -import org.apache.camel.EndpointInject; -import org.apache.camel.Exchange; -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.component.azure.servicebus.ServiceBusConstants; -import org.apache.camel.component.azure.servicebus.client.ServiceBusSenderAsyncClientWrapper; -import org.apache.camel.component.azure.servicebus.operations.ServiceBusSenderOperations; -import org.apache.camel.component.mock.MockEndpoint; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.junit.jupiter.api.condition.EnabledIfSystemProperty; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -@EnabledIfSystemProperty(named = "connectionString", matches = ".*", - disabledReason = "Make sure to supply azure servicebus connectionString, e.g: mvn verify -DconnectionString=string") -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class ServiceBusConsumerTest extends BaseCamelServiceBusTestSupport { - - @EndpointInject("mock:receiveMessagesResult") - private MockEndpoint receiveMessagesResult; - - @EndpointInject("mock:peekMessagesResult") - private MockEndpoint peekMessagesResult; - - @Test - void testReceiveMessages() throws InterruptedException { - // send test data - final List inputBatch = new LinkedList<>(); - inputBatch.add("test batch 1"); - inputBatch.add("test batch 2"); - inputBatch.add("test batch 3"); - - new ServiceBusSenderOperations(new ServiceBusSenderAsyncClientWrapper(senderAsyncClient)) - .sendMessages(inputBatch, null, null, null) - .block(); - - // test the data now - receiveMessagesResult.expectedMessageCount(3); - receiveMessagesResult.expectedBodiesReceived("test batch 1", "test batch 2", "test batch 3"); - receiveMessagesResult.assertIsSatisfied(); - - final List exchanges = receiveMessagesResult.getExchanges(); - - assertNotNull(exchanges.get(0).getMessage().getHeaders()); - assertNotNull(exchanges.get(1).getMessage().getHeaders()); - assertNotNull(exchanges.get(2).getMessage().getHeaders()); - - // we test headers - assertNotNull(exchanges.get(0).getMessage().getHeader(ServiceBusConstants.MESSAGE_ID)); - assertNotNull(exchanges.get(1).getMessage().getHeader(ServiceBusConstants.MESSAGE_ID)); - assertNotNull(exchanges.get(2).getMessage().getHeader(ServiceBusConstants.MESSAGE_ID)); - } - - @Test - @Disabled - void testPeekMessages() throws InterruptedException { - // send test data - final List inputBatch = new LinkedList<>(); - inputBatch.add("peek test batch 1"); - inputBatch.add("peek test batch 2"); - inputBatch.add("peek test batch 3"); - - new ServiceBusSenderOperations(new ServiceBusSenderAsyncClientWrapper(senderAsyncClient)) - .sendMessages(inputBatch, null, null, null) - .block(); - - // test the data now - peekMessagesResult.expectedMessageCount(3); - peekMessagesResult.expectedBodiesReceived("peek test batch 1", "peek test batch 2", "peek test batch 3"); - peekMessagesResult.assertIsSatisfied(); - - final List exchanges = peekMessagesResult.getExchanges(); - - assertNotNull(exchanges.get(0).getMessage().getHeaders()); - assertNotNull(exchanges.get(1).getMessage().getHeaders()); - assertNotNull(exchanges.get(2).getMessage().getHeaders()); - - // we test headers - assertNotNull(exchanges.get(0).getMessage().getHeader(ServiceBusConstants.MESSAGE_ID)); - assertNotNull(exchanges.get(1).getMessage().getHeader(ServiceBusConstants.MESSAGE_ID)); - assertNotNull(exchanges.get(2).getMessage().getHeader(ServiceBusConstants.MESSAGE_ID)); - } - - @Override - protected RouteBuilder createRouteBuilder() { - return new RouteBuilder() { - @Override - public void configure() { - from("azure-servicebus:test//?connectionString=test").to(receiveMessagesResult); - from("azure-servicebus:test//?connectionString=test&consumerOperation=peekMessages&peekNumMaxMessages=3") - .to(peekMessagesResult); - } - }; - } -} diff --git a/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/ServiceBusProducerIT.java b/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/ServiceBusProducerIT.java new file mode 100644 index 0000000000000..bca480746d287 --- /dev/null +++ b/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/ServiceBusProducerIT.java @@ -0,0 +1,215 @@ +/* + * 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.azure.servicebus.integration; + +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; + +import com.azure.messaging.servicebus.ServiceBusProcessorClient; +import com.azure.messaging.servicebus.ServiceBusReceivedMessage; +import org.apache.camel.CamelContext; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.azure.servicebus.ServiceBusConstants; +import org.apache.camel.test.infra.core.annotations.RouteFixture; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; + +import static org.junit.jupiter.api.Assertions.*; + +@EnabledIfSystemProperty(named = BaseServiceBusTestSupport.CONNECTION_STRING_PROPERTY_NAME, matches = ".*", + disabledReason = "Service Bus connection string must be supplied to run this test, e.g: mvn verify -D" + + BaseServiceBusTestSupport.CONNECTION_STRING_PROPERTY_NAME + "=connectionString") +public class ServiceBusProducerIT extends BaseServiceBusTestSupport { + private static final String DIRECT_SEND_TO_QUEUE_URI = "direct:sendToQueue"; + private static final String DIRECT_SEND_TO_TOPIC_URI = "direct:sendToTopic"; + private static final String DIRECT_SEND_SCHEDULED_URI = "direct:sendScheduled"; + private static final String PROPAGATED_HEADER_KEY = "PropagatedCustomHeader"; + private static final String PROPAGATED_HEADER_VALUE = "propagated header value"; + private static final Pattern MESSAGE_BODY_PATTERN = Pattern.compile("^message-[0-4]$"); + private ProducerTemplate producerTemplate; + + @BeforeEach + void beforeEach() { + producerTemplate = contextExtension.getProducerTemplate(); + receivedMessageContexts = new ArrayList<>(); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from(DIRECT_SEND_TO_QUEUE_URI) + .to("azure-servicebus:" + QUEUE_NAME); + + from(DIRECT_SEND_TO_TOPIC_URI) + .to("azure-servicebus:" + TOPIC_NAME + "?serviceBusType=topic"); + + from(DIRECT_SEND_SCHEDULED_URI) + .to("azure-servicebus:" + QUEUE_NAME + "?producerOperation=scheduleMessages"); + } + }; + } + + @RouteFixture + public void createRouteBuilder(CamelContext context) throws Exception { + context.addRoutes(createRouteBuilder()); + } + + @Test + void camelSendsMessageToServiceBusQueue() throws InterruptedException { + messageLatch = new CountDownLatch(5); + try (ServiceBusProcessorClient client = createQueueProcessorClient()) { + client.start(); + for (int i = 0; i < 5; i++) { + String message = "message-" + i; + producerTemplate.sendBodyAndHeader(DIRECT_SEND_TO_QUEUE_URI, message, PROPAGATED_HEADER_KEY, + PROPAGATED_HEADER_VALUE); + } + + assertTrue(messageLatch.await(3000, TimeUnit.MILLISECONDS)); + assertEquals(5, receivedMessageContexts.size()); + receivedMessageContexts.forEach(messageContext -> { + ServiceBusReceivedMessage message = messageContext.getMessage(); + String messageBody = message.getBody().toString(); + assertTrue(MESSAGE_BODY_PATTERN.matcher(messageBody).matches()); + Map applicationProperties = message.getApplicationProperties(); + assertEquals(1, applicationProperties.size()); + assertEquals(PROPAGATED_HEADER_VALUE, applicationProperties.get(PROPAGATED_HEADER_KEY)); + }); + } + } + + @Test + void camelSendsMessageBatchToServiceBusQueue() throws InterruptedException { + messageLatch = new CountDownLatch(5); + try (ServiceBusProcessorClient client = createQueueProcessorClient()) { + client.start(); + List messageBatch = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + String message = "message-" + i; + messageBatch.add(message); + } + + producerTemplate.send(DIRECT_SEND_TO_QUEUE_URI, exchange -> { + exchange.getIn().setHeader(PROPAGATED_HEADER_KEY, PROPAGATED_HEADER_VALUE); + exchange.getIn().setBody(messageBatch); + }); + + assertTrue(messageLatch.await(3000, TimeUnit.MILLISECONDS)); + assertEquals(5, receivedMessageContexts.size()); + receivedMessageContexts.forEach(messageContext -> { + ServiceBusReceivedMessage message = messageContext.getMessage(); + String messageBody = message.getBody().toString(); + assertTrue(MESSAGE_BODY_PATTERN.matcher(messageBody).matches()); + Map applicationProperties = message.getApplicationProperties(); + assertEquals(1, applicationProperties.size()); + assertEquals(PROPAGATED_HEADER_VALUE, applicationProperties.get(PROPAGATED_HEADER_KEY)); + }); + } + } + + @Test + void camelSendsMessageToServiceBusTopic() throws InterruptedException { + messageLatch = new CountDownLatch(5); + try (ServiceBusProcessorClient client = createTopicProcessorClient()) { + client.start(); + for (int i = 0; i < 5; i++) { + String message = "message-" + i; + producerTemplate.sendBodyAndHeader(DIRECT_SEND_TO_TOPIC_URI, message, PROPAGATED_HEADER_KEY, + PROPAGATED_HEADER_VALUE); + } + + assertTrue(messageLatch.await(3000, TimeUnit.MILLISECONDS)); + assertEquals(5, receivedMessageContexts.size()); + receivedMessageContexts.forEach(messageContext -> { + ServiceBusReceivedMessage message = messageContext.getMessage(); + String messageBody = message.getBody().toString(); + assertTrue(MESSAGE_BODY_PATTERN.matcher(messageBody).matches()); + Map applicationProperties = message.getApplicationProperties(); + assertEquals(1, applicationProperties.size()); + assertEquals(PROPAGATED_HEADER_VALUE, applicationProperties.get(PROPAGATED_HEADER_KEY)); + }); + } + } + + @Test + void camelSchedulesServiceBusMessage() throws InterruptedException { + messageLatch = new CountDownLatch(5); + try (ServiceBusProcessorClient client = createQueueProcessorClient()) { + client.start(); + for (int i = 0; i < 5; i++) { + String message = "message-" + i; + Map headers = new HashMap<>(); + headers.put(PROPAGATED_HEADER_KEY, PROPAGATED_HEADER_VALUE); + headers.put(ServiceBusConstants.SCHEDULED_ENQUEUE_TIME, OffsetDateTime.now().plusSeconds(1)); + producerTemplate.sendBodyAndHeaders(DIRECT_SEND_SCHEDULED_URI, message, headers); + } + + assertTrue(messageLatch.await(4000, TimeUnit.MILLISECONDS)); + assertEquals(5, receivedMessageContexts.size()); + receivedMessageContexts.forEach(messageContext -> { + ServiceBusReceivedMessage message = messageContext.getMessage(); + String messageBody = message.getBody().toString(); + assertTrue(MESSAGE_BODY_PATTERN.matcher(messageBody).matches()); + Map applicationProperties = message.getApplicationProperties(); + assertEquals(1, applicationProperties.size()); + assertEquals(PROPAGATED_HEADER_VALUE, applicationProperties.get(PROPAGATED_HEADER_KEY)); + assertInstanceOf(OffsetDateTime.class, message.getScheduledEnqueueTime()); + }); + } + } + + @Test + void camelSchedulesServiceBusMessageBatch() throws InterruptedException { + messageLatch = new CountDownLatch(5); + try (ServiceBusProcessorClient client = createQueueProcessorClient()) { + client.start(); + List messageBatch = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + String message = "message-" + i; + messageBatch.add(message); + } + + producerTemplate.send(DIRECT_SEND_SCHEDULED_URI, exchange -> { + exchange.getIn().setHeader(ServiceBusConstants.SCHEDULED_ENQUEUE_TIME, OffsetDateTime.now().plusSeconds(1)); + exchange.getIn().setHeader(PROPAGATED_HEADER_KEY, PROPAGATED_HEADER_VALUE); + exchange.getIn().setBody(messageBatch); + }); + + assertTrue(messageLatch.await(10000, TimeUnit.MILLISECONDS)); + assertEquals(5, receivedMessageContexts.size()); + receivedMessageContexts.forEach(messageContext -> { + ServiceBusReceivedMessage message = messageContext.getMessage(); + String messageBody = message.getBody().toString(); + assertTrue(MESSAGE_BODY_PATTERN.matcher(messageBody).matches()); + Map applicationProperties = message.getApplicationProperties(); + assertEquals(1, applicationProperties.size()); + assertEquals(PROPAGATED_HEADER_VALUE, applicationProperties.get(PROPAGATED_HEADER_KEY)); + assertInstanceOf(OffsetDateTime.class, message.getScheduledEnqueueTime()); + }); + } + } +} diff --git a/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/ServiceBusProducerTest.java b/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/ServiceBusProducerTest.java deleted file mode 100644 index 1a98a53a1e014..0000000000000 --- a/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/ServiceBusProducerTest.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * 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.azure.servicebus.integration; - -import java.nio.charset.StandardCharsets; -import java.time.OffsetDateTime; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Spliterator; -import java.util.stream.StreamSupport; - -import com.azure.messaging.servicebus.ServiceBusReceivedMessage; -import org.apache.camel.EndpointInject; -import org.apache.camel.ProducerTemplate; -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.component.azure.servicebus.ServiceBusConstants; -import org.apache.camel.component.mock.MockEndpoint; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.junit.jupiter.api.condition.EnabledIfSystemProperty; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -@EnabledIfSystemProperty(named = "connectionString", matches = ".*", - disabledReason = "Make sure to supply azure servicebus connectionString, e.g: mvn verify -DconnectionString=string") -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class ServiceBusProducerTest extends BaseCamelServiceBusTestSupport { - - @EndpointInject - private ProducerTemplate template; - - @EndpointInject("mock:result") - private MockEndpoint result; - - @Test - public void testSendMessage() throws InterruptedException { - template.send("direct:sendMessage", exchange -> { - exchange.getIn().setBody("123456789"); - exchange.getIn().setHeader(ServiceBusConstants.APPLICATION_PROPERTIES, Map.of("customKey", "customValue")); - }); - - Thread.sleep(1000); - - // let's check our data - final List receivedMessages - = receiverAsyncClient.receiveMessages().toStream().toList(); - - final boolean batch1Exists = receivedMessages.stream() - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString().equals("123456789")); - - final boolean applicationPropertiesPresent = receivedMessages.stream() - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getApplicationProperties() - .containsKey("customKey")); - - assertTrue(batch1Exists, "test message body"); - assertTrue(applicationPropertiesPresent, "test message application properties"); - - //test byte body - byte[] testByteBody = "test data".getBytes(StandardCharsets.UTF_8); - template.send("direct:sendMessage", exchange -> { - exchange.getIn().setBody(testByteBody); - exchange.getIn().setHeader(ServiceBusConstants.APPLICATION_PROPERTIES, Map.of("customKey", "customValue")); - }); - - Thread.sleep(1000); - - final List receivedMessages2 - = receiverAsyncClient.receiveMessages().toStream().toList(); - - final boolean batch2Exists = receivedMessages2.stream() - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString().equals("123456789")); - - final boolean applicationPropertiesPresent2 = receivedMessages2.stream() - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getApplicationProperties() - .containsKey("customKey")); - - assertTrue(batch2Exists, "test byte body"); - assertTrue(applicationPropertiesPresent2, "test byte message application properties"); - } - - @Test - public void testSendBatchMessages() throws InterruptedException { - template.send("direct:sendBatchMessages", exchange -> { - final List inputBatch = new LinkedList<>(); - inputBatch.add("test batch 1"); - inputBatch.add("test batch 2"); - inputBatch.add("test batch 3"); - inputBatch.add("123456"); - - exchange.getIn().setBody(inputBatch); - }); - - Thread.sleep(1000); - - // let's check our data - final Spliterator receivedMessages - = receiverAsyncClient.receiveMessages().toIterable().spliterator(); - - final boolean batch1Exists = StreamSupport.stream(receivedMessages, false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString().equals("test batch 1")); - - final boolean batch2Exists = StreamSupport.stream(receivedMessages, false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString().equals("test batch 2")); - - final boolean batch3Exists = StreamSupport.stream(receivedMessages, false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString().equals("test batch 3")); - - final boolean batch4Exists = StreamSupport.stream(receivedMessages, false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString().equals("123456")); - - assertTrue(batch1Exists, "test message body 1"); - assertTrue(batch2Exists, "test message body 2"); - assertTrue(batch3Exists, "test message body 3"); - assertTrue(batch4Exists, "test message body 4"); - - //test bytes - final List inputBatch2 = new LinkedList<>(); - byte[] byteBody1 = "test data".getBytes(StandardCharsets.UTF_8); - byte[] byteBody2 = "test data2".getBytes(StandardCharsets.UTF_8); - inputBatch2.add(byteBody1); - inputBatch2.add(byteBody2); - - template.send("direct:sendBatchMessages", exchange -> { - exchange.getIn().setBody(inputBatch2); - }); - - Thread.sleep(1000); - - // let's check our data - final Spliterator receivedMessages2 - = receiverAsyncClient.receiveMessages().toIterable().spliterator(); - final boolean byteBody1Exists = StreamSupport.stream(receivedMessages2, false) - .anyMatch(serviceBusReceivedMessage -> Arrays.equals(serviceBusReceivedMessage.getBody().toBytes(), byteBody1)); - final boolean byteBody2Exists = StreamSupport.stream(receivedMessages2, false) - .anyMatch(serviceBusReceivedMessage -> Arrays.equals(serviceBusReceivedMessage.getBody().toBytes(), byteBody2)); - - assertTrue(byteBody1Exists, "test byte body 1"); - assertTrue(byteBody2Exists, "test byte body 2"); - } - - @Test - void testScheduleMessage() throws InterruptedException { - template.send("direct:scheduleMessage", exchange -> { - exchange.getIn().setHeader(ServiceBusConstants.SCHEDULED_ENQUEUE_TIME, OffsetDateTime.now()); - exchange.getIn().setBody("test message"); - }); - - Thread.sleep(1000); - - // let's check our data - final Spliterator receivedMessages - = receiverAsyncClient.receiveMessages().toIterable().spliterator(); - - final boolean batch1Exists = StreamSupport.stream(receivedMessages, false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString().equals("test message")); - - assertTrue(batch1Exists); - - //test bytes - byte[] testByteBody = "test data".getBytes(StandardCharsets.UTF_8); - template.send("direct:scheduleMessage", exchange -> { - exchange.getIn().setHeader(ServiceBusConstants.SCHEDULED_ENQUEUE_TIME, OffsetDateTime.now()); - exchange.getIn().setBody(testByteBody); - }); - - Thread.sleep(1000); - - final Spliterator receivedMessages2 - = receiverAsyncClient.receiveMessages().toIterable().spliterator(); - - final boolean batch2Exists = StreamSupport.stream(receivedMessages2, false) - .anyMatch(serviceBusReceivedMessage -> Arrays.equals(serviceBusReceivedMessage.getBody().toBytes(), - testByteBody)); - - assertTrue(batch2Exists); - } - - @Test - public void testScheduleBatchMessages() throws InterruptedException { - template.send("direct:scheduleBatchMessages", exchange -> { - final List inputBatch = new LinkedList<>(); - inputBatch.add("test batch 1"); - inputBatch.add("test batch 2"); - inputBatch.add("test batch 3"); - inputBatch.add("123456"); - - exchange.getIn().setHeader(ServiceBusConstants.SCHEDULED_ENQUEUE_TIME, OffsetDateTime.now()); - exchange.getIn().setBody(inputBatch); - }); - - Thread.sleep(1000); - - // let's check our data - final Spliterator receivedMessages - = receiverAsyncClient.receiveMessages().toIterable().spliterator(); - - final boolean batch1Exists = StreamSupport.stream(receivedMessages, false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString().equals("test batch 1")); - - final boolean batch2Exists = StreamSupport.stream(receivedMessages, false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString().equals("test batch 2")); - - final boolean batch3Exists = StreamSupport.stream(receivedMessages, false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString().equals("test batch 3")); - - final boolean batch4Exists = StreamSupport.stream(receivedMessages, false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString().equals("123456")); - - assertTrue(batch1Exists, "test message body 1"); - assertTrue(batch2Exists, "test message body 2"); - assertTrue(batch3Exists, "test message body 3"); - assertTrue(batch4Exists, "test message body 4"); - - //test bytes - final List inputBatch2 = new LinkedList<>(); - byte[] byteBody1 = "test data".getBytes(StandardCharsets.UTF_8); - byte[] byteBody2 = "test data2".getBytes(StandardCharsets.UTF_8); - inputBatch2.add(byteBody1); - inputBatch2.add(byteBody2); - - template.send("direct:scheduleBatchMessages", exchange -> { - exchange.getIn().setHeader(ServiceBusConstants.SCHEDULED_ENQUEUE_TIME, OffsetDateTime.now()); - exchange.getIn().setBody(inputBatch2); - }); - - Thread.sleep(1000); - - // let's check our data - final Spliterator receivedMessages2 - = receiverAsyncClient.receiveMessages().toIterable().spliterator(); - - final boolean byteBody1Exists = StreamSupport.stream(receivedMessages2, false) - .anyMatch(serviceBusReceivedMessage -> Arrays.equals(serviceBusReceivedMessage.getBody().toBytes(), byteBody1)); - - final boolean byteBody2Exists = StreamSupport.stream(receivedMessages2, false) - .anyMatch(serviceBusReceivedMessage -> Arrays.equals(serviceBusReceivedMessage.getBody().toBytes(), byteBody2)); - - assertTrue(byteBody1Exists, "test byte message body 1"); - assertTrue(byteBody2Exists, "test byte message body 2"); - } - - @Override - protected RouteBuilder createRouteBuilder() { - return new RouteBuilder() { - @Override - public void configure() { - from("direct:sendBatchMessages").to("azure-servicebus:test//?connectionString=test").to(result); - from("direct:sendMessage").to("azure-servicebus:test//?connectionString=test").to(result); - from("direct:scheduleMessage") - .to("azure-servicebus:test//?connectionString=test&producerOperation=scheduleMessages").to(result); - from("direct:scheduleBatchMessages") - .to("azure-servicebus:test//?connectionString=test&producerOperation=scheduleMessages").to(result); - } - }; - } -} diff --git a/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/operations/ServiceBusSenderOperationsTest.java b/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/operations/ServiceBusSenderOperationsTest.java index b131609adc58a..2de9ed1b146a1 100644 --- a/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/operations/ServiceBusSenderOperationsTest.java +++ b/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/integration/operations/ServiceBusSenderOperationsTest.java @@ -19,89 +19,71 @@ import java.nio.charset.StandardCharsets; import java.time.OffsetDateTime; import java.util.*; -import java.util.stream.StreamSupport; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import com.azure.messaging.servicebus.ServiceBusClientBuilder; -import com.azure.messaging.servicebus.ServiceBusReceivedMessage; -import com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient; +import com.azure.messaging.servicebus.ServiceBusProcessorClient; import com.azure.messaging.servicebus.ServiceBusSenderAsyncClient; -import org.apache.camel.component.azure.servicebus.ServiceBusTestUtils; -import org.apache.camel.component.azure.servicebus.client.ServiceBusReceiverAsyncClientWrapper; +import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.azure.servicebus.client.ServiceBusSenderAsyncClientWrapper; +import org.apache.camel.component.azure.servicebus.integration.BaseServiceBusTestSupport; import org.apache.camel.component.azure.servicebus.operations.ServiceBusSenderOperations; import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.condition.EnabledIfSystemProperty; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -@EnabledIfSystemProperty(named = "connectionString", matches = ".*", - disabledReason = "Make sure to supply azure servicebus connectionString, e.g: mvn verify -DconnectionString=string") -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -public class ServiceBusSenderOperationsTest { +@EnabledIfSystemProperty(named = BaseServiceBusTestSupport.CONNECTION_STRING_PROPERTY_NAME, matches = ".*", + disabledReason = "Service Bus connection string must be supplied to run this test, e.g: mvn verify -D" + + BaseServiceBusTestSupport.CONNECTION_STRING_PROPERTY_NAME + "=connectionString") +public class ServiceBusSenderOperationsTest extends BaseServiceBusTestSupport { - private ServiceBusSenderAsyncClientWrapper clientSenderWrapper; - private ServiceBusReceiverAsyncClientWrapper clientReceiverWrapper; + private static ServiceBusSenderAsyncClientWrapper clientSenderWrapper; @BeforeAll - void prepare() throws Exception { - final Properties properties = ServiceBusTestUtils.loadAzureAccessFromJvmEnv(); - - final ServiceBusSenderAsyncClient senderClient = new ServiceBusClientBuilder() - .connectionString(properties.getProperty(ServiceBusTestUtils.CONNECTION_STRING)) - .sender() - .buildAsyncClient(); - + static void prepare() { + final ServiceBusSenderAsyncClient senderClient = new ServiceBusClientBuilder().connectionString(CONNECTION_STRING) + .sender().topicName(TOPIC_NAME).buildAsyncClient(); clientSenderWrapper = new ServiceBusSenderAsyncClientWrapper(senderClient); } - @BeforeEach - void prepareReceiver() throws Exception { - final Properties properties = ServiceBusTestUtils.loadAzureAccessFromJvmEnv(); - - final ServiceBusReceiverAsyncClient receiverClient = new ServiceBusClientBuilder() - .connectionString(properties.getProperty(ServiceBusTestUtils.CONNECTION_STRING)) - .receiver() - .topicName(properties.getProperty(ServiceBusTestUtils.TOPIC_NAME)) - .subscriptionName(properties.getProperty(ServiceBusTestUtils.SUBSCRIPTION_NAME)) - .buildAsyncClient(); - - clientReceiverWrapper = new ServiceBusReceiverAsyncClientWrapper(receiverClient); - } - @AfterAll - void closeClient() { + static void closeClient() { clientSenderWrapper.close(); } - @AfterEach - void closeSubscriber() { - clientReceiverWrapper.close(); + @BeforeEach + void beforeEach() { + receivedMessageContexts = new ArrayList<>(); } @Test - void testSendSingleMessage() { + void testSendSingleMessage() throws InterruptedException { final ServiceBusSenderOperations operations = new ServiceBusSenderOperations(clientSenderWrapper); + messageLatch = new CountDownLatch(2); - operations.sendMessages("test data", null, Map.of("customKey", "customValue"), null).block(); + try (ServiceBusProcessorClient processorClient = createTopicProcessorClient()) { + processorClient.start(); + operations.sendMessages("test data", null, Map.of("customKey", "customValue"), null).block(); + //test bytes + byte[] testByteBody = "test data".getBytes(StandardCharsets.UTF_8); + operations.sendMessages(testByteBody, null, Map.of("customKey", "customValue"), null).block(); - final boolean exists = StreamSupport.stream(clientReceiverWrapper.receiveMessages().toIterable().spliterator(), false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString().equals("test data")); + assertTrue(messageLatch.await(3000, TimeUnit.MILLISECONDS)); - assertTrue(exists, "test message body"); + final boolean exists = receivedMessageContexts.stream() + .anyMatch(messageContext -> messageContext.getMessage().getBody().toString().equals("test data")); + assertTrue(exists, "test message body"); - //test bytes - byte[] testByteBody = "test data".getBytes(StandardCharsets.UTF_8); - operations.sendMessages(testByteBody, null, Map.of("customKey", "customValue"), null).block(); - final boolean exists2 = StreamSupport.stream(clientReceiverWrapper.receiveMessages().toIterable().spliterator(), false) - .anyMatch(serviceBusReceivedMessage -> Arrays.equals(serviceBusReceivedMessage.getBody().toBytes(), - testByteBody)); - assertTrue(exists2, "test byte body"); + final boolean exists2 = receivedMessageContexts.stream() + .anyMatch(messageContext -> Arrays.equals(messageContext.getMessage().getBody().toBytes(), testByteBody)); + assertTrue(exists2, "test byte body"); + } // test if we have something other than string or byte[] assertThrows(IllegalArgumentException.class, () -> { @@ -110,73 +92,73 @@ void testSendSingleMessage() { } @Test - void testSendingBatchMessages() { + void testSendingBatchMessages() throws InterruptedException { final ServiceBusSenderOperations operations = new ServiceBusSenderOperations(clientSenderWrapper); - - final List inputBatch = new LinkedList<>(); - inputBatch.add("test batch 1"); - inputBatch.add("test batch 2"); - inputBatch.add("test batch 3"); - - operations.sendMessages(inputBatch, null, null, null).block(); - - final Spliterator receivedMessages - = clientReceiverWrapper.receiveMessages().toIterable().spliterator(); - - final boolean batch1Exists = StreamSupport.stream(receivedMessages, false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString().equals("test batch 1")); - - final boolean batch2Exists = StreamSupport.stream(receivedMessages, false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString().equals("test batch 2")); - - final boolean batch3Exists = StreamSupport.stream(receivedMessages, false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString().equals("test batch 3")); - - assertTrue(batch1Exists, "test message body 1"); - assertTrue(batch2Exists, "test message body 2"); - assertTrue(batch3Exists, "test message body 3"); - - //test bytes - final List inputBatch2 = new LinkedList<>(); - byte[] byteBody1 = "test data".getBytes(StandardCharsets.UTF_8); - byte[] byteBody2 = "test data2".getBytes(StandardCharsets.UTF_8); - inputBatch2.add(byteBody1); - inputBatch2.add(byteBody2); - - operations.sendMessages(inputBatch2, null, null, null).block(); - final Spliterator receivedMessages2 - = clientReceiverWrapper.receiveMessages().toIterable().spliterator(); - - final boolean byteBody1Exists = StreamSupport.stream(receivedMessages2, false) - .anyMatch(serviceBusReceivedMessage -> Arrays.equals(serviceBusReceivedMessage.getBody().toBytes(), byteBody1)); - final boolean byteBody2Exists = StreamSupport.stream(receivedMessages2, false) - .anyMatch(serviceBusReceivedMessage -> Arrays.equals(serviceBusReceivedMessage.getBody().toBytes(), byteBody2)); - - assertTrue(byteBody1Exists, "test byte body 1"); - assertTrue(byteBody2Exists, "test byte body 2"); - + messageLatch = new CountDownLatch(5); + + try (ServiceBusProcessorClient processorClient = createTopicProcessorClient()) { + processorClient.start(); + + final List inputBatch = new LinkedList<>(); + inputBatch.add("test batch 1"); + inputBatch.add("test batch 2"); + inputBatch.add("test batch 3"); + + operations.sendMessages(inputBatch, null, null, null).block(); + //test bytes + final List inputBatch2 = new LinkedList<>(); + byte[] byteBody1 = "test data".getBytes(StandardCharsets.UTF_8); + byte[] byteBody2 = "test data2".getBytes(StandardCharsets.UTF_8); + inputBatch2.add(byteBody1); + inputBatch2.add(byteBody2); + operations.sendMessages(inputBatch2, null, null, null).block(); + + assertTrue(messageLatch.await(3000, TimeUnit.MILLISECONDS)); + + final boolean batch1Exists = receivedMessageContexts.stream() + .anyMatch(messageContext -> messageContext.getMessage().getBody().toString().equals("test batch 1")); + final boolean batch2Exists = receivedMessageContexts.stream() + .anyMatch(messageContext -> messageContext.getMessage().getBody().toString().equals("test batch 2")); + final boolean batch3Exists = receivedMessageContexts.stream() + .anyMatch(messageContext -> messageContext.getMessage().getBody().toString().equals("test batch 3")); + + assertTrue(batch1Exists, "test message body 1"); + assertTrue(batch2Exists, "test message body 2"); + assertTrue(batch3Exists, "test message body 3"); + + final boolean byteBody1Exists = receivedMessageContexts.stream() + .anyMatch(messageContext -> Arrays.equals(messageContext.getMessage().getBody().toBytes(), byteBody1)); + final boolean byteBody2Exists = receivedMessageContexts.stream() + .anyMatch(messageContext -> Arrays.equals(messageContext.getMessage().getBody().toBytes(), byteBody2)); + + assertTrue(byteBody1Exists, "test byte body 1"); + assertTrue(byteBody2Exists, "test byte body 2"); + } } @Test - void testScheduleMessage() { + void testScheduleMessage() throws InterruptedException { final ServiceBusSenderOperations operations = new ServiceBusSenderOperations(clientSenderWrapper); + messageLatch = new CountDownLatch(2); - operations.scheduleMessages("testScheduleMessage", OffsetDateTime.now(), null, null, null).block(); + try (ServiceBusProcessorClient processorClient = createTopicProcessorClient()) { + processorClient.start(); - final boolean exists = StreamSupport.stream(clientReceiverWrapper.receiveMessages().toIterable().spliterator(), false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString() - .equals("testScheduleMessage")); + operations.scheduleMessages("testScheduleMessage", OffsetDateTime.now(), null, null, null).block(); + //test bytes + byte[] testByteBody = "test data".getBytes(StandardCharsets.UTF_8); + operations.scheduleMessages(testByteBody, OffsetDateTime.now(), null, null, null).block(); - assertTrue(exists, "test message body"); + assertTrue(messageLatch.await(3000, TimeUnit.MILLISECONDS)); - //test bytes - byte[] testByteBody = "test data".getBytes(StandardCharsets.UTF_8); - operations.scheduleMessages(testByteBody, OffsetDateTime.now(), null, null, null).block(); - final boolean exists2 = StreamSupport.stream(clientReceiverWrapper.receiveMessages().toIterable().spliterator(), false) - .anyMatch(serviceBusReceivedMessage -> Arrays.equals(serviceBusReceivedMessage.getBody().toBytes(), - testByteBody)); - assertTrue(exists2, "test byte body"); + final boolean exists = receivedMessageContexts.stream() + .anyMatch(messageContext -> messageContext.getMessage().getBody().toString().equals("testScheduleMessage")); + final boolean exists2 = receivedMessageContexts.stream() + .anyMatch(messageContext -> Arrays.equals(messageContext.getMessage().getBody().toBytes(), testByteBody)); + assertTrue(exists, "test message body"); + assertTrue(exists2, "test byte body"); + } // test if we have something other than string or byte[] assertThrows(IllegalArgumentException.class, () -> { operations.scheduleMessages(12345, OffsetDateTime.now(), null, null, null).block(); @@ -184,52 +166,56 @@ void testScheduleMessage() { } @Test - void testSchedulingBatchMessages() { + void testSchedulingBatchMessages() throws InterruptedException { final ServiceBusSenderOperations operations = new ServiceBusSenderOperations(clientSenderWrapper); + messageLatch = new CountDownLatch(5); + + try (ServiceBusProcessorClient processorClient = createTopicProcessorClient()) { + processorClient.start(); + + final List inputBatch = new LinkedList<>(); + inputBatch.add("testSchedulingBatchMessages 1"); + inputBatch.add("testSchedulingBatchMessages 2"); + inputBatch.add("testSchedulingBatchMessages 3"); + operations.scheduleMessages(inputBatch, OffsetDateTime.now(), null, null, null).block(); + //test bytes + final List inputBatch2 = new LinkedList<>(); + byte[] byteBody1 = "test data".getBytes(StandardCharsets.UTF_8); + byte[] byteBody2 = "test data2".getBytes(StandardCharsets.UTF_8); + inputBatch2.add(byteBody1); + inputBatch2.add(byteBody2); + operations.scheduleMessages(inputBatch2, OffsetDateTime.now(), null, null, null).block(); + + assertTrue(messageLatch.await(3000, TimeUnit.MILLISECONDS)); + + final boolean batch1Exists = receivedMessageContexts.stream().anyMatch( + messageContext -> messageContext.getMessage().getBody().toString().equals("testSchedulingBatchMessages 1")); + final boolean batch2Exists = receivedMessageContexts.stream().anyMatch( + messageContext -> messageContext.getMessage().getBody().toString().equals("testSchedulingBatchMessages 2")); + final boolean batch3Exists = receivedMessageContexts.stream().anyMatch( + messageContext -> messageContext.getMessage().getBody().toString().equals("testSchedulingBatchMessages 3")); + + assertTrue(batch1Exists, "test message body 1"); + assertTrue(batch2Exists, "test message body 2"); + assertTrue(batch3Exists, "test message body 3"); + + final boolean byteBody1Exists = receivedMessageContexts.stream() + .anyMatch(messageContext -> Arrays.equals(messageContext.getMessage().getBody().toBytes(), byteBody1)); + final boolean byteBody2Exists = receivedMessageContexts.stream() + .anyMatch(messageContext -> Arrays.equals(messageContext.getMessage().getBody().toBytes(), byteBody2)); + + assertTrue(byteBody1Exists, "test byte body 1"); + assertTrue(byteBody2Exists, "test byte body 2"); + } + } - final List inputBatch = new LinkedList<>(); - inputBatch.add("testSchedulingBatchMessages 1"); - inputBatch.add("testSchedulingBatchMessages 2"); - inputBatch.add("testSchedulingBatchMessages 3"); - - operations.scheduleMessages(inputBatch, OffsetDateTime.now(), null, null, null).block(); - - final Spliterator receivedMessages - = clientReceiverWrapper.receiveMessages().toIterable().spliterator(); - - final boolean batch1Exists = StreamSupport.stream(receivedMessages, false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString() - .equals("testSchedulingBatchMessages 1")); - - final boolean batch2Exists = StreamSupport.stream(receivedMessages, false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString() - .equals("testSchedulingBatchMessages 2")); - - final boolean batch3Exists = StreamSupport.stream(receivedMessages, false) - .anyMatch(serviceBusReceivedMessage -> serviceBusReceivedMessage.getBody().toString() - .equals("testSchedulingBatchMessages 3")); - - assertTrue(batch1Exists, "test message body 1"); - assertTrue(batch2Exists, "test message body 2"); - assertTrue(batch3Exists, "test message body 3"); - - //test bytes - final List inputBatch2 = new LinkedList<>(); - byte[] byteBody1 = "test data".getBytes(StandardCharsets.UTF_8); - byte[] byteBody2 = "test data2".getBytes(StandardCharsets.UTF_8); - inputBatch2.add(byteBody1); - inputBatch2.add(byteBody2); - - operations.scheduleMessages(inputBatch2, OffsetDateTime.now(), null, null, null).block(); - final Spliterator receivedMessages2 - = clientReceiverWrapper.receiveMessages().toIterable().spliterator(); - - final boolean byteBody1Exists = StreamSupport.stream(receivedMessages2, false) - .anyMatch(serviceBusReceivedMessage -> Arrays.equals(serviceBusReceivedMessage.getBody().toBytes(), byteBody1)); - final boolean byteBody2Exists = StreamSupport.stream(receivedMessages2, false) - .anyMatch(serviceBusReceivedMessage -> Arrays.equals(serviceBusReceivedMessage.getBody().toBytes(), byteBody2)); - - assertTrue(byteBody1Exists, "test byte body 1"); - assertTrue(byteBody2Exists, "test byte body 2"); + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + // No Routes required for this test + } + }; } } diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_6.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_6.adoc index bc21522b8098e..7fe09fad11df1 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_6.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_6.adoc @@ -76,6 +76,17 @@ Multiple scopes can be separated by comma. The Kafka component now supports custom subscription adapters for applications with very complex subscription logic. +=== camel-azure-servicebus + +The Camel Azure ServiceBus consumer has been refactored to internally use the high-level client instead of the low-level client to more easily support automatic reconnection, competing consumers and high availability, amongst other concerns. The corresponding changes to configuration options are: + +- The consumer now supports the Competing Consumers EIP. This can be enabled by increasing the newly added `maxConcurrentCalls` option to a value greater than 1. +- The `disableAutoComplete` option has been removed. Auto-complete is always disabled on the underlying client to ensure that Camel is able to correctly complete, abandon or dead-letter consumed messages as appropriate. The presence of the `disableAutoComplete` option made little sense, since it is not propagated to the underlying client and enabling this option caused Camel not to take any steps to acknowledge/reject consumed messages. Enabling this option would result in message locks being held indefinitely, which is almost certainly not the desired behaviour. +- The high level client always operates in `receiveMessages` mode (peek mode is not supported), so the `consumerOperation` option has been removed, along with the `ServiceBusConsumerOperationDefinition` enum. The associated `peekNumMaxMessages` option has also been removed. +- The `receiverAsyncClient` option has been replaced with a `processorClient` option to enable use of a custom-configured client. The parameter type accepted by this option is `ServiceBusProcessorClient`. +- The `reconnectDelay` option has been removed, since reconnection is now handled internally by the client. + + === camel-yaml-dsl Renamed `streamCaching` to `streamCache` on the `route` diff --git a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/AzureServicebusComponentBuilderFactory.java b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/AzureServicebusComponentBuilderFactory.java index fb9d090bf36a9..271bc9e99ed79 100644 --- a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/AzureServicebusComponentBuilderFactory.java +++ b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/AzureServicebusComponentBuilderFactory.java @@ -204,43 +204,6 @@ default AzureServicebusComponentBuilder bridgeErrorHandler(boolean bridgeErrorHa } - /** - * Sets the desired operation to be used in the consumer. - * - * The option is a: - * <code>org.apache.camel.component.azure.servicebus.ServiceBusConsumerOperationDefinition</code> type. - * - * Default: receiveMessages - * Group: consumer - * - * @param consumerOperation the value to set - * @return the dsl builder - */ - default AzureServicebusComponentBuilder consumerOperation(org.apache.camel.component.azure.servicebus.ServiceBusConsumerOperationDefinition consumerOperation) { - doSetProperty("consumerOperation", consumerOperation); - return this; - } - - - /** - * Disables auto-complete and auto-abandon of received messages. By - * default, a successfully processed message is completed. If an error - * happens when the message is abandoned. - * - * The option is a: <code>boolean</code> type. - * - * Default: false - * Group: consumer - * - * @param disableAutoComplete the value to set - * @return the dsl builder - */ - default AzureServicebusComponentBuilder disableAutoComplete(boolean disableAutoComplete) { - doSetProperty("disableAutoComplete", disableAutoComplete); - return this; - } - - /** * Enable application level deadlettering to the subscription deadletter * subqueue if deadletter related headers are set. @@ -277,19 +240,20 @@ default AzureServicebusComponentBuilder maxAutoLockRenewDuration(java.time.Durat return this; } + /** - * Set the max number of messages to be peeked during the peek - * operation. + * Sets maximum number of concurrent calls. * - * The option is a: <code>java.lang.Integer</code> type. + * The option is a: <code>int</code> type. * + * Default: 1 * Group: consumer * - * @param peekNumMaxMessages the value to set + * @param maxConcurrentCalls the value to set * @return the dsl builder */ - default AzureServicebusComponentBuilder peekNumMaxMessages(java.lang.Integer peekNumMaxMessages) { - doSetProperty("peekNumMaxMessages", peekNumMaxMessages); + default AzureServicebusComponentBuilder maxConcurrentCalls(int maxConcurrentCalls) { + doSetProperty("maxConcurrentCalls", maxConcurrentCalls); return this; } @@ -315,19 +279,19 @@ default AzureServicebusComponentBuilder prefetchCount(int prefetchCount) { } /** - * Sets the receiverAsyncClient in order to consume messages by the + * Sets the processorClient in order to consume messages by the * consumer. * * The option is a: - * <code>com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient</code> type. + * <code>com.azure.messaging.servicebus.ServiceBusProcessorClient</code> type. * * Group: consumer * - * @param receiverAsyncClient the value to set + * @param processorClient the value to set * @return the dsl builder */ - default AzureServicebusComponentBuilder receiverAsyncClient(com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient receiverAsyncClient) { - doSetProperty("receiverAsyncClient", receiverAsyncClient); + default AzureServicebusComponentBuilder processorClient(com.azure.messaging.servicebus.ServiceBusProcessorClient processorClient) { + doSetProperty("processorClient", processorClient); return this; } @@ -384,24 +348,6 @@ default AzureServicebusComponentBuilder subscriptionName(java.lang.String subscr } - /** - * If the consumer has connection failure to Azure ServiceBus, then - * delay (millis) some time before re-connecting. - * - * The option is a: <code>int</code> type. - * - * Default: 5000 - * Group: consumer (advanced) - * - * @param reconnectDelay the value to set - * @return the dsl builder - */ - default AzureServicebusComponentBuilder reconnectDelay(int reconnectDelay) { - doSetProperty("reconnectDelay", reconnectDelay); - return this; - } - - /** * Set binary mode. If true, message body will be sent as byte. By * default, it is false. @@ -628,17 +574,14 @@ protected boolean setPropertyOnComponent( case "proxyOptions": getOrCreateConfiguration((ServiceBusComponent) component).setProxyOptions((com.azure.core.amqp.ProxyOptions) value); return true; case "serviceBusType": getOrCreateConfiguration((ServiceBusComponent) component).setServiceBusType((org.apache.camel.component.azure.servicebus.ServiceBusType) value); return true; case "bridgeErrorHandler": ((ServiceBusComponent) component).setBridgeErrorHandler((boolean) value); return true; - case "consumerOperation": getOrCreateConfiguration((ServiceBusComponent) component).setConsumerOperation((org.apache.camel.component.azure.servicebus.ServiceBusConsumerOperationDefinition) value); return true; - case "disableAutoComplete": getOrCreateConfiguration((ServiceBusComponent) component).setDisableAutoComplete((boolean) value); return true; case "enableDeadLettering": getOrCreateConfiguration((ServiceBusComponent) component).setEnableDeadLettering((boolean) value); return true; case "maxAutoLockRenewDuration": getOrCreateConfiguration((ServiceBusComponent) component).setMaxAutoLockRenewDuration((java.time.Duration) value); return true; - case "peekNumMaxMessages": getOrCreateConfiguration((ServiceBusComponent) component).setPeekNumMaxMessages((java.lang.Integer) value); return true; + case "maxConcurrentCalls": getOrCreateConfiguration((ServiceBusComponent) component).setMaxConcurrentCalls((int) value); return true; case "prefetchCount": getOrCreateConfiguration((ServiceBusComponent) component).setPrefetchCount((int) value); return true; - case "receiverAsyncClient": getOrCreateConfiguration((ServiceBusComponent) component).setReceiverAsyncClient((com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient) value); return true; + case "processorClient": getOrCreateConfiguration((ServiceBusComponent) component).setProcessorClient((com.azure.messaging.servicebus.ServiceBusProcessorClient) value); return true; case "serviceBusReceiveMode": getOrCreateConfiguration((ServiceBusComponent) component).setServiceBusReceiveMode((com.azure.messaging.servicebus.models.ServiceBusReceiveMode) value); return true; case "subQueue": getOrCreateConfiguration((ServiceBusComponent) component).setSubQueue((com.azure.messaging.servicebus.models.SubQueue) value); return true; case "subscriptionName": getOrCreateConfiguration((ServiceBusComponent) component).setSubscriptionName((java.lang.String) value); return true; - case "reconnectDelay": getOrCreateConfiguration((ServiceBusComponent) component).setReconnectDelay((int) value); return true; case "binary": getOrCreateConfiguration((ServiceBusComponent) component).setBinary((boolean) value); return true; case "lazyStartProducer": ((ServiceBusComponent) component).setLazyStartProducer((boolean) value); return true; case "producerOperation": getOrCreateConfiguration((ServiceBusComponent) component).setProducerOperation((org.apache.camel.component.azure.servicebus.ServiceBusProducerOperationDefinition) value); return true; diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/ServiceBusEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/ServiceBusEndpointBuilderFactory.java index 81a0328c17b24..2059e6faaadad 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/ServiceBusEndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/ServiceBusEndpointBuilderFactory.java @@ -243,72 +243,6 @@ default ServiceBusEndpointConsumerBuilder serviceBusType(String serviceBusType) doSetProperty("serviceBusType", serviceBusType); return this; } - /** - * Sets the desired operation to be used in the consumer. - * - * The option is a: - * org.apache.camel.component.azure.servicebus.ServiceBusConsumerOperationDefinition type. - * - * Default: receiveMessages - * Group: consumer - * - * @param consumerOperation the value to set - * @return the dsl builder - */ - default ServiceBusEndpointConsumerBuilder consumerOperation(org.apache.camel.component.azure.servicebus.ServiceBusConsumerOperationDefinition consumerOperation) { - doSetProperty("consumerOperation", consumerOperation); - return this; - } - /** - * Sets the desired operation to be used in the consumer. - * - * The option will be converted to a - * org.apache.camel.component.azure.servicebus.ServiceBusConsumerOperationDefinition type. - * - * Default: receiveMessages - * Group: consumer - * - * @param consumerOperation the value to set - * @return the dsl builder - */ - default ServiceBusEndpointConsumerBuilder consumerOperation(String consumerOperation) { - doSetProperty("consumerOperation", consumerOperation); - return this; - } - /** - * Disables auto-complete and auto-abandon of received messages. By - * default, a successfully processed message is completed. If an error - * happens when the message is abandoned. - * - * The option is a: boolean type. - * - * Default: false - * Group: consumer - * - * @param disableAutoComplete the value to set - * @return the dsl builder - */ - default ServiceBusEndpointConsumerBuilder disableAutoComplete(boolean disableAutoComplete) { - doSetProperty("disableAutoComplete", disableAutoComplete); - return this; - } - /** - * Disables auto-complete and auto-abandon of received messages. By - * default, a successfully processed message is completed. If an error - * happens when the message is abandoned. - * - * The option will be converted to a boolean type. - * - * Default: false - * Group: consumer - * - * @param disableAutoComplete the value to set - * @return the dsl builder - */ - default ServiceBusEndpointConsumerBuilder disableAutoComplete(String disableAutoComplete) { - doSetProperty("disableAutoComplete", disableAutoComplete); - return this; - } /** * Enable application level deadlettering to the subscription deadletter * subqueue if deadletter related headers are set. @@ -377,34 +311,33 @@ default ServiceBusEndpointConsumerBuilder maxAutoLockRenewDuration(String maxAut return this; } /** - * Set the max number of messages to be peeked during the peek - * operation. + * Sets maximum number of concurrent calls. * - * The option is a: java.lang.Integer type. + * The option is a: int type. * + * Default: 1 * Group: consumer * - * @param peekNumMaxMessages the value to set + * @param maxConcurrentCalls the value to set * @return the dsl builder */ - default ServiceBusEndpointConsumerBuilder peekNumMaxMessages(Integer peekNumMaxMessages) { - doSetProperty("peekNumMaxMessages", peekNumMaxMessages); + default ServiceBusEndpointConsumerBuilder maxConcurrentCalls(int maxConcurrentCalls) { + doSetProperty("maxConcurrentCalls", maxConcurrentCalls); return this; } /** - * Set the max number of messages to be peeked during the peek - * operation. + * Sets maximum number of concurrent calls. * - * The option will be converted to a java.lang.Integer - * type. + * The option will be converted to a int type. * + * Default: 1 * Group: consumer * - * @param peekNumMaxMessages the value to set + * @param maxConcurrentCalls the value to set * @return the dsl builder */ - default ServiceBusEndpointConsumerBuilder peekNumMaxMessages(String peekNumMaxMessages) { - doSetProperty("peekNumMaxMessages", peekNumMaxMessages); + default ServiceBusEndpointConsumerBuilder maxConcurrentCalls(String maxConcurrentCalls) { + doSetProperty("maxConcurrentCalls", maxConcurrentCalls); return this; } /** @@ -448,35 +381,37 @@ default ServiceBusEndpointConsumerBuilder prefetchCount(String prefetchCount) { return this; } /** - * Sets the receiverAsyncClient in order to consume messages by the + * Sets the processorClient in order to consume messages by the * consumer. * * The option is a: - * com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient type. + * com.azure.messaging.servicebus.ServiceBusProcessorClient + * type. * * Group: consumer * - * @param receiverAsyncClient the value to set + * @param processorClient the value to set * @return the dsl builder */ - default ServiceBusEndpointConsumerBuilder receiverAsyncClient(com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient receiverAsyncClient) { - doSetProperty("receiverAsyncClient", receiverAsyncClient); + default ServiceBusEndpointConsumerBuilder processorClient(com.azure.messaging.servicebus.ServiceBusProcessorClient processorClient) { + doSetProperty("processorClient", processorClient); return this; } /** - * Sets the receiverAsyncClient in order to consume messages by the + * Sets the processorClient in order to consume messages by the * consumer. * * The option will be converted to a - * com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient type. + * com.azure.messaging.servicebus.ServiceBusProcessorClient + * type. * * Group: consumer * - * @param receiverAsyncClient the value to set + * @param processorClient the value to set * @return the dsl builder */ - default ServiceBusEndpointConsumerBuilder receiverAsyncClient(String receiverAsyncClient) { - doSetProperty("receiverAsyncClient", receiverAsyncClient); + default ServiceBusEndpointConsumerBuilder processorClient(String processorClient) { + doSetProperty("processorClient", processorClient); return this; } /** @@ -777,38 +712,6 @@ default AdvancedServiceBusEndpointConsumerBuilder exchangePattern(String exchang doSetProperty("exchangePattern", exchangePattern); return this; } - /** - * If the consumer has connection failure to Azure ServiceBus, then - * delay (millis) some time before re-connecting. - * - * The option is a: int type. - * - * Default: 5000 - * Group: consumer (advanced) - * - * @param reconnectDelay the value to set - * @return the dsl builder - */ - default AdvancedServiceBusEndpointConsumerBuilder reconnectDelay(int reconnectDelay) { - doSetProperty("reconnectDelay", reconnectDelay); - return this; - } - /** - * If the consumer has connection failure to Azure ServiceBus, then - * delay (millis) some time before re-connecting. - * - * The option will be converted to a int type. - * - * Default: 5000 - * Group: consumer (advanced) - * - * @param reconnectDelay the value to set - * @return the dsl builder - */ - default AdvancedServiceBusEndpointConsumerBuilder reconnectDelay(String reconnectDelay) { - doSetProperty("reconnectDelay", reconnectDelay); - return this; - } } /** diff --git a/dsl/camel-kotlin-api/src/generated/kotlin/org/apache/camel/kotlin/components/AzureServicebusUriDsl.kt b/dsl/camel-kotlin-api/src/generated/kotlin/org/apache/camel/kotlin/components/AzureServicebusUriDsl.kt index 8ba145e4675bb..8e1d501067695 100644 --- a/dsl/camel-kotlin-api/src/generated/kotlin/org/apache/camel/kotlin/components/AzureServicebusUriDsl.kt +++ b/dsl/camel-kotlin-api/src/generated/kotlin/org/apache/camel/kotlin/components/AzureServicebusUriDsl.kt @@ -101,29 +101,6 @@ public class AzureServicebusUriDsl( it.property("serviceBusType", serviceBusType) } - /** - * Sets the desired operation to be used in the consumer - */ - public fun consumerOperation(consumerOperation: String) { - it.property("consumerOperation", consumerOperation) - } - - /** - * Disables auto-complete and auto-abandon of received messages. By default, a successfully - * processed message is completed. If an error happens when the message is abandoned. - */ - public fun disableAutoComplete(disableAutoComplete: String) { - it.property("disableAutoComplete", disableAutoComplete) - } - - /** - * Disables auto-complete and auto-abandon of received messages. By default, a successfully - * processed message is completed. If an error happens when the message is abandoned. - */ - public fun disableAutoComplete(disableAutoComplete: Boolean) { - it.property("disableAutoComplete", disableAutoComplete.toString()) - } - /** * Enable application level deadlettering to the subscription deadletter subqueue if deadletter * related headers are set. @@ -149,17 +126,17 @@ public class AzureServicebusUriDsl( } /** - * Set the max number of messages to be peeked during the peek operation. + * Sets maximum number of concurrent calls */ - public fun peekNumMaxMessages(peekNumMaxMessages: String) { - it.property("peekNumMaxMessages", peekNumMaxMessages) + public fun maxConcurrentCalls(maxConcurrentCalls: String) { + it.property("maxConcurrentCalls", maxConcurrentCalls) } /** - * Set the max number of messages to be peeked during the peek operation. + * Sets maximum number of concurrent calls */ - public fun peekNumMaxMessages(peekNumMaxMessages: Int) { - it.property("peekNumMaxMessages", peekNumMaxMessages.toString()) + public fun maxConcurrentCalls(maxConcurrentCalls: Int) { + it.property("maxConcurrentCalls", maxConcurrentCalls.toString()) } /** @@ -185,10 +162,10 @@ public class AzureServicebusUriDsl( } /** - * Sets the receiverAsyncClient in order to consume messages by the consumer + * Sets the processorClient in order to consume messages by the consumer */ - public fun receiverAsyncClient(receiverAsyncClient: String) { - it.property("receiverAsyncClient", receiverAsyncClient) + public fun processorClient(processorClient: String) { + it.property("processorClient", processorClient) } /** @@ -260,22 +237,6 @@ public class AzureServicebusUriDsl( it.property("exchangePattern", exchangePattern) } - /** - * If the consumer has connection failure to Azure ServiceBus, then delay (millis) some time - * before re-connecting. - */ - public fun reconnectDelay(reconnectDelay: String) { - it.property("reconnectDelay", reconnectDelay) - } - - /** - * If the consumer has connection failure to Azure ServiceBus, then delay (millis) some time - * before re-connecting. - */ - public fun reconnectDelay(reconnectDelay: Int) { - it.property("reconnectDelay", reconnectDelay.toString()) - } - /** * Set binary mode. If true, message body will be sent as byte. By default, it is false. */