From c470acc40da70181143e0f35016e59740d32d1e6 Mon Sep 17 00:00:00 2001 From: Claus Ibsen Date: Thu, 26 Feb 2026 10:29:35 +0100 Subject: [PATCH 1/3] CAMEL-23032: camel-nats - Add AckPolicy so messages can be retried when NACK due to routing failure. Fix infra-nats to run nats broker with jetstream enabled. --- .../apache/camel/catalog/components/nats.json | 46 ++++--- .../camel/catalog/main/important-headers.json | 1 + .../nats/NatsEndpointConfigurer.java | 18 +++ .../nats/NatsEndpointUriFactory.java | 5 +- .../org/apache/camel/component/nats/nats.json | 46 ++++--- .../component/nats/NatsConfiguration.java | 50 ++++++- .../camel/component/nats/NatsConstants.java | 4 + .../camel/component/nats/NatsConsumer.java | 57 +++++++- .../jetstream/NatsJetstreamConsumerIT.java | 62 +++++++++ .../NatsJetstreamConsumerRedeliveryIT.java | 89 ++++++++++++ .../camel/util/ImportantHeaderUtils.java | 1 + .../dsl/NatsEndpointBuilderFactory.java | 128 ++++++++++++++++++ .../NatsLocalContainerAuthService.java | 2 +- .../NatsLocalContainerAuthTokenService.java | 2 +- .../NatsLocalContainerInfraService.java | 3 +- .../NatsLocalContainerTLSAuthService.java | 3 +- 16 files changed, 468 insertions(+), 49 deletions(-) create mode 100644 components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerIT.java create mode 100644 components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerRedeliveryIT.java diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/nats.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/nats.json index 23791824fbe98..446eeba966b63 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/nats.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/nats.json @@ -39,7 +39,8 @@ "CamelNatsSubject": { "index": 3, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The Subject of a consumed message.", "constantName": "org.apache.camel.component.nats.NatsConstants#NATS_SUBJECT" }, "CamelNatsQueueName": { "index": 4, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The Queue name of a consumed message (may be null).", "constantName": "org.apache.camel.component.nats.NatsConstants#NATS_QUEUE_NAME" }, "CamelNatsStatusCode": { "index": 5, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "important": true, "description": "Status message code", "constantName": "org.apache.camel.component.nats.NatsConstants#NATS_STATUS_CODE" }, - "CamelNatsStatusError": { "index": 6, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "important": true, "description": "Status message error message", "constantName": "org.apache.camel.component.nats.NatsConstants#NATS_STATUS_ERROR" } + "CamelNatsStatusError": { "index": 6, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "important": true, "description": "Status message error message", "constantName": "org.apache.camel.component.nats.NatsConstants#NATS_STATUS_ERROR" }, + "CamelNatsDeliveryCounter": { "index": 7, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "important": true, "description": "Number of times this message has been delivered (1 = first, 1 then message has been redelivered)", "constantName": "org.apache.camel.component.nats.NatsConstants#NATS_DELIVERY_COUNTER" } }, "properties": { "topic": { "index": 0, "kind": "path", "displayName": "Topic", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "The name of topic we want to use" }, @@ -59,25 +60,28 @@ "requestCleanupInterval": { "index": 14, "kind": "parameter", "displayName": "Request Cleanup Interval", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Interval to clean up cancelled\/timed out requests." }, "servers": { "index": 15, "kind": "parameter", "displayName": "Servers", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "URLs to one or more NAT servers. Use comma to separate URLs when specifying multiple servers." }, "verbose": { "index": 16, "kind": "parameter", "displayName": "Verbose", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not running in verbose mode" }, - "maxMessages": { "index": 17, "kind": "parameter", "displayName": "Max Messages", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Stop receiving messages from a topic we are subscribing to after maxMessages" }, - "poolSize": { "index": 18, "kind": "parameter", "displayName": "Pool Size", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Consumer thread pool size (default is 10)" }, - "queueName": { "index": 19, "kind": "parameter", "displayName": "Queue Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "The Queue name if we are using nats for a queue configuration" }, - "replyToDisabled": { "index": 20, "kind": "parameter", "displayName": "Reply To Disabled", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Can be used to turn off sending back reply message in the consumer." }, - "bridgeErrorHandler": { "index": 21, "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": 22, "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": 23, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "enum", "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." }, - "replySubject": { "index": 24, "kind": "parameter", "displayName": "Reply Subject", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "the subject to which subscribers should send response" }, - "requestTimeout": { "index": 25, "kind": "parameter", "displayName": "Request Timeout", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 20000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, - "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." }, - "connection": { "index": 27, "kind": "parameter", "displayName": "Connection", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.nats.client.Connection", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Reference an already instantiated connection to Nats server" }, - "consumerConfiguration": { "index": 28, "kind": "parameter", "displayName": "Consumer Configuration", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.nats.client.api.ConsumerConfiguration", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets a custom ConsumerConfiguration object for the JetStream consumer. This is an advanced option typically used when you need to configure properties not exposed as simple Camel URI parameters. When set, this object will be used to build the final consumer subscription options." }, - "durableName": { "index": 29, "kind": "parameter", "displayName": "Durable Name", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the name to assign to the JetStream durable consumer. Setting this value makes the consumer durable. The value is used to set the durable() field in the underlying NATS ConsumerConfiguration.Builder." }, - "headerFilterStrategy": { "index": 30, "kind": "parameter", "displayName": "Header Filter Strategy", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To use a custom header filter strategy." }, - "jetstreamAsync": { "index": 31, "kind": "parameter", "displayName": "Jetstream Async", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets whether to operate JetStream requests asynchronously." }, - "pullSubscription": { "index": 32, "kind": "parameter", "displayName": "Pull Subscription", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the consumer subscription type for JetStream. Set to true to use a Pull Subscription (consumer explicitly requests messages). Set to false to use a Push Subscription (messages are automatically delivered)." }, - "traceConnection": { "index": 33, "kind": "parameter", "displayName": "Trace Connection", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not connection trace messages should be printed to standard out for fine grained debugging of connection issues." }, - "credentialsFilePath": { "index": 34, "kind": "parameter", "displayName": "Credentials File Path", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "If we use useCredentialsFile to true we'll need to set the credentialsFilePath option. It can be loaded by default from classpath, but you can prefix with classpath:, file:, or http: to load the resource from different systems." }, - "secure": { "index": 35, "kind": "parameter", "displayName": "Secure", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Set secure option indicating TLS is required" }, - "sslContextParameters": { "index": 36, "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To configure security using SSLContextParameters" } + "ackPolicy": { "index": 17, "kind": "parameter", "displayName": "Ack Policy", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "io.nats.client.api.AckPolicy", "enum": [ "none", "all", "explicit" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Acknowledgement mode. none = Messages are acknowledged as soon as the server sends them. Clients do not need to ack. all = All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit = Each message must be acknowledged individually. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer." }, + "ackWait": { "index": 18, "kind": "parameter", "displayName": "Ack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 30000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "After a message is delivered to a consumer, the server waits 30 seconds (default) for an acknowledgement. If none arrives (timeout), the message becomes eligible for redelivery." }, + "maxMessages": { "index": 19, "kind": "parameter", "displayName": "Max Messages", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Stop receiving messages from a topic we are subscribing to after maxMessages" }, + "nackWait": { "index": 20, "kind": "parameter", "displayName": "Nack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "For negative acknowledgements (NAK), redelivery is delayed by 5 seconds (default). Setting this to 0 or negative makes the redelivery immediately. Be careful as this can cause the consumer to keep re-processing the same message over and over again due to intermediate error that last a while." }, + "poolSize": { "index": 21, "kind": "parameter", "displayName": "Pool Size", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Consumer thread pool size (default is 10)" }, + "queueName": { "index": 22, "kind": "parameter", "displayName": "Queue Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "The Queue name if we are using nats for a queue configuration" }, + "replyToDisabled": { "index": 23, "kind": "parameter", "displayName": "Reply To Disabled", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Can be used to turn off sending back reply message in the consumer." }, + "bridgeErrorHandler": { "index": 24, "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": 25, "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": 26, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "enum", "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." }, + "replySubject": { "index": 27, "kind": "parameter", "displayName": "Reply Subject", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "the subject to which subscribers should send response" }, + "requestTimeout": { "index": 28, "kind": "parameter", "displayName": "Request Timeout", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 20000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, + "lazyStartProducer": { "index": 29, "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." }, + "connection": { "index": 30, "kind": "parameter", "displayName": "Connection", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.nats.client.Connection", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Reference an already instantiated connection to Nats server" }, + "consumerConfiguration": { "index": 31, "kind": "parameter", "displayName": "Consumer Configuration", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.nats.client.api.ConsumerConfiguration", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets a custom ConsumerConfiguration object for the JetStream consumer. This is an advanced option typically used when you need to configure properties not exposed as simple Camel URI parameters. When set, this object will be used to build the final consumer subscription options." }, + "durableName": { "index": 32, "kind": "parameter", "displayName": "Durable Name", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the name to assign to the JetStream durable consumer. Setting this value makes the consumer durable. The value is used to set the durable() field in the underlying NATS ConsumerConfiguration.Builder." }, + "headerFilterStrategy": { "index": 33, "kind": "parameter", "displayName": "Header Filter Strategy", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To use a custom header filter strategy." }, + "jetstreamAsync": { "index": 34, "kind": "parameter", "displayName": "Jetstream Async", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets whether to operate JetStream requests asynchronously." }, + "pullSubscription": { "index": 35, "kind": "parameter", "displayName": "Pull Subscription", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the consumer subscription type for JetStream. Set to true to use a Pull Subscription (consumer explicitly requests messages). Set to false to use a Push Subscription (messages are automatically delivered)." }, + "traceConnection": { "index": 36, "kind": "parameter", "displayName": "Trace Connection", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not connection trace messages should be printed to standard out for fine grained debugging of connection issues." }, + "credentialsFilePath": { "index": 37, "kind": "parameter", "displayName": "Credentials File Path", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "If we use useCredentialsFile to true we'll need to set the credentialsFilePath option. It can be loaded by default from classpath, but you can prefix with classpath:, file:, or http: to load the resource from different systems." }, + "secure": { "index": 38, "kind": "parameter", "displayName": "Secure", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Set secure option indicating TLS is required" }, + "sslContextParameters": { "index": 39, "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To configure security using SSLContextParameters" } } } diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/important-headers.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/important-headers.json index 0de189334617e..e88ef5eb65d74 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/important-headers.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/important-headers.json @@ -10,6 +10,7 @@ "CamelHttpResponseCode", "CamelHttpResponseText", "CamelMqttTopic", + "CamelNatsDeliveryCounter", "CamelNatsSID", "CamelNatsStatusCode", "CamelNatsStatusError", diff --git a/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsEndpointConfigurer.java b/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsEndpointConfigurer.java index 34022aaccfcdf..38fb727f20db6 100644 --- a/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsEndpointConfigurer.java +++ b/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsEndpointConfigurer.java @@ -23,6 +23,10 @@ public class NatsEndpointConfigurer extends PropertyConfigurerSupport implements public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) { NatsEndpoint target = (NatsEndpoint) obj; switch (ignoreCase ? name.toLowerCase() : name) { + case "ackpolicy": + case "ackPolicy": target.getConfiguration().setAckPolicy(property(camelContext, io.nats.client.api.AckPolicy.class, value)); return true; + case "ackwait": + case "ackWait": target.getConfiguration().setAckWait(property(camelContext, long.class, value)); return true; case "bridgeerrorhandler": case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true; case "connection": target.getConfiguration().setConnection(property(camelContext, io.nats.client.Connection.class, value)); return true; @@ -58,6 +62,8 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "maxPingsOut": target.getConfiguration().setMaxPingsOut(property(camelContext, int.class, value)); return true; case "maxreconnectattempts": case "maxReconnectAttempts": target.getConfiguration().setMaxReconnectAttempts(property(camelContext, int.class, value)); return true; + case "nackwait": + case "nackWait": target.getConfiguration().setNackWait(property(camelContext, long.class, value)); return true; case "noecho": case "noEcho": target.getConfiguration().setNoEcho(property(camelContext, boolean.class, value)); return true; case "norandomizeservers": @@ -96,6 +102,10 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj @Override public Class getOptionType(String name, boolean ignoreCase) { switch (ignoreCase ? name.toLowerCase() : name) { + case "ackpolicy": + case "ackPolicy": return io.nats.client.api.AckPolicy.class; + case "ackwait": + case "ackWait": return long.class; case "bridgeerrorhandler": case "bridgeErrorHandler": return boolean.class; case "connection": return io.nats.client.Connection.class; @@ -131,6 +141,8 @@ public Class getOptionType(String name, boolean ignoreCase) { case "maxPingsOut": return int.class; case "maxreconnectattempts": case "maxReconnectAttempts": return int.class; + case "nackwait": + case "nackWait": return long.class; case "noecho": case "noEcho": return boolean.class; case "norandomizeservers": @@ -170,6 +182,10 @@ public Class getOptionType(String name, boolean ignoreCase) { public Object getOptionValue(Object obj, String name, boolean ignoreCase) { NatsEndpoint target = (NatsEndpoint) obj; switch (ignoreCase ? name.toLowerCase() : name) { + case "ackpolicy": + case "ackPolicy": return target.getConfiguration().getAckPolicy(); + case "ackwait": + case "ackWait": return target.getConfiguration().getAckWait(); case "bridgeerrorhandler": case "bridgeErrorHandler": return target.isBridgeErrorHandler(); case "connection": return target.getConfiguration().getConnection(); @@ -205,6 +221,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "maxPingsOut": return target.getConfiguration().getMaxPingsOut(); case "maxreconnectattempts": case "maxReconnectAttempts": return target.getConfiguration().getMaxReconnectAttempts(); + case "nackwait": + case "nackWait": return target.getConfiguration().getNackWait(); case "noecho": case "noEcho": return target.getConfiguration().isNoEcho(); case "norandomizeservers": diff --git a/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsEndpointUriFactory.java b/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsEndpointUriFactory.java index 9b44559a79da3..1b0f20aad58f2 100644 --- a/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsEndpointUriFactory.java +++ b/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsEndpointUriFactory.java @@ -23,7 +23,9 @@ public class NatsEndpointUriFactory extends org.apache.camel.support.component.E private static final Set SECRET_PROPERTY_NAMES; private static final Map MULTI_VALUE_PREFIXES; static { - Set props = new HashSet<>(37); + Set props = new HashSet<>(40); + props.add("ackPolicy"); + props.add("ackWait"); props.add("bridgeErrorHandler"); props.add("connection"); props.add("connectionTimeout"); @@ -42,6 +44,7 @@ public class NatsEndpointUriFactory extends org.apache.camel.support.component.E props.add("maxMessages"); props.add("maxPingsOut"); props.add("maxReconnectAttempts"); + props.add("nackWait"); props.add("noEcho"); props.add("noRandomizeServers"); props.add("pedantic"); diff --git a/components/camel-nats/src/generated/resources/META-INF/org/apache/camel/component/nats/nats.json b/components/camel-nats/src/generated/resources/META-INF/org/apache/camel/component/nats/nats.json index 23791824fbe98..446eeba966b63 100644 --- a/components/camel-nats/src/generated/resources/META-INF/org/apache/camel/component/nats/nats.json +++ b/components/camel-nats/src/generated/resources/META-INF/org/apache/camel/component/nats/nats.json @@ -39,7 +39,8 @@ "CamelNatsSubject": { "index": 3, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The Subject of a consumed message.", "constantName": "org.apache.camel.component.nats.NatsConstants#NATS_SUBJECT" }, "CamelNatsQueueName": { "index": 4, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The Queue name of a consumed message (may be null).", "constantName": "org.apache.camel.component.nats.NatsConstants#NATS_QUEUE_NAME" }, "CamelNatsStatusCode": { "index": 5, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "important": true, "description": "Status message code", "constantName": "org.apache.camel.component.nats.NatsConstants#NATS_STATUS_CODE" }, - "CamelNatsStatusError": { "index": 6, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "important": true, "description": "Status message error message", "constantName": "org.apache.camel.component.nats.NatsConstants#NATS_STATUS_ERROR" } + "CamelNatsStatusError": { "index": 6, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "important": true, "description": "Status message error message", "constantName": "org.apache.camel.component.nats.NatsConstants#NATS_STATUS_ERROR" }, + "CamelNatsDeliveryCounter": { "index": 7, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "important": true, "description": "Number of times this message has been delivered (1 = first, 1 then message has been redelivered)", "constantName": "org.apache.camel.component.nats.NatsConstants#NATS_DELIVERY_COUNTER" } }, "properties": { "topic": { "index": 0, "kind": "path", "displayName": "Topic", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "The name of topic we want to use" }, @@ -59,25 +60,28 @@ "requestCleanupInterval": { "index": 14, "kind": "parameter", "displayName": "Request Cleanup Interval", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Interval to clean up cancelled\/timed out requests." }, "servers": { "index": 15, "kind": "parameter", "displayName": "Servers", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "URLs to one or more NAT servers. Use comma to separate URLs when specifying multiple servers." }, "verbose": { "index": 16, "kind": "parameter", "displayName": "Verbose", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not running in verbose mode" }, - "maxMessages": { "index": 17, "kind": "parameter", "displayName": "Max Messages", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Stop receiving messages from a topic we are subscribing to after maxMessages" }, - "poolSize": { "index": 18, "kind": "parameter", "displayName": "Pool Size", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Consumer thread pool size (default is 10)" }, - "queueName": { "index": 19, "kind": "parameter", "displayName": "Queue Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "The Queue name if we are using nats for a queue configuration" }, - "replyToDisabled": { "index": 20, "kind": "parameter", "displayName": "Reply To Disabled", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Can be used to turn off sending back reply message in the consumer." }, - "bridgeErrorHandler": { "index": 21, "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": 22, "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": 23, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "enum", "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." }, - "replySubject": { "index": 24, "kind": "parameter", "displayName": "Reply Subject", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "the subject to which subscribers should send response" }, - "requestTimeout": { "index": 25, "kind": "parameter", "displayName": "Request Timeout", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 20000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, - "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." }, - "connection": { "index": 27, "kind": "parameter", "displayName": "Connection", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.nats.client.Connection", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Reference an already instantiated connection to Nats server" }, - "consumerConfiguration": { "index": 28, "kind": "parameter", "displayName": "Consumer Configuration", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.nats.client.api.ConsumerConfiguration", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets a custom ConsumerConfiguration object for the JetStream consumer. This is an advanced option typically used when you need to configure properties not exposed as simple Camel URI parameters. When set, this object will be used to build the final consumer subscription options." }, - "durableName": { "index": 29, "kind": "parameter", "displayName": "Durable Name", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the name to assign to the JetStream durable consumer. Setting this value makes the consumer durable. The value is used to set the durable() field in the underlying NATS ConsumerConfiguration.Builder." }, - "headerFilterStrategy": { "index": 30, "kind": "parameter", "displayName": "Header Filter Strategy", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To use a custom header filter strategy." }, - "jetstreamAsync": { "index": 31, "kind": "parameter", "displayName": "Jetstream Async", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets whether to operate JetStream requests asynchronously." }, - "pullSubscription": { "index": 32, "kind": "parameter", "displayName": "Pull Subscription", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the consumer subscription type for JetStream. Set to true to use a Pull Subscription (consumer explicitly requests messages). Set to false to use a Push Subscription (messages are automatically delivered)." }, - "traceConnection": { "index": 33, "kind": "parameter", "displayName": "Trace Connection", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not connection trace messages should be printed to standard out for fine grained debugging of connection issues." }, - "credentialsFilePath": { "index": 34, "kind": "parameter", "displayName": "Credentials File Path", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "If we use useCredentialsFile to true we'll need to set the credentialsFilePath option. It can be loaded by default from classpath, but you can prefix with classpath:, file:, or http: to load the resource from different systems." }, - "secure": { "index": 35, "kind": "parameter", "displayName": "Secure", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Set secure option indicating TLS is required" }, - "sslContextParameters": { "index": 36, "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To configure security using SSLContextParameters" } + "ackPolicy": { "index": 17, "kind": "parameter", "displayName": "Ack Policy", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "io.nats.client.api.AckPolicy", "enum": [ "none", "all", "explicit" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Acknowledgement mode. none = Messages are acknowledged as soon as the server sends them. Clients do not need to ack. all = All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit = Each message must be acknowledged individually. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer." }, + "ackWait": { "index": 18, "kind": "parameter", "displayName": "Ack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 30000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "After a message is delivered to a consumer, the server waits 30 seconds (default) for an acknowledgement. If none arrives (timeout), the message becomes eligible for redelivery." }, + "maxMessages": { "index": 19, "kind": "parameter", "displayName": "Max Messages", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Stop receiving messages from a topic we are subscribing to after maxMessages" }, + "nackWait": { "index": 20, "kind": "parameter", "displayName": "Nack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "For negative acknowledgements (NAK), redelivery is delayed by 5 seconds (default). Setting this to 0 or negative makes the redelivery immediately. Be careful as this can cause the consumer to keep re-processing the same message over and over again due to intermediate error that last a while." }, + "poolSize": { "index": 21, "kind": "parameter", "displayName": "Pool Size", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Consumer thread pool size (default is 10)" }, + "queueName": { "index": 22, "kind": "parameter", "displayName": "Queue Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "The Queue name if we are using nats for a queue configuration" }, + "replyToDisabled": { "index": 23, "kind": "parameter", "displayName": "Reply To Disabled", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Can be used to turn off sending back reply message in the consumer." }, + "bridgeErrorHandler": { "index": 24, "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": 25, "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": 26, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "enum", "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." }, + "replySubject": { "index": 27, "kind": "parameter", "displayName": "Reply Subject", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "the subject to which subscribers should send response" }, + "requestTimeout": { "index": 28, "kind": "parameter", "displayName": "Request Timeout", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 20000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, + "lazyStartProducer": { "index": 29, "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." }, + "connection": { "index": 30, "kind": "parameter", "displayName": "Connection", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.nats.client.Connection", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Reference an already instantiated connection to Nats server" }, + "consumerConfiguration": { "index": 31, "kind": "parameter", "displayName": "Consumer Configuration", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.nats.client.api.ConsumerConfiguration", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets a custom ConsumerConfiguration object for the JetStream consumer. This is an advanced option typically used when you need to configure properties not exposed as simple Camel URI parameters. When set, this object will be used to build the final consumer subscription options." }, + "durableName": { "index": 32, "kind": "parameter", "displayName": "Durable Name", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the name to assign to the JetStream durable consumer. Setting this value makes the consumer durable. The value is used to set the durable() field in the underlying NATS ConsumerConfiguration.Builder." }, + "headerFilterStrategy": { "index": 33, "kind": "parameter", "displayName": "Header Filter Strategy", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To use a custom header filter strategy." }, + "jetstreamAsync": { "index": 34, "kind": "parameter", "displayName": "Jetstream Async", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets whether to operate JetStream requests asynchronously." }, + "pullSubscription": { "index": 35, "kind": "parameter", "displayName": "Pull Subscription", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the consumer subscription type for JetStream. Set to true to use a Pull Subscription (consumer explicitly requests messages). Set to false to use a Push Subscription (messages are automatically delivered)." }, + "traceConnection": { "index": 36, "kind": "parameter", "displayName": "Trace Connection", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not connection trace messages should be printed to standard out for fine grained debugging of connection issues." }, + "credentialsFilePath": { "index": 37, "kind": "parameter", "displayName": "Credentials File Path", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "If we use useCredentialsFile to true we'll need to set the credentialsFilePath option. It can be loaded by default from classpath, but you can prefix with classpath:, file:, or http: to load the resource from different systems." }, + "secure": { "index": 38, "kind": "parameter", "displayName": "Secure", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Set secure option indicating TLS is required" }, + "sslContextParameters": { "index": 39, "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To configure security using SSLContextParameters" } } } diff --git a/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConfiguration.java b/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConfiguration.java index d5e0e0d5fbf0d..e4aa0f5a64c2e 100644 --- a/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConfiguration.java +++ b/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConfiguration.java @@ -20,9 +20,9 @@ import java.time.Duration; import io.nats.client.Connection; -import io.nats.client.Nats; import io.nats.client.Options; import io.nats.client.Options.Builder; +import io.nats.client.api.AckPolicy; import io.nats.client.api.ConsumerConfiguration; import org.apache.camel.spi.HeaderFilterStrategy; import org.apache.camel.spi.Metadata; @@ -75,6 +75,12 @@ public class NatsConfiguration { private boolean replyToDisabled; @UriParam(label = "consumer") private String maxMessages; + @UriParam(label = "consumer", defaultValue = "none", enums = "none,all,explicit") + private AckPolicy ackPolicy; + @UriParam(label = "consumer", defaultValue = "30000") + private long ackWait; + @UriParam(label = "consumer", defaultValue = "5000") + private long nackWait = 5000; @UriParam(label = "consumer", defaultValue = "10") private int poolSize = 10; @UriParam(label = "common", defaultValue = "true") @@ -574,4 +580,46 @@ public String getDurableName() { public void setDurableName(String durableName) { this.durableName = durableName; } + + public AckPolicy getAckPolicy() { + return ackPolicy; + } + + /** + * Acknowledgement mode. + * + * none = Messages are acknowledged as soon as the server sends them. Clients do not need to ack. all = All messages + * with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages + * 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit = Each message must be acknowledged + * individually. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer. + */ + public void setAckPolicy(AckPolicy ackPolicy) { + this.ackPolicy = ackPolicy; + } + + public long getAckWait() { + return ackWait; + } + + /** + * After a message is delivered to a consumer, the server waits 30 seconds (default) for an acknowledgement. If none + * arrives (timeout), the message becomes eligible for redelivery. + */ + public void setAckWait(long ackWait) { + this.ackWait = ackWait; + } + + public long getNackWait() { + return nackWait; + } + + /** + * For negative acknowledgements (NAK), redelivery is delayed by 5 seconds (default). + * + * Setting this to 0 or negative makes the redelivery immediately. Be careful as this can cause the consumer to keep + * re-processing the same message over and over again due to intermediate error that last a while. + */ + public void setNackWait(long nackWait) { + this.nackWait = nackWait; + } } diff --git a/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConstants.java b/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConstants.java index 5d2575a134880..a897652ca6d8e 100644 --- a/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConstants.java +++ b/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConstants.java @@ -34,6 +34,10 @@ public interface NatsConstants { String NATS_STATUS_CODE = "CamelNatsStatusCode"; @Metadata(label = "consumer", description = "Status message error message", javaType = "String", important = true) String NATS_STATUS_ERROR = "CamelNatsStatusError"; + @Metadata(label = "consumer", + description = "Number of times this message has been delivered (1 = first, > 1 then message has been redelivered)", + javaType = "long", important = true) + String NATS_DELIVERY_COUNTER = "CamelNatsDeliveryCounter"; String NATS_REQUEST_TIMEOUT_THREAD_PROFILE_NAME = "CamelNatsRequestTimeoutExecutor"; } diff --git a/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConsumer.java b/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConsumer.java index 4035868c103a5..75bb40bb31621 100644 --- a/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConsumer.java +++ b/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConsumer.java @@ -30,12 +30,16 @@ import io.nats.client.MessageHandler; import io.nats.client.PullSubscribeOptions; import io.nats.client.PushSubscribeOptions; +import io.nats.client.api.AckPolicy; import io.nats.client.api.ConsumerConfiguration; import io.nats.client.api.StreamConfiguration; import org.apache.camel.Exchange; import org.apache.camel.Processor; import org.apache.camel.spi.HeaderFilterStrategy; import org.apache.camel.support.DefaultConsumer; +import org.apache.camel.support.SynchronizationAdapter; +import org.apache.camel.trait.message.MessageTrait; +import org.apache.camel.trait.message.RedeliveryTraitPayload; import org.apache.camel.util.ObjectHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -184,6 +188,12 @@ private void setupJetStreamConsumer(String topic, String queueName) throws IOExc if (durableName != null) { ccBuilder.durable(durableName + "-durable"); } + if (configuration.getAckPolicy() != null) { + ccBuilder.ackPolicy(configuration.getAckPolicy()); + } + if (configuration.getAckWait() > 0) { + ccBuilder.ackWait(configuration.getAckWait()); + } cc = ccBuilder.build(); } @@ -206,12 +216,14 @@ private void setupJetStreamConsumer(String topic, String queueName) throws IOExc .deliverGroup(queueName) .build(); + boolean autoAck = configuration.getAckPolicy() == null || configuration.getAckPolicy() == AckPolicy.None; + NatsConsumer.this.jetStreamSubscription = this.connection.jetStream().subscribe( NatsConsumer.this.getEndpoint().getConfiguration().getTopic(), queueName, dispatcher, messageHandler, - true, + autoAck, pushOptions); } @@ -240,6 +252,31 @@ class CamelNatsMessageHandler implements MessageHandler { public void onMessage(Message msg) throws InterruptedException { LOG.debug("Received Message: {}", msg); final Exchange exchange = NatsConsumer.this.createExchange(false); + // ensure we either ACK or NACK the message + boolean autoAck = configuration.getAckPolicy() == null || configuration.getAckPolicy() == AckPolicy.None; + + if (!autoAck) { + long wait = configuration.getAckWait() == 0 ? 30000 : configuration.getAckWait(); + LOG.info("Consuming from topic: {} using AckPolicy: {} (ackWait:{} nackWait:{})", + configuration.getTopic(), configuration.getAckPolicy(), wait, configuration.getNackWait()); + exchange.getExchangeExtension().addOnCompletion(new SynchronizationAdapter() { + @Override + public void onComplete(Exchange exchange) { + LOG.debug("ACK (delay:{})", configuration.getAckWait()); + msg.ack(); + } + + @Override + public void onFailure(Exchange exchange) { + LOG.debug("NACK (delay:{})", configuration.getNackWait()); + if (configuration.getNackWait() <= 0) { + msg.nak(); + } else { + msg.nakWithDelay(configuration.getNackWait()); + } + } + }); + } try { exchange.getIn().setBody(msg.getData()); exchange.getIn().setHeader(NatsConstants.NATS_REPLY_TO, msg.getReplyTo()); @@ -269,6 +306,11 @@ public void onMessage(Message msg) throws InterruptedException { } }); } + + // redelivery information + exchange.getMessage().setPayloadForTrait(MessageTrait.REDELIVERY, + evalRedeliveryMessageTrait(msg, exchange)); + NatsConsumer.this.processor.process(exchange); // is there a reply? @@ -302,4 +344,17 @@ private boolean streamExists(JetStreamManagement jsm, String streamName) throws } } + private static RedeliveryTraitPayload evalRedeliveryMessageTrait(Message msg, Exchange exchange) { + long counter = 1; + if (msg.isJetStream()) { + counter = msg.metaData().deliveredCount(); + } + exchange.getIn().setHeader(NatsConstants.NATS_DELIVERY_COUNTER, counter); + + if (counter > 1) { + return RedeliveryTraitPayload.IS_REDELIVERY; + } + return RedeliveryTraitPayload.NON_REDELIVERY; + } + } diff --git a/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerIT.java b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerIT.java new file mode 100644 index 0000000000000..fb8fac836abcd --- /dev/null +++ b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerIT.java @@ -0,0 +1,62 @@ +/* + * 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.nats.jetstream; + +import org.apache.camel.EndpointInject; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.component.nats.NatsConstants; +import org.apache.camel.component.nats.integration.NatsITSupport; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIfSystemProperty; +import org.junit.jupiter.api.parallel.Isolated; + +@DisabledIfSystemProperty(named = "ci.env.name", matches = ".*", disabledReason = "Flaky on GitHub Actions") +@Isolated +public class NatsJetstreamConsumerIT extends NatsITSupport { + + @EndpointInject("mock:result") + protected MockEndpoint mockResultEndpoint; + + @Test + public void testConsumer() throws Exception { + mockResultEndpoint.expectedBodiesReceived("Hello World"); + mockResultEndpoint.expectedHeaderReceived(NatsConstants.NATS_SUBJECT, "mytopic"); + + template.sendBody("direct:send", "Hello World"); + + mockResultEndpoint.assertIsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + String uri + = "nats:mytopic?jetstreamEnabled=true&jetstreamName=mystream&jetstreamAsync=false&durableName=camel&pullSubscription=false"; + + from("direct:send") + // when running full test suite then send can fail due to nats server setup/tearndown + .errorHandler(defaultErrorHandler().maximumRedeliveries(5)) + .to(uri); + + from(uri).to(mockResultEndpoint); + } + }; + } +} diff --git a/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerRedeliveryIT.java b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerRedeliveryIT.java new file mode 100644 index 0000000000000..48d0d1f64f23e --- /dev/null +++ b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerRedeliveryIT.java @@ -0,0 +1,89 @@ +/* + * 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.nats.jetstream; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.camel.EndpointInject; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.component.nats.NatsConstants; +import org.apache.camel.component.nats.integration.NatsITSupport; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIfSystemProperty; +import org.junit.jupiter.api.parallel.Isolated; + +@DisabledIfSystemProperty(named = "ci.env.name", matches = ".*", disabledReason = "Flaky on GitHub Actions") +@Isolated +public class NatsJetstreamConsumerRedeliveryIT extends NatsITSupport { + + @EndpointInject("mock:result") + protected MockEndpoint mockResultEndpoint; + + @EndpointInject("mock:input") + protected MockEndpoint mockInputEndpoint; + + @Test + public void testConsumer() throws Exception { + mockResultEndpoint.expectedBodiesReceived("Hello World"); + mockResultEndpoint.expectedHeaderReceived(NatsConstants.NATS_SUBJECT, "mytopic2"); + mockResultEndpoint.expectedHeaderReceived("counter", 3); + mockResultEndpoint.expectedHeaderReceived(NatsConstants.NATS_DELIVERY_COUNTER, 3); + + mockInputEndpoint.expectedMessageCount(3); + mockInputEndpoint.expectedHeaderReceived(NatsConstants.NATS_SUBJECT, "mytopic2"); + mockInputEndpoint.message(0).header(NatsConstants.NATS_DELIVERY_COUNTER).isEqualTo(1); + mockInputEndpoint.message(1).header(NatsConstants.NATS_DELIVERY_COUNTER).isEqualTo(2); + mockInputEndpoint.message(2).header(NatsConstants.NATS_DELIVERY_COUNTER).isEqualTo(3); + + template.sendBody("direct:send", "Hello World"); + + mockResultEndpoint.assertIsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + String uri + = "nats:mytopic2?jetstreamEnabled=true&jetstreamName=mystream2&jetstreamAsync=false&durableName=camel2&pullSubscription=false&ackPolicy=explicit&nackWait=10"; + + from("direct:send") + // when running full test suite then send can fail due to nats server setup/tearndown + .errorHandler(defaultErrorHandler().maximumRedeliveries(5)) + .to(uri); + + final AtomicInteger counter = new AtomicInteger(); + from(uri) + .to("mock:input") + .process(new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + if (counter.incrementAndGet() < 3) { + throw new IllegalArgumentException("Forced"); + } + exchange.getMessage().setHeader("counter", counter.intValue()); + } + }) + .to(mockResultEndpoint); + } + }; + } +} diff --git a/core/camel-util/src/main/java/org/apache/camel/util/ImportantHeaderUtils.java b/core/camel-util/src/main/java/org/apache/camel/util/ImportantHeaderUtils.java index 815558277eb2c..e3c243efd5a13 100644 --- a/core/camel-util/src/main/java/org/apache/camel/util/ImportantHeaderUtils.java +++ b/core/camel-util/src/main/java/org/apache/camel/util/ImportantHeaderUtils.java @@ -38,6 +38,7 @@ public final class ImportantHeaderUtils { "CamelHttpResponseCode", "CamelHttpResponseText", "CamelMqttTopic", + "CamelNatsDeliveryCounter", "CamelNatsSID", "CamelNatsStatusCode", "CamelNatsStatusError", diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NatsEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NatsEndpointBuilderFactory.java index 47f966102faee..bbebfccdb51a7 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NatsEndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NatsEndpointBuilderFactory.java @@ -504,6 +504,83 @@ default NatsEndpointConsumerBuilder verbose(String verbose) { doSetProperty("verbose", verbose); return this; } + /** + * Acknowledgement mode. none = Messages are acknowledged as soon as the + * server sends them. Clients do not need to ack. all = All messages + * with a sequence number less than the message acked are also + * acknowledged. E.g. reading a batch of messages 1..100. Ack on message + * 100 will acknowledge 1..99 as well. explicit = Each message must be + * acknowledged individually. Message can be acked out of sequence and + * create gaps of unacknowledged messages in the consumer. + * + * The option is a: io.nats.client.api.AckPolicy type. + * + * Default: none + * Group: consumer + * + * @param ackPolicy the value to set + * @return the dsl builder + */ + default NatsEndpointConsumerBuilder ackPolicy(io.nats.client.api.AckPolicy ackPolicy) { + doSetProperty("ackPolicy", ackPolicy); + return this; + } + /** + * Acknowledgement mode. none = Messages are acknowledged as soon as the + * server sends them. Clients do not need to ack. all = All messages + * with a sequence number less than the message acked are also + * acknowledged. E.g. reading a batch of messages 1..100. Ack on message + * 100 will acknowledge 1..99 as well. explicit = Each message must be + * acknowledged individually. Message can be acked out of sequence and + * create gaps of unacknowledged messages in the consumer. + * + * The option will be converted to a + * io.nats.client.api.AckPolicy type. + * + * Default: none + * Group: consumer + * + * @param ackPolicy the value to set + * @return the dsl builder + */ + default NatsEndpointConsumerBuilder ackPolicy(String ackPolicy) { + doSetProperty("ackPolicy", ackPolicy); + return this; + } + /** + * After a message is delivered to a consumer, the server waits 30 + * seconds (default) for an acknowledgement. If none arrives (timeout), + * the message becomes eligible for redelivery. + * + * The option is a: long type. + * + * Default: 30000 + * Group: consumer + * + * @param ackWait the value to set + * @return the dsl builder + */ + default NatsEndpointConsumerBuilder ackWait(long ackWait) { + doSetProperty("ackWait", ackWait); + return this; + } + /** + * After a message is delivered to a consumer, the server waits 30 + * seconds (default) for an acknowledgement. If none arrives (timeout), + * the message becomes eligible for redelivery. + * + * The option will be converted to a long type. + * + * Default: 30000 + * Group: consumer + * + * @param ackWait the value to set + * @return the dsl builder + */ + default NatsEndpointConsumerBuilder ackWait(String ackWait) { + doSetProperty("ackWait", ackWait); + return this; + } /** * Stop receiving messages from a topic we are subscribing to after * maxMessages. @@ -519,6 +596,44 @@ default NatsEndpointConsumerBuilder maxMessages(String maxMessages) { doSetProperty("maxMessages", maxMessages); return this; } + /** + * For negative acknowledgements (NAK), redelivery is delayed by 5 + * seconds (default). Setting this to 0 or negative makes the redelivery + * immediately. Be careful as this can cause the consumer to keep + * re-processing the same message over and over again due to + * intermediate error that last a while. + * + * The option is a: long type. + * + * Default: 5000 + * Group: consumer + * + * @param nackWait the value to set + * @return the dsl builder + */ + default NatsEndpointConsumerBuilder nackWait(long nackWait) { + doSetProperty("nackWait", nackWait); + return this; + } + /** + * For negative acknowledgements (NAK), redelivery is delayed by 5 + * seconds (default). Setting this to 0 or negative makes the redelivery + * immediately. Be careful as this can cause the consumer to keep + * re-processing the same message over and over again due to + * intermediate error that last a while. + * + * The option will be converted to a long type. + * + * Default: 5000 + * Group: consumer + * + * @param nackWait the value to set + * @return the dsl builder + */ + default NatsEndpointConsumerBuilder nackWait(String nackWait) { + doSetProperty("nackWait", nackWait); + return this; + } /** * Consumer thread pool size (default is 10). * @@ -2797,6 +2912,19 @@ public String natsStatusCode() { public String natsStatusError() { return "CamelNatsStatusError"; } + /** + * Number of times this message has been delivered (1 = first, 1 then + * message has been redelivered). + * + * The option is a: {@code long} type. + * + * Group: consumer + * + * @return the name of the header {@code NatsDeliveryCounter}. + */ + public String natsDeliveryCounter() { + return "CamelNatsDeliveryCounter"; + } } static NatsEndpointBuilder endpointBuilder(String componentName, String path) { class NatsEndpointBuilderImpl extends AbstractEndpointBuilder implements NatsEndpointBuilder, AdvancedNatsEndpointBuilder { diff --git a/test-infra/camel-test-infra-nats/src/main/java/org/apache/camel/test/infra/nats/services/NatsLocalContainerAuthService.java b/test-infra/camel-test-infra-nats/src/main/java/org/apache/camel/test/infra/nats/services/NatsLocalContainerAuthService.java index fd384fd7ff648..1c8cd672dd48c 100644 --- a/test-infra/camel-test-infra-nats/src/main/java/org/apache/camel/test/infra/nats/services/NatsLocalContainerAuthService.java +++ b/test-infra/camel-test-infra-nats/src/main/java/org/apache/camel/test/infra/nats/services/NatsLocalContainerAuthService.java @@ -29,7 +29,7 @@ protected GenericContainer initContainer(String imageName, String containerName) container .waitingFor(Wait.forLogMessage(".*Server.*is.*ready.*", 1)) - .withCommand("-DV", "--user", USERNAME, "--pass", PASSWORD); + .withCommand("--jetstream", "-DV", "--user", USERNAME, "--pass", PASSWORD); return container; } diff --git a/test-infra/camel-test-infra-nats/src/main/java/org/apache/camel/test/infra/nats/services/NatsLocalContainerAuthTokenService.java b/test-infra/camel-test-infra-nats/src/main/java/org/apache/camel/test/infra/nats/services/NatsLocalContainerAuthTokenService.java index 4a2c18f8e30da..e1d8a3bc45d09 100644 --- a/test-infra/camel-test-infra-nats/src/main/java/org/apache/camel/test/infra/nats/services/NatsLocalContainerAuthTokenService.java +++ b/test-infra/camel-test-infra-nats/src/main/java/org/apache/camel/test/infra/nats/services/NatsLocalContainerAuthTokenService.java @@ -28,7 +28,7 @@ protected GenericContainer initContainer(String imageName, String containerName) container .waitingFor(Wait.forLogMessage(".*Server.*is.*ready.*", 1)) - .withCommand("-DV", "-auth", TOKEN); + .withCommand("--jetstream", "-DV", "-auth", TOKEN); return container; } diff --git a/test-infra/camel-test-infra-nats/src/main/java/org/apache/camel/test/infra/nats/services/NatsLocalContainerInfraService.java b/test-infra/camel-test-infra-nats/src/main/java/org/apache/camel/test/infra/nats/services/NatsLocalContainerInfraService.java index 2158a5aa1759c..43dde14c2fe87 100644 --- a/test-infra/camel-test-infra-nats/src/main/java/org/apache/camel/test/infra/nats/services/NatsLocalContainerInfraService.java +++ b/test-infra/camel-test-infra-nats/src/main/java/org/apache/camel/test/infra/nats/services/NatsLocalContainerInfraService.java @@ -54,7 +54,8 @@ public NatsContainer(boolean fixedPort) { super(imageName); withNetworkAliases(containerName) - .waitingFor(Wait.forLogMessage(".*Listening.*for.*route.*connections.*", 1)); + .waitingFor(Wait.forLogMessage(".*Server.*is.*ready.*", 1)) + .withCommand("--jetstream"); ContainerEnvironmentUtil.configurePort(this, fixedPort, PORT); } diff --git a/test-infra/camel-test-infra-nats/src/main/java/org/apache/camel/test/infra/nats/services/NatsLocalContainerTLSAuthService.java b/test-infra/camel-test-infra-nats/src/main/java/org/apache/camel/test/infra/nats/services/NatsLocalContainerTLSAuthService.java index e6c4bad5da3b7..4e165c874db4d 100644 --- a/test-infra/camel-test-infra-nats/src/main/java/org/apache/camel/test/infra/nats/services/NatsLocalContainerTLSAuthService.java +++ b/test-infra/camel-test-infra-nats/src/main/java/org/apache/camel/test/infra/nats/services/NatsLocalContainerTLSAuthService.java @@ -29,7 +29,8 @@ protected GenericContainer initContainer(String imageName, String containerName) container .waitingFor(Wait.forLogMessage(".*Server.*is.*ready.*", 1)) .withClasspathResourceMapping("org/apache/camel/test/infra/nats/services", "/nats", BindMode.READ_ONLY) - .withCommand("--tls", + .withCommand("--jetstream", + "--tls", "--tlscert=/nats/server.pem", "--tlskey=/nats/key.pem", "--tlsverify", From 73570582da6fccc7cb2d4d976e691550acfd0f4c Mon Sep 17 00:00:00 2001 From: Claus Ibsen Date: Thu, 26 Feb 2026 11:22:30 +0100 Subject: [PATCH 2/3] CAMEL-23032: camel-nats - Add AckPolicy so messages can be retried when NACK due to routing failure. Fix infra-nats to run nats broker with jetstream enabled. --- .../apache/camel/catalog/components/nats.json | 93 ++- .../nats/NatsComponentConfigurer.java | 208 +++++- .../nats/NatsEndpointConfigurer.java | 6 + .../nats/NatsEndpointUriFactory.java | 3 +- .../org/apache/camel/component/nats/nats.json | 93 ++- .../camel/component/nats/NatsComponent.java | 30 +- .../component/nats/NatsConfiguration.java | 59 +- .../camel/component/nats/NatsConsumer.java | 7 +- .../nats/integration/NatsAuthITSupport.java | 2 +- .../integration/NatsAuthTokenITSupport.java | 2 +- .../nats/integration/NatsITSupport.java | 2 +- .../integration/NatsTLSAuthITSupport.java | 2 +- .../jetstream/NatsJetstreamConsumerIT.java | 2 +- .../NatsJetstreamConsumerMaxDeliverIT.java | 87 +++ .../NatsJetstreamConsumerRedeliveryIT.java | 2 +- .../dsl/NatsComponentBuilderFactory.java | 651 +++++++++++++++++- .../dsl/NatsEndpointBuilderFactory.java | 404 ++++------- 17 files changed, 1263 insertions(+), 390 deletions(-) create mode 100644 components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerMaxDeliverIT.java diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/nats.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/nats.json index 446eeba966b63..046322231c623 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/nats.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/nats.json @@ -24,13 +24,47 @@ "remote": true }, "componentProperties": { - "servers": { "index": 0, "kind": "property", "displayName": "Servers", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "URLs to one or more NAT servers. Use comma to separate URLs when specifying multiple servers." }, - "verbose": { "index": 1, "kind": "property", "displayName": "Verbose", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether or not running in verbose mode" }, - "bridgeErrorHandler": { "index": 2, "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." }, - "lazyStartProducer": { "index": 3, "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." }, - "autowiredEnabled": { "index": 4, "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." }, - "headerFilterStrategy": { "index": 5, "kind": "property", "displayName": "Header Filter Strategy", "group": "filter", "label": "filter", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel message." }, - "useGlobalSslContextParameters": { "index": 6, "kind": "property", "displayName": "Use Global Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enable usage of global SSL context parameters." } + "configuration": { "index": 0, "kind": "property", "displayName": "Configuration", "group": "common", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.nats.NatsConfiguration", "deprecated": false, "autowired": false, "secret": false, "description": "To use a shared configuration" }, + "connectionTimeout": { "index": 1, "kind": "property", "displayName": "Connection Timeout", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 2000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Timeout for connection attempts. (in milliseconds)" }, + "flushConnection": { "index": 2, "kind": "property", "displayName": "Flush Connection", "group": "common", "label": "common", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Define if we want to flush connection when stopping or not" }, + "flushTimeout": { "index": 3, "kind": "property", "displayName": "Flush Timeout", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Set the flush timeout (in milliseconds)" }, + "jetstreamEnabled": { "index": 4, "kind": "property", "displayName": "Jetstream Enabled", "group": "common", "label": "common", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets whether to enable JetStream support for this endpoint." }, + "jetstreamName": { "index": 5, "kind": "property", "displayName": "Jetstream Name", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the name of the JetStream stream to use." }, + "maxPingsOut": { "index": 6, "kind": "property", "displayName": "Max Pings Out", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 2, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "maximum number of pings have not received a response allowed by the client" }, + "maxReconnectAttempts": { "index": 7, "kind": "property", "displayName": "Max Reconnect Attempts", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 60, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Max reconnection attempts" }, + "noEcho": { "index": 8, "kind": "property", "displayName": "No Echo", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Turn off echo. If supported by the gnatsd version you are connecting to this flag will prevent the server from echoing messages back to the connection if it has subscriptions on the subject being published to." }, + "noRandomizeServers": { "index": 9, "kind": "property", "displayName": "No Randomize Servers", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not randomizing the order of servers for the connection attempts" }, + "pedantic": { "index": 10, "kind": "property", "displayName": "Pedantic", "group": "common", "label": "common", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not running in pedantic mode (this affects performance)" }, + "pingInterval": { "index": 11, "kind": "property", "displayName": "Ping Interval", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 120000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Ping interval to be aware if connection is still alive (in milliseconds)" }, + "reconnect": { "index": 12, "kind": "property", "displayName": "Reconnect", "group": "common", "label": "common", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not using reconnection feature" }, + "reconnectTimeWait": { "index": 13, "kind": "property", "displayName": "Reconnect Time Wait", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 2000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Waiting time before attempts reconnection (in milliseconds)" }, + "requestCleanupInterval": { "index": 14, "kind": "property", "displayName": "Request Cleanup Interval", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Interval to clean up cancelled\/timed out requests." }, + "servers": { "index": 15, "kind": "property", "displayName": "Servers", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "URLs to one or more NAT servers. Use comma to separate URLs when specifying multiple servers." }, + "verbose": { "index": 16, "kind": "property", "displayName": "Verbose", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not running in verbose mode" }, + "ackPolicy": { "index": 17, "kind": "property", "displayName": "Ack Policy", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "io.nats.client.api.AckPolicy", "enum": [ "none", "all", "explicit" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "explicit", "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Acknowledgement mode. none = Messages are acknowledged as soon as the server sends them. Clients do not need to ack. all = All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit = Each message must be acknowledged individually. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer." }, + "ackWait": { "index": 18, "kind": "property", "displayName": "Ack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 30000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "After a message is delivered to a consumer, the server waits 30 seconds (default) for an acknowledgement. If none arrives (timeout), the message becomes eligible for redelivery." }, + "bridgeErrorHandler": { "index": 19, "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." }, + "durableName": { "index": 20, "kind": "property", "displayName": "Durable Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the name to assign to the JetStream durable consumer. Setting this value makes the consumer durable. The value is used to set the durable() field in the underlying NATS ConsumerConfiguration.Builder." }, + "maxDeliver": { "index": 21, "kind": "property", "displayName": "Max Deliver", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Maximum number of attempts to deliver a message from Nats to a consumer. Once MaxDeliver is reached, the NATS server stops attempting to deliver that specific message. The message is not deleted, it remains in the stream but is simply skipped. It is recommended to set this option to a sensible value in case a message is poison and can not successfully be processed and would always keep failing." }, + "maxMessages": { "index": 22, "kind": "property", "displayName": "Max Messages", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Stop receiving messages from a topic we are subscribing to after maxMessages" }, + "nackWait": { "index": 23, "kind": "property", "displayName": "Nack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "For negative acknowledgements (NAK), redelivery is delayed by 5 seconds (default). Setting this to 0 or negative makes the redelivery immediately. Be careful as this can cause the consumer to keep re-processing the same message over and over again due to intermediate error that last a while." }, + "poolSize": { "index": 24, "kind": "property", "displayName": "Pool Size", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Consumer thread pool size (default is 10)" }, + "pullSubscription": { "index": 25, "kind": "property", "displayName": "Pull Subscription", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the consumer subscription type for JetStream. Set to true to use a Pull Subscription (consumer explicitly requests messages). Set to false to use a Push Subscription (messages are automatically delivered)." }, + "queueName": { "index": 26, "kind": "property", "displayName": "Queue Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "The Queue name if we are using nats for a queue configuration" }, + "replyToDisabled": { "index": 27, "kind": "property", "displayName": "Reply To Disabled", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Can be used to turn off sending back reply message in the consumer." }, + "consumerConfiguration": { "index": 28, "kind": "property", "displayName": "Consumer Configuration", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "io.nats.client.api.ConsumerConfiguration", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets a custom ConsumerConfiguration object for the JetStream consumer. This is an advanced option typically used when you need to configure properties not exposed as simple Camel URI parameters. When set, this object will be used to build the final consumer subscription options." }, + "lazyStartProducer": { "index": 29, "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." }, + "replySubject": { "index": 30, "kind": "property", "displayName": "Reply Subject", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "the subject to which subscribers should send response" }, + "requestTimeout": { "index": 31, "kind": "property", "displayName": "Request Timeout", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 20000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, + "autowiredEnabled": { "index": 32, "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." }, + "connection": { "index": 33, "kind": "property", "displayName": "Connection", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.nats.client.Connection", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Reference an already instantiated connection to Nats server" }, + "headerFilterStrategy": { "index": 34, "kind": "property", "displayName": "Header Filter Strategy", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To use a custom header filter strategy." }, + "jetstreamAsync": { "index": 35, "kind": "property", "displayName": "Jetstream Async", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets whether to operate JetStream requests asynchronously." }, + "traceConnection": { "index": 36, "kind": "property", "displayName": "Trace Connection", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not connection trace messages should be printed to standard out for fine grained debugging of connection issues." }, + "credentialsFilePath": { "index": 37, "kind": "property", "displayName": "Credentials File Path", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "If we use useCredentialsFile to true we'll need to set the credentialsFilePath option. It can be loaded by default from classpath, but you can prefix with classpath:, file:, or http: to load the resource from different systems." }, + "secure": { "index": 38, "kind": "property", "displayName": "Secure", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Set secure option indicating TLS is required" }, + "sslContextParameters": { "index": 39, "kind": "property", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To configure security using SSLContextParameters" }, + "useGlobalSslContextParameters": { "index": 40, "kind": "property", "displayName": "Use Global Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enable usage of global SSL context parameters." } }, "headers": { "CamelNatsMessageTimestamp": { "index": 0, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The timestamp of a consumed message.", "constantName": "org.apache.camel.component.nats.NatsConstants#NATS_MESSAGE_TIMESTAMP" }, @@ -60,28 +94,29 @@ "requestCleanupInterval": { "index": 14, "kind": "parameter", "displayName": "Request Cleanup Interval", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Interval to clean up cancelled\/timed out requests." }, "servers": { "index": 15, "kind": "parameter", "displayName": "Servers", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "URLs to one or more NAT servers. Use comma to separate URLs when specifying multiple servers." }, "verbose": { "index": 16, "kind": "parameter", "displayName": "Verbose", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not running in verbose mode" }, - "ackPolicy": { "index": 17, "kind": "parameter", "displayName": "Ack Policy", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "io.nats.client.api.AckPolicy", "enum": [ "none", "all", "explicit" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Acknowledgement mode. none = Messages are acknowledged as soon as the server sends them. Clients do not need to ack. all = All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit = Each message must be acknowledged individually. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer." }, + "ackPolicy": { "index": 17, "kind": "parameter", "displayName": "Ack Policy", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "io.nats.client.api.AckPolicy", "enum": [ "none", "all", "explicit" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "explicit", "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Acknowledgement mode. none = Messages are acknowledged as soon as the server sends them. Clients do not need to ack. all = All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit = Each message must be acknowledged individually. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer." }, "ackWait": { "index": 18, "kind": "parameter", "displayName": "Ack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 30000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "After a message is delivered to a consumer, the server waits 30 seconds (default) for an acknowledgement. If none arrives (timeout), the message becomes eligible for redelivery." }, - "maxMessages": { "index": 19, "kind": "parameter", "displayName": "Max Messages", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Stop receiving messages from a topic we are subscribing to after maxMessages" }, - "nackWait": { "index": 20, "kind": "parameter", "displayName": "Nack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "For negative acknowledgements (NAK), redelivery is delayed by 5 seconds (default). Setting this to 0 or negative makes the redelivery immediately. Be careful as this can cause the consumer to keep re-processing the same message over and over again due to intermediate error that last a while." }, - "poolSize": { "index": 21, "kind": "parameter", "displayName": "Pool Size", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Consumer thread pool size (default is 10)" }, - "queueName": { "index": 22, "kind": "parameter", "displayName": "Queue Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "The Queue name if we are using nats for a queue configuration" }, - "replyToDisabled": { "index": 23, "kind": "parameter", "displayName": "Reply To Disabled", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Can be used to turn off sending back reply message in the consumer." }, - "bridgeErrorHandler": { "index": 24, "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": 25, "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": 26, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "enum", "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." }, - "replySubject": { "index": 27, "kind": "parameter", "displayName": "Reply Subject", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "the subject to which subscribers should send response" }, - "requestTimeout": { "index": 28, "kind": "parameter", "displayName": "Request Timeout", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 20000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, - "lazyStartProducer": { "index": 29, "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." }, - "connection": { "index": 30, "kind": "parameter", "displayName": "Connection", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.nats.client.Connection", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Reference an already instantiated connection to Nats server" }, - "consumerConfiguration": { "index": 31, "kind": "parameter", "displayName": "Consumer Configuration", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.nats.client.api.ConsumerConfiguration", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets a custom ConsumerConfiguration object for the JetStream consumer. This is an advanced option typically used when you need to configure properties not exposed as simple Camel URI parameters. When set, this object will be used to build the final consumer subscription options." }, - "durableName": { "index": 32, "kind": "parameter", "displayName": "Durable Name", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the name to assign to the JetStream durable consumer. Setting this value makes the consumer durable. The value is used to set the durable() field in the underlying NATS ConsumerConfiguration.Builder." }, - "headerFilterStrategy": { "index": 33, "kind": "parameter", "displayName": "Header Filter Strategy", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To use a custom header filter strategy." }, - "jetstreamAsync": { "index": 34, "kind": "parameter", "displayName": "Jetstream Async", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets whether to operate JetStream requests asynchronously." }, - "pullSubscription": { "index": 35, "kind": "parameter", "displayName": "Pull Subscription", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the consumer subscription type for JetStream. Set to true to use a Pull Subscription (consumer explicitly requests messages). Set to false to use a Push Subscription (messages are automatically delivered)." }, - "traceConnection": { "index": 36, "kind": "parameter", "displayName": "Trace Connection", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not connection trace messages should be printed to standard out for fine grained debugging of connection issues." }, - "credentialsFilePath": { "index": 37, "kind": "parameter", "displayName": "Credentials File Path", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "If we use useCredentialsFile to true we'll need to set the credentialsFilePath option. It can be loaded by default from classpath, but you can prefix with classpath:, file:, or http: to load the resource from different systems." }, - "secure": { "index": 38, "kind": "parameter", "displayName": "Secure", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Set secure option indicating TLS is required" }, - "sslContextParameters": { "index": 39, "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To configure security using SSLContextParameters" } + "durableName": { "index": 19, "kind": "parameter", "displayName": "Durable Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the name to assign to the JetStream durable consumer. Setting this value makes the consumer durable. The value is used to set the durable() field in the underlying NATS ConsumerConfiguration.Builder." }, + "maxDeliver": { "index": 20, "kind": "parameter", "displayName": "Max Deliver", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Maximum number of attempts to deliver a message from Nats to a consumer. Once MaxDeliver is reached, the NATS server stops attempting to deliver that specific message. The message is not deleted, it remains in the stream but is simply skipped. It is recommended to set this option to a sensible value in case a message is poison and can not successfully be processed and would always keep failing." }, + "maxMessages": { "index": 21, "kind": "parameter", "displayName": "Max Messages", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Stop receiving messages from a topic we are subscribing to after maxMessages" }, + "nackWait": { "index": 22, "kind": "parameter", "displayName": "Nack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "For negative acknowledgements (NAK), redelivery is delayed by 5 seconds (default). Setting this to 0 or negative makes the redelivery immediately. Be careful as this can cause the consumer to keep re-processing the same message over and over again due to intermediate error that last a while." }, + "poolSize": { "index": 23, "kind": "parameter", "displayName": "Pool Size", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Consumer thread pool size (default is 10)" }, + "pullSubscription": { "index": 24, "kind": "parameter", "displayName": "Pull Subscription", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the consumer subscription type for JetStream. Set to true to use a Pull Subscription (consumer explicitly requests messages). Set to false to use a Push Subscription (messages are automatically delivered)." }, + "queueName": { "index": 25, "kind": "parameter", "displayName": "Queue Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "The Queue name if we are using nats for a queue configuration" }, + "replyToDisabled": { "index": 26, "kind": "parameter", "displayName": "Reply To Disabled", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Can be used to turn off sending back reply message in the consumer." }, + "bridgeErrorHandler": { "index": 27, "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." }, + "consumerConfiguration": { "index": 28, "kind": "parameter", "displayName": "Consumer Configuration", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "io.nats.client.api.ConsumerConfiguration", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets a custom ConsumerConfiguration object for the JetStream consumer. This is an advanced option typically used when you need to configure properties not exposed as simple Camel URI parameters. When set, this object will be used to build the final consumer subscription options." }, + "exceptionHandler": { "index": 29, "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": 30, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "enum", "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." }, + "replySubject": { "index": 31, "kind": "parameter", "displayName": "Reply Subject", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "the subject to which subscribers should send response" }, + "requestTimeout": { "index": 32, "kind": "parameter", "displayName": "Request Timeout", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 20000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, + "lazyStartProducer": { "index": 33, "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." }, + "connection": { "index": 34, "kind": "parameter", "displayName": "Connection", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.nats.client.Connection", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Reference an already instantiated connection to Nats server" }, + "headerFilterStrategy": { "index": 35, "kind": "parameter", "displayName": "Header Filter Strategy", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To use a custom header filter strategy." }, + "jetstreamAsync": { "index": 36, "kind": "parameter", "displayName": "Jetstream Async", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets whether to operate JetStream requests asynchronously." }, + "traceConnection": { "index": 37, "kind": "parameter", "displayName": "Trace Connection", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not connection trace messages should be printed to standard out for fine grained debugging of connection issues." }, + "credentialsFilePath": { "index": 38, "kind": "parameter", "displayName": "Credentials File Path", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "If we use useCredentialsFile to true we'll need to set the credentialsFilePath option. It can be loaded by default from classpath, but you can prefix with classpath:, file:, or http: to load the resource from different systems." }, + "secure": { "index": 39, "kind": "parameter", "displayName": "Secure", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Set secure option indicating TLS is required" }, + "sslContextParameters": { "index": 40, "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To configure security using SSLContextParameters" } } } diff --git a/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsComponentConfigurer.java b/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsComponentConfigurer.java index a4b894701546a..96cc901207d36 100644 --- a/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsComponentConfigurer.java +++ b/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsComponentConfigurer.java @@ -19,22 +19,92 @@ @SuppressWarnings("unchecked") public class NatsComponentConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter { + private org.apache.camel.component.nats.NatsConfiguration getOrCreateConfiguration(NatsComponent target) { + if (target.getConfiguration() == null) { + target.setConfiguration(new org.apache.camel.component.nats.NatsConfiguration()); + } + return target.getConfiguration(); + } + @Override public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) { NatsComponent target = (NatsComponent) obj; switch (ignoreCase ? name.toLowerCase() : name) { + case "ackpolicy": + case "ackPolicy": getOrCreateConfiguration(target).setAckPolicy(property(camelContext, io.nats.client.api.AckPolicy.class, value)); return true; + case "ackwait": + case "ackWait": getOrCreateConfiguration(target).setAckWait(property(camelContext, long.class, value)); return true; case "autowiredenabled": case "autowiredEnabled": target.setAutowiredEnabled(property(camelContext, boolean.class, value)); return true; case "bridgeerrorhandler": case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true; + case "configuration": target.setConfiguration(property(camelContext, org.apache.camel.component.nats.NatsConfiguration.class, value)); return true; + case "connection": getOrCreateConfiguration(target).setConnection(property(camelContext, io.nats.client.Connection.class, value)); return true; + case "connectiontimeout": + case "connectionTimeout": getOrCreateConfiguration(target).setConnectionTimeout(property(camelContext, int.class, value)); return true; + case "consumerconfiguration": + case "consumerConfiguration": getOrCreateConfiguration(target).setConsumerConfiguration(property(camelContext, io.nats.client.api.ConsumerConfiguration.class, value)); return true; + case "credentialsfilepath": + case "credentialsFilePath": getOrCreateConfiguration(target).setCredentialsFilePath(property(camelContext, java.lang.String.class, value)); return true; + case "durablename": + case "durableName": getOrCreateConfiguration(target).setDurableName(property(camelContext, java.lang.String.class, value)); return true; + case "flushconnection": + case "flushConnection": getOrCreateConfiguration(target).setFlushConnection(property(camelContext, boolean.class, value)); return true; + case "flushtimeout": + case "flushTimeout": getOrCreateConfiguration(target).setFlushTimeout(property(camelContext, int.class, value)); return true; case "headerfilterstrategy": - case "headerFilterStrategy": target.setHeaderFilterStrategy(property(camelContext, org.apache.camel.spi.HeaderFilterStrategy.class, value)); return true; + case "headerFilterStrategy": getOrCreateConfiguration(target).setHeaderFilterStrategy(property(camelContext, org.apache.camel.spi.HeaderFilterStrategy.class, value)); return true; + case "jetstreamasync": + case "jetstreamAsync": getOrCreateConfiguration(target).setJetstreamAsync(property(camelContext, boolean.class, value)); return true; + case "jetstreamenabled": + case "jetstreamEnabled": getOrCreateConfiguration(target).setJetstreamEnabled(property(camelContext, boolean.class, value)); return true; + case "jetstreamname": + case "jetstreamName": getOrCreateConfiguration(target).setJetstreamName(property(camelContext, java.lang.String.class, value)); return true; case "lazystartproducer": case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; - case "servers": target.setServers(property(camelContext, java.lang.String.class, value)); return true; + case "maxdeliver": + case "maxDeliver": getOrCreateConfiguration(target).setMaxDeliver(property(camelContext, long.class, value)); return true; + case "maxmessages": + case "maxMessages": getOrCreateConfiguration(target).setMaxMessages(property(camelContext, java.lang.String.class, value)); return true; + case "maxpingsout": + case "maxPingsOut": getOrCreateConfiguration(target).setMaxPingsOut(property(camelContext, int.class, value)); return true; + case "maxreconnectattempts": + case "maxReconnectAttempts": getOrCreateConfiguration(target).setMaxReconnectAttempts(property(camelContext, int.class, value)); return true; + case "nackwait": + case "nackWait": getOrCreateConfiguration(target).setNackWait(property(camelContext, long.class, value)); return true; + case "noecho": + case "noEcho": getOrCreateConfiguration(target).setNoEcho(property(camelContext, boolean.class, value)); return true; + case "norandomizeservers": + case "noRandomizeServers": getOrCreateConfiguration(target).setNoRandomizeServers(property(camelContext, boolean.class, value)); return true; + case "pedantic": getOrCreateConfiguration(target).setPedantic(property(camelContext, boolean.class, value)); return true; + case "pinginterval": + case "pingInterval": getOrCreateConfiguration(target).setPingInterval(property(camelContext, int.class, value)); return true; + case "poolsize": + case "poolSize": getOrCreateConfiguration(target).setPoolSize(property(camelContext, int.class, value)); return true; + case "pullsubscription": + case "pullSubscription": getOrCreateConfiguration(target).setPullSubscription(property(camelContext, boolean.class, value)); return true; + case "queuename": + case "queueName": getOrCreateConfiguration(target).setQueueName(property(camelContext, java.lang.String.class, value)); return true; + case "reconnect": getOrCreateConfiguration(target).setReconnect(property(camelContext, boolean.class, value)); return true; + case "reconnecttimewait": + case "reconnectTimeWait": getOrCreateConfiguration(target).setReconnectTimeWait(property(camelContext, int.class, value)); return true; + case "replysubject": + case "replySubject": getOrCreateConfiguration(target).setReplySubject(property(camelContext, java.lang.String.class, value)); return true; + case "replytodisabled": + case "replyToDisabled": getOrCreateConfiguration(target).setReplyToDisabled(property(camelContext, boolean.class, value)); return true; + case "requestcleanupinterval": + case "requestCleanupInterval": getOrCreateConfiguration(target).setRequestCleanupInterval(property(camelContext, int.class, value)); return true; + case "requesttimeout": + case "requestTimeout": getOrCreateConfiguration(target).setRequestTimeout(property(camelContext, long.class, value)); return true; + case "secure": getOrCreateConfiguration(target).setSecure(property(camelContext, boolean.class, value)); return true; + case "servers": getOrCreateConfiguration(target).setServers(property(camelContext, java.lang.String.class, value)); return true; + case "sslcontextparameters": + case "sslContextParameters": getOrCreateConfiguration(target).setSslContextParameters(property(camelContext, org.apache.camel.support.jsse.SSLContextParameters.class, value)); return true; + case "traceconnection": + case "traceConnection": getOrCreateConfiguration(target).setTraceConnection(property(camelContext, boolean.class, value)); return true; case "useglobalsslcontextparameters": case "useGlobalSslContextParameters": target.setUseGlobalSslContextParameters(property(camelContext, boolean.class, value)); return true; - case "verbose": target.setVerbose(property(camelContext, boolean.class, value)); return true; + case "verbose": getOrCreateConfiguration(target).setVerbose(property(camelContext, boolean.class, value)); return true; default: return false; } } @@ -42,15 +112,78 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj @Override public Class getOptionType(String name, boolean ignoreCase) { switch (ignoreCase ? name.toLowerCase() : name) { + case "ackpolicy": + case "ackPolicy": return io.nats.client.api.AckPolicy.class; + case "ackwait": + case "ackWait": return long.class; case "autowiredenabled": case "autowiredEnabled": return boolean.class; case "bridgeerrorhandler": case "bridgeErrorHandler": return boolean.class; + case "configuration": return org.apache.camel.component.nats.NatsConfiguration.class; + case "connection": return io.nats.client.Connection.class; + case "connectiontimeout": + case "connectionTimeout": return int.class; + case "consumerconfiguration": + case "consumerConfiguration": return io.nats.client.api.ConsumerConfiguration.class; + case "credentialsfilepath": + case "credentialsFilePath": return java.lang.String.class; + case "durablename": + case "durableName": return java.lang.String.class; + case "flushconnection": + case "flushConnection": return boolean.class; + case "flushtimeout": + case "flushTimeout": return int.class; case "headerfilterstrategy": case "headerFilterStrategy": return org.apache.camel.spi.HeaderFilterStrategy.class; + case "jetstreamasync": + case "jetstreamAsync": return boolean.class; + case "jetstreamenabled": + case "jetstreamEnabled": return boolean.class; + case "jetstreamname": + case "jetstreamName": return java.lang.String.class; case "lazystartproducer": case "lazyStartProducer": return boolean.class; + case "maxdeliver": + case "maxDeliver": return long.class; + case "maxmessages": + case "maxMessages": return java.lang.String.class; + case "maxpingsout": + case "maxPingsOut": return int.class; + case "maxreconnectattempts": + case "maxReconnectAttempts": return int.class; + case "nackwait": + case "nackWait": return long.class; + case "noecho": + case "noEcho": return boolean.class; + case "norandomizeservers": + case "noRandomizeServers": return boolean.class; + case "pedantic": return boolean.class; + case "pinginterval": + case "pingInterval": return int.class; + case "poolsize": + case "poolSize": return int.class; + case "pullsubscription": + case "pullSubscription": return boolean.class; + case "queuename": + case "queueName": return java.lang.String.class; + case "reconnect": return boolean.class; + case "reconnecttimewait": + case "reconnectTimeWait": return int.class; + case "replysubject": + case "replySubject": return java.lang.String.class; + case "replytodisabled": + case "replyToDisabled": return boolean.class; + case "requestcleanupinterval": + case "requestCleanupInterval": return int.class; + case "requesttimeout": + case "requestTimeout": return long.class; + case "secure": return boolean.class; case "servers": return java.lang.String.class; + case "sslcontextparameters": + case "sslContextParameters": return org.apache.camel.support.jsse.SSLContextParameters.class; + case "traceconnection": + case "traceConnection": return boolean.class; case "useglobalsslcontextparameters": case "useGlobalSslContextParameters": return boolean.class; case "verbose": return boolean.class; @@ -62,18 +195,81 @@ public Class getOptionType(String name, boolean ignoreCase) { public Object getOptionValue(Object obj, String name, boolean ignoreCase) { NatsComponent target = (NatsComponent) obj; switch (ignoreCase ? name.toLowerCase() : name) { + case "ackpolicy": + case "ackPolicy": return getOrCreateConfiguration(target).getAckPolicy(); + case "ackwait": + case "ackWait": return getOrCreateConfiguration(target).getAckWait(); case "autowiredenabled": case "autowiredEnabled": return target.isAutowiredEnabled(); case "bridgeerrorhandler": case "bridgeErrorHandler": return target.isBridgeErrorHandler(); + case "configuration": return target.getConfiguration(); + case "connection": return getOrCreateConfiguration(target).getConnection(); + case "connectiontimeout": + case "connectionTimeout": return getOrCreateConfiguration(target).getConnectionTimeout(); + case "consumerconfiguration": + case "consumerConfiguration": return getOrCreateConfiguration(target).getConsumerConfiguration(); + case "credentialsfilepath": + case "credentialsFilePath": return getOrCreateConfiguration(target).getCredentialsFilePath(); + case "durablename": + case "durableName": return getOrCreateConfiguration(target).getDurableName(); + case "flushconnection": + case "flushConnection": return getOrCreateConfiguration(target).isFlushConnection(); + case "flushtimeout": + case "flushTimeout": return getOrCreateConfiguration(target).getFlushTimeout(); case "headerfilterstrategy": - case "headerFilterStrategy": return target.getHeaderFilterStrategy(); + case "headerFilterStrategy": return getOrCreateConfiguration(target).getHeaderFilterStrategy(); + case "jetstreamasync": + case "jetstreamAsync": return getOrCreateConfiguration(target).isJetstreamAsync(); + case "jetstreamenabled": + case "jetstreamEnabled": return getOrCreateConfiguration(target).isJetstreamEnabled(); + case "jetstreamname": + case "jetstreamName": return getOrCreateConfiguration(target).getJetstreamName(); case "lazystartproducer": case "lazyStartProducer": return target.isLazyStartProducer(); - case "servers": return target.getServers(); + case "maxdeliver": + case "maxDeliver": return getOrCreateConfiguration(target).getMaxDeliver(); + case "maxmessages": + case "maxMessages": return getOrCreateConfiguration(target).getMaxMessages(); + case "maxpingsout": + case "maxPingsOut": return getOrCreateConfiguration(target).getMaxPingsOut(); + case "maxreconnectattempts": + case "maxReconnectAttempts": return getOrCreateConfiguration(target).getMaxReconnectAttempts(); + case "nackwait": + case "nackWait": return getOrCreateConfiguration(target).getNackWait(); + case "noecho": + case "noEcho": return getOrCreateConfiguration(target).isNoEcho(); + case "norandomizeservers": + case "noRandomizeServers": return getOrCreateConfiguration(target).isNoRandomizeServers(); + case "pedantic": return getOrCreateConfiguration(target).isPedantic(); + case "pinginterval": + case "pingInterval": return getOrCreateConfiguration(target).getPingInterval(); + case "poolsize": + case "poolSize": return getOrCreateConfiguration(target).getPoolSize(); + case "pullsubscription": + case "pullSubscription": return getOrCreateConfiguration(target).isPullSubscription(); + case "queuename": + case "queueName": return getOrCreateConfiguration(target).getQueueName(); + case "reconnect": return getOrCreateConfiguration(target).isReconnect(); + case "reconnecttimewait": + case "reconnectTimeWait": return getOrCreateConfiguration(target).getReconnectTimeWait(); + case "replysubject": + case "replySubject": return getOrCreateConfiguration(target).getReplySubject(); + case "replytodisabled": + case "replyToDisabled": return getOrCreateConfiguration(target).isReplyToDisabled(); + case "requestcleanupinterval": + case "requestCleanupInterval": return getOrCreateConfiguration(target).getRequestCleanupInterval(); + case "requesttimeout": + case "requestTimeout": return getOrCreateConfiguration(target).getRequestTimeout(); + case "secure": return getOrCreateConfiguration(target).isSecure(); + case "servers": return getOrCreateConfiguration(target).getServers(); + case "sslcontextparameters": + case "sslContextParameters": return getOrCreateConfiguration(target).getSslContextParameters(); + case "traceconnection": + case "traceConnection": return getOrCreateConfiguration(target).isTraceConnection(); case "useglobalsslcontextparameters": case "useGlobalSslContextParameters": return target.isUseGlobalSslContextParameters(); - case "verbose": return target.isVerbose(); + case "verbose": return getOrCreateConfiguration(target).isVerbose(); default: return null; } } diff --git a/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsEndpointConfigurer.java b/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsEndpointConfigurer.java index 38fb727f20db6..3436de25552bd 100644 --- a/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsEndpointConfigurer.java +++ b/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsEndpointConfigurer.java @@ -56,6 +56,8 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "jetstreamName": target.getConfiguration().setJetstreamName(property(camelContext, java.lang.String.class, value)); return true; case "lazystartproducer": case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; + case "maxdeliver": + case "maxDeliver": target.getConfiguration().setMaxDeliver(property(camelContext, long.class, value)); return true; case "maxmessages": case "maxMessages": target.getConfiguration().setMaxMessages(property(camelContext, java.lang.String.class, value)); return true; case "maxpingsout": @@ -135,6 +137,8 @@ public Class getOptionType(String name, boolean ignoreCase) { case "jetstreamName": return java.lang.String.class; case "lazystartproducer": case "lazyStartProducer": return boolean.class; + case "maxdeliver": + case "maxDeliver": return long.class; case "maxmessages": case "maxMessages": return java.lang.String.class; case "maxpingsout": @@ -215,6 +219,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "jetstreamName": return target.getConfiguration().getJetstreamName(); case "lazystartproducer": case "lazyStartProducer": return target.isLazyStartProducer(); + case "maxdeliver": + case "maxDeliver": return target.getConfiguration().getMaxDeliver(); case "maxmessages": case "maxMessages": return target.getConfiguration().getMaxMessages(); case "maxpingsout": diff --git a/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsEndpointUriFactory.java b/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsEndpointUriFactory.java index 1b0f20aad58f2..9252e5d790b3d 100644 --- a/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsEndpointUriFactory.java +++ b/components/camel-nats/src/generated/java/org/apache/camel/component/nats/NatsEndpointUriFactory.java @@ -23,7 +23,7 @@ public class NatsEndpointUriFactory extends org.apache.camel.support.component.E private static final Set SECRET_PROPERTY_NAMES; private static final Map MULTI_VALUE_PREFIXES; static { - Set props = new HashSet<>(40); + Set props = new HashSet<>(41); props.add("ackPolicy"); props.add("ackWait"); props.add("bridgeErrorHandler"); @@ -41,6 +41,7 @@ public class NatsEndpointUriFactory extends org.apache.camel.support.component.E props.add("jetstreamEnabled"); props.add("jetstreamName"); props.add("lazyStartProducer"); + props.add("maxDeliver"); props.add("maxMessages"); props.add("maxPingsOut"); props.add("maxReconnectAttempts"); diff --git a/components/camel-nats/src/generated/resources/META-INF/org/apache/camel/component/nats/nats.json b/components/camel-nats/src/generated/resources/META-INF/org/apache/camel/component/nats/nats.json index 446eeba966b63..046322231c623 100644 --- a/components/camel-nats/src/generated/resources/META-INF/org/apache/camel/component/nats/nats.json +++ b/components/camel-nats/src/generated/resources/META-INF/org/apache/camel/component/nats/nats.json @@ -24,13 +24,47 @@ "remote": true }, "componentProperties": { - "servers": { "index": 0, "kind": "property", "displayName": "Servers", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "URLs to one or more NAT servers. Use comma to separate URLs when specifying multiple servers." }, - "verbose": { "index": 1, "kind": "property", "displayName": "Verbose", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether or not running in verbose mode" }, - "bridgeErrorHandler": { "index": 2, "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." }, - "lazyStartProducer": { "index": 3, "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." }, - "autowiredEnabled": { "index": 4, "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." }, - "headerFilterStrategy": { "index": 5, "kind": "property", "displayName": "Header Filter Strategy", "group": "filter", "label": "filter", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel message." }, - "useGlobalSslContextParameters": { "index": 6, "kind": "property", "displayName": "Use Global Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enable usage of global SSL context parameters." } + "configuration": { "index": 0, "kind": "property", "displayName": "Configuration", "group": "common", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.nats.NatsConfiguration", "deprecated": false, "autowired": false, "secret": false, "description": "To use a shared configuration" }, + "connectionTimeout": { "index": 1, "kind": "property", "displayName": "Connection Timeout", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 2000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Timeout for connection attempts. (in milliseconds)" }, + "flushConnection": { "index": 2, "kind": "property", "displayName": "Flush Connection", "group": "common", "label": "common", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Define if we want to flush connection when stopping or not" }, + "flushTimeout": { "index": 3, "kind": "property", "displayName": "Flush Timeout", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Set the flush timeout (in milliseconds)" }, + "jetstreamEnabled": { "index": 4, "kind": "property", "displayName": "Jetstream Enabled", "group": "common", "label": "common", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets whether to enable JetStream support for this endpoint." }, + "jetstreamName": { "index": 5, "kind": "property", "displayName": "Jetstream Name", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the name of the JetStream stream to use." }, + "maxPingsOut": { "index": 6, "kind": "property", "displayName": "Max Pings Out", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 2, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "maximum number of pings have not received a response allowed by the client" }, + "maxReconnectAttempts": { "index": 7, "kind": "property", "displayName": "Max Reconnect Attempts", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 60, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Max reconnection attempts" }, + "noEcho": { "index": 8, "kind": "property", "displayName": "No Echo", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Turn off echo. If supported by the gnatsd version you are connecting to this flag will prevent the server from echoing messages back to the connection if it has subscriptions on the subject being published to." }, + "noRandomizeServers": { "index": 9, "kind": "property", "displayName": "No Randomize Servers", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not randomizing the order of servers for the connection attempts" }, + "pedantic": { "index": 10, "kind": "property", "displayName": "Pedantic", "group": "common", "label": "common", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not running in pedantic mode (this affects performance)" }, + "pingInterval": { "index": 11, "kind": "property", "displayName": "Ping Interval", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 120000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Ping interval to be aware if connection is still alive (in milliseconds)" }, + "reconnect": { "index": 12, "kind": "property", "displayName": "Reconnect", "group": "common", "label": "common", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not using reconnection feature" }, + "reconnectTimeWait": { "index": 13, "kind": "property", "displayName": "Reconnect Time Wait", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 2000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Waiting time before attempts reconnection (in milliseconds)" }, + "requestCleanupInterval": { "index": 14, "kind": "property", "displayName": "Request Cleanup Interval", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Interval to clean up cancelled\/timed out requests." }, + "servers": { "index": 15, "kind": "property", "displayName": "Servers", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "URLs to one or more NAT servers. Use comma to separate URLs when specifying multiple servers." }, + "verbose": { "index": 16, "kind": "property", "displayName": "Verbose", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not running in verbose mode" }, + "ackPolicy": { "index": 17, "kind": "property", "displayName": "Ack Policy", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "io.nats.client.api.AckPolicy", "enum": [ "none", "all", "explicit" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "explicit", "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Acknowledgement mode. none = Messages are acknowledged as soon as the server sends them. Clients do not need to ack. all = All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit = Each message must be acknowledged individually. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer." }, + "ackWait": { "index": 18, "kind": "property", "displayName": "Ack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 30000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "After a message is delivered to a consumer, the server waits 30 seconds (default) for an acknowledgement. If none arrives (timeout), the message becomes eligible for redelivery." }, + "bridgeErrorHandler": { "index": 19, "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." }, + "durableName": { "index": 20, "kind": "property", "displayName": "Durable Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the name to assign to the JetStream durable consumer. Setting this value makes the consumer durable. The value is used to set the durable() field in the underlying NATS ConsumerConfiguration.Builder." }, + "maxDeliver": { "index": 21, "kind": "property", "displayName": "Max Deliver", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Maximum number of attempts to deliver a message from Nats to a consumer. Once MaxDeliver is reached, the NATS server stops attempting to deliver that specific message. The message is not deleted, it remains in the stream but is simply skipped. It is recommended to set this option to a sensible value in case a message is poison and can not successfully be processed and would always keep failing." }, + "maxMessages": { "index": 22, "kind": "property", "displayName": "Max Messages", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Stop receiving messages from a topic we are subscribing to after maxMessages" }, + "nackWait": { "index": 23, "kind": "property", "displayName": "Nack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "For negative acknowledgements (NAK), redelivery is delayed by 5 seconds (default). Setting this to 0 or negative makes the redelivery immediately. Be careful as this can cause the consumer to keep re-processing the same message over and over again due to intermediate error that last a while." }, + "poolSize": { "index": 24, "kind": "property", "displayName": "Pool Size", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Consumer thread pool size (default is 10)" }, + "pullSubscription": { "index": 25, "kind": "property", "displayName": "Pull Subscription", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the consumer subscription type for JetStream. Set to true to use a Pull Subscription (consumer explicitly requests messages). Set to false to use a Push Subscription (messages are automatically delivered)." }, + "queueName": { "index": 26, "kind": "property", "displayName": "Queue Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "The Queue name if we are using nats for a queue configuration" }, + "replyToDisabled": { "index": 27, "kind": "property", "displayName": "Reply To Disabled", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Can be used to turn off sending back reply message in the consumer." }, + "consumerConfiguration": { "index": 28, "kind": "property", "displayName": "Consumer Configuration", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "io.nats.client.api.ConsumerConfiguration", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets a custom ConsumerConfiguration object for the JetStream consumer. This is an advanced option typically used when you need to configure properties not exposed as simple Camel URI parameters. When set, this object will be used to build the final consumer subscription options." }, + "lazyStartProducer": { "index": 29, "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." }, + "replySubject": { "index": 30, "kind": "property", "displayName": "Reply Subject", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "the subject to which subscribers should send response" }, + "requestTimeout": { "index": 31, "kind": "property", "displayName": "Request Timeout", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 20000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, + "autowiredEnabled": { "index": 32, "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." }, + "connection": { "index": 33, "kind": "property", "displayName": "Connection", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.nats.client.Connection", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Reference an already instantiated connection to Nats server" }, + "headerFilterStrategy": { "index": 34, "kind": "property", "displayName": "Header Filter Strategy", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To use a custom header filter strategy." }, + "jetstreamAsync": { "index": 35, "kind": "property", "displayName": "Jetstream Async", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets whether to operate JetStream requests asynchronously." }, + "traceConnection": { "index": 36, "kind": "property", "displayName": "Trace Connection", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not connection trace messages should be printed to standard out for fine grained debugging of connection issues." }, + "credentialsFilePath": { "index": 37, "kind": "property", "displayName": "Credentials File Path", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "If we use useCredentialsFile to true we'll need to set the credentialsFilePath option. It can be loaded by default from classpath, but you can prefix with classpath:, file:, or http: to load the resource from different systems." }, + "secure": { "index": 38, "kind": "property", "displayName": "Secure", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Set secure option indicating TLS is required" }, + "sslContextParameters": { "index": 39, "kind": "property", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To configure security using SSLContextParameters" }, + "useGlobalSslContextParameters": { "index": 40, "kind": "property", "displayName": "Use Global Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enable usage of global SSL context parameters." } }, "headers": { "CamelNatsMessageTimestamp": { "index": 0, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The timestamp of a consumed message.", "constantName": "org.apache.camel.component.nats.NatsConstants#NATS_MESSAGE_TIMESTAMP" }, @@ -60,28 +94,29 @@ "requestCleanupInterval": { "index": 14, "kind": "parameter", "displayName": "Request Cleanup Interval", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Interval to clean up cancelled\/timed out requests." }, "servers": { "index": 15, "kind": "parameter", "displayName": "Servers", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "URLs to one or more NAT servers. Use comma to separate URLs when specifying multiple servers." }, "verbose": { "index": 16, "kind": "parameter", "displayName": "Verbose", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not running in verbose mode" }, - "ackPolicy": { "index": 17, "kind": "parameter", "displayName": "Ack Policy", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "io.nats.client.api.AckPolicy", "enum": [ "none", "all", "explicit" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Acknowledgement mode. none = Messages are acknowledged as soon as the server sends them. Clients do not need to ack. all = All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit = Each message must be acknowledged individually. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer." }, + "ackPolicy": { "index": 17, "kind": "parameter", "displayName": "Ack Policy", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "io.nats.client.api.AckPolicy", "enum": [ "none", "all", "explicit" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "explicit", "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Acknowledgement mode. none = Messages are acknowledged as soon as the server sends them. Clients do not need to ack. all = All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit = Each message must be acknowledged individually. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer." }, "ackWait": { "index": 18, "kind": "parameter", "displayName": "Ack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 30000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "After a message is delivered to a consumer, the server waits 30 seconds (default) for an acknowledgement. If none arrives (timeout), the message becomes eligible for redelivery." }, - "maxMessages": { "index": 19, "kind": "parameter", "displayName": "Max Messages", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Stop receiving messages from a topic we are subscribing to after maxMessages" }, - "nackWait": { "index": 20, "kind": "parameter", "displayName": "Nack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "For negative acknowledgements (NAK), redelivery is delayed by 5 seconds (default). Setting this to 0 or negative makes the redelivery immediately. Be careful as this can cause the consumer to keep re-processing the same message over and over again due to intermediate error that last a while." }, - "poolSize": { "index": 21, "kind": "parameter", "displayName": "Pool Size", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Consumer thread pool size (default is 10)" }, - "queueName": { "index": 22, "kind": "parameter", "displayName": "Queue Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "The Queue name if we are using nats for a queue configuration" }, - "replyToDisabled": { "index": 23, "kind": "parameter", "displayName": "Reply To Disabled", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Can be used to turn off sending back reply message in the consumer." }, - "bridgeErrorHandler": { "index": 24, "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": 25, "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": 26, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "enum", "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." }, - "replySubject": { "index": 27, "kind": "parameter", "displayName": "Reply Subject", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "the subject to which subscribers should send response" }, - "requestTimeout": { "index": 28, "kind": "parameter", "displayName": "Request Timeout", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 20000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, - "lazyStartProducer": { "index": 29, "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." }, - "connection": { "index": 30, "kind": "parameter", "displayName": "Connection", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.nats.client.Connection", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Reference an already instantiated connection to Nats server" }, - "consumerConfiguration": { "index": 31, "kind": "parameter", "displayName": "Consumer Configuration", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.nats.client.api.ConsumerConfiguration", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets a custom ConsumerConfiguration object for the JetStream consumer. This is an advanced option typically used when you need to configure properties not exposed as simple Camel URI parameters. When set, this object will be used to build the final consumer subscription options." }, - "durableName": { "index": 32, "kind": "parameter", "displayName": "Durable Name", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the name to assign to the JetStream durable consumer. Setting this value makes the consumer durable. The value is used to set the durable() field in the underlying NATS ConsumerConfiguration.Builder." }, - "headerFilterStrategy": { "index": 33, "kind": "parameter", "displayName": "Header Filter Strategy", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To use a custom header filter strategy." }, - "jetstreamAsync": { "index": 34, "kind": "parameter", "displayName": "Jetstream Async", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets whether to operate JetStream requests asynchronously." }, - "pullSubscription": { "index": 35, "kind": "parameter", "displayName": "Pull Subscription", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the consumer subscription type for JetStream. Set to true to use a Pull Subscription (consumer explicitly requests messages). Set to false to use a Push Subscription (messages are automatically delivered)." }, - "traceConnection": { "index": 36, "kind": "parameter", "displayName": "Trace Connection", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not connection trace messages should be printed to standard out for fine grained debugging of connection issues." }, - "credentialsFilePath": { "index": 37, "kind": "parameter", "displayName": "Credentials File Path", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "If we use useCredentialsFile to true we'll need to set the credentialsFilePath option. It can be loaded by default from classpath, but you can prefix with classpath:, file:, or http: to load the resource from different systems." }, - "secure": { "index": 38, "kind": "parameter", "displayName": "Secure", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Set secure option indicating TLS is required" }, - "sslContextParameters": { "index": 39, "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To configure security using SSLContextParameters" } + "durableName": { "index": 19, "kind": "parameter", "displayName": "Durable Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the name to assign to the JetStream durable consumer. Setting this value makes the consumer durable. The value is used to set the durable() field in the underlying NATS ConsumerConfiguration.Builder." }, + "maxDeliver": { "index": 20, "kind": "parameter", "displayName": "Max Deliver", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Maximum number of attempts to deliver a message from Nats to a consumer. Once MaxDeliver is reached, the NATS server stops attempting to deliver that specific message. The message is not deleted, it remains in the stream but is simply skipped. It is recommended to set this option to a sensible value in case a message is poison and can not successfully be processed and would always keep failing." }, + "maxMessages": { "index": 21, "kind": "parameter", "displayName": "Max Messages", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Stop receiving messages from a topic we are subscribing to after maxMessages" }, + "nackWait": { "index": 22, "kind": "parameter", "displayName": "Nack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "For negative acknowledgements (NAK), redelivery is delayed by 5 seconds (default). Setting this to 0 or negative makes the redelivery immediately. Be careful as this can cause the consumer to keep re-processing the same message over and over again due to intermediate error that last a while." }, + "poolSize": { "index": 23, "kind": "parameter", "displayName": "Pool Size", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Consumer thread pool size (default is 10)" }, + "pullSubscription": { "index": 24, "kind": "parameter", "displayName": "Pull Subscription", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the consumer subscription type for JetStream. Set to true to use a Pull Subscription (consumer explicitly requests messages). Set to false to use a Push Subscription (messages are automatically delivered)." }, + "queueName": { "index": 25, "kind": "parameter", "displayName": "Queue Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "The Queue name if we are using nats for a queue configuration" }, + "replyToDisabled": { "index": 26, "kind": "parameter", "displayName": "Reply To Disabled", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Can be used to turn off sending back reply message in the consumer." }, + "bridgeErrorHandler": { "index": 27, "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." }, + "consumerConfiguration": { "index": 28, "kind": "parameter", "displayName": "Consumer Configuration", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "io.nats.client.api.ConsumerConfiguration", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets a custom ConsumerConfiguration object for the JetStream consumer. This is an advanced option typically used when you need to configure properties not exposed as simple Camel URI parameters. When set, this object will be used to build the final consumer subscription options." }, + "exceptionHandler": { "index": 29, "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": 30, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "enum", "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." }, + "replySubject": { "index": 31, "kind": "parameter", "displayName": "Reply Subject", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "the subject to which subscribers should send response" }, + "requestTimeout": { "index": 32, "kind": "parameter", "displayName": "Request Timeout", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 20000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Request timeout in milliseconds" }, + "lazyStartProducer": { "index": 33, "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." }, + "connection": { "index": 34, "kind": "parameter", "displayName": "Connection", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.nats.client.Connection", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Reference an already instantiated connection to Nats server" }, + "headerFilterStrategy": { "index": 35, "kind": "parameter", "displayName": "Header Filter Strategy", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To use a custom header filter strategy." }, + "jetstreamAsync": { "index": 36, "kind": "parameter", "displayName": "Jetstream Async", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets whether to operate JetStream requests asynchronously." }, + "traceConnection": { "index": 37, "kind": "parameter", "displayName": "Trace Connection", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not connection trace messages should be printed to standard out for fine grained debugging of connection issues." }, + "credentialsFilePath": { "index": 38, "kind": "parameter", "displayName": "Credentials File Path", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "If we use useCredentialsFile to true we'll need to set the credentialsFilePath option. It can be loaded by default from classpath, but you can prefix with classpath:, file:, or http: to load the resource from different systems." }, + "secure": { "index": 39, "kind": "parameter", "displayName": "Secure", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Set secure option indicating TLS is required" }, + "sslContextParameters": { "index": 40, "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "To configure security using SSLContextParameters" } } } diff --git a/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsComponent.java b/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsComponent.java index 19b96a41ed1f0..ceb46dc5e25a3 100644 --- a/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsComponent.java +++ b/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsComponent.java @@ -28,21 +28,18 @@ public class NatsComponent extends HeaderFilterStrategyComponent implements SSLContextParametersAware { @Metadata - private String servers; + private NatsConfiguration configuration = new NatsConfiguration(); + @Metadata(label = "security", defaultValue = "false") private boolean useGlobalSslContextParameters; - @Metadata - private boolean verbose; @Override protected Endpoint createEndpoint(String uri, String remaining, Map parameters) throws Exception { - NatsConfiguration config = new NatsConfiguration(); + NatsConfiguration config = configuration.copy(); if (getHeaderFilterStrategy() != null) { config.setHeaderFilterStrategy(getHeaderFilterStrategy()); } config.setTopic(remaining); - config.setServers(servers); - config.setVerbose(verbose); if (config.getSslContextParameters() == null) { config.setSslContextParameters(retrieveGlobalSslContextParameters()); @@ -53,17 +50,6 @@ protected Endpoint createEndpoint(String uri, String remaining, Map * none = Messages are acknowledged as soon as the server sends them. Clients do not need to ack. all = All messages * with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages * 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit = Each message must be acknowledged @@ -615,11 +625,28 @@ public long getNackWait() { /** * For negative acknowledgements (NAK), redelivery is delayed by 5 seconds (default). - * + *

* Setting this to 0 or negative makes the redelivery immediately. Be careful as this can cause the consumer to keep * re-processing the same message over and over again due to intermediate error that last a while. */ public void setNackWait(long nackWait) { this.nackWait = nackWait; } + + public long getMaxDeliver() { + return maxDeliver; + } + + /** + * Maximum number of attempts to deliver a message from Nats to a consumer. + * + * Once MaxDeliver is reached, the NATS server stops attempting to deliver that specific message. The message is not + * deleted, it remains in the stream but is simply skipped. + * + * It is recommended to set this option to a sensible value in case a message is poison and can not successfully be + * processed and would always keep failing. + */ + public void setMaxDeliver(long maxDeliver) { + this.maxDeliver = maxDeliver; + } } diff --git a/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConsumer.java b/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConsumer.java index 75bb40bb31621..40bd8424d918f 100644 --- a/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConsumer.java +++ b/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConsumer.java @@ -194,6 +194,9 @@ private void setupJetStreamConsumer(String topic, String queueName) throws IOExc if (configuration.getAckWait() > 0) { ccBuilder.ackWait(configuration.getAckWait()); } + if (configuration.getMaxDeliver() > 0) { + ccBuilder.maxDeliver(configuration.getMaxDeliver()); + } cc = ccBuilder.build(); } @@ -216,14 +219,12 @@ private void setupJetStreamConsumer(String topic, String queueName) throws IOExc .deliverGroup(queueName) .build(); - boolean autoAck = configuration.getAckPolicy() == null || configuration.getAckPolicy() == AckPolicy.None; - NatsConsumer.this.jetStreamSubscription = this.connection.jetStream().subscribe( NatsConsumer.this.getEndpoint().getConfiguration().getTopic(), queueName, dispatcher, messageHandler, - autoAck, + true, pushOptions); } diff --git a/components/camel-nats/src/test/java/org/apache/camel/component/nats/integration/NatsAuthITSupport.java b/components/camel-nats/src/test/java/org/apache/camel/component/nats/integration/NatsAuthITSupport.java index f89c301c6571c..b4661f1e627eb 100644 --- a/components/camel-nats/src/test/java/org/apache/camel/component/nats/integration/NatsAuthITSupport.java +++ b/components/camel-nats/src/test/java/org/apache/camel/component/nats/integration/NatsAuthITSupport.java @@ -31,7 +31,7 @@ public class NatsAuthITSupport extends CamelTestSupport { protected CamelContext createCamelContext() throws Exception { CamelContext context = super.createCamelContext(); NatsComponent nats = context.getComponent("nats", NatsComponent.class); - nats.setServers(service.getServiceAddress()); + nats.getConfiguration().setServers(service.getServiceAddress()); return context; } } diff --git a/components/camel-nats/src/test/java/org/apache/camel/component/nats/integration/NatsAuthTokenITSupport.java b/components/camel-nats/src/test/java/org/apache/camel/component/nats/integration/NatsAuthTokenITSupport.java index 5e23db39653b5..198a9377dd5c4 100644 --- a/components/camel-nats/src/test/java/org/apache/camel/component/nats/integration/NatsAuthTokenITSupport.java +++ b/components/camel-nats/src/test/java/org/apache/camel/component/nats/integration/NatsAuthTokenITSupport.java @@ -30,7 +30,7 @@ public class NatsAuthTokenITSupport extends CamelTestSupport { protected CamelContext createCamelContext() throws Exception { CamelContext context = super.createCamelContext(); NatsComponent nats = context.getComponent("nats", NatsComponent.class); - nats.setServers(service.getServiceAddress()); + nats.getConfiguration().setServers(service.getServiceAddress()); return context; } diff --git a/components/camel-nats/src/test/java/org/apache/camel/component/nats/integration/NatsITSupport.java b/components/camel-nats/src/test/java/org/apache/camel/component/nats/integration/NatsITSupport.java index c5d2761d3095b..2ce8e2c09204e 100644 --- a/components/camel-nats/src/test/java/org/apache/camel/component/nats/integration/NatsITSupport.java +++ b/components/camel-nats/src/test/java/org/apache/camel/component/nats/integration/NatsITSupport.java @@ -49,7 +49,7 @@ public class NatsITSupport extends CamelTestSupport { protected CamelContext createCamelContext() throws Exception { CamelContext context = super.createCamelContext(); NatsComponent nats = context.getComponent("nats", NatsComponent.class); - nats.setServers(service.getServiceAddress()); + nats.getConfiguration().setServers(service.getServiceAddress()); return context; } } diff --git a/components/camel-nats/src/test/java/org/apache/camel/component/nats/integration/NatsTLSAuthITSupport.java b/components/camel-nats/src/test/java/org/apache/camel/component/nats/integration/NatsTLSAuthITSupport.java index dd04188e07e57..f4c7377d7f38f 100644 --- a/components/camel-nats/src/test/java/org/apache/camel/component/nats/integration/NatsTLSAuthITSupport.java +++ b/components/camel-nats/src/test/java/org/apache/camel/component/nats/integration/NatsTLSAuthITSupport.java @@ -31,7 +31,7 @@ public class NatsTLSAuthITSupport extends CamelTestSupport { protected CamelContext createCamelContext() throws Exception { CamelContext context = super.createCamelContext(); NatsComponent nats = context.getComponent("nats", NatsComponent.class); - nats.setServers(service.getServiceAddress()); + nats.getConfiguration().setServers(service.getServiceAddress()); return context; } diff --git a/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerIT.java b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerIT.java index fb8fac836abcd..c2d8a5a495587 100644 --- a/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerIT.java +++ b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerIT.java @@ -39,7 +39,7 @@ public void testConsumer() throws Exception { template.sendBody("direct:send", "Hello World"); - mockResultEndpoint.assertIsSatisfied(); + MockEndpoint.assertIsSatisfied(context); } @Override diff --git a/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerMaxDeliverIT.java b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerMaxDeliverIT.java new file mode 100644 index 0000000000000..9803aac5ef0ed --- /dev/null +++ b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerMaxDeliverIT.java @@ -0,0 +1,87 @@ +/* + * 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.nats.jetstream; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.camel.EndpointInject; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.component.nats.NatsConstants; +import org.apache.camel.component.nats.integration.NatsITSupport; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIfSystemProperty; +import org.junit.jupiter.api.parallel.Isolated; + +@DisabledIfSystemProperty(named = "ci.env.name", matches = ".*", disabledReason = "Flaky on GitHub Actions") +@Isolated +public class NatsJetstreamConsumerMaxDeliverIT extends NatsITSupport { + + @EndpointInject("mock:result") + protected MockEndpoint mockResultEndpoint; + + @EndpointInject("mock:input") + protected MockEndpoint mockInputEndpoint; + + @Test + public void testConsumer() throws Exception { + mockResultEndpoint.expectedMessageCount(0); + + mockInputEndpoint.expectedMessageCount(3); + mockInputEndpoint.expectedHeaderReceived(NatsConstants.NATS_SUBJECT, "mytopic2"); + mockInputEndpoint.message(0).header(NatsConstants.NATS_DELIVERY_COUNTER).isEqualTo(1); + mockInputEndpoint.message(1).header(NatsConstants.NATS_DELIVERY_COUNTER).isEqualTo(2); + mockInputEndpoint.message(2).header(NatsConstants.NATS_DELIVERY_COUNTER).isEqualTo(3); + + template.sendBody("direct:send", "Hello World"); + + mockInputEndpoint.setAssertPeriod(2000); // if maxDeliver is not working then we receive the message again and again + + MockEndpoint.assertIsSatisfied(context); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + String uri + = "nats:mytopic2?jetstreamEnabled=true&jetstreamName=mystream2&jetstreamAsync=false&durableName=camel2&pullSubscription=false&ackPolicy=explicit&nackWait=10&maxDeliver=3"; + + from("direct:send") + // when running full test suite then send can fail due to nats server setup/tearndown + .errorHandler(defaultErrorHandler().maximumRedeliveries(5)) + .to(uri); + + final AtomicInteger counter = new AtomicInteger(); + from(uri) + .to("mock:input") + .process(new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + // always fail + counter.incrementAndGet(); + throw new IllegalArgumentException("Forced"); + } + }) + .to(mockResultEndpoint); + } + }; + } +} diff --git a/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerRedeliveryIT.java b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerRedeliveryIT.java index 48d0d1f64f23e..267dce8bbd965 100644 --- a/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerRedeliveryIT.java +++ b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerRedeliveryIT.java @@ -54,7 +54,7 @@ public void testConsumer() throws Exception { template.sendBody("direct:send", "Hello World"); - mockResultEndpoint.assertIsSatisfied(); + MockEndpoint.assertIsSatisfied(context); } @Override diff --git a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/NatsComponentBuilderFactory.java b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/NatsComponentBuilderFactory.java index 92b4663f53fae..ce62d64a563c7 100644 --- a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/NatsComponentBuilderFactory.java +++ b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/NatsComponentBuilderFactory.java @@ -50,6 +50,264 @@ static NatsComponentBuilder nats() { */ interface NatsComponentBuilder extends ComponentBuilder { + /** + * To use a shared configuration. + * + * The option is a: + * <code>org.apache.camel.component.nats.NatsConfiguration</code> type. + * + * Group: common + * + * @param configuration the value to set + * @return the dsl builder + */ + default NatsComponentBuilder configuration(org.apache.camel.component.nats.NatsConfiguration configuration) { + doSetProperty("configuration", configuration); + return this; + } + + + /** + * Timeout for connection attempts. (in milliseconds). + * + * The option is a: <code>int</code> type. + * + * Default: 2000 + * Group: common + * + * @param connectionTimeout the value to set + * @return the dsl builder + */ + default NatsComponentBuilder connectionTimeout(int connectionTimeout) { + doSetProperty("connectionTimeout", connectionTimeout); + return this; + } + + + /** + * Define if we want to flush connection when stopping or not. + * + * The option is a: <code>boolean</code> type. + * + * Default: true + * Group: common + * + * @param flushConnection the value to set + * @return the dsl builder + */ + default NatsComponentBuilder flushConnection(boolean flushConnection) { + doSetProperty("flushConnection", flushConnection); + return this; + } + + + /** + * Set the flush timeout (in milliseconds). + * + * The option is a: <code>int</code> type. + * + * Default: 1000 + * Group: common + * + * @param flushTimeout the value to set + * @return the dsl builder + */ + default NatsComponentBuilder flushTimeout(int flushTimeout) { + doSetProperty("flushTimeout", flushTimeout); + return this; + } + + + /** + * Sets whether to enable JetStream support for this endpoint. + * + * The option is a: <code>boolean</code> type. + * + * Default: false + * Group: common + * + * @param jetstreamEnabled the value to set + * @return the dsl builder + */ + default NatsComponentBuilder jetstreamEnabled(boolean jetstreamEnabled) { + doSetProperty("jetstreamEnabled", jetstreamEnabled); + return this; + } + + /** + * Sets the name of the JetStream stream to use. + * + * The option is a: <code>java.lang.String</code> type. + * + * Group: common + * + * @param jetstreamName the value to set + * @return the dsl builder + */ + default NatsComponentBuilder jetstreamName(java.lang.String jetstreamName) { + doSetProperty("jetstreamName", jetstreamName); + return this; + } + + + /** + * maximum number of pings have not received a response allowed by the + * client. + * + * The option is a: <code>int</code> type. + * + * Default: 2 + * Group: common + * + * @param maxPingsOut the value to set + * @return the dsl builder + */ + default NatsComponentBuilder maxPingsOut(int maxPingsOut) { + doSetProperty("maxPingsOut", maxPingsOut); + return this; + } + + + /** + * Max reconnection attempts. + * + * The option is a: <code>int</code> type. + * + * Default: 60 + * Group: common + * + * @param maxReconnectAttempts the value to set + * @return the dsl builder + */ + default NatsComponentBuilder maxReconnectAttempts(int maxReconnectAttempts) { + doSetProperty("maxReconnectAttempts", maxReconnectAttempts); + return this; + } + + + /** + * Turn off echo. If supported by the gnatsd version you are connecting + * to this flag will prevent the server from echoing messages back to + * the connection if it has subscriptions on the subject being published + * to. + * + * The option is a: <code>boolean</code> type. + * + * Default: false + * Group: common + * + * @param noEcho the value to set + * @return the dsl builder + */ + default NatsComponentBuilder noEcho(boolean noEcho) { + doSetProperty("noEcho", noEcho); + return this; + } + + + /** + * Whether or not randomizing the order of servers for the connection + * attempts. + * + * The option is a: <code>boolean</code> type. + * + * Default: false + * Group: common + * + * @param noRandomizeServers the value to set + * @return the dsl builder + */ + default NatsComponentBuilder noRandomizeServers(boolean noRandomizeServers) { + doSetProperty("noRandomizeServers", noRandomizeServers); + return this; + } + + + /** + * Whether or not running in pedantic mode (this affects performance). + * + * The option is a: <code>boolean</code> type. + * + * Default: false + * Group: common + * + * @param pedantic the value to set + * @return the dsl builder + */ + default NatsComponentBuilder pedantic(boolean pedantic) { + doSetProperty("pedantic", pedantic); + return this; + } + + + /** + * Ping interval to be aware if connection is still alive (in + * milliseconds). + * + * The option is a: <code>int</code> type. + * + * Default: 120000 + * Group: common + * + * @param pingInterval the value to set + * @return the dsl builder + */ + default NatsComponentBuilder pingInterval(int pingInterval) { + doSetProperty("pingInterval", pingInterval); + return this; + } + + + /** + * Whether or not using reconnection feature. + * + * The option is a: <code>boolean</code> type. + * + * Default: true + * Group: common + * + * @param reconnect the value to set + * @return the dsl builder + */ + default NatsComponentBuilder reconnect(boolean reconnect) { + doSetProperty("reconnect", reconnect); + return this; + } + + + /** + * Waiting time before attempts reconnection (in milliseconds). + * + * The option is a: <code>int</code> type. + * + * Default: 2000 + * Group: common + * + * @param reconnectTimeWait the value to set + * @return the dsl builder + */ + default NatsComponentBuilder reconnectTimeWait(int reconnectTimeWait) { + doSetProperty("reconnectTimeWait", reconnectTimeWait); + return this; + } + + + /** + * Interval to clean up cancelled/timed out requests. + * + * The option is a: <code>int</code> type. + * + * Default: 5000 + * Group: common + * + * @param requestCleanupInterval the value to set + * @return the dsl builder + */ + default NatsComponentBuilder requestCleanupInterval(int requestCleanupInterval) { + doSetProperty("requestCleanupInterval", requestCleanupInterval); + return this; + } + /** * URLs to one or more NAT servers. Use comma to separate URLs when * specifying multiple servers. @@ -84,6 +342,49 @@ default NatsComponentBuilder verbose(boolean verbose) { } + /** + * Acknowledgement mode. none = Messages are acknowledged as soon as the + * server sends them. Clients do not need to ack. all = All messages + * with a sequence number less than the message acked are also + * acknowledged. E.g. reading a batch of messages 1..100. Ack on message + * 100 will acknowledge 1..99 as well. explicit = Each message must be + * acknowledged individually. Message can be acked out of sequence and + * create gaps of unacknowledged messages in the consumer. + * + * The option is a: + * <code>io.nats.client.api.AckPolicy</code> type. + * + * Default: explicit + * Group: consumer + * + * @param ackPolicy the value to set + * @return the dsl builder + */ + default NatsComponentBuilder ackPolicy(io.nats.client.api.AckPolicy ackPolicy) { + doSetProperty("ackPolicy", ackPolicy); + return this; + } + + + /** + * After a message is delivered to a consumer, the server waits 30 + * seconds (default) for an acknowledgement. If none arrives (timeout), + * the message becomes eligible for redelivery. + * + * The option is a: <code>long</code> type. + * + * Default: 30000 + * Group: consumer + * + * @param ackWait the value to set + * @return the dsl builder + */ + default NatsComponentBuilder ackWait(long ackWait) { + doSetProperty("ackWait", ackWait); + return this; + } + + /** * Allows for bridging the consumer to the Camel routing Error Handler, * which mean any exceptions (if possible) occurred while the Camel @@ -111,6 +412,171 @@ default NatsComponentBuilder bridgeErrorHandler(boolean bridgeErrorHandler) { return this; } + /** + * Sets the name to assign to the JetStream durable consumer. Setting + * this value makes the consumer durable. The value is used to set the + * durable() field in the underlying NATS ConsumerConfiguration.Builder. + * + * The option is a: <code>java.lang.String</code> type. + * + * Group: consumer + * + * @param durableName the value to set + * @return the dsl builder + */ + default NatsComponentBuilder durableName(java.lang.String durableName) { + doSetProperty("durableName", durableName); + return this; + } + + /** + * Maximum number of attempts to deliver a message from Nats to a + * consumer. Once MaxDeliver is reached, the NATS server stops + * attempting to deliver that specific message. The message is not + * deleted, it remains in the stream but is simply skipped. It is + * recommended to set this option to a sensible value in case a message + * is poison and can not successfully be processed and would always keep + * failing. + * + * The option is a: <code>long</code> type. + * + * Group: consumer + * + * @param maxDeliver the value to set + * @return the dsl builder + */ + default NatsComponentBuilder maxDeliver(long maxDeliver) { + doSetProperty("maxDeliver", maxDeliver); + return this; + } + + /** + * Stop receiving messages from a topic we are subscribing to after + * maxMessages. + * + * The option is a: <code>java.lang.String</code> type. + * + * Group: consumer + * + * @param maxMessages the value to set + * @return the dsl builder + */ + default NatsComponentBuilder maxMessages(java.lang.String maxMessages) { + doSetProperty("maxMessages", maxMessages); + return this; + } + + + /** + * For negative acknowledgements (NAK), redelivery is delayed by 5 + * seconds (default). Setting this to 0 or negative makes the redelivery + * immediately. Be careful as this can cause the consumer to keep + * re-processing the same message over and over again due to + * intermediate error that last a while. + * + * The option is a: <code>long</code> type. + * + * Default: 5000 + * Group: consumer + * + * @param nackWait the value to set + * @return the dsl builder + */ + default NatsComponentBuilder nackWait(long nackWait) { + doSetProperty("nackWait", nackWait); + return this; + } + + + /** + * Consumer thread pool size (default is 10). + * + * The option is a: <code>int</code> type. + * + * Default: 10 + * Group: consumer + * + * @param poolSize the value to set + * @return the dsl builder + */ + default NatsComponentBuilder poolSize(int poolSize) { + doSetProperty("poolSize", poolSize); + return this; + } + + + /** + * Sets the consumer subscription type for JetStream. Set to true to use + * a Pull Subscription (consumer explicitly requests messages). Set to + * false to use a Push Subscription (messages are automatically + * delivered). + * + * The option is a: <code>boolean</code> type. + * + * Default: true + * Group: consumer + * + * @param pullSubscription the value to set + * @return the dsl builder + */ + default NatsComponentBuilder pullSubscription(boolean pullSubscription) { + doSetProperty("pullSubscription", pullSubscription); + return this; + } + + /** + * The Queue name if we are using nats for a queue configuration. + * + * The option is a: <code>java.lang.String</code> type. + * + * Group: consumer + * + * @param queueName the value to set + * @return the dsl builder + */ + default NatsComponentBuilder queueName(java.lang.String queueName) { + doSetProperty("queueName", queueName); + return this; + } + + + /** + * Can be used to turn off sending back reply message in the consumer. + * + * The option is a: <code>boolean</code> type. + * + * Default: false + * Group: consumer + * + * @param replyToDisabled the value to set + * @return the dsl builder + */ + default NatsComponentBuilder replyToDisabled(boolean replyToDisabled) { + doSetProperty("replyToDisabled", replyToDisabled); + return this; + } + + /** + * Sets a custom ConsumerConfiguration object for the JetStream + * consumer. This is an advanced option typically used when you need to + * configure properties not exposed as simple Camel URI parameters. When + * set, this object will be used to build the final consumer + * subscription options. + * + * The option is a: + * <code>io.nats.client.api.ConsumerConfiguration</code> + * type. + * + * Group: consumer (advanced) + * + * @param consumerConfiguration the value to set + * @return the dsl builder + */ + default NatsComponentBuilder consumerConfiguration(io.nats.client.api.ConsumerConfiguration consumerConfiguration) { + doSetProperty("consumerConfiguration", consumerConfiguration); + return this; + } + /** * Whether the producer should be started lazy (on the first message). @@ -136,6 +602,38 @@ default NatsComponentBuilder lazyStartProducer(boolean lazyStartProducer) { return this; } + /** + * the subject to which subscribers should send response. + * + * The option is a: <code>java.lang.String</code> type. + * + * Group: producer + * + * @param replySubject the value to set + * @return the dsl builder + */ + default NatsComponentBuilder replySubject(java.lang.String replySubject) { + doSetProperty("replySubject", replySubject); + return this; + } + + + /** + * Request timeout in milliseconds. + * + * The option is a: <code>long</code> type. + * + * Default: 20000 + * Group: producer + * + * @param requestTimeout the value to set + * @return the dsl builder + */ + default NatsComponentBuilder requestTimeout(long requestTimeout) { + doSetProperty("requestTimeout", requestTimeout); + return this; + } + /** * Whether autowiring is enabled. This is used for automatic autowiring @@ -159,14 +657,29 @@ default NatsComponentBuilder autowiredEnabled(boolean autowiredEnabled) { } /** - * To use a custom org.apache.camel.spi.HeaderFilterStrategy to filter - * header to and from Camel message. + * Reference an already instantiated connection to Nats server. + * + * The option is a: <code>io.nats.client.Connection</code> + * type. + * + * Group: advanced + * + * @param connection the value to set + * @return the dsl builder + */ + default NatsComponentBuilder connection(io.nats.client.Connection connection) { + doSetProperty("connection", connection); + return this; + } + + /** + * To use a custom header filter strategy. * * The option is a: * <code>org.apache.camel.spi.HeaderFilterStrategy</code> * type. * - * Group: filter + * Group: advanced * * @param headerFilterStrategy the value to set * @return the dsl builder @@ -177,6 +690,92 @@ default NatsComponentBuilder headerFilterStrategy(org.apache.camel.spi.HeaderFil } + /** + * Sets whether to operate JetStream requests asynchronously. + * + * The option is a: <code>boolean</code> type. + * + * Default: true + * Group: advanced + * + * @param jetstreamAsync the value to set + * @return the dsl builder + */ + default NatsComponentBuilder jetstreamAsync(boolean jetstreamAsync) { + doSetProperty("jetstreamAsync", jetstreamAsync); + return this; + } + + + /** + * Whether or not connection trace messages should be printed to + * standard out for fine grained debugging of connection issues. + * + * The option is a: <code>boolean</code> type. + * + * Default: false + * Group: advanced + * + * @param traceConnection the value to set + * @return the dsl builder + */ + default NatsComponentBuilder traceConnection(boolean traceConnection) { + doSetProperty("traceConnection", traceConnection); + return this; + } + + /** + * If we use useCredentialsFile to true we'll need to set the + * credentialsFilePath option. It can be loaded by default from + * classpath, but you can prefix with classpath:, file:, or http: to + * load the resource from different systems. + * + * The option is a: <code>java.lang.String</code> type. + * + * Group: security + * + * @param credentialsFilePath the value to set + * @return the dsl builder + */ + default NatsComponentBuilder credentialsFilePath(java.lang.String credentialsFilePath) { + doSetProperty("credentialsFilePath", credentialsFilePath); + return this; + } + + + /** + * Set secure option indicating TLS is required. + * + * The option is a: <code>boolean</code> type. + * + * Default: false + * Group: security + * + * @param secure the value to set + * @return the dsl builder + */ + default NatsComponentBuilder secure(boolean secure) { + doSetProperty("secure", secure); + return this; + } + + /** + * To configure security using SSLContextParameters. + * + * The option is a: + * <code>org.apache.camel.support.jsse.SSLContextParameters</code> type. + * + * Group: security + * + * @param sslContextParameters the value to set + * @return the dsl builder + */ + default NatsComponentBuilder sslContextParameters(org.apache.camel.support.jsse.SSLContextParameters sslContextParameters) { + doSetProperty("sslContextParameters", sslContextParameters); + return this; + } + + /** * Enable usage of global SSL context parameters. * @@ -201,18 +800,58 @@ class NatsComponentBuilderImpl protected NatsComponent buildConcreteComponent() { return new NatsComponent(); } + private org.apache.camel.component.nats.NatsConfiguration getOrCreateConfiguration(NatsComponent component) { + if (component.getConfiguration() == null) { + component.setConfiguration(new org.apache.camel.component.nats.NatsConfiguration()); + } + return component.getConfiguration(); + } @Override protected boolean setPropertyOnComponent( Component component, String name, Object value) { switch (name) { - case "servers": ((NatsComponent) component).setServers((java.lang.String) value); return true; - case "verbose": ((NatsComponent) component).setVerbose((boolean) value); return true; + case "configuration": ((NatsComponent) component).setConfiguration((org.apache.camel.component.nats.NatsConfiguration) value); return true; + case "connectionTimeout": getOrCreateConfiguration((NatsComponent) component).setConnectionTimeout((int) value); return true; + case "flushConnection": getOrCreateConfiguration((NatsComponent) component).setFlushConnection((boolean) value); return true; + case "flushTimeout": getOrCreateConfiguration((NatsComponent) component).setFlushTimeout((int) value); return true; + case "jetstreamEnabled": getOrCreateConfiguration((NatsComponent) component).setJetstreamEnabled((boolean) value); return true; + case "jetstreamName": getOrCreateConfiguration((NatsComponent) component).setJetstreamName((java.lang.String) value); return true; + case "maxPingsOut": getOrCreateConfiguration((NatsComponent) component).setMaxPingsOut((int) value); return true; + case "maxReconnectAttempts": getOrCreateConfiguration((NatsComponent) component).setMaxReconnectAttempts((int) value); return true; + case "noEcho": getOrCreateConfiguration((NatsComponent) component).setNoEcho((boolean) value); return true; + case "noRandomizeServers": getOrCreateConfiguration((NatsComponent) component).setNoRandomizeServers((boolean) value); return true; + case "pedantic": getOrCreateConfiguration((NatsComponent) component).setPedantic((boolean) value); return true; + case "pingInterval": getOrCreateConfiguration((NatsComponent) component).setPingInterval((int) value); return true; + case "reconnect": getOrCreateConfiguration((NatsComponent) component).setReconnect((boolean) value); return true; + case "reconnectTimeWait": getOrCreateConfiguration((NatsComponent) component).setReconnectTimeWait((int) value); return true; + case "requestCleanupInterval": getOrCreateConfiguration((NatsComponent) component).setRequestCleanupInterval((int) value); return true; + case "servers": getOrCreateConfiguration((NatsComponent) component).setServers((java.lang.String) value); return true; + case "verbose": getOrCreateConfiguration((NatsComponent) component).setVerbose((boolean) value); return true; + case "ackPolicy": getOrCreateConfiguration((NatsComponent) component).setAckPolicy((io.nats.client.api.AckPolicy) value); return true; + case "ackWait": getOrCreateConfiguration((NatsComponent) component).setAckWait((long) value); return true; case "bridgeErrorHandler": ((NatsComponent) component).setBridgeErrorHandler((boolean) value); return true; + case "durableName": getOrCreateConfiguration((NatsComponent) component).setDurableName((java.lang.String) value); return true; + case "maxDeliver": getOrCreateConfiguration((NatsComponent) component).setMaxDeliver((long) value); return true; + case "maxMessages": getOrCreateConfiguration((NatsComponent) component).setMaxMessages((java.lang.String) value); return true; + case "nackWait": getOrCreateConfiguration((NatsComponent) component).setNackWait((long) value); return true; + case "poolSize": getOrCreateConfiguration((NatsComponent) component).setPoolSize((int) value); return true; + case "pullSubscription": getOrCreateConfiguration((NatsComponent) component).setPullSubscription((boolean) value); return true; + case "queueName": getOrCreateConfiguration((NatsComponent) component).setQueueName((java.lang.String) value); return true; + case "replyToDisabled": getOrCreateConfiguration((NatsComponent) component).setReplyToDisabled((boolean) value); return true; + case "consumerConfiguration": getOrCreateConfiguration((NatsComponent) component).setConsumerConfiguration((io.nats.client.api.ConsumerConfiguration) value); return true; case "lazyStartProducer": ((NatsComponent) component).setLazyStartProducer((boolean) value); return true; + case "replySubject": getOrCreateConfiguration((NatsComponent) component).setReplySubject((java.lang.String) value); return true; + case "requestTimeout": getOrCreateConfiguration((NatsComponent) component).setRequestTimeout((long) value); return true; case "autowiredEnabled": ((NatsComponent) component).setAutowiredEnabled((boolean) value); return true; - case "headerFilterStrategy": ((NatsComponent) component).setHeaderFilterStrategy((org.apache.camel.spi.HeaderFilterStrategy) value); return true; + case "connection": getOrCreateConfiguration((NatsComponent) component).setConnection((io.nats.client.Connection) value); return true; + case "headerFilterStrategy": getOrCreateConfiguration((NatsComponent) component).setHeaderFilterStrategy((org.apache.camel.spi.HeaderFilterStrategy) value); return true; + case "jetstreamAsync": getOrCreateConfiguration((NatsComponent) component).setJetstreamAsync((boolean) value); return true; + case "traceConnection": getOrCreateConfiguration((NatsComponent) component).setTraceConnection((boolean) value); return true; + case "credentialsFilePath": getOrCreateConfiguration((NatsComponent) component).setCredentialsFilePath((java.lang.String) value); return true; + case "secure": getOrCreateConfiguration((NatsComponent) component).setSecure((boolean) value); return true; + case "sslContextParameters": getOrCreateConfiguration((NatsComponent) component).setSslContextParameters((org.apache.camel.support.jsse.SSLContextParameters) value); return true; case "useGlobalSslContextParameters": ((NatsComponent) component).setUseGlobalSslContextParameters((boolean) value); return true; default: return false; } diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NatsEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NatsEndpointBuilderFactory.java index bbebfccdb51a7..ba594e328d403 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NatsEndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NatsEndpointBuilderFactory.java @@ -515,7 +515,7 @@ default NatsEndpointConsumerBuilder verbose(String verbose) { * * The option is a: io.nats.client.api.AckPolicy type. * - * Default: none + * Default: explicit * Group: consumer * * @param ackPolicy the value to set @@ -537,7 +537,7 @@ default NatsEndpointConsumerBuilder ackPolicy(io.nats.client.api.AckPolicy ackPo * The option will be converted to a * io.nats.client.api.AckPolicy type. * - * Default: none + * Default: explicit * Group: consumer * * @param ackPolicy the value to set @@ -581,6 +581,62 @@ default NatsEndpointConsumerBuilder ackWait(String ackWait) { doSetProperty("ackWait", ackWait); return this; } + /** + * Sets the name to assign to the JetStream durable consumer. Setting + * this value makes the consumer durable. The value is used to set the + * durable() field in the underlying NATS ConsumerConfiguration.Builder. + * + * The option is a: java.lang.String type. + * + * Group: consumer + * + * @param durableName the value to set + * @return the dsl builder + */ + default NatsEndpointConsumerBuilder durableName(String durableName) { + doSetProperty("durableName", durableName); + return this; + } + /** + * Maximum number of attempts to deliver a message from Nats to a + * consumer. Once MaxDeliver is reached, the NATS server stops + * attempting to deliver that specific message. The message is not + * deleted, it remains in the stream but is simply skipped. It is + * recommended to set this option to a sensible value in case a message + * is poison and can not successfully be processed and would always keep + * failing. + * + * The option is a: long type. + * + * Group: consumer + * + * @param maxDeliver the value to set + * @return the dsl builder + */ + default NatsEndpointConsumerBuilder maxDeliver(long maxDeliver) { + doSetProperty("maxDeliver", maxDeliver); + return this; + } + /** + * Maximum number of attempts to deliver a message from Nats to a + * consumer. Once MaxDeliver is reached, the NATS server stops + * attempting to deliver that specific message. The message is not + * deleted, it remains in the stream but is simply skipped. It is + * recommended to set this option to a sensible value in case a message + * is poison and can not successfully be processed and would always keep + * failing. + * + * The option will be converted to a long type. + * + * Group: consumer + * + * @param maxDeliver the value to set + * @return the dsl builder + */ + default NatsEndpointConsumerBuilder maxDeliver(String maxDeliver) { + doSetProperty("maxDeliver", maxDeliver); + return this; + } /** * Stop receiving messages from a topic we are subscribing to after * maxMessages. @@ -664,6 +720,42 @@ default NatsEndpointConsumerBuilder poolSize(String poolSize) { doSetProperty("poolSize", poolSize); return this; } + /** + * Sets the consumer subscription type for JetStream. Set to true to use + * a Pull Subscription (consumer explicitly requests messages). Set to + * false to use a Push Subscription (messages are automatically + * delivered). + * + * The option is a: boolean type. + * + * Default: true + * Group: consumer + * + * @param pullSubscription the value to set + * @return the dsl builder + */ + default NatsEndpointConsumerBuilder pullSubscription(boolean pullSubscription) { + doSetProperty("pullSubscription", pullSubscription); + return this; + } + /** + * Sets the consumer subscription type for JetStream. Set to true to use + * a Pull Subscription (consumer explicitly requests messages). Set to + * false to use a Push Subscription (messages are automatically + * delivered). + * + * The option will be converted to a boolean type. + * + * Default: true + * Group: consumer + * + * @param pullSubscription the value to set + * @return the dsl builder + */ + default NatsEndpointConsumerBuilder pullSubscription(String pullSubscription) { + doSetProperty("pullSubscription", pullSubscription); + return this; + } /** * The Queue name if we are using nats for a queue configuration. * @@ -848,6 +940,44 @@ default AdvancedNatsEndpointConsumerBuilder bridgeErrorHandler(String bridgeErro doSetProperty("bridgeErrorHandler", bridgeErrorHandler); return this; } + /** + * Sets a custom ConsumerConfiguration object for the JetStream + * consumer. This is an advanced option typically used when you need to + * configure properties not exposed as simple Camel URI parameters. When + * set, this object will be used to build the final consumer + * subscription options. + * + * The option is a: + * io.nats.client.api.ConsumerConfiguration type. + * + * Group: consumer (advanced) + * + * @param consumerConfiguration the value to set + * @return the dsl builder + */ + default AdvancedNatsEndpointConsumerBuilder consumerConfiguration(io.nats.client.api.ConsumerConfiguration consumerConfiguration) { + doSetProperty("consumerConfiguration", consumerConfiguration); + return this; + } + /** + * Sets a custom ConsumerConfiguration object for the JetStream + * consumer. This is an advanced option typically used when you need to + * configure properties not exposed as simple Camel URI parameters. When + * set, this object will be used to build the final consumer + * subscription options. + * + * The option will be converted to a + * io.nats.client.api.ConsumerConfiguration type. + * + * Group: consumer (advanced) + * + * @param consumerConfiguration the value to set + * @return the dsl builder + */ + default AdvancedNatsEndpointConsumerBuilder consumerConfiguration(String consumerConfiguration) { + doSetProperty("consumerConfiguration", consumerConfiguration); + return this; + } /** * To let the consumer use a custom ExceptionHandler. Notice if the * option bridgeErrorHandler is enabled then this option is not in use. @@ -942,60 +1072,6 @@ default AdvancedNatsEndpointConsumerBuilder connection(String connection) { doSetProperty("connection", connection); return this; } - /** - * Sets a custom ConsumerConfiguration object for the JetStream - * consumer. This is an advanced option typically used when you need to - * configure properties not exposed as simple Camel URI parameters. When - * set, this object will be used to build the final consumer - * subscription options. - * - * The option is a: - * io.nats.client.api.ConsumerConfiguration type. - * - * Group: advanced - * - * @param consumerConfiguration the value to set - * @return the dsl builder - */ - default AdvancedNatsEndpointConsumerBuilder consumerConfiguration(io.nats.client.api.ConsumerConfiguration consumerConfiguration) { - doSetProperty("consumerConfiguration", consumerConfiguration); - return this; - } - /** - * Sets a custom ConsumerConfiguration object for the JetStream - * consumer. This is an advanced option typically used when you need to - * configure properties not exposed as simple Camel URI parameters. When - * set, this object will be used to build the final consumer - * subscription options. - * - * The option will be converted to a - * io.nats.client.api.ConsumerConfiguration type. - * - * Group: advanced - * - * @param consumerConfiguration the value to set - * @return the dsl builder - */ - default AdvancedNatsEndpointConsumerBuilder consumerConfiguration(String consumerConfiguration) { - doSetProperty("consumerConfiguration", consumerConfiguration); - return this; - } - /** - * Sets the name to assign to the JetStream durable consumer. Setting - * this value makes the consumer durable. The value is used to set the - * durable() field in the underlying NATS ConsumerConfiguration.Builder. - * - * The option is a: java.lang.String type. - * - * Group: advanced - * - * @param durableName the value to set - * @return the dsl builder - */ - default AdvancedNatsEndpointConsumerBuilder durableName(String durableName) { - doSetProperty("durableName", durableName); - return this; - } /** * To use a custom header filter strategy. * @@ -1056,42 +1132,6 @@ default AdvancedNatsEndpointConsumerBuilder jetstreamAsync(String jetstreamAsync doSetProperty("jetstreamAsync", jetstreamAsync); return this; } - /** - * Sets the consumer subscription type for JetStream. Set to true to use - * a Pull Subscription (consumer explicitly requests messages). Set to - * false to use a Push Subscription (messages are automatically - * delivered). - * - * The option is a: boolean type. - * - * Default: true - * Group: advanced - * - * @param pullSubscription the value to set - * @return the dsl builder - */ - default AdvancedNatsEndpointConsumerBuilder pullSubscription(boolean pullSubscription) { - doSetProperty("pullSubscription", pullSubscription); - return this; - } - /** - * Sets the consumer subscription type for JetStream. Set to true to use - * a Pull Subscription (consumer explicitly requests messages). Set to - * false to use a Push Subscription (messages are automatically - * delivered). - * - * The option will be converted to a boolean type. - * - * Default: true - * Group: advanced - * - * @param pullSubscription the value to set - * @return the dsl builder - */ - default AdvancedNatsEndpointConsumerBuilder pullSubscription(String pullSubscription) { - doSetProperty("pullSubscription", pullSubscription); - return this; - } /** * Whether or not connection trace messages should be printed to * standard out for fine grained debugging of connection issues. @@ -1803,60 +1843,6 @@ default AdvancedNatsEndpointProducerBuilder connection(String connection) { doSetProperty("connection", connection); return this; } - /** - * Sets a custom ConsumerConfiguration object for the JetStream - * consumer. This is an advanced option typically used when you need to - * configure properties not exposed as simple Camel URI parameters. When - * set, this object will be used to build the final consumer - * subscription options. - * - * The option is a: - * io.nats.client.api.ConsumerConfiguration type. - * - * Group: advanced - * - * @param consumerConfiguration the value to set - * @return the dsl builder - */ - default AdvancedNatsEndpointProducerBuilder consumerConfiguration(io.nats.client.api.ConsumerConfiguration consumerConfiguration) { - doSetProperty("consumerConfiguration", consumerConfiguration); - return this; - } - /** - * Sets a custom ConsumerConfiguration object for the JetStream - * consumer. This is an advanced option typically used when you need to - * configure properties not exposed as simple Camel URI parameters. When - * set, this object will be used to build the final consumer - * subscription options. - * - * The option will be converted to a - * io.nats.client.api.ConsumerConfiguration type. - * - * Group: advanced - * - * @param consumerConfiguration the value to set - * @return the dsl builder - */ - default AdvancedNatsEndpointProducerBuilder consumerConfiguration(String consumerConfiguration) { - doSetProperty("consumerConfiguration", consumerConfiguration); - return this; - } - /** - * Sets the name to assign to the JetStream durable consumer. Setting - * this value makes the consumer durable. The value is used to set the - * durable() field in the underlying NATS ConsumerConfiguration.Builder. - * - * The option is a: java.lang.String type. - * - * Group: advanced - * - * @param durableName the value to set - * @return the dsl builder - */ - default AdvancedNatsEndpointProducerBuilder durableName(String durableName) { - doSetProperty("durableName", durableName); - return this; - } /** * To use a custom header filter strategy. * @@ -1917,42 +1903,6 @@ default AdvancedNatsEndpointProducerBuilder jetstreamAsync(String jetstreamAsync doSetProperty("jetstreamAsync", jetstreamAsync); return this; } - /** - * Sets the consumer subscription type for JetStream. Set to true to use - * a Pull Subscription (consumer explicitly requests messages). Set to - * false to use a Push Subscription (messages are automatically - * delivered). - * - * The option is a: boolean type. - * - * Default: true - * Group: advanced - * - * @param pullSubscription the value to set - * @return the dsl builder - */ - default AdvancedNatsEndpointProducerBuilder pullSubscription(boolean pullSubscription) { - doSetProperty("pullSubscription", pullSubscription); - return this; - } - /** - * Sets the consumer subscription type for JetStream. Set to true to use - * a Pull Subscription (consumer explicitly requests messages). Set to - * false to use a Push Subscription (messages are automatically - * delivered). - * - * The option will be converted to a boolean type. - * - * Default: true - * Group: advanced - * - * @param pullSubscription the value to set - * @return the dsl builder - */ - default AdvancedNatsEndpointProducerBuilder pullSubscription(String pullSubscription) { - doSetProperty("pullSubscription", pullSubscription); - return this; - } /** * Whether or not connection trace messages should be printed to * standard out for fine grained debugging of connection issues. @@ -2578,60 +2528,6 @@ default AdvancedNatsEndpointBuilder connection(String connection) { doSetProperty("connection", connection); return this; } - /** - * Sets a custom ConsumerConfiguration object for the JetStream - * consumer. This is an advanced option typically used when you need to - * configure properties not exposed as simple Camel URI parameters. When - * set, this object will be used to build the final consumer - * subscription options. - * - * The option is a: - * io.nats.client.api.ConsumerConfiguration type. - * - * Group: advanced - * - * @param consumerConfiguration the value to set - * @return the dsl builder - */ - default AdvancedNatsEndpointBuilder consumerConfiguration(io.nats.client.api.ConsumerConfiguration consumerConfiguration) { - doSetProperty("consumerConfiguration", consumerConfiguration); - return this; - } - /** - * Sets a custom ConsumerConfiguration object for the JetStream - * consumer. This is an advanced option typically used when you need to - * configure properties not exposed as simple Camel URI parameters. When - * set, this object will be used to build the final consumer - * subscription options. - * - * The option will be converted to a - * io.nats.client.api.ConsumerConfiguration type. - * - * Group: advanced - * - * @param consumerConfiguration the value to set - * @return the dsl builder - */ - default AdvancedNatsEndpointBuilder consumerConfiguration(String consumerConfiguration) { - doSetProperty("consumerConfiguration", consumerConfiguration); - return this; - } - /** - * Sets the name to assign to the JetStream durable consumer. Setting - * this value makes the consumer durable. The value is used to set the - * durable() field in the underlying NATS ConsumerConfiguration.Builder. - * - * The option is a: java.lang.String type. - * - * Group: advanced - * - * @param durableName the value to set - * @return the dsl builder - */ - default AdvancedNatsEndpointBuilder durableName(String durableName) { - doSetProperty("durableName", durableName); - return this; - } /** * To use a custom header filter strategy. * @@ -2692,42 +2588,6 @@ default AdvancedNatsEndpointBuilder jetstreamAsync(String jetstreamAsync) { doSetProperty("jetstreamAsync", jetstreamAsync); return this; } - /** - * Sets the consumer subscription type for JetStream. Set to true to use - * a Pull Subscription (consumer explicitly requests messages). Set to - * false to use a Push Subscription (messages are automatically - * delivered). - * - * The option is a: boolean type. - * - * Default: true - * Group: advanced - * - * @param pullSubscription the value to set - * @return the dsl builder - */ - default AdvancedNatsEndpointBuilder pullSubscription(boolean pullSubscription) { - doSetProperty("pullSubscription", pullSubscription); - return this; - } - /** - * Sets the consumer subscription type for JetStream. Set to true to use - * a Pull Subscription (consumer explicitly requests messages). Set to - * false to use a Push Subscription (messages are automatically - * delivered). - * - * The option will be converted to a boolean type. - * - * Default: true - * Group: advanced - * - * @param pullSubscription the value to set - * @return the dsl builder - */ - default AdvancedNatsEndpointBuilder pullSubscription(String pullSubscription) { - doSetProperty("pullSubscription", pullSubscription); - return this; - } /** * Whether or not connection trace messages should be printed to * standard out for fine grained debugging of connection issues. From fed39e7dd234ceaeafd5a8b2604ff1d7bdc7e345 Mon Sep 17 00:00:00 2001 From: Claus Ibsen Date: Thu, 26 Feb 2026 14:39:10 +0100 Subject: [PATCH 3/3] CAMEL-23032: camel-nats - Add AckPolicy so messages can be retried when NACK due to routing failure. Fix infra-nats to run nats broker with jetstream enabled. --- .../apache/camel/catalog/components/nats.json | 4 +- .../org/apache/camel/component/nats/nats.json | 4 +- .../camel/component/nats/NatsComponent.java | 32 +++++++ .../component/nats/NatsConfiguration.java | 12 ++- .../camel/component/nats/NatsConsumer.java | 46 ++++++---- .../NatsJetstreamConsumerAckPolicyNoneIT.java | 91 +++++++++++++++++++ .../jetstream/NatsJetstreamConsumerIT.java | 2 +- .../NatsJetstreamConsumerMaxDeliverIT.java | 2 +- .../NatsJetstreamConsumerRedeliveryIT.java | 2 +- .../dsl/NatsComponentBuilderFactory.java | 16 ++-- .../dsl/NatsEndpointBuilderFactory.java | 32 ++++--- 11 files changed, 193 insertions(+), 50 deletions(-) create mode 100644 components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerAckPolicyNoneIT.java diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/nats.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/nats.json index 046322231c623..91bcdd9ce1214 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/nats.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/nats.json @@ -41,7 +41,7 @@ "requestCleanupInterval": { "index": 14, "kind": "property", "displayName": "Request Cleanup Interval", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Interval to clean up cancelled\/timed out requests." }, "servers": { "index": 15, "kind": "property", "displayName": "Servers", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "URLs to one or more NAT servers. Use comma to separate URLs when specifying multiple servers." }, "verbose": { "index": 16, "kind": "property", "displayName": "Verbose", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not running in verbose mode" }, - "ackPolicy": { "index": 17, "kind": "property", "displayName": "Ack Policy", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "io.nats.client.api.AckPolicy", "enum": [ "none", "all", "explicit" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "explicit", "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Acknowledgement mode. none = Messages are acknowledged as soon as the server sends them. Clients do not need to ack. all = All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit = Each message must be acknowledged individually. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer." }, + "ackPolicy": { "index": 17, "kind": "property", "displayName": "Ack Policy", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "io.nats.client.api.AckPolicy", "enum": [ "none", "all", "explicit" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "explicit", "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Acknowledgement mode. none = Messages are acknowledged as soon as the server sends them (danger: messages that Camel failed to process is also ack). Clients do not need to ack. all = All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit (default) = Each message is acknowledged individually by Camel after the message has been processed, this ensures the message is only ack if success and nack if processing failed due to an exception during routing. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer." }, "ackWait": { "index": 18, "kind": "property", "displayName": "Ack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 30000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "After a message is delivered to a consumer, the server waits 30 seconds (default) for an acknowledgement. If none arrives (timeout), the message becomes eligible for redelivery." }, "bridgeErrorHandler": { "index": 19, "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." }, "durableName": { "index": 20, "kind": "property", "displayName": "Durable Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the name to assign to the JetStream durable consumer. Setting this value makes the consumer durable. The value is used to set the durable() field in the underlying NATS ConsumerConfiguration.Builder." }, @@ -94,7 +94,7 @@ "requestCleanupInterval": { "index": 14, "kind": "parameter", "displayName": "Request Cleanup Interval", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Interval to clean up cancelled\/timed out requests." }, "servers": { "index": 15, "kind": "parameter", "displayName": "Servers", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "URLs to one or more NAT servers. Use comma to separate URLs when specifying multiple servers." }, "verbose": { "index": 16, "kind": "parameter", "displayName": "Verbose", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not running in verbose mode" }, - "ackPolicy": { "index": 17, "kind": "parameter", "displayName": "Ack Policy", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "io.nats.client.api.AckPolicy", "enum": [ "none", "all", "explicit" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "explicit", "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Acknowledgement mode. none = Messages are acknowledged as soon as the server sends them. Clients do not need to ack. all = All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit = Each message must be acknowledged individually. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer." }, + "ackPolicy": { "index": 17, "kind": "parameter", "displayName": "Ack Policy", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "io.nats.client.api.AckPolicy", "enum": [ "none", "all", "explicit" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "explicit", "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Acknowledgement mode. none = Messages are acknowledged as soon as the server sends them (danger: messages that Camel failed to process is also ack). Clients do not need to ack. all = All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit (default) = Each message is acknowledged individually by Camel after the message has been processed, this ensures the message is only ack if success and nack if processing failed due to an exception during routing. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer." }, "ackWait": { "index": 18, "kind": "parameter", "displayName": "Ack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 30000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "After a message is delivered to a consumer, the server waits 30 seconds (default) for an acknowledgement. If none arrives (timeout), the message becomes eligible for redelivery." }, "durableName": { "index": 19, "kind": "parameter", "displayName": "Durable Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the name to assign to the JetStream durable consumer. Setting this value makes the consumer durable. The value is used to set the durable() field in the underlying NATS ConsumerConfiguration.Builder." }, "maxDeliver": { "index": 20, "kind": "parameter", "displayName": "Max Deliver", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Maximum number of attempts to deliver a message from Nats to a consumer. Once MaxDeliver is reached, the NATS server stops attempting to deliver that specific message. The message is not deleted, it remains in the stream but is simply skipped. It is recommended to set this option to a sensible value in case a message is poison and can not successfully be processed and would always keep failing." }, diff --git a/components/camel-nats/src/generated/resources/META-INF/org/apache/camel/component/nats/nats.json b/components/camel-nats/src/generated/resources/META-INF/org/apache/camel/component/nats/nats.json index 046322231c623..91bcdd9ce1214 100644 --- a/components/camel-nats/src/generated/resources/META-INF/org/apache/camel/component/nats/nats.json +++ b/components/camel-nats/src/generated/resources/META-INF/org/apache/camel/component/nats/nats.json @@ -41,7 +41,7 @@ "requestCleanupInterval": { "index": 14, "kind": "property", "displayName": "Request Cleanup Interval", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Interval to clean up cancelled\/timed out requests." }, "servers": { "index": 15, "kind": "property", "displayName": "Servers", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "URLs to one or more NAT servers. Use comma to separate URLs when specifying multiple servers." }, "verbose": { "index": 16, "kind": "property", "displayName": "Verbose", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not running in verbose mode" }, - "ackPolicy": { "index": 17, "kind": "property", "displayName": "Ack Policy", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "io.nats.client.api.AckPolicy", "enum": [ "none", "all", "explicit" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "explicit", "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Acknowledgement mode. none = Messages are acknowledged as soon as the server sends them. Clients do not need to ack. all = All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit = Each message must be acknowledged individually. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer." }, + "ackPolicy": { "index": 17, "kind": "property", "displayName": "Ack Policy", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "io.nats.client.api.AckPolicy", "enum": [ "none", "all", "explicit" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "explicit", "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Acknowledgement mode. none = Messages are acknowledged as soon as the server sends them (danger: messages that Camel failed to process is also ack). Clients do not need to ack. all = All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit (default) = Each message is acknowledged individually by Camel after the message has been processed, this ensures the message is only ack if success and nack if processing failed due to an exception during routing. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer." }, "ackWait": { "index": 18, "kind": "property", "displayName": "Ack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 30000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "After a message is delivered to a consumer, the server waits 30 seconds (default) for an acknowledgement. If none arrives (timeout), the message becomes eligible for redelivery." }, "bridgeErrorHandler": { "index": 19, "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." }, "durableName": { "index": 20, "kind": "property", "displayName": "Durable Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the name to assign to the JetStream durable consumer. Setting this value makes the consumer durable. The value is used to set the durable() field in the underlying NATS ConsumerConfiguration.Builder." }, @@ -94,7 +94,7 @@ "requestCleanupInterval": { "index": 14, "kind": "parameter", "displayName": "Request Cleanup Interval", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 5000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Interval to clean up cancelled\/timed out requests." }, "servers": { "index": 15, "kind": "parameter", "displayName": "Servers", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "URLs to one or more NAT servers. Use comma to separate URLs when specifying multiple servers." }, "verbose": { "index": 16, "kind": "parameter", "displayName": "Verbose", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Whether or not running in verbose mode" }, - "ackPolicy": { "index": 17, "kind": "parameter", "displayName": "Ack Policy", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "io.nats.client.api.AckPolicy", "enum": [ "none", "all", "explicit" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "explicit", "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Acknowledgement mode. none = Messages are acknowledged as soon as the server sends them. Clients do not need to ack. all = All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit = Each message must be acknowledged individually. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer." }, + "ackPolicy": { "index": 17, "kind": "parameter", "displayName": "Ack Policy", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "io.nats.client.api.AckPolicy", "enum": [ "none", "all", "explicit" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "explicit", "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Acknowledgement mode. none = Messages are acknowledged as soon as the server sends them (danger: messages that Camel failed to process is also ack). Clients do not need to ack. all = All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit (default) = Each message is acknowledged individually by Camel after the message has been processed, this ensures the message is only ack if success and nack if processing failed due to an exception during routing. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer." }, "ackWait": { "index": 18, "kind": "parameter", "displayName": "Ack Wait", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 30000, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "After a message is delivered to a consumer, the server waits 30 seconds (default) for an acknowledgement. If none arrives (timeout), the message becomes eligible for redelivery." }, "durableName": { "index": 19, "kind": "parameter", "displayName": "Durable Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Sets the name to assign to the JetStream durable consumer. Setting this value makes the consumer durable. The value is used to set the durable() field in the underlying NATS ConsumerConfiguration.Builder." }, "maxDeliver": { "index": 20, "kind": "parameter", "displayName": "Max Deliver", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.nats.NatsConfiguration", "configurationField": "configuration", "description": "Maximum number of attempts to deliver a message from Nats to a consumer. Once MaxDeliver is reached, the NATS server stops attempting to deliver that specific message. The message is not deleted, it remains in the stream but is simply skipped. It is recommended to set this option to a sensible value in case a message is poison and can not successfully be processed and would always keep failing." }, diff --git a/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsComponent.java b/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsComponent.java index ceb46dc5e25a3..dccbe8c6b91bb 100644 --- a/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsComponent.java +++ b/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsComponent.java @@ -50,6 +50,38 @@ protected Endpoint createEndpoint(String uri, String remaining, Map - * none = Messages are acknowledged as soon as the server sends them. Clients do not need to ack. all = All messages - * with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages - * 1..100. Ack on message 100 will acknowledge 1..99 as well. explicit = Each message must be acknowledged - * individually. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer. + * none = Messages are acknowledged as soon as the server sends them (danger: messages that Camel failed to process + * is also ack). Clients do not need to ack. all = All messages with a sequence number less than the message acked + * are also acknowledged. E.g. reading a batch of messages 1..100. Ack on message 100 will acknowledge 1..99 as + * well. explicit (default) = Each message is acknowledged individually by Camel after the message has been + * processed, this ensures the message is only ack if success and nack if processing failed due to an exception + * during routing. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer. */ public void setAckPolicy(AckPolicy ackPolicy) { this.ackPolicy = ackPolicy; diff --git a/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConsumer.java b/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConsumer.java index 40bd8424d918f..fcedd2c1f2df7 100644 --- a/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConsumer.java +++ b/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConsumer.java @@ -161,7 +161,7 @@ private void setupJetStreamConsumer(String topic, String queueName) throws IOExc String durableName = this.configuration.getDurableName(); String subscriptionType = this.configuration.isPullSubscription() ? "PULL" : "PUSH"; - LOG.debug("Setting up JetStream {}/{} consumer for stream: '{}', subject: {}", + LOG.debug("Setting up JetStream {}/{} consumer for stream: '{}', topic: {}", subscriptionType, ObjectHelper.isNotEmpty(durableName) ? String.format("DURABLE, durableName: '%s'", durableName) : "EPHEMERAL", @@ -219,12 +219,18 @@ private void setupJetStreamConsumer(String topic, String queueName) throws IOExc .deliverGroup(queueName) .build(); + boolean autoAck = false; // ACK is handled by Camel + + LOG.info("Subscribing topic: {} queue:{} using AckPolicy: {} (ackWait:{} nackWait:{})", + configuration.getTopic(), queueName, configuration.getAckPolicy(), configuration.getAckWait(), + configuration.getNackWait()); + NatsConsumer.this.jetStreamSubscription = this.connection.jetStream().subscribe( NatsConsumer.this.getEndpoint().getConfiguration().getTopic(), queueName, dispatcher, messageHandler, - true, + autoAck, pushOptions); } @@ -232,7 +238,6 @@ private void setupJetStreamConsumer(String topic, String queueName) throws IOExc } private void setupStandardNatsConsumer(String topic, String queueName, Integer maxMessages) { - LOG.debug("Setting up standard NATS consumer for subject: {}", topic); NatsConsumer.this.dispatcher = connection.createDispatcher(new CamelNatsMessageHandler()); if (ObjectHelper.isNotEmpty(queueName)) { NatsConsumer.this.dispatcher = NatsConsumer.this.dispatcher.subscribe(topic, queueName); @@ -249,26 +254,27 @@ private void setupStandardNatsConsumer(String topic, String queueName, Integer m class CamelNatsMessageHandler implements MessageHandler { + final boolean ackPolicyNone = configuration.getAckPolicy() == AckPolicy.None; + @Override public void onMessage(Message msg) throws InterruptedException { LOG.debug("Received Message: {}", msg); final Exchange exchange = NatsConsumer.this.createExchange(false); - // ensure we either ACK or NACK the message - boolean autoAck = configuration.getAckPolicy() == null || configuration.getAckPolicy() == AckPolicy.None; - - if (!autoAck) { - long wait = configuration.getAckWait() == 0 ? 30000 : configuration.getAckWait(); - LOG.info("Consuming from topic: {} using AckPolicy: {} (ackWait:{} nackWait:{})", - configuration.getTopic(), configuration.getAckPolicy(), wait, configuration.getNackWait()); - exchange.getExchangeExtension().addOnCompletion(new SynchronizationAdapter() { - @Override - public void onComplete(Exchange exchange) { - LOG.debug("ACK (delay:{})", configuration.getAckWait()); - msg.ack(); - } - @Override - public void onFailure(Exchange exchange) { + exchange.getExchangeExtension().addOnCompletion(new SynchronizationAdapter() { + @Override + public void onComplete(Exchange exchange) { + LOG.debug("ACK"); + msg.ack(); + } + + @Override + public void onFailure(Exchange exchange) { + if (ackPolicyNone) { + // ACK policy is none which means that we should auto ACK even if the message processed failed in Camel + LOG.debug("ACK"); + msg.ack(); + } else { LOG.debug("NACK (delay:{})", configuration.getNackWait()); if (configuration.getNackWait() <= 0) { msg.nak(); @@ -276,8 +282,8 @@ public void onFailure(Exchange exchange) { msg.nakWithDelay(configuration.getNackWait()); } } - }); - } + } + }); try { exchange.getIn().setBody(msg.getData()); exchange.getIn().setHeader(NatsConstants.NATS_REPLY_TO, msg.getReplyTo()); diff --git a/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerAckPolicyNoneIT.java b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerAckPolicyNoneIT.java new file mode 100644 index 0000000000000..f2908c2e946b2 --- /dev/null +++ b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerAckPolicyNoneIT.java @@ -0,0 +1,91 @@ +/* + * 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.nats.jetstream; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.camel.EndpointInject; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.component.nats.NatsConstants; +import org.apache.camel.component.nats.integration.NatsITSupport; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIfSystemProperty; +import org.junit.jupiter.api.parallel.Isolated; + +@DisabledIfSystemProperty(named = "ci.env.name", matches = ".*", disabledReason = "Flaky on GitHub Actions") +@Isolated +public class NatsJetstreamConsumerAckPolicyNoneIT extends NatsITSupport { + + @EndpointInject("mock:result") + protected MockEndpoint mockResultEndpoint; + + @EndpointInject("mock:input") + protected MockEndpoint mockInputEndpoint; + + @Test + public void testConsumer() throws Exception { + mockResultEndpoint.expectedBodiesReceived("Hello World 3"); + mockResultEndpoint.expectedHeaderReceived(NatsConstants.NATS_SUBJECT, "mytopic2"); + mockResultEndpoint.expectedHeaderReceived("counter", 3); + mockResultEndpoint.expectedHeaderReceived(NatsConstants.NATS_DELIVERY_COUNTER, 1); + + mockInputEndpoint.expectedBodiesReceived("Hello World 1", "Hello World 2", "Hello World 3"); + mockInputEndpoint.expectedHeaderReceived(NatsConstants.NATS_SUBJECT, "mytopic2"); + mockInputEndpoint.message(0).header(NatsConstants.NATS_DELIVERY_COUNTER).isEqualTo(1); + mockInputEndpoint.message(1).header(NatsConstants.NATS_DELIVERY_COUNTER).isEqualTo(1); + mockInputEndpoint.message(2).header(NatsConstants.NATS_DELIVERY_COUNTER).isEqualTo(1); + + template.sendBody("direct:send", "Hello World 1"); + template.sendBody("direct:send", "Hello World 2"); + template.sendBody("direct:send", "Hello World 3"); + + MockEndpoint.assertIsSatisfied(context); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + String uri + = "nats:mytopic2?jetstreamEnabled=true&jetstreamName=mystream2&jetstreamAsync=false&durableName=camel2&pullSubscription=false&ackPolicy=none"; + + from("direct:send") + // when running full test suite then send can fail due to nats server setup/teardown + .errorHandler(defaultErrorHandler().maximumRedeliveries(5)) + .to(uri); + + final AtomicInteger counter = new AtomicInteger(); + from(uri) + .to("mock:input") + .process(new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + if (counter.incrementAndGet() < 3) { + throw new IllegalArgumentException("Forced"); + } + exchange.getMessage().setHeader("counter", counter.intValue()); + } + }) + .to(mockResultEndpoint); + } + }; + } +} diff --git a/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerIT.java b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerIT.java index c2d8a5a495587..520f581952857 100644 --- a/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerIT.java +++ b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerIT.java @@ -51,7 +51,7 @@ public void configure() { = "nats:mytopic?jetstreamEnabled=true&jetstreamName=mystream&jetstreamAsync=false&durableName=camel&pullSubscription=false"; from("direct:send") - // when running full test suite then send can fail due to nats server setup/tearndown + // when running full test suite then send can fail due to nats server setup/teardown .errorHandler(defaultErrorHandler().maximumRedeliveries(5)) .to(uri); diff --git a/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerMaxDeliverIT.java b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerMaxDeliverIT.java index 9803aac5ef0ed..558fd69efd309 100644 --- a/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerMaxDeliverIT.java +++ b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerMaxDeliverIT.java @@ -65,7 +65,7 @@ public void configure() { = "nats:mytopic2?jetstreamEnabled=true&jetstreamName=mystream2&jetstreamAsync=false&durableName=camel2&pullSubscription=false&ackPolicy=explicit&nackWait=10&maxDeliver=3"; from("direct:send") - // when running full test suite then send can fail due to nats server setup/tearndown + // when running full test suite then send can fail due to nats server setup/teardown .errorHandler(defaultErrorHandler().maximumRedeliveries(5)) .to(uri); diff --git a/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerRedeliveryIT.java b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerRedeliveryIT.java index 267dce8bbd965..b72e96b7af366 100644 --- a/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerRedeliveryIT.java +++ b/components/camel-nats/src/test/java/org/apache/camel/component/nats/jetstream/NatsJetstreamConsumerRedeliveryIT.java @@ -66,7 +66,7 @@ public void configure() { = "nats:mytopic2?jetstreamEnabled=true&jetstreamName=mystream2&jetstreamAsync=false&durableName=camel2&pullSubscription=false&ackPolicy=explicit&nackWait=10"; from("direct:send") - // when running full test suite then send can fail due to nats server setup/tearndown + // when running full test suite then send can fail due to nats server setup/teardown .errorHandler(defaultErrorHandler().maximumRedeliveries(5)) .to(uri); diff --git a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/NatsComponentBuilderFactory.java b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/NatsComponentBuilderFactory.java index ce62d64a563c7..dd6bf8b64a5c0 100644 --- a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/NatsComponentBuilderFactory.java +++ b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/NatsComponentBuilderFactory.java @@ -344,12 +344,16 @@ default NatsComponentBuilder verbose(boolean verbose) { /** * Acknowledgement mode. none = Messages are acknowledged as soon as the - * server sends them. Clients do not need to ack. all = All messages - * with a sequence number less than the message acked are also - * acknowledged. E.g. reading a batch of messages 1..100. Ack on message - * 100 will acknowledge 1..99 as well. explicit = Each message must be - * acknowledged individually. Message can be acked out of sequence and - * create gaps of unacknowledged messages in the consumer. + * server sends them (danger: messages that Camel failed to process is + * also ack). Clients do not need to ack. all = All messages with a + * sequence number less than the message acked are also acknowledged. + * E.g. reading a batch of messages 1..100. Ack on message 100 will + * acknowledge 1..99 as well. explicit (default) = Each message is + * acknowledged individually by Camel after the message has been + * processed, this ensures the message is only ack if success and nack + * if processing failed due to an exception during routing. Message can + * be acked out of sequence and create gaps of unacknowledged messages + * in the consumer. * * The option is a: * <code>io.nats.client.api.AckPolicy</code> type. diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NatsEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NatsEndpointBuilderFactory.java index ba594e328d403..4b9f9b7de8543 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NatsEndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NatsEndpointBuilderFactory.java @@ -506,12 +506,16 @@ default NatsEndpointConsumerBuilder verbose(String verbose) { } /** * Acknowledgement mode. none = Messages are acknowledged as soon as the - * server sends them. Clients do not need to ack. all = All messages - * with a sequence number less than the message acked are also - * acknowledged. E.g. reading a batch of messages 1..100. Ack on message - * 100 will acknowledge 1..99 as well. explicit = Each message must be - * acknowledged individually. Message can be acked out of sequence and - * create gaps of unacknowledged messages in the consumer. + * server sends them (danger: messages that Camel failed to process is + * also ack). Clients do not need to ack. all = All messages with a + * sequence number less than the message acked are also acknowledged. + * E.g. reading a batch of messages 1..100. Ack on message 100 will + * acknowledge 1..99 as well. explicit (default) = Each message is + * acknowledged individually by Camel after the message has been + * processed, this ensures the message is only ack if success and nack + * if processing failed due to an exception during routing. Message can + * be acked out of sequence and create gaps of unacknowledged messages + * in the consumer. * * The option is a: io.nats.client.api.AckPolicy type. * @@ -527,12 +531,16 @@ default NatsEndpointConsumerBuilder ackPolicy(io.nats.client.api.AckPolicy ackPo } /** * Acknowledgement mode. none = Messages are acknowledged as soon as the - * server sends them. Clients do not need to ack. all = All messages - * with a sequence number less than the message acked are also - * acknowledged. E.g. reading a batch of messages 1..100. Ack on message - * 100 will acknowledge 1..99 as well. explicit = Each message must be - * acknowledged individually. Message can be acked out of sequence and - * create gaps of unacknowledged messages in the consumer. + * server sends them (danger: messages that Camel failed to process is + * also ack). Clients do not need to ack. all = All messages with a + * sequence number less than the message acked are also acknowledged. + * E.g. reading a batch of messages 1..100. Ack on message 100 will + * acknowledge 1..99 as well. explicit (default) = Each message is + * acknowledged individually by Camel after the message has been + * processed, this ensures the message is only ack if success and nack + * if processing failed due to an exception during routing. Message can + * be acked out of sequence and create gaps of unacknowledged messages + * in the consumer. * * The option will be converted to a * io.nats.client.api.AckPolicy type.