diff --git a/spring-boot-autoconfigure/pom.xml b/spring-boot-autoconfigure/pom.xml
index b5ba8a6ea3..017a68059f 100644
--- a/spring-boot-autoconfigure/pom.xml
+++ b/spring-boot-autoconfigure/pom.xml
@@ -111,6 +111,16 @@
hibernate-jpa-2.0-api
true
+
+ org.hornetq
+ hornetq-jms-client
+ true
+
+
+ org.hornetq
+ hornetq-jms-server
+ true
+
org.springframework
spring-jdbc
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/HornetQAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/HornetQAutoConfiguration.java
new file mode 100644
index 0000000000..db8596a29f
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/HornetQAutoConfiguration.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2012-2014 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;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.ConnectionFactory;
+
+import org.hornetq.api.core.TransportConfiguration;
+import org.hornetq.api.core.client.HornetQClient;
+import org.hornetq.api.core.client.ServerLocator;
+import org.hornetq.api.jms.HornetQJMSClient;
+import org.hornetq.api.jms.JMSFactoryType;
+import org.hornetq.core.remoting.impl.invm.InVMConnectorFactory;
+import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory;
+import org.hornetq.core.remoting.impl.netty.TransportConstants;
+import org.hornetq.jms.client.HornetQConnectionFactory;
+import org.hornetq.jms.server.config.JMSConfiguration;
+import org.hornetq.jms.server.config.JMSQueueConfiguration;
+import org.hornetq.jms.server.config.TopicConfiguration;
+import org.hornetq.jms.server.config.impl.JMSConfigurationImpl;
+import org.hornetq.jms.server.config.impl.JMSQueueConfigurationImpl;
+import org.hornetq.jms.server.config.impl.TopicConfigurationImpl;
+import org.hornetq.jms.server.embedded.EmbeddedJMS;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+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.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.AnnotationAwareOrderComparator;
+import org.springframework.util.ClassUtils;
+
+/**
+ * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
+ * Auto-configuration} to integrate with an HornetQ broker. Connect by default to a broker
+ * available on the local machine with the default settings. If the necessary classes are
+ * present, the broker can also be embedded in the application itself.
+ *
+ * @author Stephane Nicoll
+ * @since 1.1.0
+ */
+@Configuration
+@AutoConfigureBefore(JmsAutoConfiguration.class)
+@ConditionalOnClass({ ConnectionFactory.class, HornetQJMSClient.class })
+@EnableConfigurationProperties(HornetQProperties.class)
+public class HornetQAutoConfiguration {
+
+ private static final String EMBEDDED_JMS_CLASS = "org.hornetq.jms.server.embedded.EmbeddedJMS";
+
+ @Autowired
+ private HornetQProperties properties;
+
+ /**
+ * Create the {@link ConnectionFactory} to use if none is provided. If no
+ * {@linkplain HornetQProperties#getMode() mode} has been explicitly set, connect to
+ * the embedded server if it has been requested or to a broker available on the local
+ * machine with the default settings otherwise.
+ */
+ @Bean
+ @ConditionalOnMissingBean
+ public ConnectionFactory jmsConnectionFactory() {
+ HornetQMode mode = this.properties.getMode();
+ if (mode == null) {
+ mode = deduceMode();
+ }
+ if (mode == HornetQMode.EMBEDDED) {
+ return createEmbeddedConnectionFactory();
+ }
+ return createNativeConnectionFactory();
+ }
+
+ /**
+ * Deduce the {@link HornetQMode} to use if none has been set.
+ */
+ private HornetQMode deduceMode() {
+ if (this.properties.getEmbedded().isEnabled()
+ && ClassUtils.isPresent(EMBEDDED_JMS_CLASS, null)) {
+ return HornetQMode.EMBEDDED;
+ }
+ return HornetQMode.NATIVE;
+ }
+
+ private ConnectionFactory createEmbeddedConnectionFactory() {
+ try {
+ TransportConfiguration transportConfiguration = new TransportConfiguration(
+ InVMConnectorFactory.class.getName());
+ ServerLocator serviceLocator = HornetQClient
+ .createServerLocatorWithoutHA(transportConfiguration);
+ return new HornetQConnectionFactory(serviceLocator);
+ }
+ catch (NoClassDefFoundError ex) {
+ throw new IllegalStateException("Unable to create InVM "
+ + "HornetQ connection, ensure that hornet-jms-server.jar "
+ + "is in the classpath", ex);
+ }
+ }
+
+ private ConnectionFactory createNativeConnectionFactory() {
+ 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);
+ return HornetQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF,
+ transportConfiguration);
+ }
+
+ /**
+ * Configuration used to create the embedded HornetQ server.
+ */
+ @Configuration
+ @ConditionalOnClass(name = EMBEDDED_JMS_CLASS)
+ @ConditionalOnProperty(prefix = "spring.hornetq.embedded", value = "enabled")
+ static class EmbeddedServerConfiguration {
+
+ @Autowired
+ private HornetQProperties properties;
+
+ @Autowired(required = false)
+ private List configurationCustomizers;
+
+ @Autowired(required = false)
+ private List queuesConfiguration;
+
+ @Autowired(required = false)
+ private List topicsConfiguration;
+
+ @Bean
+ @ConditionalOnMissingBean
+ public org.hornetq.core.config.Configuration hornetQConfiguration() {
+ return new HornetQEmbeddedConfigurationFactory(this.properties)
+ .createConfiguration();
+ }
+
+ @Bean(initMethod = "start", destroyMethod = "stop")
+ @ConditionalOnMissingBean
+ public EmbeddedJMS hornetQServer(
+ org.hornetq.core.config.Configuration configuration,
+ JMSConfiguration jmsConfiguration) {
+ EmbeddedJMS server = new EmbeddedJMS();
+ applyCustomizers(configuration);
+ server.setConfiguration(configuration);
+ server.setJmsConfiguration(jmsConfiguration);
+ server.setRegistry(new HornetQNoOpBindingRegistry());
+ return server;
+ }
+
+ private void applyCustomizers(org.hornetq.core.config.Configuration configuration) {
+ if (this.configurationCustomizers != null) {
+ AnnotationAwareOrderComparator.sort(this.configurationCustomizers);
+ for (HornetQConfigurationCustomizer customizer : this.configurationCustomizers) {
+ customizer.customize(configuration);
+ }
+ }
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public JMSConfiguration hornetQJmsConfiguration() {
+ JMSConfiguration configuration = new JMSConfigurationImpl();
+ addAll(configuration.getQueueConfigurations(), this.queuesConfiguration);
+ addAll(configuration.getTopicConfigurations(), this.topicsConfiguration);
+ addQueues(configuration, this.properties.getEmbedded().getQueues());
+ addTopis(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) {
+ configuration.getQueueConfigurations().add(
+ new JMSQueueConfigurationImpl(queue, null, persistent, "/queue/"
+ + queue));
+ }
+ }
+
+ private void addTopis(JMSConfiguration configuration, String[] topics) {
+ for (String topic : topics) {
+ configuration.getTopicConfigurations().add(
+ new TopicConfigurationImpl(topic, "/topic/" + topic));
+ }
+ }
+
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/HornetQConfigurationCustomizer.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/HornetQConfigurationCustomizer.java
new file mode 100644
index 0000000000..6ef1afd2f3
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/HornetQConfigurationCustomizer.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012-2014 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;
+
+import org.hornetq.core.config.Configuration;
+import org.hornetq.jms.server.embedded.EmbeddedJMS;
+
+/**
+ * Callback interface that can be implemented by beans wishing to customize the HornetQ
+ * JMS server {@link Configuration} before it is used by an auto-configured
+ * {@link EmbeddedJMS} instance.
+ *
+ * @author Phillip Webb
+ * @since 1.1.0
+ * @see HornetQAutoConfiguration
+ */
+public interface HornetQConfigurationCustomizer {
+
+ /**
+ * 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/HornetQEmbeddedConfigurationFactory.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/HornetQEmbeddedConfigurationFactory.java
new file mode 100644
index 0000000000..783a258733
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/HornetQEmbeddedConfigurationFactory.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012-2014 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;
+
+import java.io.File;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hornetq.api.core.TransportConfiguration;
+import org.hornetq.core.config.Configuration;
+import org.hornetq.core.config.impl.ConfigurationImpl;
+import org.hornetq.core.remoting.impl.invm.InVMAcceptorFactory;
+import org.hornetq.core.server.JournalType;
+import org.springframework.boot.autoconfigure.jms.HornetQProperties.Embedded;
+
+/**
+ * Factory class to create a HornetQ {@link Configuration} from {@link HornetQProperties}.
+ *
+ * @author Stephane Nicol
+ * @author Phillip Webb
+ * @since 1.1.0
+ */
+class HornetQEmbeddedConfigurationFactory {
+
+ private Log logger = LogFactory.getLog(HornetQAutoConfiguration.class);
+
+ private final Embedded properties;
+
+ public HornetQEmbeddedConfigurationFactory(HornetQProperties properties) {
+ this.properties = properties.getEmbedded();
+ }
+
+ public Configuration createConfiguration() {
+ ConfigurationImpl configuration = new ConfigurationImpl();
+ configuration.setSecurityEnabled(false);
+ configuration.setPersistenceEnabled(this.properties.isPersistent());
+
+ String dataDir = getDataDir();
+
+ // HORNETQ-1302
+ 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());
+ configuration.getAcceptorConfigurations().add(transportConfiguration);
+
+ // HORNETQ-1143
+ if (this.properties.isDefaultClusterPassword()) {
+ this.logger.debug("Using default HornetQ 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, "hornetq-data").getAbsolutePath();
+ }
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/HornetQMode.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/HornetQMode.java
new file mode 100644
index 0000000000..d35fe3808e
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/HornetQMode.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2012-2014 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;
+
+/**
+ * Define the mode in which HornetQ can operate.
+ *
+ * @author Stephane Nicoll
+ * @since 1.1.0
+ */
+public enum HornetQMode {
+
+ /**
+ * Connect to a broker using the native HornetQ 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/HornetQNoOpBindingRegistry.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/HornetQNoOpBindingRegistry.java
new file mode 100644
index 0000000000..7c848f6f25
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/HornetQNoOpBindingRegistry.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2012-2014 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;
+
+import org.hornetq.spi.core.naming.BindingRegistry;
+
+/**
+ * A no-op implementation of the {@link org.hornetq.spi.core.naming.BindingRegistry}.
+ *
+ * @author Stephane Nicoll
+ * @since 1.1.0
+ */
+public class HornetQNoOpBindingRegistry implements BindingRegistry {
+
+ @Override
+ public Object lookup(String name) {
+ // This callback is used to check if an entry is present in the context before
+ // creating a queue on the fly. This is actually never used to try to fetch a
+ // destination that is unknown.
+ return null;
+ }
+
+ @Override
+ public boolean bind(String name, Object obj) {
+ // This callback is used bind a Destination created on the fly by the embedded
+ // broker using the JNDI name that was specified in the configuration. This does
+ // not look very useful since it's used nowhere. It could be interesting to
+ // autowire a destination to use it but the wiring is a bit "asynchronous" so
+ // better not provide that feature at all.
+ return false;
+ }
+
+ @Override
+ public void unbind(String name) {
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public Object getContext() {
+ return this;
+ }
+
+ @Override
+ public void setContext(Object ctx) {
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/HornetQProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/HornetQProperties.java
new file mode 100644
index 0000000000..1cd229a04b
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/HornetQProperties.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2012-2014 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;
+
+import java.util.UUID;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * Configuration properties for HornetQ
+ *
+ * @author Stephane Nicoll
+ * @since 1.1.0
+ */
+@ConfigurationProperties(prefix = "spring.hornetq")
+public class HornetQProperties {
+
+ private HornetQMode mode;
+
+ private String host = "localhost";
+
+ private int port = 5445;
+
+ private final Embedded embedded = new Embedded();
+
+ public HornetQMode getMode() {
+ return this.mode;
+ }
+
+ public void setMode(HornetQMode 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 HornetQ server.
+ */
+ public static class Embedded {
+
+ private boolean enabled;
+
+ private boolean persistent;
+
+ private String dataDirectory;
+
+ private String[] queues = new String[0];
+
+ private String[] topics = new String[0];
+
+ private String clusterPassword = UUID.randomUUID().toString();
+
+ private boolean defaultClusterPassword = true;
+
+ 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;
+ }
+
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfiguration.java
index 568335badd..f225c3ae43 100644
--- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfiguration.java
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfiguration.java
@@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.jms;
import javax.jms.ConnectionFactory;
import org.springframework.beans.factory.annotation.Autowired;
+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;
@@ -37,6 +38,7 @@ import org.springframework.jms.core.JmsTemplate;
@ConditionalOnClass(JmsTemplate.class)
@ConditionalOnBean(ConnectionFactory.class)
@EnableConfigurationProperties(JmsProperties.class)
+@AutoConfigureAfter({ HornetQAutoConfiguration.class, ActiveMQAutoConfiguration.class })
public class JmsAutoConfiguration {
@Autowired
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 8fd434cc77..1696504f29 100644
--- a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
+++ b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
@@ -19,6 +19,7 @@ org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.ActiveMQAutoConfiguration,\
+org.springframework.boot.autoconfigure.jms.HornetQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/ActiveMQPropertiesTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/ActiveMQPropertiesTests.java
index dd61c4f042..ad0ab44cab 100644
--- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/ActiveMQPropertiesTests.java
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/ActiveMQPropertiesTests.java
@@ -30,6 +30,7 @@ import static org.junit.Assert.assertEquals;
public class ActiveMQPropertiesTests {
private final ActiveMQProperties properties = new ActiveMQProperties();
+
private final StandardEnvironment environment = new StandardEnvironment();
@Test
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/HornetQAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/HornetQAutoConfigurationTests.java
new file mode 100644
index 0000000000..5321dc9a42
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/HornetQAutoConfigurationTests.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2012-2014 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;
+
+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.hornetq.api.core.TransportConfiguration;
+import org.hornetq.core.remoting.impl.invm.InVMConnectorFactory;
+import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory;
+import org.hornetq.jms.client.HornetQConnectionFactory;
+import org.hornetq.jms.server.config.JMSConfiguration;
+import org.hornetq.jms.server.config.JMSQueueConfiguration;
+import org.hornetq.jms.server.config.TopicConfiguration;
+import org.hornetq.jms.server.config.impl.JMSConfigurationImpl;
+import org.hornetq.jms.server.config.impl.JMSQueueConfigurationImpl;
+import org.hornetq.jms.server.config.impl.TopicConfigurationImpl;
+import org.hornetq.jms.server.embedded.EmbeddedJMS;
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.springframework.beans.factory.annotation.Autowired;
+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.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;
+
+/**
+ * Tests for {@link HornetQAutoConfiguration}.
+ *
+ * @author Stephane Nicoll
+ */
+public class HornetQAutoConfigurationTests {
+
+ @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.hornetq.mode:native");
+ JmsTemplate jmsTemplate = this.context.getBean(JmsTemplate.class);
+ HornetQConnectionFactory connectionFactory = this.context
+ .getBean(HornetQConnectionFactory.class);
+ assertEquals(jmsTemplate.getConnectionFactory(), connectionFactory);
+ assertNettyConnectionFactory(connectionFactory, "localhost", 5445);
+ }
+
+ @Test
+ public void nativeConnectionFactoryCustomHost() {
+ load(EmptyConfiguration.class, "spring.hornetq.host:192.168.1.144",
+ "spring.hornetq.port:9876");
+ HornetQConnectionFactory connectionFactory = this.context
+ .getBean(HornetQConnectionFactory.class);
+ assertNettyConnectionFactory(connectionFactory, "192.168.1.144", 9876);
+ }
+
+ @Test
+ public void embeddedConnectionFactory() {
+ load(EmptyConfiguration.class, "spring.hornetq.mode:embedded",
+ "spring.hornetq.embedded.enabled:true");
+
+ HornetQProperties properties = this.context.getBean(HornetQProperties.class);
+ assertEquals(HornetQMode.EMBEDDED, properties.getMode());
+
+ assertEquals(1, this.context.getBeansOfType(EmbeddedJMS.class).size());
+ org.hornetq.core.config.Configuration configuration = this.context
+ .getBean(org.hornetq.core.config.Configuration.class);
+ assertFalse("Persistence disabled by default",
+ configuration.isPersistenceEnabled());
+ assertFalse("Security disabled by default", configuration.isSecurityEnabled());
+
+ HornetQConnectionFactory connectionFactory = this.context
+ .getBean(HornetQConnectionFactory.class);
+ assertInVmConnectionFactory(connectionFactory);
+ }
+
+ @Test
+ public void nativeConnectionFactoryByDefault() {
+ // No mode is specified
+ load(EmptyConfiguration.class);
+ HornetQConnectionFactory connectionFactory = this.context
+ .getBean(HornetQConnectionFactory.class);
+ assertNettyConnectionFactory(connectionFactory, "localhost", 5445);
+ }
+
+ @Test
+ public void embeddedConnectionFactoryIfEmbeddedServiceEnabled() {
+ // No mode enabled, embedded server required
+ load(EmptyConfiguration.class, "spring.hornetq.embedded.enabled:true");
+ HornetQConnectionFactory connectionFactory = this.context
+ .getBean(HornetQConnectionFactory.class);
+ assertInVmConnectionFactory(connectionFactory);
+ }
+
+ @Test
+ public void embeddedServerWithDestinations() {
+ load(EmptyConfiguration.class, "spring.hornetq.embedded.enabled:true",
+ "spring.hornetq.embedded.queues=Queue1,Queue2",
+ "spring.hornetq.embedded.topics=Topic1");
+
+ DestinationChecker checker = new DestinationChecker(this.context);
+ checker.checkQueue("Queue1", true);
+ checker.checkQueue("Queue2", true);
+ checker.checkQueue("QueueDoesNotExist", false);
+
+ checker.checkTopic("Topic1", true);
+ checker.checkTopic("TopicDoesNotExist", false);
+ }
+
+ @Test
+ public void embeddedServerWithDestinationConfig() {
+ load(DestinationConfiguration.class, "spring.hornetq.embedded.enabled:true");
+
+ DestinationChecker checker = new DestinationChecker(this.context);
+ checker.checkQueue("sampleQueue", true);
+ checker.checkTopic("sampleTopic", true);
+ }
+
+ @Test
+ public void embeddedServiceWithCustomJmsConfiguration() {
+ load(CustomJmsConfiguration.class, "spring.hornetq.embedded.enabled:true",
+ "spring.hornetq.embedded.queues=Queue1,Queue2"); // Ignored with custom
+ // config
+ DestinationChecker checker = new DestinationChecker(this.context);
+ checker.checkQueue("custom", true); // See CustomJmsConfiguration
+
+ checker.checkQueue("Queue1", false);
+ checker.checkQueue("Queue2", false);
+ }
+
+ @Test
+ public void embeddedServiceWithCustomHornetQConfiguration() {
+ load(CustomHornetQConfiguration.class, "spring.hornetq.embedded.enabled:true");
+ org.hornetq.core.config.Configuration configuration = this.context
+ .getBean(org.hornetq.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.hornetq.embedded.enabled:true",
+ "spring.hornetq.embedded.queues=TestQueue",
+ "spring.hornetq.embedded.persistent:true",
+ "spring.hornetq.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.hornetq.embedded.enabled:true",
+ "spring.hornetq.embedded.queues=TestQueue",
+ "spring.hornetq.embedded.persistent:true",
+ "spring.hornetq.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());
+ }
+
+ private TransportConfiguration assertInVmConnectionFactory(
+ HornetQConnectionFactory connectionFactory) {
+ TransportConfiguration transportConfig = getSingleTransportConfiguration(connectionFactory);
+ assertEquals(InVMConnectorFactory.class.getName(),
+ transportConfig.getFactoryClassName());
+ return transportConfig;
+ }
+
+ private TransportConfiguration assertNettyConnectionFactory(
+ HornetQConnectionFactory 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(
+ HornetQConnectionFactory connectionFactory) {
+ TransportConfiguration[] transportConfigurations = connectionFactory
+ .getServerLocator().getStaticTransportConfigurations();
+ assertEquals(1, transportConfigurations.length);
+ return transportConfigurations[0];
+ }
+
+ private void load(Class> config, String... environment) {
+ this.context = new AnnotationConfigApplicationContext();
+ this.context.register(config);
+ this.context.register(HornetQAutoConfiguration.class, JmsAutoConfiguration.class);
+ EnvironmentTestUtils.addEnvironment(this.context, environment);
+ this.context.refresh();
+ }
+
+ 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() {
+ return new JMSQueueConfigurationImpl("sampleQueue", "foo=bar", false,
+ "/queue/1");
+ }
+
+ @Bean
+ TopicConfiguration sampleTopicConfiguration() {
+ return new TopicConfigurationImpl("sampleTopic", "/topic/1");
+ }
+ }
+
+ @Configuration
+ protected static class CustomJmsConfiguration {
+
+ @Bean
+ public JMSConfiguration myJmsConfiguration() {
+ JMSConfiguration config = new JMSConfigurationImpl();
+ config.getQueueConfigurations().add(
+ new JMSQueueConfigurationImpl("custom", null, false));
+ return config;
+ }
+ }
+
+ @Configuration
+ protected static class CustomHornetQConfiguration {
+
+ @Autowired
+ private HornetQProperties properties;
+
+ @Bean
+ public HornetQConfigurationCustomizer myHornetQCustomize() {
+ return new HornetQConfigurationCustomizer() {
+ @Override
+ public void customize(org.hornetq.core.config.Configuration configuration) {
+ configuration.setClusterPassword("Foobar");
+ configuration.setName("customFooBar");
+ }
+ };
+ }
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/HornetQEmbeddedConfigurationFactoryTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/HornetQEmbeddedConfigurationFactoryTests.java
new file mode 100644
index 0000000000..288c4b24bd
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/HornetQEmbeddedConfigurationFactoryTests.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2012-2014 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;
+
+import org.hornetq.core.config.Configuration;
+import org.hornetq.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 HornetQEmbeddedConfigurationFactory}.
+ *
+ * @author Stephane Nicol
+ * @author Phillip Webb
+ */
+public class HornetQEmbeddedConfigurationFactoryTests {
+
+ @Test
+ public void defaultDataDir() {
+ HornetQProperties properties = new HornetQProperties();
+ properties.getEmbedded().setPersistent(true);
+ Configuration configuration = new HornetQEmbeddedConfigurationFactory(properties)
+ .createConfiguration();
+ assertThat(configuration.getJournalDirectory(),
+ startsWith(System.getProperty("java.io.tmpdir")));
+ assertThat(configuration.getJournalDirectory(), endsWith("/journal"));
+ }
+
+ @Test
+ public void persistenceSetup() {
+ HornetQProperties properties = new HornetQProperties();
+ properties.getEmbedded().setPersistent(true);
+ Configuration configuration = new HornetQEmbeddedConfigurationFactory(properties)
+ .createConfiguration();
+ assertThat(configuration.isPersistenceEnabled(), equalTo(true));
+ assertThat(configuration.getJournalType(), equalTo(JournalType.NIO));
+ }
+
+ @Test
+ public void generatedClusterPassoword() throws Exception {
+ HornetQProperties properties = new HornetQProperties();
+ Configuration configuration = new HornetQEmbeddedConfigurationFactory(properties)
+ .createConfiguration();
+ assertThat(configuration.getClusterPassword().length(), equalTo(36));
+ }
+
+ @Test
+ public void specificClusterPassoword() throws Exception {
+ HornetQProperties properties = new HornetQProperties();
+ properties.getEmbedded().setClusterPassword("password");
+ Configuration configuration = new HornetQEmbeddedConfigurationFactory(properties)
+ .createConfiguration();
+ assertThat(configuration.getClusterPassword(), equalTo("password"));
+ }
+
+}
diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml
index edf00f2267..5058e8cffe 100644
--- a/spring-boot-dependencies/pom.xml
+++ b/spring-boot-dependencies/pom.xml
@@ -68,6 +68,7 @@
1.3.8
4.3.3
4.0.1
+ 2.4.1.Final
2.3.2
2.3.3
3.18.1-GA
@@ -212,6 +213,11 @@
spring-boot-starter-groovy-templates
1.1.0.BUILD-SNAPSHOT
+
+ org.springframework.boot
+ spring-boot-starter-hornetq
+ 1.1.0.BUILD-SNAPSHOT
+
org.springframework.boot
spring-boot-starter-integration
@@ -714,6 +720,16 @@
hibernate-jpa-2.0-api
${hibernate-jpa-api.version}
+
+ org.hornetq
+ hornetq-jms-server
+ ${hornetq.version}
+
+
+ org.hornetq
+ hornetq-jms-client
+ ${hornetq.version}
+
org.hsqldb
hsqldb
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 2d67717bb1..3c44b9f7f8 100644
--- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
+++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
@@ -242,6 +242,17 @@ 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/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)
+ spring.hornetq.embedded.enabled=true # if the embedded server is enabled (needs hornetq-jms-server.jar)
+ spring.hornetq.embedded.persistent=false # message persistence
+ spring.hornetq.embedded.data-directory= # location of data content (when persistence is enabled)
+ spring.hornetq.embedded.queues= # comma separate queues to create on startup
+ spring.hornetq.embedded.topics= # comma separate topics to create on startup
+ spring.hornetq.embedded.cluster-password = # customer password (randomly generated by default)
+
# JMS ({sc-spring-boot-autoconfigure}/jms/JmsTemplateProperties.{sc-ext}[JmsTemplateProperties])
spring.jms.pub-sub-domain= # false for queue (default), true for topic
diff --git a/spring-boot-docs/src/main/asciidoc/appendix-auto-configuration-classes.adoc b/spring-boot-docs/src/main/asciidoc/appendix-auto-configuration-classes.adoc
index 6a85e9dec6..6fb5bffbe5 100644
--- a/spring-boot-docs/src/main/asciidoc/appendix-auto-configuration-classes.adoc
+++ b/spring-boot-docs/src/main/asciidoc/appendix-auto-configuration-classes.adoc
@@ -53,6 +53,12 @@ The following auto-configuration classes are from the `spring-boot-autoconfigure
|{sc-spring-boot-autoconfigure}/web/HttpMessageConvertersAutoConfiguration.{sc-ext}[HttpMessageConvertersAutoConfiguration]
|{dc-spring-boot-autoconfigure}/web/HttpMessageConvertersAutoConfiguration.{dc-ext}[javadoc]
+|{sc-spring-boot-autoconfigure}/jms/ActiveMQAutoConfiguration.{sc-ext}[ActiveMQAutoConfiguration]
+|{dc-spring-boot-autoconfigure}/jms/ActiveMQAutoConfiguration.{dc-ext}[javadoc]
+
+|{sc-spring-boot-autoconfigure}/jms/HornetQAutoConfiguration.{sc-ext}[HornetQAutoConfiguration]
+|{dc-spring-boot-autoconfigure}/jms/HornetQAutoConfiguration.{dc-ext}[javadoc]
+
|{sc-spring-boot-autoconfigure}/jms/JmsTemplateAutoConfiguration.{sc-ext}[JmsTemplateAutoConfiguration]
|{dc-spring-boot-autoconfigure}/jms/JmsTemplateAutoConfiguration.{dc-ext}[javadoc]
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 6015ea1b15..b7a67803f0 100644
--- a/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc
+++ b/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc
@@ -245,6 +245,9 @@ and Hibernate.
|`spring-boot-starter-groovy-templates`
|Support for the Groovy templating engine
+|`spring-boot-starter-hornetq`
+|Support for ``Java Message Service API'' via HornetQ.
+
|`spring-boot-starter-integration`
|Support for common `spring-integration` modules.
diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml
index 48da9418c2..881c2e013d 100644
--- a/spring-boot-samples/pom.xml
+++ b/spring-boot-samples/pom.xml
@@ -34,6 +34,7 @@
spring-boot-sample-data-rest
spring-boot-sample-data-solr
spring-boot-sample-flyway
+ spring-boot-sample-hornetq
spring-boot-sample-integration
spring-boot-sample-jetty
spring-boot-sample-liquibase
diff --git a/spring-boot-samples/spring-boot-sample-hornetq/pom.xml b/spring-boot-samples/spring-boot-sample-hornetq/pom.xml
new file mode 100644
index 0000000000..fbe5f44e54
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-hornetq/pom.xml
@@ -0,0 +1,44 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-samples
+ 1.1.0.BUILD-SNAPSHOT
+
+ spring-boot-sample-hornetq
+ Spring Boot HornetQ Sample
+ Spring Boot HornetQ Sample
+ http://projects.spring.io/spring-boot/
+
+ Pivotal Software, Inc.
+ http://www.spring.io
+
+
+ ${basedir}/../..
+
+
+
+ org.springframework.boot
+ spring-boot-starter-hornetq
+
+
+ org.hornetq
+ hornetq-jms-server
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/spring-boot-samples/spring-boot-sample-hornetq/src/main/java/sample/hornetq/SampleHornetQApplication.java b/spring-boot-samples/spring-boot-sample-hornetq/src/main/java/sample/hornetq/SampleHornetQApplication.java
new file mode 100644
index 0000000000..b73a8626ca
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-hornetq/src/main/java/sample/hornetq/SampleHornetQApplication.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2012-2013 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 sample.hornetq;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jms.listener.DefaultMessageListenerContainer;
+import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor;
+
+@Configuration
+@EnableAutoConfiguration
+@ComponentScan
+public class SampleHornetQApplication {
+
+ @Autowired
+ private ConnectionFactory connectionFactory;
+
+ @Bean
+ public ScheduledAnnotationBeanPostProcessor scheduledAnnotationBeanPostProcessor() {
+ return new ScheduledAnnotationBeanPostProcessor();
+ }
+
+ @Bean
+ public DefaultMessageListenerContainer messageListener() {
+ DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
+ container.setConnectionFactory(this.connectionFactory);
+ container.setDestinationName("testQueue");
+ container.setMessageListener(new MessageListener() {
+ @Override
+ public void onMessage(Message message) {
+ try {
+ System.out.println(message.getBody(Object.class));
+ }
+ catch (JMSException ex) {
+ ex.printStackTrace();
+ }
+ }
+ });
+ return container;
+ }
+
+ public static void main(String[] args) throws Exception {
+ SpringApplication.run(SampleHornetQApplication.class, args);
+ }
+}
diff --git a/spring-boot-samples/spring-boot-sample-hornetq/src/main/java/sample/hornetq/Sender.java b/spring-boot-samples/spring-boot-sample-hornetq/src/main/java/sample/hornetq/Sender.java
new file mode 100644
index 0000000000..5c34c4d4c6
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-hornetq/src/main/java/sample/hornetq/Sender.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2012-2013 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 sample.hornetq;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jms.core.JmsTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+@Component
+public class Sender {
+
+ @Autowired
+ private JmsTemplate jmsTemplate;
+
+ @Scheduled(fixedDelay = 1000L)
+ public void send() {
+ this.jmsTemplate.convertAndSend("testQueue", "Hello");
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-hornetq/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-hornetq/src/main/resources/application.properties
new file mode 100644
index 0000000000..f7c09bcefd
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-hornetq/src/main/resources/application.properties
@@ -0,0 +1,3 @@
+spring.hornetq.mode=embedded
+spring.hornetq.embedded.enabled=true
+spring.hornetq.embedded.queues=testQueue,anotherQueue
diff --git a/spring-boot-starters/pom.xml b/spring-boot-starters/pom.xml
index bb7a588aae..b9cee097aa 100644
--- a/spring-boot-starters/pom.xml
+++ b/spring-boot-starters/pom.xml
@@ -31,6 +31,7 @@
spring-boot-starter-data-solr
spring-boot-starter-freemarker
spring-boot-starter-groovy-templates
+ spring-boot-starter-hornetq
spring-boot-starter-integration
spring-boot-starter-jdbc
spring-boot-starter-jetty
diff --git a/spring-boot-starters/spring-boot-starter-hornetq/pom.xml b/spring-boot-starters/spring-boot-starter-hornetq/pom.xml
new file mode 100644
index 0000000000..25e7f14d52
--- /dev/null
+++ b/spring-boot-starters/spring-boot-starter-hornetq/pom.xml
@@ -0,0 +1,34 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starters
+ 1.1.0.BUILD-SNAPSHOT
+
+ spring-boot-starter-hornetq
+ Spring Boot HornetQ Starter
+ Spring Boot HornetQ 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.hornetq
+ hornetq-jms-client
+
+
+