All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.camel.component.jms.JmsConfiguration Maven / Gradle / Ivy

There is a newer version: 4.8.1
Show newest version
/*
 * 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.jms;

import jakarta.jms.ConnectionFactory;
import jakarta.jms.Destination;
import jakarta.jms.ExceptionListener;
import jakarta.jms.JMSException;
import jakarta.jms.Message;
import jakarta.jms.MessageProducer;
import jakarta.jms.Session;

import org.apache.camel.LoggingLevel;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.spi.UriParam;
import org.apache.camel.spi.UriParams;
import org.apache.camel.util.ObjectHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.task.TaskExecutor;
import org.springframework.jms.JmsException;
import org.springframework.jms.connection.JmsTransactionManager;
import org.springframework.jms.core.JmsOperations;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.jms.listener.AbstractMessageListenerContainer;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
import org.springframework.jms.listener.SimpleMessageListenerContainer;
import org.springframework.jms.support.JmsUtils;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.destination.DestinationResolver;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.Assert;
import org.springframework.util.ErrorHandler;

import static org.apache.camel.component.jms.JmsMessageHelper.normalizeDestinationName;

@UriParams
public class JmsConfiguration implements Cloneable {

    public static final String QUEUE_PREFIX = "queue:";
    public static final String TOPIC_PREFIX = "topic:";
    public static final String TEMP_QUEUE_PREFIX = "temp-queue:";
    public static final String TEMP_TOPIC_PREFIX = "temp-topic:";

    private static final Logger LOG = LoggerFactory.getLogger(JmsConfiguration.class);

    // these are too advanced and seldom used, we should consider removing those as there is plenty of options already
    private JmsOperations jmsOperations;
    private ConnectionFactory templateConnectionFactory;
    private ConnectionFactory listenerConnectionFactory;

    @UriParam(description = "The connection factory to be use. A connection factory must be configured either on the component or endpoint.")
    private ConnectionFactory connectionFactory;
    @UriParam(label = "security", secret = true,
              description = "Username to use with the ConnectionFactory. You can also configure username/password directly on the ConnectionFactory.")
    private String username;
    @UriParam(label = "security", secret = true,
              description = "Password to use with the ConnectionFactory. You can also configure username/password directly on the ConnectionFactory.")
    private String password;

    private int acknowledgementMode = -1;
    @UriParam(defaultValue = "AUTO_ACKNOWLEDGE",
              enums = "SESSION_TRANSACTED,CLIENT_ACKNOWLEDGE,AUTO_ACKNOWLEDGE,DUPS_OK_ACKNOWLEDGE", label = "consumer",
              description = "The JMS acknowledgement name, which is one of: SESSION_TRANSACTED, CLIENT_ACKNOWLEDGE, AUTO_ACKNOWLEDGE, DUPS_OK_ACKNOWLEDGE")
    private String acknowledgementModeName;
    @UriParam(label = "advanced",
              description = "A pluggable org.springframework.jms.support.destination.DestinationResolver that allows you to use your own resolver"
                            + " (for example, to lookup the real destination in a JNDI registry).")
    private DestinationResolver destinationResolver;
    // Used to configure the spring Container
    @UriParam(label = "advanced",
              description = "Specifies the JMS Exception Listener that is to be notified of any underlying JMS exceptions.")
    private ExceptionListener exceptionListener;
    @UriParam(label = "consumer,advanced", defaultValue = "Default",
              description = "The consumer type to use, which can be one of: Simple, Default, or Custom."
                            + " The consumer type determines which Spring JMS listener to use. Default will use org.springframework.jms.listener.DefaultMessageListenerContainer,"
                            + " Simple will use org.springframework.jms.listener.SimpleMessageListenerContainer."
                            + " When Custom is specified, the MessageListenerContainerFactory defined by the messageListenerContainerFactory option"
                            + " will determine what org.springframework.jms.listener.AbstractMessageListenerContainer to use.")
    private ConsumerType consumerType = ConsumerType.Default;
    @UriParam(label = "consumer,advanced", defaultValue = "Default",
              description = "The consumer type of the reply consumer (when doing request/reply), which can be one of: Simple, Default, or Custom."
                            + " The consumer type determines which Spring JMS listener to use. Default will use org.springframework.jms.listener.DefaultMessageListenerContainer,"
                            + " Simple will use org.springframework.jms.listener.SimpleMessageListenerContainer."
                            + " When Custom is specified, the MessageListenerContainerFactory defined by the messageListenerContainerFactory option"
                            + " will determine what org.springframework.jms.listener.AbstractMessageListenerContainer to use.")
    private ConsumerType replyToConsumerType = ConsumerType.Default;
    @UriParam(label = "advanced",
              description = "Specifies a org.springframework.util.ErrorHandler to be invoked in case of any uncaught exceptions thrown while processing a Message."
                            + " By default these exceptions will be logged at the WARN level, if no errorHandler has been configured."
                            + " You can configure logging level and whether stack traces should be logged using errorHandlerLoggingLevel and errorHandlerLogStackTrace options."
                            + " This makes it much easier to configure, than having to code a custom errorHandler.")
    private ErrorHandler errorHandler;
    @UriParam(defaultValue = "WARN", label = "consumer,logging",
              description = "Allows to configure the default errorHandler logging level for logging uncaught exceptions.")
    private LoggingLevel errorHandlerLoggingLevel = LoggingLevel.WARN;
    @UriParam(defaultValue = "true", label = "consumer,logging",
              description = "Allows to control whether stacktraces should be logged or not, by the default errorHandler.")
    private boolean errorHandlerLogStackTrace = true;
    @UriParam(label = "consumer", defaultValue = "true",
              description = "Specifies whether the consumer container should auto-startup.")
    private boolean autoStartup = true;
    @UriParam(label = "consumer,advanced",
              description = "Whether the DefaultMessageListenerContainer used in the reply managers for request-reply messaging allow "
                            + " the DefaultMessageListenerContainer.runningAllowed flag to quick stop in case JmsConfiguration#isAcceptMessagesWhileStopping"
                            + " is enabled, and org.apache.camel.CamelContext is currently being stopped. This quick stop ability is enabled by"
                            + " default in the regular JMS consumers but to enable for reply managers you must enable this flag.")
    private boolean allowReplyManagerQuickStop;
    @UriParam(label = "consumer,advanced",
              description = "Specifies whether the consumer accept messages while it is stopping."
                            + " You may consider enabling this option, if you start and stop JMS routes at runtime, while there are still messages"
                            + " enqueued on the queue. If this option is false, and you stop the JMS route, then messages may be rejected,"
                            + " and the JMS broker would have to attempt redeliveries, which yet again may be rejected, and eventually the message"
                            + " may be moved at a dead letter queue on the JMS broker. To avoid this its recommended to enable this option.")
    private boolean acceptMessagesWhileStopping;
    @UriParam(description = "Sets the JMS client ID to use. Note that this value, if specified, must be unique and can only be used by a single JMS connection instance."
                            + " It is typically only required for durable topic subscriptions."
                            + " If using Apache ActiveMQ you may prefer to use Virtual Topics instead.")
    private String clientId;
    @UriParam(description = "The durable subscriber name for specifying durable topic subscriptions. The clientId option must be configured as well.")
    private String durableSubscriptionName;
    @UriParam(label = "consumer,advanced",
              description = "Specifies whether the listener session should be exposed when consuming messages.")
    private boolean exposeListenerSession = true;
    @UriParam(label = "consumer,advanced",
              description = "Allows you to specify a custom task executor for consuming messages.")
    private TaskExecutor taskExecutor;
    @UriParam(label = "advanced",
              description = "Specifies whether to inhibit the delivery of messages published by its own connection.")
    private boolean pubSubNoLocal;
    @UriParam(defaultValue = "1", label = "consumer",
              description = "Specifies the default number of concurrent consumers when consuming from JMS (not for request/reply over JMS)."
                            + " See also the maxMessagesPerTask option to control dynamic scaling up/down of threads."
                            + " When doing request/reply over JMS then the option replyToConcurrentConsumers is used to control number"
                            + " of concurrent consumers on the reply message listener.")
    private int concurrentConsumers = 1;
    @UriParam(defaultValue = "1", label = "producer",
              description = "Specifies the default number of concurrent consumers when doing request/reply over JMS."
                            + " See also the maxMessagesPerTask option to control dynamic scaling up/down of threads.")
    private int replyToConcurrentConsumers = 1;
    @UriParam(defaultValue = "-1", label = "advanced",
              description = "The number of messages per task. -1 is unlimited."
                            + " If you use a range for concurrent consumers (eg min < max), then this option can be used to set"
                            + " a value to eg 100 to control how fast the consumers will shrink when less work is required.")
    private int maxMessagesPerTask = -1;
    @UriParam(label = "consumer",
              description = "Sets the cache level by ID for the underlying JMS resources. See cacheLevelName option for more details.")
    private int cacheLevel = -1;
    @UriParam(defaultValue = "CACHE_AUTO", enums = "CACHE_AUTO,CACHE_CONNECTION,CACHE_CONSUMER,CACHE_NONE,CACHE_SESSION",
              label = "consumer",
              description = "Sets the cache level by name for the underlying JMS resources."
                            + " Possible values are: CACHE_AUTO, CACHE_CONNECTION, CACHE_CONSUMER, CACHE_NONE, and CACHE_SESSION."
                            + " The default setting is CACHE_AUTO. See the Spring documentation and Transactions Cache Levels for more information.")
    private String cacheLevelName;
    @UriParam(defaultValue = "5000", label = "advanced", javaType = "java.time.Duration",
              description = "Specifies the interval between recovery attempts, i.e. when a connection is being refreshed, in milliseconds."
                            + " The default is 5000 ms, that is, 5 seconds.")
    private long recoveryInterval = 5000;
    @UriParam(defaultValue = "1000", label = "advanced", javaType = "java.time.Duration",
              description = "The timeout for receiving messages (in milliseconds).")
    private long receiveTimeout = 1000;
    @UriParam(defaultValue = "20000", label = "producer", javaType = "java.time.Duration",
              description = "The timeout for waiting for a reply when using the InOut Exchange Pattern (in milliseconds)."
                            + " The default is 20 seconds. You can include the header \"CamelJmsRequestTimeout\" to override this endpoint configured"
                            + " timeout value, and thus have per message individual timeout values."
                            + " See also the requestTimeoutCheckerInterval option.")
    private long requestTimeout = 20000L;
    @UriParam(defaultValue = "1000", label = "advanced", javaType = "java.time.Duration",
              description = "Configures how often Camel should check for timed out Exchanges when doing request/reply over JMS."
                            + " By default Camel checks once per second. But if you must react faster when a timeout occurs,"
                            + " then you can lower this interval, to check more frequently. The timeout is determined by the option requestTimeout.")
    private long requestTimeoutCheckerInterval = 1000L;
    @UriParam(defaultValue = "1", label = "advanced",
              description = "Specifies the limit for idle executions of a receive task, not having received any message within its execution."
                            + " If this limit is reached, the task will shut down and leave receiving to other executing tasks"
                            + " (in the case of dynamic scheduling; see the maxConcurrentConsumers setting)."
                            + " There is additional doc available from Spring.")
    private int idleTaskExecutionLimit = 1;
    @UriParam(defaultValue = "1", label = "advanced",
              description = "Specify the limit for the number of consumers that are allowed to be idle at any given time.")
    private int idleConsumerLimit = 1;
    @UriParam(defaultValue = "100", label = "advanced", javaType = "java.time.Duration",
              description = "Interval in millis to sleep each time while waiting for provisional correlation id to be updated.")
    private long waitForProvisionCorrelationToBeUpdatedThreadSleepingTime = 100L;
    @UriParam(defaultValue = "50", label = "advanced",
              description = "Number of times to wait for provisional correlation id to be updated to the actual correlation id when doing request/reply over JMS"
                            + " and when the option useMessageIDAsCorrelationID is enabled.")
    private int waitForProvisionCorrelationToBeUpdatedCounter = 50;
    @UriParam(label = "consumer",
              description = "Specifies the maximum number of concurrent consumers when consuming from JMS (not for request/reply over JMS)."
                            + " See also the maxMessagesPerTask option to control dynamic scaling up/down of threads."
                            + " When doing request/reply over JMS then the option replyToMaxConcurrentConsumers is used to control number"
                            + " of concurrent consumers on the reply message listener.")
    private int maxConcurrentConsumers;
    @UriParam(label = "producer",
              description = "Specifies the maximum number of concurrent consumers when using request/reply over JMS."
                            + " See also the maxMessagesPerTask option to control dynamic scaling up/down of threads.")
    private int replyToMaxConcurrentConsumers;
    @UriParam(label = "producer", defaultValue = "1",
              description = "Specifies the maximum number of concurrent consumers for continue routing when timeout occurred when using request/reply over JMS.")
    private int replyToOnTimeoutMaxConcurrentConsumers = 1;
    // JmsTemplate only
    @UriParam(label = "producer", defaultValue = "false",
              description = "Set if the deliveryMode, priority or timeToLive qualities of service should be used when sending messages."
                            + " This option is based on Spring's JmsTemplate. The deliveryMode, priority and timeToLive options are applied to the current endpoint."
                            + " This contrasts with the preserveMessageQos option, which operates at message granularity,"
                            + " reading QoS properties exclusively from the Camel In message headers.")
    private Boolean explicitQosEnabled;
    @UriParam(defaultValue = "true", label = "producer",
              description = "Specifies whether persistent delivery is used by default.")
    private boolean deliveryPersistent = true;
    @UriParam(enums = "1,2", label = "producer",
              description = "Specifies the delivery mode to be used."
                            + " Possible values are those defined by jakarta.jms.DeliveryMode."
                            + " NON_PERSISTENT = 1 and PERSISTENT = 2.")
    private Integer deliveryMode;
    @UriParam(defaultValue = "true", label = "consumer",
              description = "Specifies whether to use persistent delivery by default for replies.")
    private boolean replyToDeliveryPersistent = true;
    @UriParam(label = "consumer", description = "Sets the JMS selector to use")
    private String selector;
    @UriParam(defaultValue = "-1", label = "producer",
              description = "When sending messages, specifies the time-to-live of the message (in milliseconds).")
    private long timeToLive = -1;
    @UriParam(label = "advanced",
              description = "To use a custom Spring org.springframework.jms.support.converter.MessageConverter so you can be in control how to map to/from a jakarta.jms.Message.")
    private MessageConverter messageConverter;
    @UriParam(defaultValue = "true", label = "advanced",
              description = "Specifies whether Camel should auto map the received JMS message to a suited payload type, such as jakarta.jms.TextMessage to a String etc.")
    private boolean mapJmsMessage = true;
    @UriParam(defaultValue = "true", label = "advanced",
              description = "When sending, specifies whether message IDs should be added. This is just an hint to the JMS broker."
                            + " If the JMS provider accepts this hint, these messages must have the message ID set to null; if the provider ignores the hint, "
                            + "the message ID must be set to its normal unique value.")
    private boolean messageIdEnabled = true;
    @UriParam(defaultValue = "true", label = "advanced",
              description = "Specifies whether timestamps should be enabled by default on sending messages. This is just an hint to the JMS broker."
                            + " If the JMS provider accepts this hint, these messages must have the timestamp set to zero; if the provider ignores the hint "
                            + "the timestamp must be set to its normal value.")
    private boolean messageTimestampEnabled = true;
    @UriParam(defaultValue = "" + Message.DEFAULT_PRIORITY, enums = "1,2,3,4,5,6,7,8,9", label = "producer",
              description = "Values greater than 1 specify the message priority when sending (where 1 is the lowest priority and 9 is the highest)."
                            + " The explicitQosEnabled option must also be enabled in order for this option to have any effect.")
    private int priority = Message.DEFAULT_PRIORITY;
    // Transaction related configuration
    @UriParam(label = "transaction",
              description = "Specifies whether to use transacted mode")
    private boolean transacted;
    @UriParam(label = "transaction",
              description = "Specifies whether InOut operations (request reply) default to using transacted mode"
                            + " If this flag is set to true, then Spring JmsTemplate will have"
                            + " sessionTransacted set to true, and the acknowledgeMode as transacted"
                            + " on the JmsTemplate used for InOut operations."
                            + " Note from Spring JMS: that within a JTA transaction, the parameters passed to"
                            + " createQueue, createTopic methods are not taken into account. Depending on the Java EE transaction context,"
                            + " the container makes its own decisions on these values. Analogously, these"
                            + " parameters are not taken into account within a locally managed transaction"
                            + " either, since Spring JMS operates on an existing JMS Session in this case."
                            + " Setting this flag to true will use a short local JMS transaction"
                            + " when running outside of a managed transaction, and a synchronized local"
                            + " JMS transaction in case of a managed transaction (other than an XA"
                            + " transaction) being present. This has the effect of a local JMS"
                            + " transaction being managed alongside the main transaction (which might"
                            + " be a native JDBC transaction), with the JMS transaction committing"
                            + " right after the main transaction.")
    private boolean transactedInOut;
    @UriParam(defaultValue = "true", label = "transaction,advanced",
              description = "If true, Camel will create a JmsTransactionManager, if there is no transactionManager injected when option transacted=true.")
    private boolean lazyCreateTransactionManager = true;
    @UriParam(label = "transaction,advanced",
              description = "The Spring transaction manager to use.")
    private PlatformTransactionManager transactionManager;
    @UriParam(label = "transaction,advanced",
              description = "The name of the transaction to use.")
    private String transactionName;
    @UriParam(defaultValue = "-1", label = "transaction,advanced",
              description = "The timeout value of the transaction (in seconds), if using transacted mode.")
    private int transactionTimeout = -1;
    @UriParam(label = "producer",
              description = "Set to true, if you want to send message using the QoS settings specified on the message,"
                            + " instead of the QoS settings on the JMS endpoint. The following three headers are considered JMSPriority, JMSDeliveryMode,"
                            + " and JMSExpiration. You can provide all or only some of them. If not provided, Camel will fall back to use the"
                            + " values from the endpoint instead. So, when using this option, the headers override the values from the endpoint."
                            + " The explicitQosEnabled option, by contrast, will only use options set on the endpoint, and not values from the message header.")
    private boolean preserveMessageQos;
    @UriParam(description = "Specifies whether Camel ignores the JMSReplyTo header in messages. If true, Camel does not send a reply back to"
                            + " the destination specified in the JMSReplyTo header. You can use this option if you want Camel to consume from a"
                            + " route and you do not want Camel to automatically send back a reply message because another component in your code"
                            + " handles the reply message. You can also use this option if you want to use Camel as a proxy between different"
                            + " message brokers and you want to route message from one system to another.")
    private boolean disableReplyTo;
    @UriParam(label = "consumer,advanced", defaultValue = "Poison JMS message due to ${exception.message}",
              description = "If eagerLoadingOfProperties is enabled and the JMS message payload (JMS body or JMS properties) is poison (cannot be read/mapped),"
                            + " then set this text as the message body instead so the message can be processed"
                            + " (the cause of the poison are already stored as exception on the Exchange)."
                            + " This can be turned off by setting eagerPoisonBody=false."
                            + " See also the option eagerLoadingOfProperties.")
    private String eagerPoisonBody = "Poison JMS message payload: ${exception.message}";
    @UriParam(label = "consumer,advanced",
              description = "Enables eager loading of JMS properties and payload as soon as a message is loaded"
                            + " which generally is inefficient as the JMS properties may not be required"
                            + " but sometimes can catch early any issues with the underlying JMS provider"
                            + " and the use of JMS properties. See also the option eagerPoisonBody.")
    private boolean eagerLoadingOfProperties;
    // Always make a JMS message copy when it's passed to Producer
    @UriParam(label = "producer,advanced",
              description = "If true, Camel will always make a JMS message copy of the message when it is passed to the producer for sending."
                            + " Copying the message is needed in some situations, such as when a replyToDestinationSelectorName is set"
                            + " (incidentally, Camel will set the alwaysCopyMessage option to true, if a replyToDestinationSelectorName is set)")
    private boolean alwaysCopyMessage;
    @UriParam(label = "advanced",
              description = "Specifies whether JMSMessageID should always be used as JMSCorrelationID for InOut messages.")
    private boolean useMessageIDAsCorrelationID;
    @UriParam(label = "common",
              description = "Provides an explicit ReplyTo destination (overrides any incoming value of Message.getJMSReplyTo() in consumer).")
    private String replyTo;
    @UriParam(label = "producer,advanced",
              description = "Sets the JMS Selector using the fixed name to be used so you can filter out your own replies"
                            + " from the others when using a shared queue (that is, if you are not using a temporary reply queue).")
    private String replyToDestinationSelectorName;
    @UriParam(label = "producer",
              description = "Provides an explicit ReplyTo destination in the JMS message, which overrides the setting of replyTo."
                            + " It is useful if you want to forward the message to a remote Queue and receive the reply message from the ReplyTo destination.")
    private String replyToOverride;
    @UriParam(label = "consumer,advanced",
              description = "Whether a JMS consumer is allowed to send a reply message to the same destination that the consumer is using to"
                            + " consume from. This prevents an endless loop by consuming and sending back the same message to itself.")
    private boolean replyToSameDestinationAllowed;
    @UriParam(enums = "Bytes,Map,Object,Stream,Text",
              description = "Allows you to force the use of a specific jakarta.jms.Message implementation for sending JMS messages."
                            + " Possible values are: Bytes, Map, Object, Stream, Text."
                            + " By default, Camel would determine which JMS message type to use from the In body type. This option allows you to specify it.")
    private JmsMessageType jmsMessageType;
    @UriParam(label = "advanced", enums = "default,passthrough",
              description = "Pluggable strategy for encoding and decoding JMS keys so they can be compliant with the JMS specification."
                            + " Camel provides two implementations out of the box: default and passthrough."
                            + " The default strategy will safely marshal dots and hyphens (. and -). The passthrough strategy leaves the key as is."
                            + " Can be used for JMS brokers which do not care whether JMS header keys contain illegal characters."
                            + " You can provide your own implementation of the org.apache.camel.component.jms.JmsKeyFormatStrategy"
                            + " and refer to it using the # notation.")
    private JmsKeyFormatStrategy jmsKeyFormatStrategy;
    @UriParam(label = "advanced",
              description = "You can transfer the exchange over the wire instead of just the body and headers."
                            + " The following fields are transferred: In body, Out body, Fault body, In headers, Out headers, Fault headers,"
                            + " exchange properties, exchange exception."
                            + " This requires that the objects are serializable. Camel will exclude any non-serializable objects and log it at WARN level."
                            + " You must enable this option on both the producer and consumer side, so Camel knows the payloads is an Exchange and not a regular payload."
                            + " Use this with caution as the data is using Java Object serialization and requires the receiver to be able to deserialize the data at Class level, "
                            + " which forces a strong coupling between the producers and consumers having to use compatible Camel versions!")
    private boolean transferExchange;
    @UriParam(label = "advanced",
              description = "Controls whether or not to include serialized headers."
                            + " Applies only when {@code transferExchange} is {@code true}."
                            + " This requires that the objects are serializable. Camel will exclude any non-serializable objects and log it at WARN level.")
    private boolean allowSerializedHeaders;
    @UriParam(label = "advanced",
              description = "If enabled and you are using Request Reply messaging (InOut) and an Exchange failed on the consumer side,"
                            + " then the caused Exception will be send back in response as a jakarta.jms.ObjectMessage."
                            + " If the client is Camel, the returned Exception is rethrown. This allows you to use Camel JMS as a bridge"
                            + " in your routing - for example, using persistent queues to enable robust routing."
                            + " Notice that if you also have transferExchange enabled, this option takes precedence."
                            + " The caught exception is required to be serializable."
                            + " The original Exception on the consumer side can be wrapped in an outer exception"
                            + " such as org.apache.camel.RuntimeCamelException when returned to the producer."
                            + " Use this with caution as the data is using Java Object serialization and requires the received to be able to deserialize the data at Class level, "
                            + " which forces a strong coupling between the producers and consumer!")
    private boolean transferException;
    @UriParam(description = "Specifies whether to test the connection on startup."
                            + " This ensures that when Camel starts that all the JMS consumers have a valid connection to the JMS broker."
                            + " If a connection cannot be granted then Camel throws an exception on startup."
                            + " This ensures that Camel is not started with failed connections."
                            + " The JMS producers is tested as well.")
    private boolean testConnectionOnStartup;
    @UriParam(label = "advanced",
              description = "Whether to startup the JmsConsumer message listener asynchronously, when starting a route."
                            + " For example if a JmsConsumer cannot get a connection to a remote JMS broker, then it may block while retrying"
                            + " and/or failover. This will cause Camel to block while starting routes. By setting this option to true,"
                            + " you will let routes startup, while the JmsConsumer connects to the JMS broker using a dedicated thread"
                            + " in asynchronous mode. If this option is used, then beware that if the connection could not be established,"
                            + " then an exception is logged at WARN level, and the consumer will not be able to receive messages;"
                            + " You can then restart the route to retry.")
    private boolean asyncStartListener;
    @UriParam(label = "advanced",
              description = "Whether to stop the JmsConsumer message listener asynchronously, when stopping a route.")
    private boolean asyncStopListener;
    // if the message is a JmsMessage and mapJmsMessage=false, force the
    // producer to send the jakarta.jms.Message body to the next JMS destination
    @UriParam(label = "producer,advanced",
              description = "When using mapJmsMessage=false Camel will create a new JMS message to send to a new JMS destination"
                            + " if you touch the headers (get or set) during the route. Set this option to true to force Camel to send"
                            + " the original JMS message that was received.")
    private boolean forceSendOriginalMessage;
    // to force disabling time to live (works in both in-only or in-out mode)
    @UriParam(label = "producer,advanced",
              description = "Use this option to force disabling time to live."
                            + " For example when you do request/reply over JMS, then Camel will by default use the requestTimeout value"
                            + " as time to live on the message being sent. The problem is that the sender and receiver systems have"
                            + " to have their clocks synchronized, so they are in sync. This is not always so easy to archive."
                            + " So you can use disableTimeToLive=true to not set a time to live value on the sent message."
                            + " Then the message will not expire on the receiver system. See below in section About time to live for more details.")
    private boolean disableTimeToLive;
    @UriParam(label = "producer",
              description = "Allows for explicitly specifying which kind of strategy to use for replyTo queues when doing request/reply over JMS."
                            + " Possible values are: Temporary, Shared, or Exclusive."
                            + " By default Camel will use temporary queues. However if replyTo has been configured, then Shared is used by default."
                            + " This option allows you to use exclusive queues instead of shared ones."
                            + " See Camel JMS documentation for more details, and especially the notes about the implications if running in a clustered environment,"
                            + " and the fact that Shared reply queues has lower performance than its alternatives Temporary and Exclusive.")
    private ReplyToType replyToType;
    @UriParam(label = "consumer",
              description = "Whether the JmsConsumer processes the Exchange asynchronously."
                            + " If enabled then the JmsConsumer may pickup the next message from the JMS queue,"
                            + " while the previous message is being processed asynchronously (by the Asynchronous Routing Engine)."
                            + " This means that messages may be processed not 100% strictly in order. If disabled (as default)"
                            + " then the Exchange is fully processed before the JmsConsumer will pickup the next message from the JMS queue."
                            + " Note if transacted has been enabled, then asyncConsumer=true does not run asynchronously, as transaction"
                            + "  must be executed synchronously (Camel 3.0 may support async transactions).")
    private boolean asyncConsumer;
    // the cacheLevelName of reply manager
    @UriParam(label = "producer,advanced", enums = "CACHE_AUTO,CACHE_CONNECTION,CACHE_CONSUMER,CACHE_NONE,CACHE_SESSION",
              description = "Sets the cache level by name for the reply consumer when doing request/reply over JMS."
                            + " This option only applies when using fixed reply queues (not temporary)."
                            + " Camel will by default use: CACHE_CONSUMER for exclusive or shared w/ replyToSelectorName."
                            + " And CACHE_SESSION for shared without replyToSelectorName. Some JMS brokers such as IBM WebSphere"
                            + " may require to set the replyToCacheLevelName=CACHE_NONE to work."
                            + " Note: If using temporary queues then CACHE_NONE is not allowed,"
                            + " and you must use a higher value such as CACHE_CONSUMER or CACHE_SESSION.")
    private String replyToCacheLevelName;
    @UriParam(defaultValue = "true", label = "producer,advanced",
              description = "Whether to allow sending messages with no body. If this option is false and the message body is null, then an JMSException is thrown.")
    private boolean allowNullBody = true;
    @UriParam(label = "advanced",
              description = "Registry ID of the MessageListenerContainerFactory used to determine what"
                            + " org.springframework.jms.listener.AbstractMessageListenerContainer to use to consume messages."
                            + " Setting this will automatically set consumerType to Custom.")
    private MessageListenerContainerFactory messageListenerContainerFactory;
    @UriParam(label = "producer,advanced",
              description = "Only applicable when sending to JMS destination using InOnly (eg fire and forget)."
                            + " Enabling this option will enrich the Camel Exchange with the actual JMSMessageID"
                            + " that was used by the JMS client when the message was sent to the JMS destination.")
    private boolean includeSentJMSMessageID;
    @UriParam(label = "consumer,advanced",
              description = "Specifies what default TaskExecutor type to use in the DefaultMessageListenerContainer,"
                            + " for both consumer endpoints and the ReplyTo consumer of producer endpoints."
                            + " Possible values: SimpleAsync (uses Spring's SimpleAsyncTaskExecutor) or ThreadPool"
                            + " (uses Spring's ThreadPoolTaskExecutor with optimal values - cached threadpool-like)."
                            + " If not set, it defaults to the previous behaviour, which uses a cached thread pool"
                            + " for consumer endpoints and SimpleAsync for reply consumers."
                            + " The use of ThreadPool is recommended to reduce thread trash in elastic configurations"
                            + " with dynamically increasing and decreasing concurrent consumers.")
    private DefaultTaskExecutorType defaultTaskExecutorType;
    @UriParam(label = "advanced",
              description = "Whether to include all JMSXxxx properties when mapping from JMS to Camel Message."
                            + " Setting this to true will include properties such as JMSXAppID, and JMSXUserID etc."
                            + " Note: If you are using a custom headerFilterStrategy then this option does not apply.")
    private boolean includeAllJMSXProperties;
    @UriParam(label = "advanced",
              description = "To use the given MessageCreatedStrategy which are invoked when Camel creates new instances of jakarta.jms.Message objects when Camel is sending a JMS message.")
    private MessageCreatedStrategy messageCreatedStrategy;
    @UriParam(label = "producer,advanced",
              description = "When using InOut exchange pattern use this JMS property instead of JMSCorrelationID"
                            + " JMS property to correlate messages. If set messages will be correlated solely on the"
                            + " value of this property JMSCorrelationID property will be ignored and not set by Camel.")
    private String correlationProperty;
    @UriParam(label = "producer,advanced",
              description = "This option is used to allow additional headers which may have values that are invalid according to JMS specification."
                            + " For example some message systems such as WMQ do this with header names using prefix JMS_IBM_MQMD_ containing values with byte array or other invalid types."
                            + " You can specify multiple header names separated by comma, and use * as suffix for wildcard matching.")
    private String allowAdditionalHeaders;
    @UriParam(label = "producer",
              description = "Sets whether JMS date properties should be formatted according to the ISO 8601 standard.")
    private boolean formatDateHeadersToIso8601;
    @UriParam(label = "advanced",
              description = "Whether optimizing for Apache Artemis streaming mode. This can reduce memory overhead when using Artemis with JMS StreamMessage types."
                            + " This option must only be enabled if Apache Artemis is being used.")
    private boolean artemisStreamingEnabled;
    @UriParam(label = "consumer", description = "Consumer priorities allow you to ensure that high priority consumers"
                                                + " receive messages while they are active. Normally, active consumers connected to a queue receive messages"
                                                + " from it in a round-robin fashion. When consumer priorities are in use, messages are delivered round-robin"
                                                + " if multiple active consumers exist with the same high priority. Messages will only going to lower priority"
                                                + " consumers when the high priority consumers do not have credit available to consume the message, or those"
                                                + " high priority consumers have declined to accept the message (for instance because it does not meet the"
                                                + " criteria of any selectors associated with the consumer).")
    private int artemisConsumerPriority;

    // JMS 2.0 API
    @UriParam(label = "consumer", description = "Set the name of a subscription to create. To be applied in case"
                                                + " of a topic (pub-sub domain) with a shared or durable subscription."
                                                + " The subscription name needs to be unique within this client's"
                                                + " JMS client id. Default is the class name of the specified message listener."
                                                + " Note: Only 1 concurrent consumer (which is the default of this"
                                                + " message listener container) is allowed for each subscription,"
                                                + " except for a shared subscription (which requires JMS 2.0).")
    private String subscriptionName;
    @UriParam(label = "consumer", description = "Set whether to make the subscription durable. The durable subscription name"
                                                + " to be used can be specified through the subscriptionName property."
                                                + " Default is false. Set this to true to register a durable subscription,"
                                                + " typically in combination with a subscriptionName value (unless"
                                                + " your message listener class name is good enough as subscription name)."
                                                + " Only makes sense when listening to a topic (pub-sub domain),"
                                                + " therefore this method switches the pubSubDomain flag as well.")
    private boolean subscriptionDurable;
    @UriParam(label = "consumer", description = "Set whether to make the subscription shared. The shared subscription name"
                                                + " to be used can be specified through the subscriptionName property."
                                                + " Default is false. Set this to true to register a shared subscription,"
                                                + " typically in combination with a subscriptionName value (unless"
                                                + " your message listener class name is good enough as subscription name)."
                                                + " Note that shared subscriptions may also be durable, so this flag can"
                                                + " (and often will) be combined with subscriptionDurable as well."
                                                + " Only makes sense when listening to a topic (pub-sub domain),"
                                                + " therefore this method switches the pubSubDomain flag as well."
                                                + " Requires a JMS 2.0 compatible message broker.")
    private boolean subscriptionShared;
    @UriParam(label = "producer,advanced", description = "Sets whether StreamMessage type is enabled or not."
                                                         + " Message payloads of streaming kind such as files, InputStream, etc will either by sent as BytesMessage or StreamMessage."
                                                         + " This option controls which kind will be used. By default BytesMessage is used which enforces the entire message payload to be read into memory."
                                                         + " By enabling this option the message payload is read into memory in chunks and each chunk is then written to the StreamMessage until no more data.")
    private boolean streamMessageTypeEnabled;
    @UriParam(defaultValue = "-1", label = "producer", description = "Sets delivery delay to use for send calls for JMS. "
                                                                     + "This option requires JMS 2.0 compliant broker.")
    private long deliveryDelay = -1;
    @UriParam(defaultValue = "false", label = "advanced",
              description = "Sets whether synchronous processing should be strictly used")
    private boolean synchronous;

    public JmsConfiguration() {
    }

    public JmsConfiguration(ConnectionFactory connectionFactory) {
        this.connectionFactory = connectionFactory;
    }

    /**
     * Returns a copy of this configuration
     */
    public JmsConfiguration copy() {
        try {
            return (JmsConfiguration) clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeCamelException(e);
        }
    }

    public static class CamelJmsTemplate extends JmsTemplate {
        private JmsConfiguration config;

        public CamelJmsTemplate(JmsConfiguration config, ConnectionFactory connectionFactory) {
            super(connectionFactory);
            this.config = config;
        }

        public void send(
                final String destinationName,
                final MessageCreator messageCreator,
                final MessageSentCallback callback)
                throws JmsException {
            execute(session -> {
                Destination destination = resolveDestinationName(session, destinationName);
                return doSendToDestination(destination, messageCreator, callback, session);
            }, false);
        }

        public void send(
                final Destination destination,
                final MessageCreator messageCreator,
                final MessageSentCallback callback)
                throws JmsException {
            execute(session -> doSendToDestination(destination, messageCreator, callback, session), false);
        }

        @Override
        public void send(
                final String destinationName,
                final MessageCreator messageCreator)
                throws JmsException {
            execute(session -> {
                Destination destination = resolveDestinationName(session, destinationName);
                return doSendToDestination(destination, messageCreator, null, session);
            }, false);
        }

        @Override
        public void send(
                final Destination destination,
                final MessageCreator messageCreator)
                throws JmsException {
            execute(session -> doSendToDestination(destination, messageCreator, null, session), false);
        }

        private Object doSendToDestination(
                final Destination destination,
                final MessageCreator messageCreator,
                final MessageSentCallback callback,
                final Session session)
                throws JMSException {

            Assert.notNull(messageCreator, "MessageCreator must not be null");
            MessageProducer producer = createProducer(session, destination);
            Message message;
            try {
                message = messageCreator.createMessage(session);
                doSend(producer, message);
                if (message != null && callback != null) {
                    callback.sent(session, message, destination);
                }
                // Check commit - avoid commit call within a JTA transaction.
                if (session.getTransacted() && isSessionLocallyTransacted(session)) {
                    // Transacted session created by this template -> commit.
                    JmsUtils.commitIfNecessary(session);
                }
            } finally {
                JmsUtils.closeMessageProducer(producer);
            }
            return null;
        }

        /**
         * Override so we can support preserving the Qos settings that have been set on the message.
         */
        @Override
        protected void doSend(MessageProducer producer, Message message) throws JMSException {
            if (config.isPreserveMessageQos()) {
                long ttl = message.getJMSExpiration();
                if (ttl != 0) {
                    ttl = ttl - System.currentTimeMillis();
                    // Message had expired.. so set the ttl as small as possible
                    if (ttl <= 0) {
                        ttl = 1;
                    }
                }

                int priority = message.getJMSPriority();
                if (priority < 0 || priority > 9) {
                    // use priority from endpoint if not provided on message with a valid range
                    priority = this.getPriority();
                }

                // if a delivery mode was set as a JMS header then we have used a temporary
                // property to store it - CamelJMSDeliveryMode. Otherwise we could not keep
                // track whether it was set or not as getJMSDeliveryMode() will default return 1 regardless
                // if it was set or not, so we can never tell if end user provided it in a header
                int deliveryMode;
                if (JmsMessageHelper.hasProperty(message, JmsConstants.JMS_DELIVERY_MODE)) {
                    deliveryMode = message.getIntProperty(JmsConstants.JMS_DELIVERY_MODE);
                    // remove the temporary property
                    JmsMessageHelper.removeJmsProperty(message, JmsConstants.JMS_DELIVERY_MODE);
                } else {
                    // use the existing delivery mode from the message
                    deliveryMode = message.getJMSDeliveryMode();
                }

                // need to log just before so the message is 100% correct when logged
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Sending JMS message to: {} with message: {}", producer.getDestination(), message);
                }
                producer.send(message, deliveryMode, priority, ttl);
            } else {
                // need to log just before so the message is 100% correct when logged
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Sending JMS message to: {} with message: {}", producer.getDestination(), message);
                }
                super.doSend(producer, message);
                if (LOG.isTraceEnabled()) {
                    LOG.trace("Sent JMS message to: {} with message: {}", producer.getDestination(), message);
                }
            }
        }
    }

    /**
     * Creates a {@link JmsOperations} object used for request/response using a request timeout value
     */
    public JmsOperations createInOutTemplate(
            JmsEndpoint endpoint, boolean pubSubDomain, String destination, long requestTimeout) {
        JmsOperations answer = createInOnlyTemplate(endpoint, pubSubDomain, destination);
        if (answer instanceof JmsTemplate && requestTimeout > 0) {
            JmsTemplate jmsTemplate = (JmsTemplate) answer;
            jmsTemplate.setExplicitQosEnabled(true);

            // prefer to use timeToLive over requestTimeout if both specified
            long ttl = timeToLive > 0 ? timeToLive : requestTimeout;
            if (!isDisableTimeToLive()) {
                // only use TTL if not disabled
                jmsTemplate.setTimeToLive(ttl);
            }

            jmsTemplate.setSessionTransacted(transactedInOut);
            if (transactedInOut) {
                jmsTemplate.setSessionAcknowledgeMode(Session.SESSION_TRANSACTED);
            } else {
                if (acknowledgementMode >= 0) {
                    jmsTemplate.setSessionAcknowledgeMode(acknowledgementMode);
                } else if (acknowledgementModeName != null) {
                    jmsTemplate.setSessionAcknowledgeModeName(acknowledgementModeName);
                } else {
                    // default to AUTO
                    jmsTemplate.setSessionAcknowledgeMode(Session.AUTO_ACKNOWLEDGE);
                }
            }
        }
        return answer;
    }

    /**
     * Creates a {@link JmsOperations} object used for one way messaging
     */
    public JmsOperations createInOnlyTemplate(JmsEndpoint endpoint, boolean pubSubDomain, String destination) {
        if (jmsOperations != null) {
            return jmsOperations;
        }

        ConnectionFactory factory = getOrCreateTemplateConnectionFactory();
        JmsTemplate template = new CamelJmsTemplate(this, factory);

        template.setPubSubDomain(pubSubDomain);
        if (destinationResolver != null) {
            template.setDestinationResolver(destinationResolver);
            if (endpoint instanceof DestinationEndpoint) {
                LOG.debug(
                        "You are overloading the destinationResolver property on a DestinationEndpoint; are you sure you want to do that?");
            }
        } else if (endpoint instanceof DestinationEndpoint) {
            DestinationEndpoint destinationEndpoint = (DestinationEndpoint) endpoint;
            template.setDestinationResolver(createDestinationResolver(destinationEndpoint));
        }
        template.setDefaultDestinationName(destination);

        template.setExplicitQosEnabled(isExplicitQosEnabled());

        // have to use one or the other.. doesn't make sense to use both
        if (deliveryMode != null) {
            template.setDeliveryMode(deliveryMode);
        } else {
            template.setDeliveryPersistent(deliveryPersistent);
        }

        if (messageConverter != null) {
            template.setMessageConverter(messageConverter);
        }
        template.setMessageIdEnabled(messageIdEnabled);
        template.setMessageTimestampEnabled(messageTimestampEnabled);
        if (priority >= 0) {
            template.setPriority(priority);
        }
        template.setPubSubNoLocal(pubSubNoLocal);
        // only set TTL if we have a positive value and it has not been disabled
        if (timeToLive >= 0 && !isDisableTimeToLive()) {
            template.setTimeToLive(timeToLive);
        }

        template.setSessionTransacted(transacted);
        if (transacted) {
            template.setSessionAcknowledgeMode(Session.SESSION_TRANSACTED);
        } else {
            // This is here for completeness, but the template should not get
            // used for receiving messages.
            if (acknowledgementMode >= 0) {
                template.setSessionAcknowledgeMode(acknowledgementMode);
            } else if (acknowledgementModeName != null) {
                template.setSessionAcknowledgeModeName(acknowledgementModeName);
            }
        }

        template.setDeliveryDelay(deliveryDelay);

        return template;
    }

    public AbstractMessageListenerContainer createMessageListenerContainer(JmsEndpoint endpoint) {
        AbstractMessageListenerContainer container = chooseMessageListenerContainerImplementation(endpoint);
        configureMessageListenerContainer(container, endpoint);
        return container;
    }

    @Deprecated
    public AbstractMessageListenerContainer chooseMessageListenerContainerImplementation(JmsEndpoint endpoint) {
        return chooseMessageListenerContainerImplementation(endpoint, consumerType);
    }

    public AbstractMessageListenerContainer chooseMessageListenerContainerImplementation(
            JmsEndpoint endpoint, ConsumerType type) {
        switch (type) {
            case Simple:
                return new SimpleJmsMessageListenerContainer(endpoint);
            case Default:
                return new DefaultJmsMessageListenerContainer(endpoint);
            case Custom:
                return getCustomMessageListenerContainer(endpoint);
            default:
                throw new IllegalArgumentException("Unknown consumer type: " + type);
        }
    }

    private AbstractMessageListenerContainer getCustomMessageListenerContainer(JmsEndpoint endpoint) {
        if (messageListenerContainerFactory != null) {
            return messageListenerContainerFactory.createMessageListenerContainer(endpoint);
        }
        return null;
    }

    // Properties
    // -------------------------------------------------------------------------

    public ConsumerType getConsumerType() {
        return consumerType;
    }

    /**
     * The consumer type to use, which can be one of: Simple, Default, or Custom. The consumer type determines which
     * Spring JMS listener to use. Default will use org.springframework.jms.listener.DefaultMessageListenerContainer,
     * Simple will use org.springframework.jms.listener.SimpleMessageListenerContainer. When Custom is specified, the
     * MessageListenerContainerFactory defined by the messageListenerContainerFactory option will determine what
     * org.springframework.jms.listener.AbstractMessageListenerContainer to use.
     */
    public void setConsumerType(ConsumerType consumerType) {
        this.consumerType = consumerType;
    }

    public ConsumerType getReplyToConsumerType() {
        return replyToConsumerType;
    }

    /**
     * The consumer type of the reply consumer (when doing request/reply), which can be one of: Simple, Default, or
     * Custom." The consumer type determines which Spring JMS listener to use. Default will use
     * org.springframework.jms.listener.DefaultMessageListenerContainer," Simple will use
     * org.springframework.jms.listener.SimpleMessageListenerContainer." When Custom is specified, the
     * MessageListenerContainerFactory defined by the messageListenerContainerFactory option" will determine what
     * org.springframework.jms.listener.AbstractMessageListenerContainer to use.
     */
    public void setReplyToConsumerType(ConsumerType replyToConsumerType) {
        this.replyToConsumerType = replyToConsumerType;
    }

    public ConnectionFactory getConnectionFactory() {
        return connectionFactory;
    }

    public ConnectionFactory getOrCreateConnectionFactory() {
        if (connectionFactory == null) {
            connectionFactory = createConnectionFactory();
        }
        return connectionFactory;
    }

    /**
     * Sets the default connection factory to be used if a connection factory is not specified for either
     * {@link #setTemplateConnectionFactory(ConnectionFactory)} or
     * {@link #setListenerConnectionFactory(ConnectionFactory)}
     */
    public void setConnectionFactory(ConnectionFactory connectionFactory) {
        this.connectionFactory = connectionFactory;
    }

    public String getUsername() {
        return username;
    }

    /**
     * Username to use with the ConnectionFactory. You can also configure username/password directly on the
     * ConnectionFactory.
     */
    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    /**
     * Password to use with the ConnectionFactory. You can also configure username/password directly on the
     * ConnectionFactory.
     */
    public void setPassword(String password) {
        this.password = password;
    }

    public ConnectionFactory getListenerConnectionFactory() {
        return listenerConnectionFactory;
    }

    public ConnectionFactory getOrCreateListenerConnectionFactory() {
        if (listenerConnectionFactory == null) {
            listenerConnectionFactory = createListenerConnectionFactory();
        }
        return listenerConnectionFactory;
    }

    /**
     * Sets the connection factory to be used for consuming messages
     */
    public void setListenerConnectionFactory(ConnectionFactory listenerConnectionFactory) {
        this.listenerConnectionFactory = listenerConnectionFactory;
    }

    public ConnectionFactory getTemplateConnectionFactory() {
        return templateConnectionFactory;
    }

    public ConnectionFactory getOrCreateTemplateConnectionFactory() {
        if (templateConnectionFactory == null) {
            templateConnectionFactory = createTemplateConnectionFactory();
        }
        return templateConnectionFactory;
    }

    /**
     * Sets the connection factory to be used for sending messages via the {@link JmsTemplate} via
     * {@link #createInOnlyTemplate(JmsEndpoint, boolean, String)}
     */
    public void setTemplateConnectionFactory(ConnectionFactory templateConnectionFactory) {
        this.templateConnectionFactory = templateConnectionFactory;
    }

    public boolean isAutoStartup() {
        return autoStartup;
    }

    /**
     * Specifies whether the consumer container should auto-startup.
     */
    public void setAutoStartup(boolean autoStartup) {
        this.autoStartup = autoStartup;
    }

    public boolean isAcceptMessagesWhileStopping() {
        return acceptMessagesWhileStopping;
    }

    /**
     * Specifies whether the consumer accept messages while it is stopping. You may consider enabling this option, if
     * you start and stop JMS routes at runtime, while there are still messages enqueued on the queue. If this option is
     * false, and you stop the JMS route, then messages may be rejected, and the JMS broker would have to attempt
     * redeliveries, which yet again may be rejected, and eventually the message may be moved at a dead letter queue on
     * the JMS broker. To avoid this its recommended to enable this option.
     */
    public void setAcceptMessagesWhileStopping(boolean acceptMessagesWhileStopping) {
        this.acceptMessagesWhileStopping = acceptMessagesWhileStopping;
    }

    /**
     * Whether the {@link DefaultMessageListenerContainer} used in the reply managers for request-reply messaging allow
     * the {@link DefaultMessageListenerContainer#runningAllowed()} flag to quick stop in case
     * {@link JmsConfiguration#isAcceptMessagesWhileStopping()} is enabled, and {@link org.apache.camel.CamelContext} is
     * currently being stopped. This quick stop ability is enabled by default in the regular JMS consumers but to enable
     * for reply managers you must enable this flag.
     */
    public boolean isAllowReplyManagerQuickStop() {
        return allowReplyManagerQuickStop;
    }

    public void setAllowReplyManagerQuickStop(boolean allowReplyManagerQuickStop) {
        this.allowReplyManagerQuickStop = allowReplyManagerQuickStop;
    }

    public String getClientId() {
        return clientId;
    }

    /**
     * Sets the JMS client ID to use. Note that this value, if specified, must be unique and can only be used by a
     * single JMS connection instance. It is typically only required for durable topic subscriptions.
     * 

* If using Apache ActiveMQ you may prefer to use Virtual Topics instead. */ public void setClientId(String consumerClientId) { this.clientId = consumerClientId; } public String getDurableSubscriptionName() { return durableSubscriptionName; } /** * The durable subscriber name for specifying durable topic subscriptions. The clientId option must be configured as * well. */ public void setDurableSubscriptionName(String durableSubscriptionName) { this.durableSubscriptionName = durableSubscriptionName; } public ExceptionListener getExceptionListener() { return exceptionListener; } /** * Specifies the JMS Exception Listener that is to be notified of any underlying JMS exceptions. */ public void setExceptionListener(ExceptionListener exceptionListener) { this.exceptionListener = exceptionListener; } /** * Specifies a org.springframework.util.ErrorHandler to be invoked in case of any uncaught exceptions thrown while * processing a Message. By default these exceptions will be logged at the WARN level, if no errorHandler has been * configured. You can configure logging level and whether stack traces should be logged using * errorHandlerLoggingLevel and errorHandlerLogStackTrace options. This makes it much easier to configure, than * having to code a custom errorHandler. */ public void setErrorHandler(ErrorHandler errorHandler) { this.errorHandler = errorHandler; } public ErrorHandler getErrorHandler() { return errorHandler; } public LoggingLevel getErrorHandlerLoggingLevel() { return errorHandlerLoggingLevel; } /** * Allows to configure the default errorHandler logging level for logging uncaught exceptions. */ public void setErrorHandlerLoggingLevel(LoggingLevel errorHandlerLoggingLevel) { this.errorHandlerLoggingLevel = errorHandlerLoggingLevel; } public boolean isErrorHandlerLogStackTrace() { return errorHandlerLogStackTrace; } /** * Allows to control whether stacktraces should be logged or not, by the default errorHandler. */ public void setErrorHandlerLogStackTrace(boolean errorHandlerLogStackTrace) { this.errorHandlerLogStackTrace = errorHandlerLogStackTrace; } public String getAcknowledgementModeName() { return acknowledgementModeName; } /** * The JMS acknowledgement name, which is one of: SESSION_TRANSACTED, CLIENT_ACKNOWLEDGE, AUTO_ACKNOWLEDGE, * DUPS_OK_ACKNOWLEDGE */ public void setAcknowledgementModeName(String consumerAcknowledgementMode) { this.acknowledgementModeName = consumerAcknowledgementMode; this.acknowledgementMode = -1; } public boolean isExposeListenerSession() { return exposeListenerSession; } /** * Specifies whether the listener session should be exposed when consuming messages. */ public void setExposeListenerSession(boolean exposeListenerSession) { this.exposeListenerSession = exposeListenerSession; } public TaskExecutor getTaskExecutor() { return taskExecutor; } /** * Allows you to specify a custom task executor for consuming messages. */ public void setTaskExecutor(TaskExecutor taskExecutor) { this.taskExecutor = taskExecutor; } public boolean isPubSubNoLocal() { return pubSubNoLocal; } /** * Specifies whether to inhibit the delivery of messages published by its own connection. */ public void setPubSubNoLocal(boolean pubSubNoLocal) { this.pubSubNoLocal = pubSubNoLocal; } public int getConcurrentConsumers() { return concurrentConsumers; } /** * Specifies the default number of concurrent consumers when consuming from JMS (not for request/reply over JMS). * See also the maxMessagesPerTask option to control dynamic scaling up/down of threads. *

* When doing request/reply over JMS then the option replyToConcurrentConsumers is used to control number of * concurrent consumers on the reply message listener. */ public void setConcurrentConsumers(int concurrentConsumers) { this.concurrentConsumers = concurrentConsumers; } public int getReplyToConcurrentConsumers() { return replyToConcurrentConsumers; } /** * Specifies the default number of concurrent consumers when doing request/reply over JMS. See also the * maxMessagesPerTask option to control dynamic scaling up/down of threads. */ public void setReplyToConcurrentConsumers(int replyToConcurrentConsumers) { this.replyToConcurrentConsumers = replyToConcurrentConsumers; } public int getMaxMessagesPerTask() { return maxMessagesPerTask; } /** * The number of messages per task. -1 is unlimited. If you use a range for concurrent consumers (eg min < max), * then this option can be used to set a value to eg 100 to control how fast the consumers will shrink when less * work is required. */ public void setMaxMessagesPerTask(int maxMessagesPerTask) { this.maxMessagesPerTask = maxMessagesPerTask; } public int getCacheLevel() { return cacheLevel; } /** * Sets the cache level by ID for the underlying JMS resources. See cacheLevelName option for more details. */ public void setCacheLevel(int cacheLevel) { this.cacheLevel = cacheLevel; } public String getCacheLevelName() { return cacheLevelName; } /** * Sets the cache level by name for the underlying JMS resources. Possible values are: CACHE_AUTO, CACHE_CONNECTION, * CACHE_CONSUMER, CACHE_NONE, and CACHE_SESSION. The default setting is CACHE_AUTO. See the Spring documentation * and Transactions Cache Levels for more information. */ public void setCacheLevelName(String cacheName) { this.cacheLevelName = cacheName; } public long getRecoveryInterval() { return recoveryInterval; } /** * Specifies the interval between recovery attempts, i.e. when a connection is being refreshed, in milliseconds. The * default is 5000 ms, that is, 5 seconds. */ public void setRecoveryInterval(long recoveryInterval) { this.recoveryInterval = recoveryInterval; } public long getReceiveTimeout() { return receiveTimeout; } /** * The timeout for receiving messages (in milliseconds). */ public void setReceiveTimeout(long receiveTimeout) { this.receiveTimeout = receiveTimeout; } public PlatformTransactionManager getTransactionManager() { return transactionManager; } public PlatformTransactionManager getOrCreateTransactionManager() { if (transactionManager == null && isTransacted() && isLazyCreateTransactionManager()) { transactionManager = createTransactionManager(); } return transactionManager; } /** * The Spring transaction manager to use. */ public void setTransactionManager(PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } public String getTransactionName() { return transactionName; } /** * The name of the transaction to use. */ public void setTransactionName(String transactionName) { this.transactionName = transactionName; } public int getTransactionTimeout() { return transactionTimeout; } /** * The timeout value of the transaction (in seconds), if using transacted mode. */ public void setTransactionTimeout(int transactionTimeout) { this.transactionTimeout = transactionTimeout; } public int getIdleTaskExecutionLimit() { return idleTaskExecutionLimit; } /** * Specifies the limit for idle executions of a receive task, not having received any message within its execution. * If this limit is reached, the task will shut down and leave receiving to other executing tasks (in the case of * dynamic scheduling; see the maxConcurrentConsumers setting). There is additional doc available from Spring. */ public void setIdleTaskExecutionLimit(int idleTaskExecutionLimit) { this.idleTaskExecutionLimit = idleTaskExecutionLimit; } public int getIdleConsumerLimit() { return idleConsumerLimit; } /** * Specify the limit for the number of consumers that are allowed to be idle at any given time. */ public void setIdleConsumerLimit(int idleConsumerLimit) { this.idleConsumerLimit = idleConsumerLimit; } public int getWaitForProvisionCorrelationToBeUpdatedCounter() { return waitForProvisionCorrelationToBeUpdatedCounter; } /** * Number of times to wait for provisional correlation id to be updated to the actual correlation id when doing * request/reply over JMS and when the option useMessageIDAsCorrelationID is enabled. */ public void setWaitForProvisionCorrelationToBeUpdatedCounter(int counter) { this.waitForProvisionCorrelationToBeUpdatedCounter = counter; } public long getWaitForProvisionCorrelationToBeUpdatedThreadSleepingTime() { return waitForProvisionCorrelationToBeUpdatedThreadSleepingTime; } /** * Interval in millis to sleep each time while waiting for provisional correlation id to be updated. */ public void setWaitForProvisionCorrelationToBeUpdatedThreadSleepingTime(long sleepingTime) { this.waitForProvisionCorrelationToBeUpdatedThreadSleepingTime = sleepingTime; } public int getMaxConcurrentConsumers() { return maxConcurrentConsumers; } /** * Specifies the maximum number of concurrent consumers when consuming from JMS (not for request/reply over JMS). * See also the maxMessagesPerTask option to control dynamic scaling up/down of threads. *

* When doing request/reply over JMS then the option replyToMaxConcurrentConsumers is used to control number of * concurrent consumers on the reply message listener. */ public void setMaxConcurrentConsumers(int maxConcurrentConsumers) { this.maxConcurrentConsumers = maxConcurrentConsumers; } public int getReplyToMaxConcurrentConsumers() { return replyToMaxConcurrentConsumers; } /** * Specifies the maximum number of concurrent consumers when using request/reply over JMS. See also the * maxMessagesPerTask option to control dynamic scaling up/down of threads. */ public void setReplyToMaxConcurrentConsumers(int replyToMaxConcurrentConsumers) { this.replyToMaxConcurrentConsumers = replyToMaxConcurrentConsumers; } public int getReplyToOnTimeoutMaxConcurrentConsumers() { return replyToOnTimeoutMaxConcurrentConsumers; } /** * Specifies the maximum number of concurrent consumers for continue routing when timeout occurred when using * request/reply over JMS. */ public void setReplyToOnTimeoutMaxConcurrentConsumers(int replyToOnTimeoutMaxConcurrentConsumers) { this.replyToOnTimeoutMaxConcurrentConsumers = replyToOnTimeoutMaxConcurrentConsumers; } public boolean isExplicitQosEnabled() { return explicitQosEnabled != null ? explicitQosEnabled : false; } public Boolean getExplicitQosEnabled() { return explicitQosEnabled; } /** * Set if the deliveryMode, priority or timeToLive qualities of service should be used when sending messages. This * option is based on Spring's JmsTemplate. The deliveryMode, priority and timeToLive options are applied to the * current endpoint. This contrasts with the preserveMessageQos option, which operates at message granularity, * reading QoS properties exclusively from the Camel In message headers. */ public void setExplicitQosEnabled(boolean explicitQosEnabled) { this.explicitQosEnabled = explicitQosEnabled; } public boolean isDeliveryPersistent() { return deliveryPersistent; } /** * Specifies whether persistent delivery is used by default. */ public void setDeliveryPersistent(boolean deliveryPersistent) { this.deliveryPersistent = deliveryPersistent; configuredQoS(); } public Integer getDeliveryMode() { return deliveryMode; } /** * Specifies the delivery mode to be used. Possible values are those defined by jakarta.jms.DeliveryMode. * NON_PERSISTENT = 1 and PERSISTENT = 2. */ public void setDeliveryMode(Integer deliveryMode) { this.deliveryMode = deliveryMode; configuredQoS(); } public boolean isReplyToDeliveryPersistent() { return replyToDeliveryPersistent; } /** * Specifies whether to use persistent delivery by default for replies. */ public void setReplyToDeliveryPersistent(boolean replyToDeliveryPersistent) { this.replyToDeliveryPersistent = replyToDeliveryPersistent; } public long getTimeToLive() { return timeToLive; } /** * When sending messages, specifies the time-to-live of the message (in milliseconds). */ public void setTimeToLive(long timeToLive) { this.timeToLive = timeToLive; configuredQoS(); } public MessageConverter getMessageConverter() { return messageConverter; } /** * To use a custom Spring org.springframework.jms.support.converter.MessageConverter so you can be in control how to * map to/from a jakarta.jms.Message. */ public void setMessageConverter(MessageConverter messageConverter) { this.messageConverter = messageConverter; } public boolean isMapJmsMessage() { return mapJmsMessage; } /** * Specifies whether Camel should auto map the received JMS message to a suited payload type, such as * jakarta.jms.TextMessage to a String etc. */ public void setMapJmsMessage(boolean mapJmsMessage) { this.mapJmsMessage = mapJmsMessage; } public boolean isMessageIdEnabled() { return messageIdEnabled; } /** * When sending, specifies whether message IDs should be added. This is just an hint to the JMS Broker. If the JMS * provider accepts this hint, these messages must have the message ID set to null; if the provider ignores the * hint, the message ID must be set to its normal unique value */ public void setMessageIdEnabled(boolean messageIdEnabled) { this.messageIdEnabled = messageIdEnabled; } public boolean isMessageTimestampEnabled() { return messageTimestampEnabled; } /** * Specifies whether timestamps should be enabled by default on sending messages. This is just an hint to the JMS * Broker. If the JMS provider accepts this hint, these messages must have the timestamp set to zero; if the * provider ignores the hint, the timestamp must be set to its normal value. */ public void setMessageTimestampEnabled(boolean messageTimestampEnabled) { this.messageTimestampEnabled = messageTimestampEnabled; } public int getPriority() { return priority; } /** * Values greater than 1 specify the message priority when sending (where 0 is the lowest priority and 9 is the * highest). The explicitQosEnabled option must also be enabled in order for this option to have any effect. */ public void setPriority(int priority) { this.priority = priority; configuredQoS(); } public int getAcknowledgementMode() { return acknowledgementMode; } /** * The JMS acknowledgement mode defined as an Integer. Allows you to set vendor-specific extensions to the * acknowledgment mode. For the regular modes, it is preferable to use the acknowledgementModeName instead. */ public void setAcknowledgementMode(int consumerAcknowledgementMode) { this.acknowledgementMode = consumerAcknowledgementMode; this.acknowledgementModeName = null; } public boolean isTransacted() { return transacted; } /** * Specifies whether to use transacted mode */ public void setTransacted(boolean transacted) { this.transacted = transacted; } public boolean isTransactedInOut() { return transactedInOut; } /** * Specifies whether InOut operations (request reply) default to using transacted mode. * * If this flag is set to true, then Spring JmsTemplate will have sessionTransacted set to true, and the * acknowledgeMode as transacted on the JmsTemplate used for InOut operations. * * Note from Spring JMS: that within a JTA transaction, the parameters passed to createQueue, createTopic methods * are not taken into account. Depending on the Java EE transaction context, the container makes its own decisions * on these values. Analogously, these parameters are not taken into account within a locally managed transaction * either, since Spring JMS operates on an existing JMS Session in this case. *

* Setting this flag to true will use a short local JMS transaction when running outside of a managed transaction, * and a synchronized local JMS transaction in case of a managed transaction (other than an XA transaction) being * present. This has the effect of a local JMS transaction being managed alongside the main transaction (which might * be a native JDBC transaction), with the JMS transaction committing right after the main transaction. */ public void setTransactedInOut(boolean transactedInOut) { this.transactedInOut = transactedInOut; } public boolean isLazyCreateTransactionManager() { return lazyCreateTransactionManager; } /** * If true, Camel will create a JmsTransactionManager, if there is no transactionManager injected when option * transacted=true. */ public void setLazyCreateTransactionManager(boolean lazyCreating) { this.lazyCreateTransactionManager = lazyCreating; } public String getEagerPoisonBody() { return eagerPoisonBody; } /** * If eagerLoadingOfProperties is enabled and the JMS message payload (JMS body or JMS properties) cannot be * read/mapped, then set this text as the message body instead so the message can be processed (the cause of the * poison are already stored as exception on the Exchange). This can be turned off by setting eagerPoisonBody=false. * See also the option eagerLoadingOfProperties. */ public void setEagerPoisonBody(String eagerPoisonBody) { this.eagerPoisonBody = eagerPoisonBody; } public boolean isEagerLoadingOfProperties() { return eagerLoadingOfProperties; } /** * Enables eager loading of JMS properties and payload as soon as a message is loaded which generally is inefficient * as the JMS properties may not be required but sometimes can catch early any issues with the underlying JMS * provider and the use of JMS properties. See also the option eagerPoisonBody. */ public void setEagerLoadingOfProperties(boolean eagerLoadingOfProperties) { this.eagerLoadingOfProperties = eagerLoadingOfProperties; } public boolean isDisableReplyTo() { return disableReplyTo; } /** * Specifies whether Camel ignores the JMSReplyTo header in messages. If true, Camel does not send a reply back to * the destination specified in the JMSReplyTo header. You can use this option if you want Camel to consume from a * route and you do not want Camel to automatically send back a reply message because another component in your code * handles the reply message. You can also use this option if you want to use Camel as a proxy between different * message brokers and you want to route message from one system to another. */ public void setDisableReplyTo(boolean disableReplyTo) { this.disableReplyTo = disableReplyTo; } /** * Set to true, if you want to send message using the QoS settings specified on the message, instead of the QoS * settings on the JMS endpoint. The following three headers are considered JMSPriority, JMSDeliveryMode, and * JMSExpiration. You can provide all or only some of them. If not provided, Camel will fall back to use the values * from the endpoint instead. So, when using this option, the headers override the values from the endpoint. The * explicitQosEnabled option, by contrast, will only use options set on the endpoint, and not values from the * message header. */ public void setPreserveMessageQos(boolean preserveMessageQos) { this.preserveMessageQos = preserveMessageQos; } public JmsOperations getJmsOperations() { return jmsOperations; } /** * Allows you to use your own implementation of the org.springframework.jms.core.JmsOperations interface. Camel uses * JmsTemplate as default. Can be used for testing purpose, but not used much as stated in the spring API docs. */ public void setJmsOperations(JmsOperations jmsOperations) { this.jmsOperations = jmsOperations; } public DestinationResolver getDestinationResolver() { return destinationResolver; } /** * A pluggable org.springframework.jms.support.destination.DestinationResolver that allows you to use your own * resolver (for example, to lookup the real destination in a JNDI registry). */ public void setDestinationResolver(DestinationResolver destinationResolver) { this.destinationResolver = destinationResolver; } // Implementation methods // ------------------------------------------------------------------------- public static DestinationResolver createDestinationResolver(final DestinationEndpoint destinationEndpoint) { return (session, destinationName, pubSubDomain) -> destinationEndpoint.getJmsDestination(session); } protected void configureMessageListenerContainer( AbstractMessageListenerContainer container, JmsEndpoint endpoint) { container.setConnectionFactory(getOrCreateListenerConnectionFactory()); if (endpoint instanceof DestinationEndpoint) { container.setDestinationResolver(createDestinationResolver((DestinationEndpoint) endpoint)); } else if (destinationResolver != null) { container.setDestinationResolver(destinationResolver); } container.setAutoStartup(autoStartup); if (durableSubscriptionName != null) { container.setDurableSubscriptionName(durableSubscriptionName); container.setSubscriptionDurable(true); } if (clientId != null) { container.setClientId(clientId); } if (exceptionListener != null) { container.setExceptionListener(exceptionListener); } if (errorHandler != null) { container.setErrorHandler(errorHandler); } else { ErrorHandler handler = new DefaultSpringErrorHandler( endpoint.getCamelContext(), EndpointMessageListener.class, getErrorHandlerLoggingLevel(), isErrorHandlerLogStackTrace()); container.setErrorHandler(handler); } container.setAcceptMessagesWhileStopping(acceptMessagesWhileStopping); container.setExposeListenerSession(exposeListenerSession); container.setSessionTransacted(transacted); if (transacted) { container.setSessionAcknowledgeMode(Session.SESSION_TRANSACTED); } else { if (acknowledgementMode >= 0) { container.setSessionAcknowledgeMode(acknowledgementMode); } else if (acknowledgementModeName != null) { container.setSessionAcknowledgeModeName(acknowledgementModeName); } } if (endpoint.getSelector() != null && endpoint.getSelector().length() != 0) { container.setMessageSelector(endpoint.getSelector()); } if (container instanceof DefaultMessageListenerContainer) { DefaultMessageListenerContainer listenerContainer = (DefaultMessageListenerContainer) container; configureDefaultMessageListenerContainer(endpoint, listenerContainer); } else if (container instanceof SimpleMessageListenerContainer) { SimpleMessageListenerContainer listenerContainer = (SimpleMessageListenerContainer) container; configureSimpleMessageListenerContainer(listenerContainer); } } private void configureSimpleMessageListenerContainer(SimpleMessageListenerContainer listenerContainer) { if (maxConcurrentConsumers > 0) { if (maxConcurrentConsumers < concurrentConsumers) { throw new IllegalArgumentException( "Property maxConcurrentConsumers: " + maxConcurrentConsumers + " must be higher than concurrentConsumers: " + concurrentConsumers); } listenerContainer.setConcurrency(concurrentConsumers + "-" + maxConcurrentConsumers); } else if (concurrentConsumers >= 0) { listenerContainer.setConcurrentConsumers(concurrentConsumers); } listenerContainer.setPubSubNoLocal(pubSubNoLocal); if (taskExecutor != null) { listenerContainer.setTaskExecutor(taskExecutor); } } private void configureDefaultMessageListenerContainer(JmsEndpoint endpoint, DefaultMessageListenerContainer container) { if (concurrentConsumers >= 0) { container.setConcurrentConsumers(concurrentConsumers); } if (cacheLevel >= 0) { container.setCacheLevel(cacheLevel); } else if (cacheLevelName != null) { container.setCacheLevelName(cacheLevelName); } else { container.setCacheLevel(defaultCacheLevel(endpoint)); } if (idleTaskExecutionLimit >= 0) { container.setIdleTaskExecutionLimit(idleTaskExecutionLimit); } if (idleConsumerLimit >= 0) { container.setIdleConsumerLimit(idleConsumerLimit); } if (maxConcurrentConsumers > 0) { if (maxConcurrentConsumers < concurrentConsumers) { throw new IllegalArgumentException( "Property maxConcurrentConsumers: " + maxConcurrentConsumers + " must be higher than concurrentConsumers: " + concurrentConsumers); } container.setMaxConcurrentConsumers(maxConcurrentConsumers); } if (maxMessagesPerTask >= 0) { container.setMaxMessagesPerTask(maxMessagesPerTask); } container.setPubSubNoLocal(pubSubNoLocal); if (receiveTimeout >= 0) { container.setReceiveTimeout(receiveTimeout); } if (recoveryInterval >= 0) { container.setRecoveryInterval(recoveryInterval); } if (taskExecutor != null) { container.setTaskExecutor(taskExecutor); } PlatformTransactionManager tm = getOrCreateTransactionManager(); if (tm != null) { container.setTransactionManager(tm); } else if (transactionManager == null && transacted && !lazyCreateTransactionManager) { container.setSessionTransacted(true); } if (transactionName != null) { container.setTransactionName(transactionName); } if (transactionTimeout >= 0) { container.setTransactionTimeout(transactionTimeout); } } public void configureMessageListener(EndpointMessageListener listener) { if (isDisableReplyTo()) { listener.setDisableReplyTo(true); } if (!"false".equals(eagerPoisonBody)) { listener.setEagerPoisonBody(eagerPoisonBody); } listener.setEagerLoadingOfProperties(eagerLoadingOfProperties); if (getReplyTo() != null) { listener.setReplyToDestination(getReplyTo()); } JmsOperations operations = listener.getTemplate(); if (operations instanceof JmsTemplate) { JmsTemplate template = (JmsTemplate) operations; template.setDeliveryPersistent(isReplyToDeliveryPersistent()); } } /** * Defaults the JMS cache level if none is explicitly specified. *

