Remove support for Artemis

Closes gh-28593
pull/28862/head
Madhura Bhave 3 years ago committed by Andy Wilkinson
parent 8bf2ffd93c
commit c8fd5f0080

@ -158,17 +158,6 @@ dependencies {
exclude group: "org.jboss.spec.javax.servlet", module: "jboss-servlet-api_4.0_spec"
}
testImplementation("jakarta.xml.bind:jakarta.xml.bind-api")
testImplementation("org.apache.activemq:artemis-jms-client") {
exclude group: "commons-logging", module: "commons-logging"
exclude group: "org.apache.geronimo.specs", module: "geronimo-jms_2.0_spec"
exclude group: "org.apache.geronimo.specs", module: "geronimo-json_1.0_spec"
}
testImplementation("org.apache.activemq:artemis-jms-server") {
exclude group: "commons-logging", module: "commons-logging"
exclude group: "org.apache.geronimo.specs", module: "geronimo-jms_2.0_spec"
exclude group: "org.apache.geronimo.specs", module: "geronimo-json_1.0_spec"
exclude group: "org.apache.geronimo.specs", module: "geronimo-jta_1.1_spec"
}
testImplementation("org.apache.logging.log4j:log4j-to-slf4j")
testImplementation("org.aspectj:aspectjrt")
testImplementation("org.assertj:assertj-core")

@ -24,12 +24,10 @@ import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthCont
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
import org.springframework.boot.actuate.health.HealthContributor;
import org.springframework.boot.actuate.jms.JmsHealthIndicator;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
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.jms.artemis.ArtemisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -43,7 +41,6 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnClass(ConnectionFactory.class)
@ConditionalOnBean(ConnectionFactory.class)
@ConditionalOnEnabledHealthIndicator("jms")
@AutoConfigureAfter(ArtemisAutoConfiguration.class)
public class JmsHealthContributorAutoConfiguration
extends CompositeHealthContributorConfiguration<JmsHealthIndicator, ConnectionFactory> {

@ -16,16 +16,20 @@
package org.springframework.boot.actuate.autoconfigure.jms;
import javax.jms.ConnectionFactory;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
import org.springframework.boot.actuate.jms.JmsHealthIndicator;
import org.springframework.boot.actuate.ldap.LdapHealthIndicator;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link JmsHealthContributorAutoConfiguration}.
@ -35,8 +39,9 @@ import static org.assertj.core.api.Assertions.assertThat;
class JmsHealthContributorAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ArtemisAutoConfiguration.class,
JmsHealthContributorAutoConfiguration.class, HealthContributorAutoConfiguration.class));
.withConfiguration(AutoConfigurations.of(JmsHealthContributorAutoConfiguration.class,
HealthContributorAutoConfiguration.class))
.withUserConfiguration(TestConfiguration.class);
@Test
void runShouldCreateIndicator() {
@ -49,4 +54,14 @@ class JmsHealthContributorAutoConfigurationTests {
.run((context) -> assertThat(context).doesNotHaveBean(LdapHealthIndicator.class));
}
@Configuration(proxyBeanMethods = false)
static class TestConfiguration {
@Bean
ConnectionFactory connectionFactory() {
return mock(ConnectionFactory.class);
}
}
}

@ -52,17 +52,6 @@ dependencies {
optional("jakarta.ws.rs:jakarta.ws.rs-api")
optional("javax.cache:cache-api")
optional("javax.money:money-api")
optional("org.apache.activemq:artemis-jms-client") {
exclude group: "commons-logging", module: "commons-logging"
exclude group: "org.apache.geronimo.specs", module: "geronimo-jms_2.0_spec"
exclude group: "org.apache.geronimo.specs", module: "geronimo-json_1.0_spec"
}
optional("org.apache.activemq:artemis-jms-server") {
exclude group: "commons-logging", module: "commons-logging"
exclude group: "org.apache.geronimo.specs", module: "geronimo-jms_2.0_spec"
exclude group: "org.apache.geronimo.specs", module: "geronimo-json_1.0_spec"
exclude group: "org.apache.geronimo.specs", module: "geronimo-jta_1.1_spec"
}
optional("org.apache.commons:commons-dbcp2") {
exclude group: "commons-logging", module: "commons-logging"
}
@ -91,7 +80,7 @@ dependencies {
exclude(group: "org.eclipse.jetty", module: "jetty-jndi")
}
optional("org.eclipse.jetty:jetty-reactive-httpclient")
optional("org.eclipse.jetty.websocket:javax-websocket-server-impl") {
optional("org.eclipse.jetty.websocket:javax-websocket-server-impl") {
exclude group: "javax.annotation", module: "javax.annotation-api"
exclude group: "javax.servlet", module: "javax.servlet-api"
exclude group: "javax.websocket", module: "javax.websocket-api"
@ -193,7 +182,7 @@ dependencies {
optional("org.springframework.session:spring-session-data-redis")
optional("org.springframework.session:spring-session-hazelcast") {
exclude group: "javax.annotation", module: "javax.annotation-api"
}
}
optional("org.springframework.session:spring-session-jdbc")
optional("org.springframework.amqp:spring-rabbit")
optional("org.springframework.amqp:spring-rabbit-stream")

@ -1,56 +0,0 @@
/*
* Copyright 2012-2019 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.artemis;
import javax.jms.ConnectionFactory;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
import org.springframework.boot.autoconfigure.jms.JmsProperties;
import org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* {@link EnableAutoConfiguration Auto-configuration} to integrate with an Artemis broker.
* If the necessary classes are present, embed the broker in the application by default.
* Otherwise, connect to a broker available on the local machine with the default
* settings.
*
* @author Eddú Meléndez
* @author Stephane Nicoll
* @since 1.3.0
* @see ArtemisProperties
*/
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(JmsAutoConfiguration.class)
@AutoConfigureAfter({ JndiConnectionFactoryAutoConfiguration.class })
@ConditionalOnClass({ ConnectionFactory.class, ActiveMQConnectionFactory.class })
@ConditionalOnMissingBean(ConnectionFactory.class)
@EnableConfigurationProperties({ ArtemisProperties.class, JmsProperties.class })
@Import({ ArtemisEmbeddedServerConfiguration.class, ArtemisXAConnectionFactoryConfiguration.class,
ArtemisConnectionFactoryConfiguration.class })
public class ArtemisAutoConfiguration {
}

@ -1,41 +0,0 @@
/*
* Copyright 2012-2020 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.artemis;
import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;
/**
* Callback interface that can be implemented by beans wishing to customize the Artemis
* JMS server {@link Configuration} before it is used by an auto-configured
* {@link EmbeddedActiveMQ} instance.
*
* @author Eddú Meléndez
* @author Phillip Webb
* @since 1.3.0
* @see ArtemisAutoConfiguration
*/
@FunctionalInterface
public interface ArtemisConfigurationCustomizer {
/**
* Customize the configuration.
* @param configuration the configuration to customize
*/
void customize(Configuration configuration);
}

@ -1,101 +0,0 @@
/*
* Copyright 2012-2020 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.artemis;
import javax.jms.ConnectionFactory;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.apache.commons.pool2.PooledObject;
import org.messaginghub.pooled.jms.JmsPoolConnectionFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jms.JmsPoolConnectionFactoryFactory;
import org.springframework.boot.autoconfigure.jms.JmsProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.connection.CachingConnectionFactory;
/**
* Configuration for Artemis {@link ConnectionFactory}.
*
* @author Eddú Meléndez
* @author Phillip Webb
* @author Stephane Nicoll
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(ConnectionFactory.class)
class ArtemisConnectionFactoryConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(CachingConnectionFactory.class)
@ConditionalOnProperty(prefix = "spring.artemis.pool", name = "enabled", havingValue = "false",
matchIfMissing = true)
static class SimpleConnectionFactoryConfiguration {
private final ArtemisProperties properties;
private final ListableBeanFactory beanFactory;
SimpleConnectionFactoryConfiguration(ArtemisProperties properties, ListableBeanFactory beanFactory) {
this.properties = properties;
this.beanFactory = beanFactory;
}
@Bean(name = "jmsConnectionFactory")
@ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "true",
matchIfMissing = true)
CachingConnectionFactory cachingJmsConnectionFactory(JmsProperties jmsProperties) {
JmsProperties.Cache cacheProperties = jmsProperties.getCache();
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(createConnectionFactory());
connectionFactory.setCacheConsumers(cacheProperties.isConsumers());
connectionFactory.setCacheProducers(cacheProperties.isProducers());
connectionFactory.setSessionCacheSize(cacheProperties.getSessionCacheSize());
return connectionFactory;
}
@Bean(name = "jmsConnectionFactory")
@ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "false")
ActiveMQConnectionFactory jmsConnectionFactory() {
return createConnectionFactory();
}
private ActiveMQConnectionFactory createConnectionFactory() {
return new ArtemisConnectionFactoryFactory(this.beanFactory, this.properties)
.createConnectionFactory(ActiveMQConnectionFactory.class);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ JmsPoolConnectionFactory.class, PooledObject.class })
@ConditionalOnProperty(prefix = "spring.artemis.pool", name = "enabled", havingValue = "true")
static class PooledConnectionFactoryConfiguration {
@Bean(destroyMethod = "stop")
JmsPoolConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory, ArtemisProperties properties) {
ActiveMQConnectionFactory connectionFactory = new ArtemisConnectionFactoryFactory(beanFactory, properties)
.createConnectionFactory(ActiveMQConnectionFactory.class);
return new JmsPoolConnectionFactoryFactory(properties.getPool())
.createPooledConnectionFactory(connectionFactory);
}
}
}

@ -1,161 +0,0 @@
/*
* Copyright 2012-2020 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.artemis;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
import org.apache.activemq.artemis.api.core.client.ServerLocator;
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* Factory to create an Artemis {@link ActiveMQConnectionFactory} instance from properties
* defined in {@link ArtemisProperties}.
*
* @author Eddú Meléndez
* @author Phillip Webb
* @author Stephane Nicoll
* @author Justin Bertram
*/
class ArtemisConnectionFactoryFactory {
private static final String DEFAULT_BROKER_URL = "tcp://localhost:61616";
static final String[] EMBEDDED_JMS_CLASSES = { "org.apache.activemq.artemis.jms.server.embedded.EmbeddedJMS",
"org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ" };
private final ArtemisProperties properties;
private final ListableBeanFactory beanFactory;
ArtemisConnectionFactoryFactory(ListableBeanFactory beanFactory, ArtemisProperties properties) {
Assert.notNull(beanFactory, "BeanFactory must not be null");
Assert.notNull(properties, "Properties must not be null");
this.beanFactory = beanFactory;
this.properties = properties;
}
<T extends ActiveMQConnectionFactory> T createConnectionFactory(Class<T> factoryClass) {
try {
startEmbeddedJms();
return doCreateConnectionFactory(factoryClass);
}
catch (Exception ex) {
throw new IllegalStateException("Unable to create ActiveMQConnectionFactory", ex);
}
}
private void startEmbeddedJms() {
for (String embeddedJmsClass : EMBEDDED_JMS_CLASSES) {
if (ClassUtils.isPresent(embeddedJmsClass, null)) {
try {
this.beanFactory.getBeansOfType(Class.forName(embeddedJmsClass));
}
catch (Exception ex) {
// Ignore
}
}
}
}
private <T extends ActiveMQConnectionFactory> T doCreateConnectionFactory(Class<T> factoryClass) throws Exception {
ArtemisMode mode = this.properties.getMode();
if (mode == null) {
mode = deduceMode();
}
if (mode == ArtemisMode.EMBEDDED) {
return createEmbeddedConnectionFactory(factoryClass);
}
return createNativeConnectionFactory(factoryClass);
}
/**
* Deduce the {@link ArtemisMode} to use if none has been set.
* @return the mode
*/
private ArtemisMode deduceMode() {
if (this.properties.getEmbedded().isEnabled() && isEmbeddedJmsClassPresent()) {
return ArtemisMode.EMBEDDED;
}
return ArtemisMode.NATIVE;
}
private boolean isEmbeddedJmsClassPresent() {
for (String embeddedJmsClass : EMBEDDED_JMS_CLASSES) {
if (ClassUtils.isPresent(embeddedJmsClass, null)) {
return true;
}
}
return false;
}
private <T extends ActiveMQConnectionFactory> T createEmbeddedConnectionFactory(Class<T> factoryClass)
throws Exception {
try {
TransportConfiguration transportConfiguration = new TransportConfiguration(
InVMConnectorFactory.class.getName(), this.properties.getEmbedded().generateTransportParameters());
ServerLocator serviceLocator = ActiveMQClient.createServerLocatorWithoutHA(transportConfiguration);
return factoryClass.getConstructor(ServerLocator.class).newInstance(serviceLocator);
}
catch (NoClassDefFoundError ex) {
throw new IllegalStateException("Unable to create InVM "
+ "Artemis connection, ensure that artemis-jms-server.jar is in the classpath", ex);
}
}
private <T extends ActiveMQConnectionFactory> T createNativeConnectionFactory(Class<T> factoryClass)
throws Exception {
T connectionFactory = newNativeConnectionFactory(factoryClass);
String user = this.properties.getUser();
if (StringUtils.hasText(user)) {
connectionFactory.setUser(user);
connectionFactory.setPassword(this.properties.getPassword());
}
return connectionFactory;
}
@SuppressWarnings("deprecation")
private <T extends ActiveMQConnectionFactory> T newNativeConnectionFactory(Class<T> factoryClass) throws Exception {
// Fallback if the broker url is not set
if (!StringUtils.hasText(this.properties.getBrokerUrl()) && StringUtils.hasText(this.properties.getHost())) {
Map<String, Object> params = new HashMap<>();
params.put(TransportConstants.HOST_PROP_NAME, this.properties.getHost());
params.put(TransportConstants.PORT_PROP_NAME, this.properties.getPort());
TransportConfiguration transportConfiguration = new TransportConfiguration(
NettyConnectorFactory.class.getName(), params);
Constructor<T> constructor = factoryClass.getConstructor(boolean.class, TransportConfiguration[].class);
return constructor.newInstance(false, new TransportConfiguration[] { transportConfiguration });
}
String brokerUrl = StringUtils.hasText(this.properties.getBrokerUrl()) ? this.properties.getBrokerUrl()
: DEFAULT_BROKER_URL;
Constructor<T> constructor = factoryClass.getConstructor(String.class);
return constructor.newInstance(brokerUrl);
}
}

@ -1,91 +0,0 @@
/*
* Copyright 2012-2020 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.artemis;
import java.io.File;
import org.apache.activemq.artemis.api.core.QueueConfiguration;
import org.apache.activemq.artemis.api.core.RoutingType;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.core.config.CoreAddressConfiguration;
import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory;
import org.apache.activemq.artemis.core.server.JournalType;
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Configuration used to create the embedded Artemis server.
*
* @author Eddú Meléndez
* @author Stephane Nicoll
* @author Phillip Webb
*/
class ArtemisEmbeddedConfigurationFactory {
private static final Log logger = LogFactory.getLog(ArtemisEmbeddedConfigurationFactory.class);
private final ArtemisProperties.Embedded properties;
ArtemisEmbeddedConfigurationFactory(ArtemisProperties properties) {
this.properties = properties.getEmbedded();
}
Configuration createConfiguration() {
ConfigurationImpl configuration = new ConfigurationImpl();
configuration.setSecurityEnabled(false);
configuration.setPersistenceEnabled(this.properties.isPersistent());
String dataDir = getDataDir();
configuration.setJournalDirectory(dataDir + "/journal");
if (this.properties.isPersistent()) {
configuration.setJournalType(JournalType.NIO);
configuration.setLargeMessagesDirectory(dataDir + "/largemessages");
configuration.setBindingsDirectory(dataDir + "/bindings");
configuration.setPagingDirectory(dataDir + "/paging");
}
TransportConfiguration transportConfiguration = new TransportConfiguration(InVMAcceptorFactory.class.getName(),
this.properties.generateTransportParameters());
configuration.getAcceptorConfigurations().add(transportConfiguration);
if (this.properties.isDefaultClusterPassword() && logger.isDebugEnabled()) {
logger.debug("Using default Artemis cluster password: " + this.properties.getClusterPassword());
}
configuration.setClusterPassword(this.properties.getClusterPassword());
configuration.addAddressConfiguration(createAddressConfiguration("DLQ"));
configuration.addAddressConfiguration(createAddressConfiguration("ExpiryQueue"));
configuration.addAddressesSetting("#",
new AddressSettings().setDeadLetterAddress(SimpleString.toSimpleString("DLQ"))
.setExpiryAddress(SimpleString.toSimpleString("ExpiryQueue")));
return configuration;
}
private CoreAddressConfiguration createAddressConfiguration(String name) {
return new CoreAddressConfiguration().setName(name).addRoutingType(RoutingType.ANYCAST).addQueueConfiguration(
new QueueConfiguration(name).setRoutingType(RoutingType.ANYCAST).setAddress(name));
}
private String getDataDir() {
if (this.properties.getDataDirectory() != null) {
return this.properties.getDataDirectory();
}
String tempDirectory = System.getProperty("java.io.tmpdir");
return new File(tempDirectory, "artemis-data").getAbsolutePath();
}
}

@ -1,126 +0,0 @@
/*
* Copyright 2012-2020 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.artemis;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.activemq.artemis.api.core.QueueConfiguration;
import org.apache.activemq.artemis.api.core.RoutingType;
import org.apache.activemq.artemis.core.config.CoreAddressConfiguration;
import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;
import org.apache.activemq.artemis.jms.server.config.JMSConfiguration;
import org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration;
import org.apache.activemq.artemis.jms.server.config.TopicConfiguration;
import org.apache.activemq.artemis.jms.server.config.impl.JMSConfigurationImpl;
import org.apache.activemq.artemis.jms.server.config.impl.JMSQueueConfigurationImpl;
import org.apache.activemq.artemis.jms.server.config.impl.TopicConfigurationImpl;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Configuration used to create the embedded Artemis server.
*
* @author Eddú Meléndez
* @author Phillip Webb
* @author Stephane Nicoll
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(EmbeddedActiveMQ.class)
@ConditionalOnProperty(prefix = "spring.artemis.embedded", name = "enabled", havingValue = "true",
matchIfMissing = true)
class ArtemisEmbeddedServerConfiguration {
private final ArtemisProperties properties;
ArtemisEmbeddedServerConfiguration(ArtemisProperties properties) {
this.properties = properties;
}
@Bean
@ConditionalOnMissingBean
org.apache.activemq.artemis.core.config.Configuration artemisConfiguration() {
return new ArtemisEmbeddedConfigurationFactory(this.properties).createConfiguration();
}
@Bean(initMethod = "start", destroyMethod = "stop")
@ConditionalOnMissingBean
EmbeddedActiveMQ embeddedActiveMq(org.apache.activemq.artemis.core.config.Configuration configuration,
JMSConfiguration jmsConfiguration, ObjectProvider<ArtemisConfigurationCustomizer> configurationCustomizers)
throws Exception {
for (JMSQueueConfiguration queueConfiguration : jmsConfiguration.getQueueConfigurations()) {
String queueName = queueConfiguration.getName();
configuration.addAddressConfiguration(
new CoreAddressConfiguration().setName(queueName).addRoutingType(RoutingType.ANYCAST)
.addQueueConfiguration(new QueueConfiguration(queueName).setAddress(queueName)
.setFilterString(queueConfiguration.getSelector())
.setDurable(queueConfiguration.isDurable()).setRoutingType(RoutingType.ANYCAST)));
}
for (TopicConfiguration topicConfiguration : jmsConfiguration.getTopicConfigurations()) {
configuration.addAddressConfiguration(new CoreAddressConfiguration().setName(topicConfiguration.getName())
.addRoutingType(RoutingType.MULTICAST));
}
configurationCustomizers.orderedStream().forEach((customizer) -> customizer.customize(configuration));
EmbeddedActiveMQ embeddedActiveMq = new EmbeddedActiveMQ();
embeddedActiveMq.setConfiguration(configuration);
return embeddedActiveMq;
}
@Bean
@ConditionalOnMissingBean
JMSConfiguration artemisJmsConfiguration(ObjectProvider<JMSQueueConfiguration> queuesConfiguration,
ObjectProvider<TopicConfiguration> topicsConfiguration) {
JMSConfiguration configuration = new JMSConfigurationImpl();
addAll(configuration.getQueueConfigurations(), queuesConfiguration);
addAll(configuration.getTopicConfigurations(), topicsConfiguration);
addQueues(configuration, this.properties.getEmbedded().getQueues());
addTopics(configuration, this.properties.getEmbedded().getTopics());
return configuration;
}
private <T> void addAll(List<T> list, ObjectProvider<T> items) {
if (items != null) {
list.addAll(items.orderedStream().collect(Collectors.toList()));
}
}
private void addQueues(JMSConfiguration configuration, String[] queues) {
boolean persistent = this.properties.getEmbedded().isPersistent();
for (String queue : queues) {
JMSQueueConfigurationImpl jmsQueueConfiguration = new JMSQueueConfigurationImpl();
jmsQueueConfiguration.setName(queue);
jmsQueueConfiguration.setDurable(persistent);
jmsQueueConfiguration.setBindings("/queue/" + queue);
configuration.getQueueConfigurations().add(jmsQueueConfiguration);
}
}
private void addTopics(JMSConfiguration configuration, String[] topics) {
for (String topic : topics) {
TopicConfigurationImpl topicConfiguration = new TopicConfigurationImpl();
topicConfiguration.setName(topic);
topicConfiguration.setBindings("/topic/" + topic);
configuration.getTopicConfigurations().add(topicConfiguration);
}
}
}

@ -1,38 +0,0 @@
/*
* Copyright 2012-2019 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.artemis;
/**
* Define the mode in which Artemis can operate.
*
* @author Eddú Meléndez
* @author Stephane Nicoll
* @since 1.3.0
*/
public enum ArtemisMode {
/**
* Connect to a broker using the native Artemis protocol (i.e. netty).
*/
NATIVE,
/**
* Embed (i.e. start) the broker in the application.
*/
EMBEDDED
}

@ -1,48 +0,0 @@
/*
* Copyright 2012-2019 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.artemis;
import org.apache.activemq.artemis.spi.core.naming.BindingRegistry;
/**
* A no-op implementation of the {@link BindingRegistry}.
*
* @author Eddú Meléndez
* @author Stephane Nicoll
* @since 1.3.0
*/
public class ArtemisNoOpBindingRegistry implements BindingRegistry {
@Override
public Object lookup(String s) {
return null;
}
@Override
public boolean bind(String s, Object o) {
return false;
}
@Override
public void unbind(String s) {
}
@Override
public void close() {
}
}

@ -1,268 +0,0 @@
/*
* Copyright 2012-2021 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.artemis;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.activemq.artemis.core.remoting.impl.invm.TransportConstants;
import org.springframework.boot.autoconfigure.jms.JmsPoolConnectionFactoryProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
/**
* Configuration properties for Artemis.
*
* @author Eddú Meléndez
* @author Stephane Nicoll
* @author Justin Bertram
* @since 1.3.0
*/
@ConfigurationProperties(prefix = "spring.artemis")
public class ArtemisProperties {
/**
* Artemis deployment mode, auto-detected by default.
*/
private ArtemisMode mode;
/**
* Artemis broker port.
*/
private String brokerUrl;
/**
* Artemis broker host.
*/
private String host;
/**
* Artemis broker port.
*/
private int port = 61616;
/**
* Login user of the broker.
*/
private String user;
/**
* Login password of the broker.
*/
private String password;
private final Embedded embedded = new Embedded();
@NestedConfigurationProperty
private final JmsPoolConnectionFactoryProperties pool = new JmsPoolConnectionFactoryProperties();
public ArtemisMode getMode() {
return this.mode;
}
public void setMode(ArtemisMode mode) {
this.mode = mode;
}
public String getBrokerUrl() {
return this.brokerUrl;
}
public void setBrokerUrl(String brokerUrl) {
this.brokerUrl = brokerUrl;
}
/**
* Return the host of the broker.
* @return the host
* @deprecated since 2.5.0 for removal in 2.7.0 in favor of broker url
*/
@Deprecated
@DeprecatedConfigurationProperty(replacement = "spring.artemis.broker-url")
public String getHost() {
return this.host;
}
@Deprecated
public void setHost(String host) {
this.host = host;
}
/**
* Return the port of the broker.
* @return the port
* @deprecated since 2.5.0 for removal in 2.7.0 in favor of broker url
*/
@Deprecated
@DeprecatedConfigurationProperty(replacement = "spring.artemis.broker-url")
public int getPort() {
return this.port;
}
@Deprecated
public void setPort(int port) {
this.port = port;
}
public String getUser() {
return this.user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public Embedded getEmbedded() {
return this.embedded;
}
public JmsPoolConnectionFactoryProperties getPool() {
return this.pool;
}
/**
* Configuration for an embedded Artemis server.
*/
public static class Embedded {
private static final AtomicInteger serverIdCounter = new AtomicInteger();
/**
* Server ID. By default, an auto-incremented counter is used.
*/
private int serverId = serverIdCounter.getAndIncrement();
/**
* Whether to enable embedded mode if the Artemis server APIs are available.
*/
private boolean enabled = true;
/**
* Whether to enable persistent store.
*/
private boolean persistent;
/**
* Journal file directory. Not necessary if persistence is turned off.
*/
private String dataDirectory;
/**
* Comma-separated list of queues to create on startup.
*/
private String[] queues = new String[0];
/**
* Comma-separated list of topics to create on startup.
*/
private String[] topics = new String[0];
/**
* Cluster password. Randomly generated on startup by default.
*/
private String clusterPassword = UUID.randomUUID().toString();
private boolean defaultClusterPassword = true;
public int getServerId() {
return this.serverId;
}
public void setServerId(int serverId) {
this.serverId = serverId;
}
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isPersistent() {
return this.persistent;
}
public void setPersistent(boolean persistent) {
this.persistent = persistent;
}
public String getDataDirectory() {
return this.dataDirectory;
}
public void setDataDirectory(String dataDirectory) {
this.dataDirectory = dataDirectory;
}
public String[] getQueues() {
return this.queues;
}
public void setQueues(String[] queues) {
this.queues = queues;
}
public String[] getTopics() {
return this.topics;
}
public void setTopics(String[] topics) {
this.topics = topics;
}
public String getClusterPassword() {
return this.clusterPassword;
}
public void setClusterPassword(String clusterPassword) {
this.clusterPassword = clusterPassword;
this.defaultClusterPassword = false;
}
public boolean isDefaultClusterPassword() {
return this.defaultClusterPassword;
}
/**
* Creates the minimal transport parameters for an embedded transport
* configuration.
* @return the transport parameters
* @see TransportConstants#SERVER_ID_PROP_NAME
*/
public Map<String, Object> generateTransportParameters() {
Map<String, Object> parameters = new HashMap<>();
parameters.put(TransportConstants.SERVER_ID_PROP_NAME, getServerId());
return parameters;
}
}
}

@ -1,60 +0,0 @@
/*
* Copyright 2012-2019 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.artemis;
import javax.jms.ConnectionFactory;
import javax.transaction.TransactionManager;
import org.apache.activemq.artemis.jms.client.ActiveMQXAConnectionFactory;
import org.springframework.beans.factory.ListableBeanFactory;
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.jms.XAConnectionFactoryWrapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* Configuration for Artemis XA {@link ConnectionFactory}.
*
* @author Eddú Meléndez
* @author Phillip Webb
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(ConnectionFactory.class)
@ConditionalOnClass(TransactionManager.class)
@ConditionalOnBean(XAConnectionFactoryWrapper.class)
class ArtemisXAConnectionFactoryConfiguration {
@Primary
@Bean(name = { "jmsConnectionFactory", "xaJmsConnectionFactory" })
ConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory, ArtemisProperties properties,
XAConnectionFactoryWrapper wrapper) throws Exception {
return wrapper.wrapConnectionFactory(new ArtemisConnectionFactoryFactory(beanFactory, properties)
.createConnectionFactory(ActiveMQXAConnectionFactory.class));
}
@Bean
ActiveMQXAConnectionFactory nonXaJmsConnectionFactory(ListableBeanFactory beanFactory,
ArtemisProperties properties) {
return new ArtemisConnectionFactoryFactory(beanFactory, properties)
.createConnectionFactory(ActiveMQXAConnectionFactory.class);
}
}

@ -1,22 +0,0 @@
/*
* Copyright 2012-2019 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.
*/
/**
* Auto-configuration for Artemis.
*
* @author Eddú Meléndez
*/
package org.springframework.boot.autoconfigure.jms.artemis;

@ -21,7 +21,6 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@ -37,8 +36,7 @@ import org.springframework.context.annotation.Import;
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(javax.transaction.Transaction.class)
@ConditionalOnProperty(prefix = "spring.jta", value = "enabled", matchIfMissing = true)
@AutoConfigureBefore({ XADataSourceAutoConfiguration.class, ArtemisAutoConfiguration.class,
HibernateJpaAutoConfiguration.class })
@AutoConfigureBefore({ XADataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
@Import(JndiJtaConfiguration.class)
public class JtaAutoConfiguration {

@ -83,7 +83,6 @@ org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConf
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\

@ -22,12 +22,10 @@ import javax.jms.ConnectionFactory;
import javax.jms.ExceptionListener;
import javax.jms.Session;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
@ -40,7 +38,6 @@ import org.springframework.jms.config.JmsListenerConfigUtils;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerEndpoint;
import org.springframework.jms.config.SimpleJmsListenerContainerFactory;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
@ -62,32 +59,8 @@ import static org.mockito.Mockito.mock;
class JmsAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ArtemisAutoConfiguration.class, JmsAutoConfiguration.class));
@Test
void testDefaultJmsConfiguration() {
this.contextRunner.withUserConfiguration(TestConfiguration.class).run(this::testDefaultJmsConfiguration);
}
private void testDefaultJmsConfiguration(AssertableApplicationContext loaded) {
assertThat(loaded).hasSingleBean(ConnectionFactory.class);
assertThat(loaded).hasSingleBean(CachingConnectionFactory.class);
CachingConnectionFactory factory = loaded.getBean(CachingConnectionFactory.class);
assertThat(factory.getTargetConnectionFactory()).isInstanceOf(ActiveMQConnectionFactory.class);
JmsTemplate jmsTemplate = loaded.getBean(JmsTemplate.class);
JmsMessagingTemplate messagingTemplate = loaded.getBean(JmsMessagingTemplate.class);
assertThat(factory).isEqualTo(jmsTemplate.getConnectionFactory());
assertThat(messagingTemplate.getJmsTemplate()).isEqualTo(jmsTemplate);
assertThat(getBrokerUrl(factory)).startsWith("vm://");
assertThat(loaded.containsBean("jmsListenerContainerFactory")).isTrue();
}
@Test
void testConnectionFactoryBackOff() {
this.contextRunner.withUserConfiguration(TestConfiguration2.class)
.run((context) -> assertThat(context.getBeansOfType(ActiveMQConnectionFactory.class))
.containsOnlyKeys("customConnectionFactory"));
}
.withConfiguration(AutoConfigurations.of(JmsAutoConfiguration.class))
.withUserConfiguration(ConnectionFactoryConfiguration.class);
@Test
void testJmsTemplateBackOff() {
@ -104,15 +77,13 @@ class JmsAutoConfigurationTests {
@Test
void testJmsTemplateBackOffEverything() {
this.contextRunner
.withUserConfiguration(TestConfiguration2.class, TestConfiguration3.class, TestConfiguration5.class)
this.contextRunner.withUserConfiguration(TestConfiguration3.class, TestConfiguration5.class)
.run(this::testJmsTemplateBackOffEverything);
}
private void testJmsTemplateBackOffEverything(AssertableApplicationContext loaded) throws IOException {
JmsTemplate jmsTemplate = loaded.getBean(JmsTemplate.class);
assertThat(jmsTemplate.getPriority()).isEqualTo(999);
assertThat(loaded.getBeansOfType(ActiveMQConnectionFactory.class)).containsOnlyKeys("customConnectionFactory");
JmsMessagingTemplate messagingTemplate = loaded.getBean(JmsMessagingTemplate.class);
assertThat(messagingTemplate.getDefaultDestinationName()).isEqualTo("fooBar");
assertThat(messagingTemplate.getJmsTemplate()).isEqualTo(jmsTemplate);
@ -317,16 +288,6 @@ class JmsAutoConfigurationTests {
});
}
private String getBrokerUrl(CachingConnectionFactory connectionFactory) {
assertThat(connectionFactory.getTargetConnectionFactory()).isInstanceOf(ActiveMQConnectionFactory.class);
try {
return ((ActiveMQConnectionFactory) connectionFactory.getTargetConnectionFactory()).toURI().toString();
}
catch (IOException ex) {
throw new RuntimeException(ex);
}
}
@Test
void enableJmsAutomatically() {
this.contextRunner.withUserConfiguration(NoEnableJmsConfiguration.class)
@ -336,17 +297,17 @@ class JmsAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
static class TestConfiguration {
static class ConnectionFactoryConfiguration {
@Bean
ConnectionFactory connectionFactory() {
return mock(ConnectionFactory.class);
}
}
@Configuration(proxyBeanMethods = false)
static class TestConfiguration2 {
@Bean
ConnectionFactory customConnectionFactory() {
return new ActiveMQConnectionFactory();
}
static class TestConfiguration {
}
@ -476,12 +437,12 @@ class JmsAutoConfigurationTests {
@Bean
ConnectionFactory connectionFactory1() {
return new ActiveMQConnectionFactory();
return mock(ConnectionFactory.class);
}
@Bean
ConnectionFactory connectionFactory2() {
return new ActiveMQConnectionFactory();
return mock(ConnectionFactory.class);
}
}

@ -1,501 +0,0 @@
/*
* Copyright 2012-2020 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.artemis;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.UUID;
import javax.jms.ConnectionFactory;
import javax.jms.Message;
import javax.jms.TextMessage;
import org.apache.activemq.artemis.api.core.RoutingType;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.BindingQueryResult;
import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.apache.activemq.artemis.jms.server.config.JMSConfiguration;
import org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration;
import org.apache.activemq.artemis.jms.server.config.TopicConfiguration;
import org.apache.activemq.artemis.jms.server.config.impl.JMSConfigurationImpl;
import org.apache.activemq.artemis.jms.server.config.impl.JMSQueueConfigurationImpl;
import org.apache.activemq.artemis.jms.server.config.impl.TopicConfigurationImpl;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.messaginghub.pooled.jms.JmsPoolConnectionFactory;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.core.JmsTemplate;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ArtemisAutoConfiguration}.
*
* @author Eddú Meléndez
* @author Stephane Nicoll
*/
class ArtemisAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ArtemisAutoConfiguration.class, JmsAutoConfiguration.class));
@Test
void connectionFactoryIsCachedByDefault() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(ConnectionFactory.class).hasSingleBean(CachingConnectionFactory.class)
.hasBean("jmsConnectionFactory");
CachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);
assertThat(context.getBean("jmsConnectionFactory")).isSameAs(connectionFactory);
assertThat(connectionFactory.getTargetConnectionFactory()).isInstanceOf(ActiveMQConnectionFactory.class);
assertThat(connectionFactory.isCacheConsumers()).isFalse();
assertThat(connectionFactory.isCacheProducers()).isTrue();
assertThat(connectionFactory.getSessionCacheSize()).isEqualTo(1);
});
}
@Test
void connectionFactoryCachingCanBeCustomized() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.jms.cache.consumers=true", "spring.jms.cache.producers=false",
"spring.jms.cache.session-cache-size=10")
.run((context) -> {
assertThat(context).hasSingleBean(ConnectionFactory.class)
.hasSingleBean(CachingConnectionFactory.class).hasBean("jmsConnectionFactory");
CachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);
assertThat(context.getBean("jmsConnectionFactory")).isSameAs(connectionFactory);
assertThat(connectionFactory.isCacheConsumers()).isTrue();
assertThat(connectionFactory.isCacheProducers()).isFalse();
assertThat(connectionFactory.getSessionCacheSize()).isEqualTo(10);
});
}
@Test
void connectionFactoryCachingCanBeDisabled() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.jms.cache.enabled=false").run((context) -> {
assertThat(context).doesNotHaveBean(CachingConnectionFactory.class);
ConnectionFactory connectionFactory = getConnectionFactory(context);
assertThat(connectionFactory).isInstanceOf(ActiveMQConnectionFactory.class);
});
}
@Test
void nativeConnectionFactory() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.mode:native").run((context) -> {
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
ConnectionFactory connectionFactory = getConnectionFactory(context);
assertThat(connectionFactory).isEqualTo(jmsTemplate.getConnectionFactory());
ActiveMQConnectionFactory activeMQConnectionFactory = getActiveMQConnectionFactory(
connectionFactory);
assertNettyConnectionFactory(activeMQConnectionFactory, "localhost", 61616);
assertThat(activeMQConnectionFactory.getUser()).isNull();
assertThat(activeMQConnectionFactory.getPassword()).isNull();
});
}
@Test
void nativeConnectionFactoryCustomBrokerUrl() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.mode:native", "spring.artemis.broker-url:tcp://192.168.1.144:9876")
.run((context) -> assertNettyConnectionFactory(
getActiveMQConnectionFactory(getConnectionFactory(context)), "192.168.1.144", 9876));
}
@Test
@Deprecated
void nativeConnectionFactoryCustomHost() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.mode:native", "spring.artemis.host:192.168.1.144",
"spring.artemis.port:9876")
.run((context) -> assertNettyConnectionFactory(
getActiveMQConnectionFactory(getConnectionFactory(context)), "192.168.1.144", 9876));
}
@Test
@Deprecated
void nativeConnectionFactoryCustomBrokerUrlAndHost() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.mode:native", "spring.artemis.host:192.168.1.144",
"spring.artemis.port:9876", "spring.artemis.broker-url=tcp://192.168.1.221:6543")
.run((context) -> assertNettyConnectionFactory(
getActiveMQConnectionFactory(getConnectionFactory(context)), "192.168.1.221", 6543));
}
@Test
void nativeConnectionFactoryCredentials() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.mode:native", "spring.artemis.user:user",
"spring.artemis.password:secret")
.run((context) -> {
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
ConnectionFactory connectionFactory = getConnectionFactory(context);
assertThat(connectionFactory).isEqualTo(jmsTemplate.getConnectionFactory());
ActiveMQConnectionFactory activeMQConnectionFactory = getActiveMQConnectionFactory(
connectionFactory);
assertNettyConnectionFactory(activeMQConnectionFactory, "localhost", 61616);
assertThat(activeMQConnectionFactory.getUser()).isEqualTo("user");
assertThat(activeMQConnectionFactory.getPassword()).isEqualTo("secret");
});
}
@Test
void embeddedConnectionFactory() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.mode:embedded").run((context) -> {
ArtemisProperties properties = context.getBean(ArtemisProperties.class);
assertThat(properties.getMode()).isEqualTo(ArtemisMode.EMBEDDED);
assertThat(context).hasSingleBean(EmbeddedActiveMQ.class);
org.apache.activemq.artemis.core.config.Configuration configuration = context
.getBean(org.apache.activemq.artemis.core.config.Configuration.class);
assertThat(configuration.isPersistenceEnabled()).isFalse();
assertThat(configuration.isSecurityEnabled()).isFalse();
assertInVmConnectionFactory(getActiveMQConnectionFactory(getConnectionFactory(context)));
});
}
@Test
void embeddedConnectionFactoryByDefault() {
// No mode is specified
this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(EmbeddedActiveMQ.class);
org.apache.activemq.artemis.core.config.Configuration configuration = context
.getBean(org.apache.activemq.artemis.core.config.Configuration.class);
assertThat(configuration.isPersistenceEnabled()).isFalse();
assertThat(configuration.isSecurityEnabled()).isFalse();
assertInVmConnectionFactory(getActiveMQConnectionFactory(getConnectionFactory(context)));
});
}
@Test
void nativeConnectionFactoryIfEmbeddedServiceDisabledExplicitly() {
// No mode is specified
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.embedded.enabled:false").run((context) -> {
assertThat(context).doesNotHaveBean(ActiveMQServer.class);
assertNettyConnectionFactory(getActiveMQConnectionFactory(getConnectionFactory(context)),
"localhost", 61616);
});
}
@Test
void embeddedConnectionFactoryEvenIfEmbeddedServiceDisabled() {
// No mode is specified
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.mode:embedded", "spring.artemis.embedded.enabled:false")
.run((context) -> {
assertThat(context.getBeansOfType(ActiveMQServer.class)).isEmpty();
assertInVmConnectionFactory(getActiveMQConnectionFactory(getConnectionFactory(context)));
});
}
@Test
void embeddedServerWithDestinations() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.embedded.queues=Queue1,Queue2",
"spring.artemis.embedded.topics=Topic1")
.run((context) -> {
DestinationChecker checker = new DestinationChecker(context);
checker.checkQueue("Queue1", true);
checker.checkQueue("Queue2", true);
checker.checkQueue("NonExistentQueue", false);
checker.checkTopic("Topic1", true);
checker.checkTopic("NonExistentTopic", false);
});
}
@Test
void embeddedServerWithDestinationConfig() {
this.contextRunner.withUserConfiguration(DestinationConfiguration.class).run((context) -> {
DestinationChecker checker = new DestinationChecker(context);
checker.checkQueue("sampleQueue", true);
checker.checkTopic("sampleTopic", true);
});
}
@Test
void embeddedServiceWithCustomJmsConfiguration() {
// Ignored with custom config
this.contextRunner.withUserConfiguration(CustomJmsConfiguration.class)
.withPropertyValues("spring.artemis.embedded.queues=Queue1,Queue2").run((context) -> {
DestinationChecker checker = new DestinationChecker(context);
checker.checkQueue("custom", true); // See CustomJmsConfiguration
checker.checkQueue("Queue1", false);
checker.checkQueue("Queue2", false);
});
}
@Test
void embeddedServiceWithCustomArtemisConfiguration() {
this.contextRunner.withUserConfiguration(CustomArtemisConfiguration.class)
.run((context) -> assertThat(
context.getBean(org.apache.activemq.artemis.core.config.Configuration.class).getName())
.isEqualTo("customFooBar"));
}
@Test
void embeddedWithPersistentMode(@TempDir Path temp) throws IOException {
File dataDirectory = Files.createTempDirectory(temp, null).toFile();
final String messageId = UUID.randomUUID().toString();
// Start the server and post a message to some queue
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.embedded.queues=TestQueue",
"spring.artemis.embedded.persistent:true",
"spring.artemis.embedded.dataDirectory:" + dataDirectory.getAbsolutePath())
.run((context) -> context.getBean(JmsTemplate.class).send("TestQueue",
(session) -> session.createTextMessage(messageId)))
.run((context) -> {
// Start the server again and check if our message is still here
JmsTemplate jmsTemplate2 = context.getBean(JmsTemplate.class);
jmsTemplate2.setReceiveTimeout(1000L);
Message message = jmsTemplate2.receive("TestQueue");
assertThat(message).isNotNull();
assertThat(((TextMessage) message).getText()).isEqualTo(messageId);
});
}
@Test
void severalEmbeddedBrokers() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.embedded.queues=Queue1").run((first) -> {
this.contextRunner.withPropertyValues("spring.artemis.embedded.queues=Queue2").run((second) -> {
ArtemisProperties firstProperties = first.getBean(ArtemisProperties.class);
ArtemisProperties secondProperties = second.getBean(ArtemisProperties.class);
assertThat(firstProperties.getEmbedded().getServerId())
.isLessThan(secondProperties.getEmbedded().getServerId());
DestinationChecker firstChecker = new DestinationChecker(first);
firstChecker.checkQueue("Queue1", true);
firstChecker.checkQueue("Queue2", false);
DestinationChecker secondChecker = new DestinationChecker(second);
secondChecker.checkQueue("Queue1", false);
secondChecker.checkQueue("Queue2", true);
});
});
}
@Test
void connectToASpecificEmbeddedBroker() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.embedded.serverId=93", "spring.artemis.embedded.queues=Queue1")
.run((first) -> {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.mode=embedded",
// Connect to the "main" broker
"spring.artemis.embedded.serverId=93",
// Do not start a specific one
"spring.artemis.embedded.enabled=false")
.run((secondContext) -> {
first.getBean(JmsTemplate.class).convertAndSend("Queue1", "test");
assertThat(secondContext.getBean(JmsTemplate.class).receiveAndConvert("Queue1"))
.isEqualTo("test");
});
});
}
@Test
void defaultPoolConnectionFactoryIsApplied() {
this.contextRunner.withPropertyValues("spring.artemis.pool.enabled=true").run((context) -> {
assertThat(context.getBeansOfType(JmsPoolConnectionFactory.class)).hasSize(1);
JmsPoolConnectionFactory connectionFactory = context.getBean(JmsPoolConnectionFactory.class);
JmsPoolConnectionFactory defaultFactory = new JmsPoolConnectionFactory();
assertThat(connectionFactory.isBlockIfSessionPoolIsFull())
.isEqualTo(defaultFactory.isBlockIfSessionPoolIsFull());
assertThat(connectionFactory.getBlockIfSessionPoolIsFullTimeout())
.isEqualTo(defaultFactory.getBlockIfSessionPoolIsFullTimeout());
assertThat(connectionFactory.getConnectionIdleTimeout())
.isEqualTo(defaultFactory.getConnectionIdleTimeout());
assertThat(connectionFactory.getMaxConnections()).isEqualTo(defaultFactory.getMaxConnections());
assertThat(connectionFactory.getMaxSessionsPerConnection())
.isEqualTo(defaultFactory.getMaxSessionsPerConnection());
assertThat(connectionFactory.getConnectionCheckInterval())
.isEqualTo(defaultFactory.getConnectionCheckInterval());
assertThat(connectionFactory.isUseAnonymousProducers()).isEqualTo(defaultFactory.isUseAnonymousProducers());
});
}
@Test
void customPoolConnectionFactoryIsApplied() {
this.contextRunner
.withPropertyValues("spring.artemis.pool.enabled=true", "spring.artemis.pool.blockIfFull=false",
"spring.artemis.pool.blockIfFullTimeout=64", "spring.artemis.pool.idleTimeout=512",
"spring.artemis.pool.maxConnections=256", "spring.artemis.pool.maxSessionsPerConnection=1024",
"spring.artemis.pool.timeBetweenExpirationCheck=2048",
"spring.artemis.pool.useAnonymousProducers=false")
.run((context) -> {
assertThat(context.getBeansOfType(JmsPoolConnectionFactory.class)).hasSize(1);
JmsPoolConnectionFactory connectionFactory = context.getBean(JmsPoolConnectionFactory.class);
assertThat(connectionFactory.isBlockIfSessionPoolIsFull()).isFalse();
assertThat(connectionFactory.getBlockIfSessionPoolIsFullTimeout()).isEqualTo(64);
assertThat(connectionFactory.getConnectionIdleTimeout()).isEqualTo(512);
assertThat(connectionFactory.getMaxConnections()).isEqualTo(256);
assertThat(connectionFactory.getMaxSessionsPerConnection()).isEqualTo(1024);
assertThat(connectionFactory.getConnectionCheckInterval()).isEqualTo(2048);
assertThat(connectionFactory.isUseAnonymousProducers()).isFalse();
});
}
@Test
void poolConnectionFactoryConfiguration() {
this.contextRunner.withPropertyValues("spring.artemis.pool.enabled:true").run((context) -> {
ConnectionFactory factory = getConnectionFactory(context);
assertThat(factory).isInstanceOf(JmsPoolConnectionFactory.class);
context.getSourceApplicationContext().close();
assertThat(factory.createConnection()).isNull();
});
}
private ConnectionFactory getConnectionFactory(AssertableApplicationContext context) {
assertThat(context).hasSingleBean(ConnectionFactory.class).hasBean("jmsConnectionFactory");
ConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class);
assertThat(connectionFactory).isSameAs(context.getBean("jmsConnectionFactory"));
return connectionFactory;
}
private ActiveMQConnectionFactory getActiveMQConnectionFactory(ConnectionFactory connectionFactory) {
assertThat(connectionFactory).isInstanceOf(CachingConnectionFactory.class);
return (ActiveMQConnectionFactory) ((CachingConnectionFactory) connectionFactory).getTargetConnectionFactory();
}
private TransportConfiguration assertInVmConnectionFactory(ActiveMQConnectionFactory connectionFactory) {
TransportConfiguration transportConfig = getSingleTransportConfiguration(connectionFactory);
assertThat(transportConfig.getFactoryClassName()).isEqualTo(InVMConnectorFactory.class.getName());
return transportConfig;
}
private TransportConfiguration assertNettyConnectionFactory(ActiveMQConnectionFactory connectionFactory,
String host, int port) {
TransportConfiguration transportConfig = getSingleTransportConfiguration(connectionFactory);
assertThat(transportConfig.getFactoryClassName()).isEqualTo(NettyConnectorFactory.class.getName());
assertThat(transportConfig.getParams().get("host")).isEqualTo(host);
Object transportConfigPort = transportConfig.getParams().get("port");
if (transportConfigPort instanceof String) {
transportConfigPort = Integer.parseInt((String) transportConfigPort);
}
assertThat(transportConfigPort).isEqualTo(port);
return transportConfig;
}
private TransportConfiguration getSingleTransportConfiguration(ActiveMQConnectionFactory connectionFactory) {
TransportConfiguration[] transportConfigurations = connectionFactory.getServerLocator()
.getStaticTransportConfigurations();
assertThat(transportConfigurations).hasSize(1);
return transportConfigurations[0];
}
private static final class DestinationChecker {
private final ActiveMQServer server;
private DestinationChecker(ApplicationContext applicationContext) {
this.server = applicationContext.getBean(EmbeddedActiveMQ.class).getActiveMQServer();
}
void checkQueue(String name, boolean shouldExist) {
checkDestination(name, RoutingType.ANYCAST, shouldExist);
}
void checkTopic(String name, boolean shouldExist) {
checkDestination(name, RoutingType.MULTICAST, shouldExist);
}
void checkDestination(String name, RoutingType routingType, boolean shouldExist) {
try {
BindingQueryResult result = this.server.bindingQuery(new SimpleString(name));
assertThat(result.isExists()).isEqualTo(shouldExist);
if (shouldExist) {
assertThat(result.getAddressInfo().getRoutingType()).isEqualTo(routingType);
}
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
@Configuration(proxyBeanMethods = false)
static class EmptyConfiguration {
}
@Configuration(proxyBeanMethods = false)
static class DestinationConfiguration {
@Bean
JMSQueueConfiguration sampleQueueConfiguration() {
JMSQueueConfigurationImpl jmsQueueConfiguration = new JMSQueueConfigurationImpl();
jmsQueueConfiguration.setName("sampleQueue");
jmsQueueConfiguration.setSelector("foo=bar");
jmsQueueConfiguration.setDurable(false);
jmsQueueConfiguration.setBindings("/queue/1");
return jmsQueueConfiguration;
}
@Bean
TopicConfiguration sampleTopicConfiguration() {
TopicConfigurationImpl topicConfiguration = new TopicConfigurationImpl();
topicConfiguration.setName("sampleTopic");
topicConfiguration.setBindings("/topic/1");
return topicConfiguration;
}
}
@Configuration(proxyBeanMethods = false)
static class CustomJmsConfiguration {
@Bean
JMSConfiguration myJmsConfiguration() {
JMSConfiguration config = new JMSConfigurationImpl();
JMSQueueConfiguration jmsQueueConfiguration = new JMSQueueConfigurationImpl();
jmsQueueConfiguration.setName("custom");
jmsQueueConfiguration.setDurable(false);
config.getQueueConfigurations().add(jmsQueueConfiguration);
return config;
}
}
@Configuration(proxyBeanMethods = false)
static class CustomArtemisConfiguration {
@Bean
ArtemisConfigurationCustomizer myArtemisCustomize() {
return (configuration) -> {
configuration.setClusterPassword("Foobar");
configuration.setName("customFooBar");
};
}
}
}

@ -1,92 +0,0 @@
/*
* Copyright 2012-2019 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.artemis;
import java.util.List;
import java.util.Map;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.core.config.CoreAddressConfiguration;
import org.apache.activemq.artemis.core.server.JournalType;
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ArtemisEmbeddedConfigurationFactory}
*
* @author Eddú Meléndez
* @author Stephane Nicoll
* @author Phillip Webb
*/
class ArtemisEmbeddedConfigurationFactoryTests {
@Test
void defaultDataDir() {
ArtemisProperties properties = new ArtemisProperties();
properties.getEmbedded().setPersistent(true);
Configuration configuration = new ArtemisEmbeddedConfigurationFactory(properties).createConfiguration();
assertThat(configuration.getJournalDirectory()).startsWith(System.getProperty("java.io.tmpdir"))
.endsWith("/journal");
}
@Test
void persistenceSetup() {
ArtemisProperties properties = new ArtemisProperties();
properties.getEmbedded().setPersistent(true);
Configuration configuration = new ArtemisEmbeddedConfigurationFactory(properties).createConfiguration();
assertThat(configuration.isPersistenceEnabled()).isTrue();
assertThat(configuration.getJournalType()).isEqualTo(JournalType.NIO);
}
@Test
void generatedClusterPassword() {
ArtemisProperties properties = new ArtemisProperties();
Configuration configuration = new ArtemisEmbeddedConfigurationFactory(properties).createConfiguration();
assertThat(configuration.getClusterPassword()).hasSize(36);
}
@Test
void specificClusterPassword() {
ArtemisProperties properties = new ArtemisProperties();
properties.getEmbedded().setClusterPassword("password");
Configuration configuration = new ArtemisEmbeddedConfigurationFactory(properties).createConfiguration();
assertThat(configuration.getClusterPassword()).isEqualTo("password");
}
@Test
void hasDlqExpiryQueueAddressSettingsConfigured() {
ArtemisProperties properties = new ArtemisProperties();
Configuration configuration = new ArtemisEmbeddedConfigurationFactory(properties).createConfiguration();
Map<String, AddressSettings> addressesSettings = configuration.getAddressesSettings();
assertThat((Object) addressesSettings.get("#").getDeadLetterAddress())
.isEqualTo(SimpleString.toSimpleString("DLQ"));
assertThat((Object) addressesSettings.get("#").getExpiryAddress())
.isEqualTo(SimpleString.toSimpleString("ExpiryQueue"));
}
@Test
void hasDlqExpiryQueueConfigured() {
ArtemisProperties properties = new ArtemisProperties();
Configuration configuration = new ArtemisEmbeddedConfigurationFactory(properties).createConfiguration();
List<CoreAddressConfiguration> addressConfigurations = configuration.getAddressConfigurations();
assertThat(addressConfigurations).hasSize(2);
}
}

@ -73,7 +73,6 @@ dependencies {
testRepository(project(path: ":spring-boot-project:spring-boot-starters:spring-boot-starter-actuator", configuration: "mavenRepository"))
testRepository(project(path: ":spring-boot-project:spring-boot-starters:spring-boot-starter-amqp", configuration: "mavenRepository"))
testRepository(project(path: ":spring-boot-project:spring-boot-starters:spring-boot-starter-aop", configuration: "mavenRepository"))
testRepository(project(path: ":spring-boot-project:spring-boot-starters:spring-boot-starter-artemis", configuration: "mavenRepository"))
testRepository(project(path: ":spring-boot-project:spring-boot-starters:spring-boot-starter-batch", configuration: "mavenRepository"))
testRepository(project(path: ":spring-boot-project:spring-boot-starters:spring-boot-starter-data-jpa", configuration: "mavenRepository"))
testRepository(project(path: ":spring-boot-project:spring-boot-starters:spring-boot-starter-jdbc", configuration: "mavenRepository"))

@ -127,6 +127,7 @@ class SampleIntegrationTests {
}
@Test
@Disabled("Requires Artemis to be run, so disable it")
void jmsSample() throws Exception {
System.setProperty("spring.artemis.embedded.queues", "spring-boot");
try {

@ -31,32 +31,6 @@ bom {
]
}
}
library("Artemis", "2.19.0") {
group("org.apache.activemq") {
modules = [
"artemis-amqp-protocol",
"artemis-commons" {
exclude group: "commons-logging", module: "commons-logging"
},
"artemis-core-client" {
exclude group: "org.apache.geronimo.specs", module: "geronimo-json_1.0_spec"
},
"artemis-jms-client" {
exclude group: "org.apache.geronimo.specs", module: "geronimo-json_1.0_spec"
},
"artemis-jms-server" {
exclude group: "org.apache.geronimo.specs", module: "geronimo-json_1.0_spec"
},
"artemis-journal",
"artemis-selector",
"artemis-server" {
exclude group: "commons-logging", module: "commons-logging"
exclude group: "org.apache.geronimo.specs", module: "geronimo-json_1.0_spec"
},
"artemis-service-extensions"
]
}
}
library("AspectJ", "1.9.7") {
group("org.aspectj") {
modules = [

@ -2,7 +2,7 @@
== Messaging
If your application uses any messaging protocol, see one or more of the following sections:
* *JMS:* <<messaging#messaging.jms, Auto-configuration for ActiveMQ and Artemis, Sending and Receiving messages through JMS>>
* *JMS:* <<messaging#messaging.jms, Auto-configuration for ActiveMQ, Sending and Receiving messages through JMS>>
* *AMQP:* <<messaging#messaging.amqp, Auto-configuration for RabbitMQ>>
* *Kafka:* <<messaging#messaging.kafka, Auto-configuration for Spring Kafka>>
* *RSocket:* <<messaging#messaging.rsocket, Auto-configuration for Spring Framework's RSocket Support>>

@ -7,59 +7,6 @@ Spring Boot also auto-configures the necessary infrastructure to send and receiv
[[messaging.jms.artemis]]
=== ActiveMQ Artemis Support
Spring Boot can auto-configure a `ConnectionFactory` when it detects that https://activemq.apache.org/components/artemis/[ActiveMQ Artemis] is available on the classpath.
If the broker is present, an embedded broker is automatically started and configured (unless the mode property has been explicitly set).
The supported modes are `embedded` (to make explicit that an embedded broker is required and that an error should occur if the broker is not available on the classpath) and `native` (to connect to a broker using the `netty` transport protocol).
When the latter is configured, Spring Boot configures a `ConnectionFactory` that connects to a broker running on the local machine with the default settings.
NOTE: If you use `spring-boot-starter-artemis`, the necessary dependencies to connect to an existing ActiveMQ Artemis instance are provided, as well as the Spring infrastructure to integrate with JMS.
Adding `org.apache.activemq:artemis-jms-server` to your application lets you use embedded mode.
ActiveMQ Artemis configuration is controlled by external configuration properties in `+spring.artemis.*+`.
For example, you might declare the following section in `application.properties`:
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
----
spring:
artemis:
mode: native
broker-url: "tcp://192.168.1.210:9876"
user: "admin"
password: "secret"
----
When embedding the broker, you can choose if you want to enable persistence and list the destinations that should be made available.
These can be specified as a comma-separated list to create them with the default options, or you can define bean(s) of type `org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration` or `org.apache.activemq.artemis.jms.server.config.TopicConfiguration`, for advanced queue and topic configurations, respectively.
By default, a `CachingConnectionFactory` wraps the native `ConnectionFactory` with sensible settings that you can control by external configuration properties in `+spring.jms.*+`:
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
----
spring:
jms:
cache:
session-cache-size: 5
----
If you'd rather use native pooling, you can do so by adding a dependency to `org.messaginghub:pooled-jms` and configuring the `JmsPoolConnectionFactory` accordingly, as shown in the following example:
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
----
spring:
artemis:
pool:
enabled: true
max-connections: 50
----
See {spring-boot-autoconfigure-module-code}/jms/artemis/ArtemisProperties.java[`ArtemisProperties`] for more supported options.
No JNDI lookup is involved, and destinations are resolved against their names, using either the `name` attribute in the Artemis configuration or the names provided through configuration.
[[messaging.jms.jndi]]
=== Using a JNDI ConnectionFactory
If you are running your application in an application server, Spring Boot tries to locate a JMS `ConnectionFactory` by using JNDI.

@ -1,13 +0,0 @@
plugins {
id "org.springframework.boot.starter"
}
description = "Starter for JMS messaging using Apache Artemis"
dependencies {
api(project(":spring-boot-project:spring-boot-starters:spring-boot-starter"))
api("org.springframework:spring-jms")
api("org.apache.activemq:artemis-jms-client") {
exclude group: "commons-logging", module: "commons-logging"
}
}
Loading…
Cancel
Save