Skip to content

Commit da88bb4

Browse files
committed
Update JMS auto-configuration to support XA
Update JMS auto-configuration for ActiveMQ and HornetQ to support XA transactions. See spring-projectsgh-947
1 parent 8219f2b commit da88bb4

13 files changed

+557
-349
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfiguration.java

+7-61
Original file line numberDiff line numberDiff line change
@@ -19,87 +19,33 @@
1919
import javax.jms.ConnectionFactory;
2020

2121
import org.apache.activemq.ActiveMQConnectionFactory;
22-
import org.apache.activemq.transport.vm.VMTransportFactory;
22+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
2323
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
2424
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
25-
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
2625
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2726
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
28-
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
2927
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
30-
import org.springframework.context.annotation.ConditionContext;
31-
import org.springframework.context.annotation.Conditional;
28+
import org.springframework.boot.autoconfigure.jta.JtaAutoConfiguration;
29+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3230
import org.springframework.context.annotation.Configuration;
3331
import org.springframework.context.annotation.Import;
34-
import org.springframework.core.type.AnnotatedTypeMetadata;
3532

3633
/**
3734
* {@link EnableAutoConfiguration Auto-configuration} to integrate with an ActiveMQ
3835
* broker. Validates that the classpath contain the necessary classes before starting an
3936
* embedded broker.
4037
*
4138
* @author Stephane Nicoll
39+
* @author Phillip Webb
4240
* @since 1.1.0
4341
*/
4442
@Configuration
4543
@AutoConfigureBefore(JmsAutoConfiguration.class)
44+
@AutoConfigureAfter(JtaAutoConfiguration.class)
4645
@ConditionalOnClass({ ConnectionFactory.class, ActiveMQConnectionFactory.class })
4746
@ConditionalOnMissingBean(ConnectionFactory.class)
47+
@EnableConfigurationProperties(ActiveMQProperties.class)
48+
@Import({ ActiveMQXAConnectionFactoryConfiguration.class, ActiveMQConnectionFactoryConfiguration.class })
4849
public class ActiveMQAutoConfiguration {
4950

50-
@Configuration
51-
@ConditionalOnClass(VMTransportFactory.class)
52-
@Conditional(EmbeddedBrokerCondition.class)
53-
@Import(ActiveMQConnectionFactoryConfiguration.class)
54-
protected static class EmbeddedBroker {
55-
}
56-
57-
@Configuration
58-
@Conditional(NonEmbeddedBrokerCondition.class)
59-
@Import(ActiveMQConnectionFactoryConfiguration.class)
60-
protected static class NetworkBroker {
61-
}
62-
63-
static abstract class BrokerTypeCondition extends SpringBootCondition {
64-
private final boolean embedded;
65-
66-
BrokerTypeCondition(boolean embedded) {
67-
this.embedded = embedded;
68-
}
69-
70-
@Override
71-
public ConditionOutcome getMatchOutcome(ConditionContext context,
72-
AnnotatedTypeMetadata metadata) {
73-
String brokerUrl = ActiveMQProperties.determineBrokerUrl(context
74-
.getEnvironment());
75-
boolean match = brokerUrl.contains("vm://");
76-
boolean outcome = (match == this.embedded);
77-
return new ConditionOutcome(outcome, buildMessage(brokerUrl, outcome));
78-
}
79-
80-
protected String buildMessage(String brokerUrl, boolean outcome) {
81-
String brokerType = this.embedded ? "Embedded" : "Network";
82-
String detected = outcome ? "detected" : "not detected";
83-
return brokerType + " ActiveMQ broker " + detected + " - brokerUrl '"
84-
+ brokerUrl + "'";
85-
}
86-
87-
}
88-
89-
static class EmbeddedBrokerCondition extends BrokerTypeCondition {
90-
91-
EmbeddedBrokerCondition() {
92-
super(true);
93-
}
94-
95-
}
96-
97-
static class NonEmbeddedBrokerCondition extends BrokerTypeCondition {
98-
99-
NonEmbeddedBrokerCondition() {
100-
super(false);
101-
}
102-
103-
}
104-
10551
}

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java

+16-9
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,34 @@
1818

1919
import javax.jms.ConnectionFactory;
2020

21-
import org.springframework.beans.factory.annotation.Autowired;
22-
import org.springframework.boot.context.properties.EnableConfigurationProperties;
21+
import org.apache.activemq.ActiveMQConnectionFactory;
22+
import org.apache.activemq.pool.PooledConnectionFactory;
23+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2324
import org.springframework.context.annotation.Bean;
2425
import org.springframework.context.annotation.Configuration;
2526