* Will return CACHE_AUTO which will pickup and use CACHE_NONE if transacted has been enabled, * otherwise it will use CACHE_CONSUMER which is the most efficient. * * @param endpoint the endpoint * @return the cache level */ protected int defaultCacheLevel(JmsEndpoint endpoint) { return DefaultMessageListenerContainer.CACHE_AUTO; } /** * Factory method which allows derived classes to customize the lazy creation */ protected ConnectionFactory createConnectionFactory() { ObjectHelper.notNull(connectionFactory, "connectionFactory"); return null; } /** * Factory method which allows derived classes to customize the lazy creation */ protected ConnectionFactory createListenerConnectionFactory() { return getOrCreateConnectionFactory(); } /** * Factory method which allows derived classes to customize the lazy creation */ protected ConnectionFactory createTemplateConnectionFactory() { return getOrCreateConnectionFactory(); } /** * Factory method which which allows derived classes to customize the lazy transaction manager creation */ protected PlatformTransactionManager createTransactionManager() { JmsTransactionManager answer = new JmsTransactionManager(); answer.setConnectionFactory(getOrCreateConnectionFactory()); return answer; } public boolean isPreserveMessageQos() { return preserveMessageQos; } /** * When one of the QoS properties are configured such as {@link #setDeliveryPersistent(boolean)}, * {@link #setPriority(int)} or {@link #setTimeToLive(long)} then we should auto default the setting of * {@link #setExplicitQosEnabled(boolean)} if its not been configured yet */ protected void configuredQoS() { if (explicitQosEnabled == null) { explicitQosEnabled = true; } } public boolean isAlwaysCopyMessage() { return alwaysCopyMessage; } /** * If true, Camel will always make a JMS message copy of the message when it is passed to the producer for sending. * Copying the message is needed in some situations, such as when a replyToDestinationSelectorName is set * (incidentally, Camel will set the alwaysCopyMessage option to true, if a replyToDestinationSelectorName is set) */ public void setAlwaysCopyMessage(boolean alwaysCopyMessage) { this.alwaysCopyMessage = alwaysCopyMessage; } public boolean isUseMessageIDAsCorrelationID() { return useMessageIDAsCorrelationID; } /** * Specifies whether JMSMessageID should always be used as JMSCorrelationID for InOut messages. */ public void setUseMessageIDAsCorrelationID(boolean useMessageIDAsCorrelationID) { this.useMessageIDAsCorrelationID = useMessageIDAsCorrelationID; } public long getRequestTimeout() { return requestTimeout; } /** * The timeout for waiting for a reply when using the InOut Exchange Pattern (in milliseconds). The default is 20 * seconds. You can include the header "CamelJmsRequestTimeout" to override this endpoint configured timeout value, * and thus have per message individual timeout values. See also the requestTimeoutCheckerInterval option. */ public void setRequestTimeout(long requestTimeout) { this.requestTimeout = requestTimeout; } public long getRequestTimeoutCheckerInterval() { return requestTimeoutCheckerInterval; } /** * Configures how often Camel should check for timed out Exchanges when doing request/reply over JMS. By default * Camel checks once per second. But if you must react faster when a timeout occurs, then you can lower this * interval, to check more frequently. The timeout is determined by the option requestTimeout. */ public void setRequestTimeoutCheckerInterval(long requestTimeoutCheckerInterval) { this.requestTimeoutCheckerInterval = requestTimeoutCheckerInterval; } public String getReplyTo() { return replyTo; } /** * Provides an explicit ReplyTo destination, which overrides any incoming value of Message.getJMSReplyTo(). */ public void setReplyTo(String replyToDestination) { this.replyTo = normalizeDestinationName(replyToDestination); } public String getReplyToDestinationSelectorName() { return replyToDestinationSelectorName; } /** * Sets the JMS Selector using the fixed name to be used so you can filter out your own replies from the others when * using a shared queue (that is, if you are not using a temporary reply queue). */ public void setReplyToDestinationSelectorName(String replyToDestinationSelectorName) { this.replyToDestinationSelectorName = replyToDestinationSelectorName; // in case of consumer -> producer and a named replyTo correlation selector // message pass through is impossible as we need to set the value of selector into // outgoing message, which would be read-only if pass through were to remain enabled if (replyToDestinationSelectorName != null) { setAlwaysCopyMessage(true); } } public String getReplyToOverride() { return replyToOverride; } /** * Provides an explicit ReplyTo destination in the JMS message, which overrides the setting of replyTo. It is useful * if you want to forward the message to a remote Queue and receive the reply message from the ReplyTo destination. */ public void setReplyToOverride(String replyToDestination) { this.replyToOverride = normalizeDestinationName(replyToDestination); } public boolean isReplyToSameDestinationAllowed() { return replyToSameDestinationAllowed; } /** * Whether a JMS consumer is allowed to send a reply message to the same destination that the consumer is using to * consume from. This prevents an endless loop by consuming and sending back the same message to itself. */ public void setReplyToSameDestinationAllowed(boolean replyToSameDestinationAllowed) { this.replyToSameDestinationAllowed = replyToSameDestinationAllowed; } public JmsMessageType getJmsMessageType() { return jmsMessageType; } /** * Allows you to force the use of a specific jakarta.jms.Message implementation for sending JMS messages. Possible * values are: Bytes, Map, Object, Stream, Text. By default, Camel would determine which JMS message type to use * from the In body type. This option allows you to specify it. */ public void setJmsMessageType(JmsMessageType jmsMessageType) { if (jmsMessageType == JmsMessageType.Blob && !supportBlobMessage()) { throw new IllegalArgumentException("BlobMessage is not supported by this implementation"); } this.jmsMessageType = jmsMessageType; } /** * Should get overridden by implementations which support BlobMessages * * @return false */ protected boolean supportBlobMessage() { return false; } public JmsKeyFormatStrategy getJmsKeyFormatStrategy() { if (jmsKeyFormatStrategy == null) { jmsKeyFormatStrategy = new DefaultJmsKeyFormatStrategy(); } return jmsKeyFormatStrategy; } /** * Pluggable strategy for encoding and decoding JMS keys so they can be compliant with the JMS specification. Camel * provides two implementations out of the box: default and passthrough. The default strategy will safely marshal * dots and hyphens (. and -). The passthrough strategy leaves the key as is. Can be used for JMS brokers which do * not care whether JMS header keys contain illegal characters. You can provide your own implementation of the * org.apache.camel.component.jms.JmsKeyFormatStrategy and refer to it using the # notation. */ public void setJmsKeyFormatStrategy(JmsKeyFormatStrategy jmsKeyFormatStrategy) { this.jmsKeyFormatStrategy = jmsKeyFormatStrategy; } public boolean isTransferExchange() { return transferExchange; } /** * You can transfer the exchange over the wire instead of just the body and headers. The following fields are * transferred: In body, Out body, Fault body, In headers, Out headers, Fault headers, exchange properties, exchange * exception. This requires that the objects are serializable. Camel will exclude any non-serializable objects and * log it at WARN level. You must enable this option on both the producer and consumer side, so Camel knows the * payloads is an Exchange and not a regular payload. Use this with caution as the data is using Java Object * serialization and requires the receiver to be able to deserialize the data at Class level, which forces a strong * coupling between the producers and consumers having to use compatible Camel versions! */ public void setTransferExchange(boolean transferExchange) { this.transferExchange = transferExchange; } public boolean isAllowSerializedHeaders() { return allowSerializedHeaders; } /** * Controls whether or not to include serialized headers. Applies only when {@link #isTransferExchange()} is * {@code true}. This requires that the objects are serializable. Camel will exclude any non-serializable objects * and log it at WARN level. */ public void setAllowSerializedHeaders(boolean allowSerializedHeaders) { this.allowSerializedHeaders = allowSerializedHeaders; } public boolean isTransferException() { return transferException; } /** * If enabled and you are using Request Reply messaging (InOut) and an Exchange failed on the consumer side, then * the caused Exception will be send back in response as a jakarta.jms.ObjectMessage. If the client is Camel, the * returned Exception is rethrown. This allows you to use Camel JMS as a bridge in your routing - for example, using * persistent queues to enable robust routing. Notice that if you also have transferExchange enabled, this option * takes precedence. The caught exception is required to be serializable. The original Exception on the consumer * side can be wrapped in an outer exception such as org.apache.camel.RuntimeCamelException when returned to the * producer. Use this with caution as the data is using Java Object serialization and requires the received to be * able to deserialize the data at Class level, which forces a strong coupling between the producers and consumer! */ public void setTransferException(boolean transferException) { this.transferException = transferException; } public boolean isAsyncStartListener() { return asyncStartListener; } /** * Whether to startup the JmsConsumer message listener asynchronously, when starting a route. For example if a * JmsConsumer cannot get a connection to a remote JMS broker, then it may block while retrying and/or failover. * This will cause Camel to block while starting routes. By setting this option to true, you will let routes * startup, while the JmsConsumer connects to the JMS broker using a dedicated thread in asynchronous mode. If this * option is used, then beware that if the connection could not be established, then an exception is logged at WARN * level, and the consumer will not be able to receive messages; You can then restart the route to retry. */ public void setAsyncStartListener(boolean asyncStartListener) { this.asyncStartListener = asyncStartListener; } public boolean isAsyncStopListener() { return asyncStopListener; } /** * Whether to stop the JmsConsumer message listener asynchronously, when stopping a route. */ public void setAsyncStopListener(boolean asyncStopListener) { this.asyncStopListener = asyncStopListener; } public boolean isTestConnectionOnStartup() { return testConnectionOnStartup; } /** * Specifies whether to test the connection on startup. This ensures that when Camel starts that all the JMS * consumers have a valid connection to the JMS broker. If a connection cannot be granted then Camel throws an * exception on startup. This ensures that Camel is not started with failed connections. The JMS producers is tested * as well. */ public void setTestConnectionOnStartup(boolean testConnectionOnStartup) { this.testConnectionOnStartup = testConnectionOnStartup; } /** * When using mapJmsMessage=false Camel will create a new JMS message to send to a new JMS destination if you touch * the headers (get or set) during the route. Set this option to true to force Camel to send the original JMS * message that was received. */ public void setForceSendOriginalMessage(boolean forceSendOriginalMessage) { this.forceSendOriginalMessage = forceSendOriginalMessage; } public boolean isForceSendOriginalMessage() { return forceSendOriginalMessage; } public boolean isDisableTimeToLive() { return disableTimeToLive; } /** * Use this option to force disabling time to live. For example when you do request/reply over JMS, then Camel will * by default use the requestTimeout value as time to live on the message being sent. The problem is that the sender * and receiver systems have to have their clocks synchronized, so they are in sync. This is not always so easy to * archive. So you can use disableTimeToLive=true to not set a time to live value on the sent message. Then the * message will not expire on the receiver system. See below in section About time to live for more details. */ public void setDisableTimeToLive(boolean disableTimeToLive) { this.disableTimeToLive = disableTimeToLive; } public ReplyToType getReplyToType() { return replyToType; } /** * Allows for explicitly specifying which kind of strategy to use for replyTo queues when doing request/reply over * JMS. Possible values are: Temporary, Shared, or Exclusive. By default Camel will use temporary queues. However if * replyTo has been configured, then Shared is used by default. This option allows you to use exclusive queues * instead of shared ones. See Camel JMS documentation for more details, and especially the notes about the * implications if running in a clustered environment, and the fact that Shared reply queues has lower performance * than its alternatives Temporary and Exclusive. */ public void setReplyToType(ReplyToType replyToType) { this.replyToType = replyToType; } public boolean isAsyncConsumer() { return asyncConsumer; } /** * Whether the JmsConsumer processes the Exchange asynchronously. If enabled then the JmsConsumer may pickup the * next message from the JMS queue, while the previous message is being processed asynchronously (by the * Asynchronous Routing Engine). This means that messages may be processed not 100% strictly in order. If disabled * (as default) then the Exchange is fully processed before the JmsConsumer will pickup the next message from the * JMS queue. Note if transacted has been enabled, then asyncConsumer=true does not run asynchronously, as * transaction must be executed synchronously (Camel 3.0 may support async transactions). */ public void setAsyncConsumer(boolean asyncConsumer) { this.asyncConsumer = asyncConsumer; } /** * Sets the cache level by name for the reply consumer when doing request/reply over JMS. This option only applies * when using fixed reply queues (not temporary). Camel will by default use: CACHE_CONSUMER for exclusive or shared * w/ replyToSelectorName. And CACHE_SESSION for shared without replyToSelectorName. Some JMS brokers such as IBM * WebSphere may require to set the replyToCacheLevelName=CACHE_NONE to work. Note: If using temporary queues then * CACHE_NONE is not allowed, and you must use a higher value such as CACHE_CONSUMER or CACHE_SESSION. */ public void setReplyToCacheLevelName(String name) { this.replyToCacheLevelName = name; } public String getReplyToCacheLevelName() { return replyToCacheLevelName; } public boolean isAllowNullBody() { return allowNullBody; } /** * Whether to allow sending messages with no body. If this option is false and the message body is null, then an * JMSException is thrown. */ public void setAllowNullBody(boolean allowNullBody) { this.allowNullBody = allowNullBody; } public MessageListenerContainerFactory getMessageListenerContainerFactory() { return messageListenerContainerFactory; } /** * Registry ID of the MessageListenerContainerFactory used to determine what * org.springframework.jms.listener.AbstractMessageListenerContainer to use to consume messages. Setting this will * automatically set consumerType to Custom. */ public void setMessageListenerContainerFactory(MessageListenerContainerFactory messageListenerContainerFactory) { this.messageListenerContainerFactory = messageListenerContainerFactory; } public boolean isIncludeSentJMSMessageID() { return includeSentJMSMessageID; } /** * Only applicable when sending to JMS destination using InOnly (eg fire and forget). Enabling this option will * enrich the Camel Exchange with the actual JMSMessageID that was used by the JMS client when the message was sent * to the JMS destination. */ public void setIncludeSentJMSMessageID(boolean includeSentJMSMessageID) { this.includeSentJMSMessageID = includeSentJMSMessageID; } public DefaultTaskExecutorType getDefaultTaskExecutorType() { return defaultTaskExecutorType; } /** * Specifies what default TaskExecutor type to use in the DefaultMessageListenerContainer, for both consumer * endpoints and the ReplyTo consumer of producer endpoints. Possible values: SimpleAsync (uses Spring's * SimpleAsyncTaskExecutor) or ThreadPool (uses Spring's ThreadPoolTaskExecutor with optimal values - cached * threadpool-like). If not set, it defaults to the previous behaviour, which uses a cached thread pool for consumer * endpoints and SimpleAsync for reply consumers. The use of ThreadPool is recommended to reduce "thread trash" in * elastic configurations with dynamically increasing and decreasing concurrent consumers. */ public void setDefaultTaskExecutorType(DefaultTaskExecutorType defaultTaskExecutorType) { this.defaultTaskExecutorType = defaultTaskExecutorType; } public boolean isIncludeAllJMSXProperties() { return includeAllJMSXProperties; } /** * Whether to include all JMSXxxx properties when mapping from JMS to Camel Message. Setting this to true will * include properties such as JMSXAppID, and JMSXUserID etc. Note: If you are using a custom headerFilterStrategy * then this option does not apply. */ public void setIncludeAllJMSXProperties(boolean includeAllJMSXProperties) { this.includeAllJMSXProperties = includeAllJMSXProperties; } public MessageCreatedStrategy getMessageCreatedStrategy() { return messageCreatedStrategy; } /** * To use the given MessageCreatedStrategy which are invoked when Camel creates new instances of * jakarta.jms.Message objects when Camel is sending a JMS message. */ public void setMessageCreatedStrategy(MessageCreatedStrategy messageCreatedStrategy) { this.messageCreatedStrategy = messageCreatedStrategy; } public String getSelector() { return selector; } /** * Sets the JMS selector to use */ public void setSelector(String selector) { this.selector = selector; } /** * Use this JMS property to correlate messages in InOut exchange pattern (request-reply) instead of JMSCorrelationID * property. This allows you to exchange messages with systems that do not correlate messages using JMSCorrelationID * JMS property. If used JMSCorrelationID will not be used or set by Camel. The value of here named property will be * generated if not supplied in the header of the message under the same name. */ public void setCorrelationProperty(final String correlationProperty) { this.correlationProperty = correlationProperty; } public String getCorrelationProperty() { return correlationProperty; } public String getAllowAdditionalHeaders() { return allowAdditionalHeaders; } /** * This option is used to allow additional headers which may have values that are invalid according to JMS * specification. + For example some message systems such as WMQ do this with header names using prefix * JMS_IBM_MQMD_ containing values with byte array or other invalid types. + You can specify multiple header names * separated by comma, and use * as suffix for wildcard matching. */ public void setAllowAdditionalHeaders(String allowAdditionalHeaders) { this.allowAdditionalHeaders = allowAdditionalHeaders; } public boolean isSubscriptionDurable() { return subscriptionDurable; } /** * Set whether to make the subscription durable. The durable subscription name to be used can be specified through * the "subscriptionName" property. *

* Default is "false". Set this to "true" to register a durable subscription, typically in combination with a * "subscriptionName" value (unless your message listener class name is good enough as subscription name). *

* Only makes sense when listening to a topic (pub-sub domain), therefore this method switches the "pubSubDomain" * flag as well. */ public void setSubscriptionDurable(boolean subscriptionDurable) { this.subscriptionDurable = subscriptionDurable; } public boolean isSubscriptionShared() { return subscriptionShared; } /** * Set whether to make the subscription shared. The shared subscription name to be used can be specified through the * "subscriptionName" property. *

* Default is "false". Set this to "true" to register a shared subscription, typically in combination with a * "subscriptionName" value (unless your message listener class name is good enough as subscription name). Note that * shared subscriptions may also be durable, so this flag can (and often will) be combined with * "subscriptionDurable" as well. *

* Only makes sense when listening to a topic (pub-sub domain), therefore this method switches the "pubSubDomain" * flag as well. *

* Requires a JMS 2.0 compatible message broker. */ public void setSubscriptionShared(boolean subscriptionShared) { this.subscriptionShared = subscriptionShared; } public String getSubscriptionName() { return subscriptionName; } /** * Set the name of a subscription to create. To be applied in case of a topic (pub-sub domain) with a shared or * durable subscription. *

* The subscription name needs to be unique within this client's JMS client id. Default is the class name of the * specified message listener. *

* Note: Only 1 concurrent consumer (which is the default of this message listener container) is allowed for each * subscription, except for a shared subscription (which requires JMS 2.0). */ public void setSubscriptionName(String subscriptionName) { this.subscriptionName = subscriptionName; } public boolean isStreamMessageTypeEnabled() { return streamMessageTypeEnabled; } /** * Sets whether StreamMessage type is enabled or not. Message payloads of streaming kind such as files, InputStream, * etc will either by sent as BytesMessage or StreamMessage. This option controls which kind will be used. By * default BytesMessage is used which enforces the entire message payload to be read into memory. By enabling this * option the message payload is read into memory in chunks and each chunk is then written to the StreamMessage * until no more data. */ public void setStreamMessageTypeEnabled(boolean streamMessageTypeEnabled) { this.streamMessageTypeEnabled = streamMessageTypeEnabled; } /** * Gets whether date headers should be formatted according to the ISO 8601 standard. */ public boolean isFormatDateHeadersToIso8601() { return formatDateHeadersToIso8601; } /** * Sets whether date headers should be formatted according to the ISO 8601 standard. */ public void setFormatDateHeadersToIso8601(boolean formatDateHeadersToIso8601) { this.formatDateHeadersToIso8601 = formatDateHeadersToIso8601; } public long getDeliveryDelay() { return deliveryDelay; } /** * Sets delivery delay to use for send calls for JMS. This option requires JMS 2.0 compliant broker. */ public void setDeliveryDelay(long deliveryDelay) { this.deliveryDelay = deliveryDelay; } public boolean isArtemisStreamingEnabled() { return artemisStreamingEnabled; } /** * Whether optimizing for Apache Artemis streaming mode. This can reduce memory overhead when using Artemis with JMS * StreamMessage types. This option must only be enabled if Apache Artemis is being used. */ public void setArtemisStreamingEnabled(boolean artemisStreamingEnabled) { this.artemisStreamingEnabled = artemisStreamingEnabled; } public void setArtemisConsumerPriority(int priority) { this.artemisConsumerPriority = priority; } public int getArtemisConsumerPriority() { return artemisConsumerPriority; } public boolean isSynchronous() { return synchronous; } public void setSynchronous(boolean synchronous) { this.synchronous = synchronous; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy