diff --git a/spring-boot-autoconfigure/pom.xml b/spring-boot-autoconfigure/pom.xml
index ce883887b9..7de84e78c8 100644
--- a/spring-boot-autoconfigure/pom.xml
+++ b/spring-boot-autoconfigure/pom.xml
@@ -130,6 +130,16 @@
activemq-pool
true
+
+ org.apache.activemq
+ artemis-jms-client
+ true
+
+
+ org.apache.activemq
+ artemis-jms-server
+ true
+
org.apache.commons
commons-dbcp2
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfiguration.java
new file mode 100644
index 0000000000..41d0022c64
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfiguration.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012-2015 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
+ *
+ * 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.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.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
+ * @since 1.3.0
+ * @see ArtemisProperties
+ */
+@Configuration
+@AutoConfigureBefore(JmsAutoConfiguration.class)
+@AutoConfigureAfter({ JndiConnectionFactoryAutoConfiguration.class })
+@ConditionalOnClass({ ConnectionFactory.class, ActiveMQConnectionFactory.class })
+@ConditionalOnMissingBean(ConnectionFactory.class)
+@EnableConfigurationProperties(ArtemisProperties.class)
+@Import({ ArtemisXAConnectionFactoryConfiguration.class,
+ ArtemisConnectionFactoryConfiguration.class })
+public class ArtemisAutoConfiguration {
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConfigurationCustomizer.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConfigurationCustomizer.java
new file mode 100644
index 0000000000..1716a46d87
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConfigurationCustomizer.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012-2015 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
+ *
+ * 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.springframework.boot.autoconfigure.jms.artemis;
+
+import org.apache.activemq.artemis.core.config.Configuration;
+import org.apache.activemq.artemis.jms.server.embedded.EmbeddedJMS;
+
+/**
+ * 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 EmbeddedJMS} instance.
+ *
+ * @author Eddú Meléndez
+ * @author Phillip Webb
+ * @since 1.3.0
+ * @see ArtemisAutoConfiguration
+ */
+public interface ArtemisConfigurationCustomizer {
+
+ /**
+ * Customize the configuration.
+ * @param configuration the configuration to customize
+ */
+ void customize(Configuration configuration);
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java
new file mode 100644
index 0000000000..760f8c42ae
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012-2015 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
+ *
+ * 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.springframework.boot.autoconfigure.jms.artemis;
+
+import javax.jms.ConnectionFactory;
+
+import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
+import org.springframework.beans.factory.ListableBeanFactory;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Configuration for Artemis {@link ConnectionFactory}.
+ *
+ * @author Eddú Meléndez
+ * @author Phillip Webb
+ */
+@Configuration
+@ConditionalOnMissingBean(ConnectionFactory.class)
+class ArtemisConnectionFactoryConfiguration {
+
+ @Bean
+ public ConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory,
+ ArtemisProperties properties) {
+ return new ArtemisConnectionFactoryFactory(beanFactory, properties)
+ .createConnectionFactory(ActiveMQConnectionFactory.class);
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryFactory.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryFactory.java
new file mode 100644
index 0000000000..322f963da6
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryFactory.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2012-2015 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
+ *
+ * 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.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;
+
+/**
+ * Factory to create a Artemis {@link ActiveMQConnectionFactory} instance from properties
+ * defined in {@link ArtemisProperties}.
+ *
+ * @author Eddú Meléndez
+ * @author Phillip Webb
+ * @author Stephane Nicoll
+ */
+class ArtemisConnectionFactoryFactory {
+
+ static final String EMBEDDED_JMS_CLASS = "org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ";
+
+ private final ArtemisProperties properties;
+
+ private final ListableBeanFactory beanFactory;
+
+ public 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;
+ }
+
+ public T createConnectionFactory(
+ Class factoryClass) {
+ try {
+ startEmbeddedJms();
+ return doCreateConnectionFactory(factoryClass);
+ }
+ catch (Exception ex) {
+ throw new IllegalStateException("Unable to create "
+ + "ActiveMQConnectionFactory", ex);
+ }
+ }
+
+ private void startEmbeddedJms() {
+ if (ClassUtils.isPresent(EMBEDDED_JMS_CLASS, null)) {
+ try {
+ this.beanFactory.getBeansOfType(Class.forName(EMBEDDED_JMS_CLASS));
+ }
+ catch (Exception ex) {
+ // Ignore
+ }
+ }
+ }
+
+ private T doCreateConnectionFactory(
+ Class 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.
+ */
+ private ArtemisMode deduceMode() {
+ if (this.properties.getEmbedded().isEnabled()
+ && ClassUtils.isPresent(EMBEDDED_JMS_CLASS, null)) {
+ return ArtemisMode.EMBEDDED;
+ }
+ return ArtemisMode.NATIVE;
+ }
+
+ private T createEmbeddedConnectionFactory(
+ Class 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 createNativeConnectionFactory(
+ Class factoryClass) throws Exception {
+ Map 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 constructor = factoryClass.getConstructor(boolean.class,
+ TransportConfiguration[].class);
+ return constructor.newInstance(false,
+ new TransportConfiguration[] { transportConfiguration });
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedConfigurationFactory.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedConfigurationFactory.java
new file mode 100644
index 0000000000..701254efc1
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedConfigurationFactory.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012-2015 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
+ *
+ * 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.springframework.boot.autoconfigure.jms.artemis;
+
+import java.io.File;
+
+import org.apache.activemq.artemis.api.core.TransportConfiguration;
+import org.apache.activemq.artemis.core.config.Configuration;
+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.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Configuration used to create the embedded Artemis server.
+ *
+ * @author Eddú Meléndez
+ * @author Stephane Nicol
+ * @author Phillip Webb
+ */
+class ArtemisEmbeddedConfigurationFactory {
+
+ private Log logger = LogFactory.getLog(ArtemisEmbeddedConfigurationFactory.class);
+
+ private final ArtemisProperties.Embedded properties;
+
+ public ArtemisEmbeddedConfigurationFactory(ArtemisProperties properties) {
+ this.properties = properties.getEmbedded();
+ }
+
+ public 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()) {
+ this.logger.debug("Using default Artemis cluster password: "
+ + this.properties.getClusterPassword());
+ }
+ configuration.setClusterPassword(this.properties.getClusterPassword());
+ return configuration;
+ }
+
+ 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();
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedServerConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedServerConfiguration.java
new file mode 100644
index 0000000000..686b4f91ef
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedServerConfiguration.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2012-2015 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
+ *
+ * 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.springframework.boot.autoconfigure.jms.artemis;
+
+import java.util.Collection;
+import java.util.List;
+
+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.apache.activemq.artemis.jms.server.embedded.EmbeddedJMS;
+import org.springframework.beans.factory.annotation.Autowired;
+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;
+import org.springframework.core.annotation.AnnotationAwareOrderComparator;
+
+/**
+ * Configuration used to create the embedded Artemis server.
+ *
+ * @author Eddú Meléndez
+ * @author Phillip Webb
+ * @author Stephane Nicoll
+ */
+@Configuration
+@ConditionalOnClass(name = ArtemisConnectionFactoryFactory.EMBEDDED_JMS_CLASS)
+@ConditionalOnProperty(prefix = "spring.artemis.embedded", name = "enabled", havingValue = "true", matchIfMissing = true)
+class ArtemisEmbeddedServerConfiguration {
+
+ @Autowired
+ private ArtemisProperties properties;
+
+ @Autowired(required = false)
+ private List configurationCustomizers;
+
+ @Autowired(required = false)
+ private List queuesConfiguration;
+
+ @Autowired(required = false)
+ private List topicsConfiguration;
+
+ @Bean
+ @ConditionalOnMissingBean
+ public org.apache.activemq.artemis.core.config.Configuration artemisConfiguration() {
+ return new ArtemisEmbeddedConfigurationFactory(this.properties)
+ .createConfiguration();
+ }
+
+ @Bean(initMethod = "start", destroyMethod = "stop")
+ @ConditionalOnMissingBean
+ public EmbeddedJMS artemisServer(
+ org.apache.activemq.artemis.core.config.Configuration configuration,
+ JMSConfiguration jmsConfiguration) {
+ EmbeddedJMS server = new EmbeddedJMS();
+ customize(configuration);
+ server.setConfiguration(configuration);
+ server.setJmsConfiguration(jmsConfiguration);
+ server.setRegistry(new ArtemisNoOpBindingRegistry());
+ return server;
+ }
+
+ private void customize(
+ org.apache.activemq.artemis.core.config.Configuration configuration) {
+ if (this.configurationCustomizers != null) {
+ AnnotationAwareOrderComparator.sort(this.configurationCustomizers);
+ for (ArtemisConfigurationCustomizer customizer : this.configurationCustomizers) {
+ customizer.customize(configuration);
+ }
+ }
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public JMSConfiguration artemisJmsConfiguration() {
+ JMSConfiguration configuration = new JMSConfigurationImpl();
+ addAll(configuration.getQueueConfigurations(), this.queuesConfiguration);
+ addAll(configuration.getTopicConfigurations(), this.topicsConfiguration);
+ addQueues(configuration, this.properties.getEmbedded().getQueues());
+ addTopics(configuration, this.properties.getEmbedded().getTopics());
+ return configuration;
+ }
+
+ private void addAll(List list, Collection extends T> items) {
+ if (items != null) {
+ list.addAll(items);
+ }
+ }
+
+ 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);
+ }
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisMode.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisMode.java
new file mode 100644
index 0000000000..c5ed813875
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisMode.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012-2015 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
+ *
+ * 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.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
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisNoOpBindingRegistry.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisNoOpBindingRegistry.java
new file mode 100644
index 0000000000..6d991be7b3
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisNoOpBindingRegistry.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2012-2015 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
+ *
+ * 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.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() {
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisProperties.java
new file mode 100644
index 0000000000..249d6f0d8c
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisProperties.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2012-2015 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
+ *
+ * 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.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.context.properties.ConfigurationProperties;
+
+/**
+ * Configuration properties for Artemis
+ *
+ * @author Eddú Meléndez
+ * @author Stephane Nicoll
+ * @since 1.3.0
+ */
+@ConfigurationProperties(prefix = "spring.artemis")
+public class ArtemisProperties {
+
+ /**
+ * Artemis deployment mode, auto-detected by default. Can be explicitly set to
+ * "native" or "embedded".
+ */
+ private ArtemisMode mode;
+
+ /**
+ * Artemis broker host.
+ */
+ private String host = "localhost";
+
+ /**
+ * Artemis broker port.
+ */
+ private int port = 61616;
+
+ private final Embedded embedded = new Embedded();
+
+ public ArtemisMode getMode() {
+ return this.mode;
+ }
+
+ public void setMode(ArtemisMode mode) {
+ this.mode = mode;
+ }
+
+ public String getHost() {
+ return this.host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public int getPort() {
+ return this.port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public Embedded getEmbedded() {
+ return this.embedded;
+ }
+
+ /**
+ * 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();
+
+ /**
+ * Enable embedded mode if the Artemis server APIs are available.
+ */
+ private boolean enabled = true;
+
+ /**
+ * 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 generateTransportParameters() {
+ Map parameters = new HashMap();
+ parameters.put(TransportConstants.SERVER_ID_PROP_NAME, getServerId());
+ return parameters;
+ }
+
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisXAConnectionFactoryConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisXAConnectionFactoryConfiguration.java
new file mode 100644
index 0000000000..783154a4c1
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisXAConnectionFactoryConfiguration.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2012-2015 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
+ *
+ * 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.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.jta.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
+ * @since 1.3.0
+ */
+@Configuration
+@ConditionalOnMissingBean(ConnectionFactory.class)
+@ConditionalOnClass(TransactionManager.class)
+@ConditionalOnBean(XAConnectionFactoryWrapper.class)
+class ArtemisXAConnectionFactoryConfiguration {
+
+ @Primary
+ @Bean(name = { "jmsConnectionFactory", "xaJmsConnectionFactory" })
+ public ConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory,
+ ArtemisProperties properties, XAConnectionFactoryWrapper wrapper)
+ throws Exception {
+ return wrapper.wrapConnectionFactory(new ArtemisConnectionFactoryFactory(
+ beanFactory, properties)
+ .createConnectionFactory(ActiveMQXAConnectionFactory.class));
+ }
+
+ @Bean
+ public ConnectionFactory nonXaJmsConnectionFactory(ListableBeanFactory beanFactory,
+ ArtemisProperties properties) {
+ return new ArtemisConnectionFactoryFactory(beanFactory, properties)
+ .createConnectionFactory(ActiveMQXAConnectionFactory.class);
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/package-info.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/package-info.java
new file mode 100644
index 0000000000..d069cf1234
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2012-2015 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
+ *
+ * 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.
+ */
+
+/**
+ * Auto-configuration for Artemis.
+ *
+ * @author Eddú Meléndez
+ */
+package org.springframework.boot.autoconfigure.jms.artemis;
diff --git a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
index 171256c361..05834600d2 100644
--- a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
+++ b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
@@ -32,6 +32,7 @@ org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
+org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.hornetq.HornetQAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchDataAutoConfiguration,\
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java
new file mode 100644
index 0000000000..95b880757b
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java
@@ -0,0 +1,421 @@
+/*
+ * Copyright 2012-2015 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
+ *
+ * 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.springframework.boot.autoconfigure.jms.artemis;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.UUID;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+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.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.apache.activemq.artemis.jms.server.embedded.EmbeddedJMS;
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.test.EnvironmentTestUtils;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.jms.core.JmsTemplate;
+import org.springframework.jms.core.MessageCreator;
+import org.springframework.jms.core.SessionCallback;
+import org.springframework.jms.support.destination.DestinationResolver;
+import org.springframework.jms.support.destination.DynamicDestinationResolver;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for {@link ArtemisAutoConfiguration}.
+ *
+ * @author Eddú Meléndez
+ * @author Stephane Nicoll
+ */
+public class ArtemisAutoConfigurationTests {
+
+ @Rule
+ public final TemporaryFolder folder = new TemporaryFolder();
+
+ private AnnotationConfigApplicationContext context;
+
+ @After
+ public void tearDown() {
+ if (this.context != null) {
+ this.context.close();
+ }
+ }
+
+ @Test
+ public void nativeConnectionFactory() {
+ load(EmptyConfiguration.class, "spring.artemis.mode:native");
+ JmsTemplate jmsTemplate = this.context.getBean(JmsTemplate.class);
+ ActiveMQConnectionFactory connectionFactory = this.context
+ .getBean(ActiveMQConnectionFactory.class);
+ assertEquals(jmsTemplate.getConnectionFactory(), connectionFactory);
+ assertNettyConnectionFactory(connectionFactory, "localhost", 61616);
+ }
+
+ @Test
+ public void nativeConnectionFactoryCustomHost() {
+ load(EmptyConfiguration.class, "spring.artemis.mode:native",
+ "spring.artemis.host:192.168.1.144", "spring.artemis.port:9876");
+ ActiveMQConnectionFactory connectionFactory = this.context
+ .getBean(ActiveMQConnectionFactory.class);
+ assertNettyConnectionFactory(connectionFactory, "192.168.1.144", 9876);
+ }
+
+ @Test
+ public void embeddedConnectionFactory() {
+ load(EmptyConfiguration.class, "spring.artemis.mode:embedded");
+ ArtemisProperties properties = this.context.getBean(ArtemisProperties.class);
+ assertEquals(ArtemisMode.EMBEDDED, properties.getMode());
+ assertEquals(1, this.context.getBeansOfType(EmbeddedJMS.class).size());
+ org.apache.activemq.artemis.core.config.Configuration configuration = this.context
+ .getBean(org.apache.activemq.artemis.core.config.Configuration.class);
+ assertFalse("Persistence disabled by default",
+ configuration.isPersistenceEnabled());
+ assertFalse("Security disabled by default", configuration.isSecurityEnabled());
+
+ ActiveMQConnectionFactory connectionFactory = this.context
+ .getBean(ActiveMQConnectionFactory.class);
+ assertInVmConnectionFactory(connectionFactory);
+ }
+
+ @Test
+ public void embeddedConnectionFactoryByDefault() {
+ // No mode is specified
+ load(EmptyConfiguration.class);
+ assertEquals(1, this.context.getBeansOfType(EmbeddedJMS.class).size());
+ org.apache.activemq.artemis.core.config.Configuration configuration = this.context
+ .getBean(org.apache.activemq.artemis.core.config.Configuration.class);
+ assertFalse("Persistence disabled by default",
+ configuration.isPersistenceEnabled());
+ assertFalse("Security disabled by default", configuration.isSecurityEnabled());
+
+ ActiveMQConnectionFactory connectionFactory = this.context
+ .getBean(ActiveMQConnectionFactory.class);
+ assertInVmConnectionFactory(connectionFactory);
+ }
+
+ @Test
+ public void nativeConnectionFactoryIfEmbeddedServiceDisabledExplicitly() {
+ // No mode is specified
+ load(EmptyConfiguration.class, "spring.artemis.embedded.enabled:false");
+ assertEquals(0, this.context.getBeansOfType(EmbeddedJMS.class).size());
+ ActiveMQConnectionFactory connectionFactory = this.context
+ .getBean(ActiveMQConnectionFactory.class);
+ assertNettyConnectionFactory(connectionFactory, "localhost", 61616);
+ }
+
+ @Test
+ public void embeddedConnectionFactorEvenIfEmbeddedServiceDisabled() {
+ // No mode is specified
+ load(EmptyConfiguration.class, "spring.artemis.mode:embedded",
+ "spring.artemis.embedded.enabled:false");
+ assertEquals(0, this.context.getBeansOfType(EmbeddedJMS.class).size());
+ ActiveMQConnectionFactory connectionFactory = this.context
+ .getBean(ActiveMQConnectionFactory.class);
+ assertInVmConnectionFactory(connectionFactory);
+ }
+
+ @Test
+ public void embeddedServerWithDestinations() {
+ load(EmptyConfiguration.class, "spring.artemis.embedded.queues=Queue1,Queue2",
+ "spring.artemis.embedded.topics=Topic1");
+ DestinationChecker checker = new DestinationChecker(this.context);
+ checker.checkQueue("Queue1", true);
+ checker.checkQueue("Queue2", true);
+ checker.checkQueue("QueueDoesNotExist", true);
+ checker.checkTopic("Topic1", true);
+ checker.checkTopic("TopicDoesNotExist", false);
+ }
+
+ @Test
+ public void embeddedServerWithDestinationConfig() {
+ load(DestinationConfiguration.class);
+ DestinationChecker checker = new DestinationChecker(this.context);
+ checker.checkQueue("sampleQueue", true);
+ checker.checkTopic("sampleTopic", true);
+ }
+
+ @Test
+ public void embeddedServiceWithCustomJmsConfiguration() {
+ // Ignored with custom config
+ load(CustomJmsConfiguration.class, "spring.artemis.embedded.queues=Queue1,Queue2");
+ DestinationChecker checker = new DestinationChecker(this.context);
+ checker.checkQueue("custom", true); // See CustomJmsConfiguration
+ checker.checkQueue("Queue1", true);
+ checker.checkQueue("Queue2", true);
+ }
+
+ @Test
+ public void embeddedServiceWithCustomArtemisConfiguration() {
+ load(CustomArtemisConfiguration.class);
+ org.apache.activemq.artemis.core.config.Configuration configuration = this.context
+ .getBean(org.apache.activemq.artemis.core.config.Configuration.class);
+ assertEquals("customFooBar", configuration.getName());
+ }
+
+ @Test
+ public void embeddedWithPersistentMode() throws IOException, JMSException {
+ File dataFolder = this.folder.newFolder();
+
+ // Start the server and post a message to some queue
+ load(EmptyConfiguration.class, "spring.artemis.embedded.queues=TestQueue",
+ "spring.artemis.embedded.persistent:true",
+ "spring.artemis.embedded.dataDirectory:" + dataFolder.getAbsolutePath());
+
+ final String msgId = UUID.randomUUID().toString();
+ JmsTemplate jmsTemplate = this.context.getBean(JmsTemplate.class);
+ jmsTemplate.send("TestQueue", new MessageCreator() {
+ @Override
+ public Message createMessage(Session session) throws JMSException {
+ return session.createTextMessage(msgId);
+ }
+ });
+ this.context.close(); // Shutdown the broker
+
+ // Start the server again and check if our message is still here
+ load(EmptyConfiguration.class, "spring.artemis.embedded.queues=TestQueue",
+ "spring.artemis.embedded.persistent:true",
+ "spring.artemis.embedded.dataDirectory:" + dataFolder.getAbsolutePath());
+
+ JmsTemplate jmsTemplate2 = this.context.getBean(JmsTemplate.class);
+ jmsTemplate2.setReceiveTimeout(1000L);
+ Message message = jmsTemplate2.receive("TestQueue");
+ assertNotNull("No message on persistent queue", message);
+ assertEquals("Invalid message received on queue", msgId,
+ ((TextMessage) message).getText());
+ }
+
+ @Test
+ public void severalEmbeddedBrokers() {
+ load(EmptyConfiguration.class, "spring.artemis.embedded.queues=Queue1");
+ AnnotationConfigApplicationContext anotherContext = doLoad(
+ EmptyConfiguration.class, "spring.artemis.embedded.queues=Queue2");
+ try {
+ ArtemisProperties properties = this.context.getBean(ArtemisProperties.class);
+ ArtemisProperties anotherProperties = anotherContext
+ .getBean(ArtemisProperties.class);
+ assertTrue("ServerId should not match", properties.getEmbedded()
+ .getServerId() < anotherProperties.getEmbedded().getServerId());
+
+ DestinationChecker checker = new DestinationChecker(this.context);
+ checker.checkQueue("Queue1", true);
+ checker.checkQueue("Queue2", true);
+
+ DestinationChecker anotherChecker = new DestinationChecker(anotherContext);
+ anotherChecker.checkQueue("Queue2", true);
+ anotherChecker.checkQueue("Queue1", true);
+ }
+ finally {
+ anotherContext.close();
+ }
+ }
+
+ @Test
+ public void connectToASpecificEmbeddedBroker() {
+ load(EmptyConfiguration.class, "spring.artemis.embedded.serverId=93",
+ "spring.artemis.embedded.queues=Queue1");
+ AnnotationConfigApplicationContext anotherContext = doLoad(
+ EmptyConfiguration.class, "spring.artemis.mode=embedded",
+ "spring.artemis.embedded.serverId=93", // Connect to the "main" broker
+ "spring.artemis.embedded.enabled=false"); // do not start a specific one
+ try {
+ DestinationChecker checker = new DestinationChecker(this.context);
+ checker.checkQueue("Queue1", true);
+
+ DestinationChecker anotherChecker = new DestinationChecker(anotherContext);
+ anotherChecker.checkQueue("Queue1", true);
+ }
+ finally {
+ anotherContext.close();
+ }
+ }
+
+ private TransportConfiguration assertInVmConnectionFactory(
+ ActiveMQConnectionFactory connectionFactory) {
+ TransportConfiguration transportConfig = getSingleTransportConfiguration(connectionFactory);
+ assertEquals(InVMConnectorFactory.class.getName(),
+ transportConfig.getFactoryClassName());
+ return transportConfig;
+ }
+
+ private TransportConfiguration assertNettyConnectionFactory(
+ ActiveMQConnectionFactory connectionFactory, String host, int port) {
+ TransportConfiguration transportConfig = getSingleTransportConfiguration(connectionFactory);
+ assertEquals(NettyConnectorFactory.class.getName(),
+ transportConfig.getFactoryClassName());
+ assertEquals(host, transportConfig.getParams().get("host"));
+ assertEquals(port, transportConfig.getParams().get("port"));
+ return transportConfig;
+ }
+
+ private TransportConfiguration getSingleTransportConfiguration(
+ ActiveMQConnectionFactory connectionFactory) {
+ TransportConfiguration[] transportConfigurations = connectionFactory
+ .getServerLocator().getStaticTransportConfigurations();
+ assertEquals(1, transportConfigurations.length);
+ return transportConfigurations[0];
+ }
+
+ private void load(Class> config, String... environment) {
+ this.context = doLoad(config, environment);
+ }
+
+ private AnnotationConfigApplicationContext doLoad(Class> config,
+ String... environment) {
+ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
+ applicationContext.register(config);
+ applicationContext.register(ArtemisAutoConfigurationWithoutXA.class,
+ JmsAutoConfiguration.class);
+ EnvironmentTestUtils.addEnvironment(applicationContext, environment);
+ applicationContext.refresh();
+ return applicationContext;
+ }
+
+ private static class DestinationChecker {
+
+ private final JmsTemplate jmsTemplate;
+
+ private final DestinationResolver destinationResolver;
+
+ private DestinationChecker(ApplicationContext applicationContext) {
+ this.jmsTemplate = applicationContext.getBean(JmsTemplate.class);
+ this.destinationResolver = new DynamicDestinationResolver();
+ }
+
+ public void checkQueue(String name, boolean shouldExist) {
+ checkDestination(name, false, shouldExist);
+ }
+
+ public void checkTopic(String name, boolean shouldExist) {
+ checkDestination(name, true, shouldExist);
+ }
+
+ public void checkDestination(final String name, final boolean pubSub,
+ final boolean shouldExist) {
+ this.jmsTemplate.execute(new SessionCallback() {
+ @Override
+ public Void doInJms(Session session) throws JMSException {
+ try {
+ Destination destination = DestinationChecker.this.destinationResolver
+ .resolveDestinationName(session, name, pubSub);
+ if (!shouldExist) {
+ throw new IllegalStateException("Destination '" + name
+ + "' was not expected but got " + destination);
+ }
+ }
+ catch (JMSException e) {
+ if (shouldExist) {
+ throw new IllegalStateException("Destination '" + name
+ + "' was expected but got " + e.getMessage());
+ }
+ }
+ return null;
+ }
+ });
+ }
+ }
+
+ @Configuration
+ protected static class EmptyConfiguration {
+ }
+
+ @Configuration
+ protected 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
+ protected static class CustomJmsConfiguration {
+
+ @Bean
+ public JMSConfiguration myJmsConfiguration() {
+ JMSConfiguration config = new JMSConfigurationImpl();
+ JMSQueueConfiguration jmsQueueConfiguration = new JMSQueueConfigurationImpl();
+ jmsQueueConfiguration.setName("custom");
+ jmsQueueConfiguration.setDurable(false);
+ config.getQueueConfigurations().add(jmsQueueConfiguration);
+ return config;
+ }
+ }
+
+ @Configuration
+ protected static class CustomArtemisConfiguration {
+
+ @Bean
+ public ArtemisConfigurationCustomizer myArtemisCustomize() {
+ return new ArtemisConfigurationCustomizer() {
+ @Override
+ public void customize(
+ org.apache.activemq.artemis.core.config.Configuration configuration) {
+ configuration.setClusterPassword("Foobar");
+ configuration.setName("customFooBar");
+ }
+ };
+ }
+
+ }
+
+ @Configuration
+ @EnableConfigurationProperties(ArtemisProperties.class)
+ @Import({ ArtemisEmbeddedServerConfiguration.class,
+ ArtemisConnectionFactoryConfiguration.class })
+ protected static class ArtemisAutoConfigurationWithoutXA {
+
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedConfigurationFactoryTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedConfigurationFactoryTests.java
new file mode 100644
index 0000000000..81320f36de
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedConfigurationFactoryTests.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2012-2015 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
+ *
+ * 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.springframework.boot.autoconfigure.jms.artemis;
+
+import org.apache.activemq.artemis.core.config.Configuration;
+import org.apache.activemq.artemis.core.server.JournalType;
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.endsWith;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Tests for {@link ArtemisEmbeddedConfigurationFactory}
+ *
+ * @author Eddú Meléndez
+ * @author Stephane Nicol
+ * @author Phillip Webb
+ */
+public class ArtemisEmbeddedConfigurationFactoryTests {
+
+ @Test
+ public 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")));
+ assertThat(configuration.getJournalDirectory(), endsWith("/journal"));
+ }
+
+ @Test
+ public void persistenceSetup() {
+ ArtemisProperties properties = new ArtemisProperties();
+ properties.getEmbedded().setPersistent(true);
+ Configuration configuration = new ArtemisEmbeddedConfigurationFactory(properties)
+ .createConfiguration();
+ assertThat(configuration.isPersistenceEnabled(), equalTo(true));
+ assertThat(configuration.getJournalType(), equalTo(JournalType.NIO));
+ }
+
+ @Test
+ public void generatedClusterPassword() throws Exception {
+ ArtemisProperties properties = new ArtemisProperties();
+ Configuration configuration = new ArtemisEmbeddedConfigurationFactory(properties)
+ .createConfiguration();
+ assertThat(configuration.getClusterPassword().length(), equalTo(36));
+ }
+
+ @Test
+ public void specificClusterPassword() throws Exception {
+ ArtemisProperties properties = new ArtemisProperties();
+ properties.getEmbedded().setClusterPassword("password");
+ Configuration configuration = new ArtemisEmbeddedConfigurationFactory(properties)
+ .createConfiguration();
+ assertThat(configuration.getClusterPassword(), equalTo("password"));
+ }
+
+}
diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml
index 223babbdad..a22347cfed 100644
--- a/spring-boot-dependencies/pom.xml
+++ b/spring-boot-dependencies/pom.xml
@@ -48,6 +48,7 @@
5.11.1
2.7.7
+ 1.0.0
1.8.6
3.9.3
2.1.4
@@ -933,6 +934,16 @@
activemq-web-console
${activemq.version}
+
+ org.apache.activemq
+ artemis-jms-client
+ ${artemis.version}
+
+
+ org.apache.activemq
+ artemis-jms-server
+ ${artemis.version}
+
org.apache.commons
commons-dbcp2
diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
index aaebefbed2..0fae679d16 100644
--- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
+++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
@@ -484,7 +484,19 @@ content into your application; rather pick only the properties that you need.
spring.activemq.in-memory=true # broker kind to create if no broker-url is specified
spring.activemq.pooled=false
- # HornetQ ({sc-spring-boot-autoconfigure}/jms/hornetq/HornetQProperties.{sc-ext}[HornetQProperties])
+ # ARTEMIS ({sc-spring-boot-autoconfigure}/jms/artemis/ArtemisProperties.{sc-ext}[ArtemisProperties])
+ spring.artemis.mode= # connection mode (native, embedded)
+ spring.artemis.host=localhost # hornetQ host (native mode)
+ spring.artemis.port=5445 # hornetQ port (native mode)
+ spring.artemis.embedded.enabled=true # if the embedded server is enabled (needs hornetq-jms-server.jar)
+ spring.artemis.embedded.server-id= # auto-generated id of the embedded server (integer)
+ spring.artemis.embedded.persistent=false # message persistence
+ spring.artemis.embedded.data-directory= # location of data content (when persistence is enabled)
+ spring.artemis.embedded.queues= # comma-separated queues to create on startup
+ spring.artemis.embedded.topics= # comma-separated topics to create on startup
+ spring.artemis.embedded.cluster-password= # customer password (randomly generated by default)
+
+ # HORNETQ ({sc-spring-boot-autoconfigure}/jms/hornetq/HornetQProperties.{sc-ext}[HornetQProperties])
spring.hornetq.mode= # connection mode (native, embedded)
spring.hornetq.host=localhost # hornetQ host (native mode)
spring.hornetq.port=5445 # hornetQ port (native mode)
diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
index 7abe2979ce..5461bdbd13 100644
--- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
+++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
@@ -2515,6 +2515,43 @@ to send and receive messages.
+[[boot-features-activemq]]
+==== ActiveMQ support
+Spring Boot can also configure a `ConnectionFactory` when it detects that ActiveMQ is
+available on the classpath. If the broker is present, an embedded broker is started and
+configured automatically (as long as no broker URL is specified through configuration).
+
+ActiveMQ configuration is controlled by external configuration properties in
+`+spring.activemq.*+`. For example, you might declare the following section in
+`application.properties`:
+
+[source,properties,indent=0]
+----
+ spring.activemq.broker-url=tcp://192.168.1.210:9876
+ spring.activemq.user=admin
+ spring.activemq.password=secret
+----
+
+See
+{sc-spring-boot-autoconfigure}/jms/activemq/ActiveMQProperties.{sc-ext}[`ActiveMQProperties`]
+for more of the supported options.
+
+By default, ActiveMQ creates a destination if it does not exist yet, so destinations are
+resolved against their provided names.
+
+
+
+[[boot-features-artemis]]
+==== Artemis support
+Apache Artemis was formed in 2015 when HornetQ was donated to the Apache Foundation. All
+the features listed in the <> section below can be applied to
+Artemis. Simply replace `+++spring.hornetq.*+++` properties with `+++spring.artemis.*+++`
+and use `spring-boot-starter-artemis` instead of `spring-boot-starter-hornetq`.
+
+NOTE: You should not try and use Artemis and HornetQ and the same time.
+
+
+
[[boot-features-hornetq]]
==== HornetQ support
Spring Boot can auto-configure a `ConnectionFactory` when it detects that HornetQ is
@@ -2559,32 +2596,6 @@ through configuration.
-[[boot-features-activemq]]
-==== ActiveMQ support
-Spring Boot can also configure a `ConnectionFactory` when it detects that ActiveMQ is
-available on the classpath. If the broker is present, an embedded broker is started and
-configured automatically (as long as no broker URL is specified through configuration).
-
-ActiveMQ configuration is controlled by external configuration properties in
-`+spring.activemq.*+`. For example, you might declare the following section in
-`application.properties`:
-
-[source,properties,indent=0]
-----
- spring.activemq.broker-url=tcp://192.168.1.210:9876
- spring.activemq.user=admin
- spring.activemq.password=secret
-----
-
-See
-{sc-spring-boot-autoconfigure}/jms/activemq/ActiveMQProperties.{sc-ext}[`ActiveMQProperties`]
-for more of the supported options.
-
-By default, ActiveMQ creates a destination if it does not exist yet, so destinations are
-resolved against their provided names.
-
-
-
[[boot-features-jms-jndi]]
==== Using a JNDI ConnectionFactory
If you are running your application in an Application Server Spring Boot will attempt to
diff --git a/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc b/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc
index 5dcc8ba3ee..362bae95f1 100644
--- a/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc
+++ b/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc
@@ -264,6 +264,9 @@ The following application starters are provided by Spring Boot under the
|`spring-boot-starter-aop`
|Support for aspect-oriented programming including `spring-aop` and AspectJ.
+|`spring-boot-starter-artemis`
+|Support for "`Java Message Service API`" via Apache Artemis.
+
|`spring-boot-starter-batch`
|Support for "`Spring Batch`" including HSQLDB database.
diff --git a/spring-boot-starters/pom.xml b/spring-boot-starters/pom.xml
index 9b56298077..c683196be9 100644
--- a/spring-boot-starters/pom.xml
+++ b/spring-boot-starters/pom.xml
@@ -23,6 +23,7 @@
spring-boot-starter
spring-boot-starter-amqp
spring-boot-starter-aop
+ spring-boot-starter-artemis
spring-boot-starter-batch
spring-boot-starter-cache
spring-boot-starter-cloud-connectors
diff --git a/spring-boot-starters/spring-boot-starter-artemis/pom.xml b/spring-boot-starters/spring-boot-starter-artemis/pom.xml
new file mode 100644
index 0000000000..5b4c7582c3
--- /dev/null
+++ b/spring-boot-starters/spring-boot-starter-artemis/pom.xml
@@ -0,0 +1,34 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starters
+ 1.3.0.BUILD-SNAPSHOT
+
+ spring-boot-starter-artemis
+ Spring Boot Artemis Starter
+ Spring Boot Artemis Starter
+ http://projects.spring.io/spring-boot/
+
+ Pivotal Software, Inc.
+ http://www.spring.io
+
+
+ ${basedir}/../..
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework
+ spring-jms
+
+
+ org.apache.activemq
+ artemis-jms-client
+
+
+
diff --git a/spring-boot-starters/spring-boot-starter-artemis/src/main/resources/META-INF/spring.provides b/spring-boot-starters/spring-boot-starter-artemis/src/main/resources/META-INF/spring.provides
new file mode 100644
index 0000000000..7c604a7157
--- /dev/null
+++ b/spring-boot-starters/spring-boot-starter-artemis/src/main/resources/META-INF/spring.provides
@@ -0,0 +1 @@
+provides: artemis-jms-client,spring-jms