2627
/**
27-
* Creates a {@link ConnectionFactory} based on {@link ActiveMQProperties}.
28+
* Configuration for ActiveMQ {@link ConnectionFactory}.
2829
*
2930
* @author Greg Turnquist
3031
* @author Stephane Nicoll
32+
* @author Phillip Webb
3133
* @since 1.1.0
3234
*/
3335
@Configuration
34-
@EnableConfigurationProperties(ActiveMQProperties.class)
36+
@ConditionalOnMissingBean(ConnectionFactory.class)
3537
class ActiveMQConnectionFactoryConfiguration {
3638

37-
@Autowired
38-
private ActiveMQProperties properties;
39-
4039
@Bean
41-
public ConnectionFactory jmsConnectionFactory() {
42-
return this.properties.createConnectionFactory();
40+
public ConnectionFactory jmsConnectionFactory(ActiveMQProperties properties) {
41+
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
42+
properties).createConnectionFactory(ActiveMQConnectionFactory.class);
43+
if (properties.isPooled()) {
44+
PooledConnectionFactory pool = new PooledConnectionFactory();
45+
pool.setConnectionFactory(connectionFactory);
46+
return pool;
47+
}
48+
return connectionFactory;
4349
}
50+
4451
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright 2012-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.jms.activemq;
18+
19+
import org.apache.activemq.ActiveMQConnectionFactory;
20+
import org.springframework.util.Assert;
21+
import org.springframework.util.StringUtils;
22+
23+
/**
24+
* Factory to create a {@link ActiveMQConnectionFactory} instance from properties defined
25+
* in {@link ActiveMQProperties}.
26+
*
27+
* @author Phillip Webb
28+
* @since 1.2.0
29+
*/
30+
class ActiveMQConnectionFactoryFactory {
31+
32+
private static final String DEFAULT_EMBEDDED_BROKER_URL = "vm://localhost?broker.persistent=false";
33+
34+
private static final String DEFAULT_NETWORK_BROKER_URL = "tcp://localhost:61616";
35+
36+
private final ActiveMQProperties properties;
37+
38+
public ActiveMQConnectionFactoryFactory(ActiveMQProperties properties) {
39+
Assert.notNull(properties, "Properties must not be null");
40+
this.properties = properties;
41+
}
42+
43+
public <T extends ActiveMQConnectionFactory> T createConnectionFactory(
44+
Class<T> factoryClass) {
45+
try {
46+
return doCreateConnectionFactory(factoryClass);
47+
}
48+
catch (Exception ex) {
49+
throw new IllegalStateException("Unable to create "
50+
+ "ActiveMQConnectionFactory", ex);
51+
}
52+
}
53+
54+
private <T extends ActiveMQConnectionFactory> T doCreateConnectionFactory(
55+
Class<T> factoryClass) throws Exception {
56+
String brokerUrl = determineBrokerUrl();
57+
String user = this.properties.getUser();
58+
String password = this.properties.getPassword();
59+
if (StringUtils.hasLength(user) && StringUtils.hasLength(password)) {
60+
return factoryClass.getConstructor(String.class, String.class, String.class)
61+
.newInstance(user, password, brokerUrl);
62+
}
63+
return factoryClass.getConstructor(String.class).newInstance(brokerUrl);
64+
}
65+
66+
String determineBrokerUrl() {
67+
if (this.properties.getBrokerUrl() != null) {
68+
return this.properties.getBrokerUrl();
69+
}
70+
if (this.properties.isInMemory()) {
71+
return DEFAULT_EMBEDDED_BROKER_URL;
72+
}
73+
return DEFAULT_NETWORK_BROKER_URL;
74+
}
75+
76+
}

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQProperties.java

-60
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,7 @@
1616

1717
package org.springframework.boot.autoconfigure.jms.activemq;
1818

19-
import javax.jms.ConnectionFactory;
20-
21-
import org.apache.activemq.ActiveMQConnectionFactory;
22-
import org.apache.activemq.pool.PooledConnectionFactory;
23-
import org.springframework.boot.bind.RelaxedPropertyResolver;
2419
import org.springframework.boot.context.properties.ConfigurationProperties;
25-
import org.springframework.core.env.Environment;
26-
import org.springframework.core.env.PropertyResolver;
27-
import org.springframework.util.StringUtils;
2820

2921
/**
3022
* Configuration properties for ActiveMQ
@@ -35,10 +27,6 @@
3527
@ConfigurationProperties(prefix = "spring.activemq")
3628
public class ActiveMQProperties {
3729

38-
public static final String DEFAULT_EMBEDDED_BROKER_URL = "vm://localhost?broker.persistent=false";
39-
40-
public static final String DEFAULT_NETWORK_BROKER_URL = "tcp://localhost:61616";
41-
4230
private String brokerUrl;
4331

4432
private boolean inMemory = true;
@@ -93,52 +81,4 @@ public void setPassword(String password) {
9381
this.password = password;
9482
}
9583

96-
/**
97-
* Return a new {@link ConnectionFactory} from these properties.
98-
*/
99-
public ConnectionFactory createConnectionFactory() {
100-
ConnectionFactory connectionFactory = createActiveMQConnectionFactory();
101-
if (isPooled()) {
102-
PooledConnectionFactory pool = new PooledConnectionFactory();
103-
pool.setConnectionFactory(connectionFactory);
104-
return pool;
105-
}
106-
return connectionFactory;
107-
}
108-
109-
private ConnectionFactory createActiveMQConnectionFactory() {
110-
String brokerUrl = determineBrokerUrl();
111-
if (StringUtils.hasLength(this.user) && StringUtils.hasLength(this.password)) {
112-
return new ActiveMQConnectionFactory(this.user, this.password, brokerUrl);
113-
}
114-
return new ActiveMQConnectionFactory(brokerUrl);
115-
}
116-
117-
String determineBrokerUrl() {
118-
return determineBrokerUrl(this.brokerUrl, this.inMemory);
119-
}
120-
121-
/**
122-
* Determine the broker url to use for the specified {@link Environment}. If no broker
123-
* url is specified through configuration, a default broker is provided, that is
124-
* {@value #DEFAULT_EMBEDDED_BROKER_URL} if the {@code inMemory} flag is {@code null}
125-
* or {@code true}, {@value #DEFAULT_NETWORK_BROKER_URL} otherwise.
126-
* @param environment the environment to extract configuration from
127-
* @return the broker url to use
128-
*/
129-
public static String determineBrokerUrl(Environment environment) {
130-
PropertyResolver resolver = new RelaxedPropertyResolver(environment,
131-
"spring.activemq.");
132-
String brokerUrl = resolver.getProperty("brokerUrl");
133-
Boolean inMemory = resolver.getProperty("inMemory", Boolean.class);
134-
return determineBrokerUrl(brokerUrl, inMemory);
135-
}
136-
137-
private static String determineBrokerUrl(String brokerUrl, Boolean inMemory) {
138-
if (brokerUrl != null) {
139-
return brokerUrl;
140-
}
141-
boolean embedded = inMemory == null || inMemory;
142-
return (embedded ? DEFAULT_EMBEDDED_BROKER_URL : DEFAULT_NETWORK_BROKER_URL);
143-
}
14484
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2012-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.jms.activemq;
18+
19+
import javax.jms.ConnectionFactory;
20+
import javax.transaction.TransactionManager;
21+
22+
import org.apache.activemq.ActiveMQXAConnectionFactory;
23+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
24+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
25+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
26+
import org.springframework.boot.jta.XAConnectionFactoryWrapper;
27+
import org.springframework.context.annotation.Bean;
28+
import org.springframework.context.annotation.Configuration;
29+
30+
/**
31+
* Configuration for ActiveMQ XA {@link ConnectionFactory}.
32+
*
33+
* @author Phillip Webb
34+
* @since 1.2.0
35+
*/
36+
@Configuration
37+
@ConditionalOnClass(TransactionManager.class)
38+
@ConditionalOnBean(XAConnectionFactoryWrapper.class)
39+
@ConditionalOnMissingBean(ConnectionFactory.class)
40+
class ActiveMQXAConnectionFactoryConfiguration {
41+
42+
@Bean
43+
public ConnectionFactory jmsConnectionFactory(ActiveMQProperties properties,
44+
XAConnectionFactoryWrapper wrapper) throws Exception {
45+
ActiveMQXAConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
46+
properties).createConnectionFactory(ActiveMQXAConnectionFactory.class);
47+
return wrapper.wrapConnectionFactory(connectionFactory);
48+
}
49+
50+
}

0 commit comments

Comments
 (0)