Add support for configuring non-standard JMS acknowledge modes

Prior to this commit, `spring.jms.listener.session.acknowledge-mode`
and `spring.jms.template.session.acknowledge-mode` accepted only a
predefined set of values representing standard JMS acknowledge modes.

This commit adds support for also using arbitrary integer values to
these configuration properties, which allows vendor-specific JMS
acknowledge modes to be configured.

See gh-37576
This commit is contained in:
Vedran Pavic 2023-09-25 16:50:09 +02:00 committed by Andy Wilkinson
parent 5556739c8c
commit d72fb8e127
5 changed files with 93 additions and 53 deletions

View File

@ -111,7 +111,9 @@ public final class DefaultJmsListenerContainerFactoryConfigurer {
map.from(this.destinationResolver).to(factory::setDestinationResolver);
map.from(this.messageConverter).to(factory::setMessageConverter);
map.from(this.exceptionListener).to(factory::setExceptionListener);
map.from(sessionProperties.getAcknowledgeMode()::getMode).to(factory::setSessionAcknowledgeMode);
map.from(sessionProperties.getAcknowledgeMode())
.as(JmsAcknowledgeModeMapper::map)
.to(factory::setSessionAcknowledgeMode);
if (this.transactionManager == null && sessionProperties.getTransacted() == null) {
factory.setSessionTransacted(true);
}

View File

@ -0,0 +1,46 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.autoconfigure.jms;
import java.util.HashMap;
import java.util.Map;
import jakarta.jms.Session;
/**
* Helper class used to map JMS acknowledge modes.
*
* @author Vedran Pavic
*/
final class JmsAcknowledgeModeMapper {
private static final Map<String, Integer> acknowledgeModes = new HashMap<>(3);
static {
acknowledgeModes.put("auto", Session.AUTO_ACKNOWLEDGE);
acknowledgeModes.put("client", Session.CLIENT_ACKNOWLEDGE);
acknowledgeModes.put("dups_ok", Session.DUPS_OK_ACKNOWLEDGE);
}
private JmsAcknowledgeModeMapper() {
}
static int map(String acknowledgeMode) {
return acknowledgeModes.computeIfAbsent(acknowledgeMode.toLowerCase(), Integer::parseInt);
}
}

View File

@ -28,7 +28,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.autoconfigure.jms.JmsProperties.AcknowledgeMode;
import org.springframework.boot.autoconfigure.jms.JmsProperties.DeliveryMode;
import org.springframework.boot.autoconfigure.jms.JmsProperties.Template;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@ -91,8 +90,8 @@ public class JmsAutoConfiguration {
private void mapTemplateProperties(Template properties, JmsTemplate template) {
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
map.from(properties.getSession()::getAcknowledgeMode)
.asInt(AcknowledgeMode::getMode)
.to(template::setSessionAcknowledgeMode);
.to((acknowledgeMode) -> template
.setSessionAcknowledgeMode(JmsAcknowledgeModeMapper.map(acknowledgeMode)));
map.from(properties.getSession()::isTransacted).to(template::setSessionTransacted);
map.from(properties::getDefaultDestination).whenNonNull().to(template::setDefaultDestinationName);
map.from(properties::getDeliveryDelay).whenNonNull().as(Duration::toMillis).to(template::setDeliveryDelay);

View File

@ -171,12 +171,12 @@ public class JmsProperties {
@Deprecated(since = "3.2.0", forRemoval = true)
@DeprecatedConfigurationProperty(replacement = "spring.jms.listener.session.acknowledge-mode", since = "3.2.0")
public AcknowledgeMode getAcknowledgeMode() {
public String getAcknowledgeMode() {
return this.session.getAcknowledgeMode();
}
@Deprecated(since = "3.2.0", forRemoval = true)
public void setAcknowledgeMode(AcknowledgeMode acknowledgeMode) {
public void setAcknowledgeMode(String acknowledgeMode) {
this.session.setAcknowledgeMode(acknowledgeMode);
}
@ -232,7 +232,7 @@ public class JmsProperties {
/**
* Acknowledge mode of the listener container.
*/
private AcknowledgeMode acknowledgeMode = AcknowledgeMode.AUTO;
private String acknowledgeMode = "auto";
/**
* Whether the listener container should use transacted JMS sessions. Defaults
@ -240,11 +240,11 @@ public class JmsProperties {
*/
private Boolean transacted;
public AcknowledgeMode getAcknowledgeMode() {
public String getAcknowledgeMode() {
return this.acknowledgeMode;
}
public void setAcknowledgeMode(AcknowledgeMode acknowledgeMode) {
public void setAcknowledgeMode(String acknowledgeMode) {
this.acknowledgeMode = acknowledgeMode;
}
@ -376,18 +376,18 @@ public class JmsProperties {
/**
* Acknowledge mode used when creating sessions.
*/
private AcknowledgeMode acknowledgeMode = AcknowledgeMode.AUTO;
private String acknowledgeMode = "auto";
/**
* Whether to use transacted sessions.
*/
private boolean transacted = false;
public AcknowledgeMode getAcknowledgeMode() {
public String getAcknowledgeMode() {
return this.acknowledgeMode;
}
public void setAcknowledgeMode(AcknowledgeMode acknowledgeMode) {
public void setAcknowledgeMode(String acknowledgeMode) {
this.acknowledgeMode = acknowledgeMode;
}
@ -403,47 +403,6 @@ public class JmsProperties {
}
/**
* Translate the acknowledge modes defined on the {@link jakarta.jms.Session}.
*
* <p>
* {@link jakarta.jms.Session#SESSION_TRANSACTED} is not defined as we take care of
* this already through a call to {@code setSessionTransacted}.
*/
public enum AcknowledgeMode {
/**
* Messages sent or received from the session are automatically acknowledged. This
* is the simplest mode and enables once-only message delivery guarantee.
*/
AUTO(1),
/**
* Messages are acknowledged once the message listener implementation has called
* {@link jakarta.jms.Message#acknowledge()}. This mode gives the application
* (rather than the JMS provider) complete control over message acknowledgement.
*/
CLIENT(2),
/**
* Similar to auto acknowledgment except that said acknowledgment is lazy. As a
* consequence, the messages might be delivered more than once. This mode enables
* at-least-once message delivery guarantee.
*/
DUPS_OK(3);
private final int mode;
AcknowledgeMode(int mode) {
this.mode = mode;
}
public int getMode() {
return this.mode;
}
}
public enum DeliveryMode {
/**

View File

@ -3011,6 +3011,40 @@
}
]
},
{
"name": "spring.jms.listener.session.acknowledge-mode",
"values": [
{
"value": "auto",
"description": "Messages sent or received from the session are automatically acknowledged. This is the simplest mode and enables once-only message delivery guarantee."
},
{
"value": "client",
"description": "Messages are acknowledged once the message listener implementation has called \"jakarta.jms.Message#acknowledge()\". This mode gives the application (rather than the JMS provider) complete control over message acknowledgement."
},
{
"value": "dups_ok",
"description": "Similar to auto acknowledgment except that said acknowledgment is lazy. As a consequence, the messages might be delivered more than once. This mode enables at-least-once message delivery guarantee."
}
]
},
{
"name": "spring.jms.template.session.acknowledge-mode",
"values": [
{
"value": "auto",
"description": "Messages sent or received from the session are automatically acknowledged. This is the simplest mode and enables once-only message delivery guarantee."
},
{
"value": "client",
"description": "Messages are acknowledged once the message listener implementation has called \"jakarta.jms.Message#acknowledge()\". This mode gives the application (rather than the JMS provider) complete control over message acknowledgement."
},
{
"value": "dups_ok",
"description": "Similar to auto acknowledgment except that said acknowledgment is lazy. As a consequence, the messages might be delivered more than once. This mode enables at-least-once message delivery guarantee."
}
]
},
{
"name": "spring.jmx.server",
"providers": [