commit
c24667f6b1
|
@ -25,6 +25,16 @@
|
|||
<artifactId>spring-boot</artifactId>
|
||||
</dependency>
|
||||
<!-- Optional -->
|
||||
<dependency>
|
||||
<groupId>com.atomikos</groupId>
|
||||
<artifactId>transactions-jdbc</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.atomikos</groupId>
|
||||
<artifactId>transactions-jta</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
|
@ -80,6 +90,11 @@
|
|||
<artifactId>velocity</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.btm</groupId>
|
||||
<artifactId>btm</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-templates</artifactId>
|
||||
|
|
|
@ -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.condition;
|
||||
|
||||
import javax.naming.InitialContext;
|
||||
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
|
||||
/**
|
||||
* {@link Conditional} that matches based on the availability of a JNDI
|
||||
* {@link InitialContext} and the ability to lookup specific locations.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Conditional(OnJndiCondition.class)
|
||||
public @interface ConditionalOnJndi {
|
||||
|
||||
/**
|
||||
* JNDI Locations, one of which must exist. If no locations are specific the condition
|
||||
* matches solely based on the presence of an {@link InitialContext}.
|
||||
*/
|
||||
String[] value() default {};
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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.condition;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.jndi.JndiLocatorDelegate;
|
||||
import org.springframework.jndi.JndiLocatorSupport;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link Condition} that checks for JNDI locations.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
* @see ConditionalOnJndi
|
||||
*/
|
||||
class OnJndiCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(metadata
|
||||
.getAnnotationAttributes(ConditionalOnJndi.class.getName()));
|
||||
String[] locations = annotationAttributes.getStringArray("value");
|
||||
try {
|
||||
return getMatchOutcome(locations);
|
||||
}
|
||||
catch (NoClassDefFoundError ex) {
|
||||
return ConditionOutcome.noMatch("JNDI class not found");
|
||||
}
|
||||
}
|
||||
|
||||
private ConditionOutcome getMatchOutcome(String[] locations) {
|
||||
if (!isJndiAvailable()) {
|
||||
return ConditionOutcome.noMatch("JNDI environment is not available");
|
||||
}
|
||||
if (locations.length == 0) {
|
||||
return ConditionOutcome.match("JNDI environment is available");
|
||||
}
|
||||
JndiLocator locator = getJndiLocator(locations);
|
||||
String location = locator.lookupFirstLocation();
|
||||
if (location != null) {
|
||||
return ConditionOutcome.match("JNDI location '" + location
|
||||
+ "' found from candidates "
|
||||
+ StringUtils.arrayToCommaDelimitedString(locations));
|
||||
}
|
||||
return ConditionOutcome.noMatch("No JNDI location found from candidates "
|
||||
+ StringUtils.arrayToCommaDelimitedString(locations));
|
||||
}
|
||||
|
||||
protected boolean isJndiAvailable() {
|
||||
return JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable();
|
||||
}
|
||||
|
||||
protected JndiLocator getJndiLocator(String[] locations) {
|
||||
return new JndiLocator(locations);
|
||||
}
|
||||
|
||||
protected static class JndiLocator extends JndiLocatorSupport {
|
||||
|
||||
private String[] locations;
|
||||
|
||||
public JndiLocator(String[] locations) {
|
||||
this.locations = locations;
|
||||
}
|
||||
|
||||
public String lookupFirstLocation() {
|
||||
for (String location : this.locations) {
|
||||
try {
|
||||
lookup(location);
|
||||
return location;
|
||||
}
|
||||
catch (NamingException ex) {
|
||||
// Swallow and continue
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.boot.autoconfigure.jdbc;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import javax.sql.XADataSource;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
|
@ -74,7 +75,7 @@ public class DataSourceAutoConfiguration {
|
|||
}
|
||||
|
||||
@Conditional(DataSourceAutoConfiguration.EmbeddedDataSourceCondition.class)
|
||||
@ConditionalOnMissingBean(DataSource.class)
|
||||
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
|
||||
@Import(EmbeddedDataSourceConfiguration.class)
|
||||
protected static class EmbeddedConfiguration {
|
||||
|
||||
|
@ -92,7 +93,7 @@ public class DataSourceAutoConfiguration {
|
|||
}
|
||||
|
||||
@Conditional(DataSourceAutoConfiguration.NonEmbeddedDataSourceCondition.class)
|
||||
@ConditionalOnMissingBean(DataSource.class)
|
||||
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
|
||||
protected static class NonEmbeddedConfiguration {
|
||||
|
||||
@Autowired
|
||||
|
@ -196,7 +197,8 @@ public class DataSourceAutoConfiguration {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
if (hasBean(context, DataSource.class)) {
|
||||
if (hasBean(context, DataSource.class)
|
||||
|| hasBean(context, XADataSource.class)) {
|
||||
return ConditionOutcome
|
||||
.match("existing bean configured database detected");
|
||||
}
|
||||
|
@ -210,6 +212,7 @@ public class DataSourceAutoConfiguration {
|
|||
return BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
|
||||
context.getBeanFactory(), type, true, false).length > 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,8 +49,6 @@ public class DataSourceBuilder {
|
|||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
private DriverClassNameProvider driverClassNameProvider = new DriverClassNameProvider();
|
||||
|
||||
private Map<String, String> properties = new HashMap<String, String>();
|
||||
|
||||
public static DataSourceBuilder create() {
|
||||
|
@ -76,9 +74,9 @@ public class DataSourceBuilder {
|
|||
private void maybeGetDriverClassName() {
|
||||
if (!this.properties.containsKey("driverClassName")
|
||||
&& this.properties.containsKey("url")) {
|
||||
String cls = this.driverClassNameProvider.getDriverClassName(this.properties
|
||||
.get("url"));
|
||||
this.properties.put("driverClassName", cls);
|
||||
String url = this.properties.get("url");
|
||||
String driverClass = DatabaseDriver.fromJdbcUrl(url).getDriverClassName();
|
||||
this.properties.put("driverClassName", driverClass);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.jdbc;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
@ -64,7 +67,7 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
|
|||
|
||||
private EmbeddedDatabaseConnection embeddedDatabaseConnection = EmbeddedDatabaseConnection.NONE;
|
||||
|
||||
private DriverClassNameProvider driverClassNameProvider = new DriverClassNameProvider();
|
||||
private Xa xa = new Xa();
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
|
@ -86,7 +89,7 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
|
|||
String driverClassName = null;
|
||||
|
||||
if (StringUtils.hasText(this.url)) {
|
||||
driverClassName = this.driverClassNameProvider.getDriverClassName(this.url);
|
||||
driverClassName = DatabaseDriver.fromJdbcUrl(this.url).getDriverClassName();
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(driverClassName)) {
|
||||
|
@ -113,7 +116,7 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
|
|||
"Cannot determine embedded database url for database type "
|
||||
+ this.embeddedDatabaseConnection
|
||||
+ ". If you want an embedded "
|
||||
+ "database please put a supported on on the classpath.");
|
||||
+ "database please put a supported one on the classpath.");
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
@ -228,4 +231,39 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
|
|||
return this.classLoader;
|
||||
}
|
||||
|
||||
public Xa getXa() {
|
||||
return this.xa;
|
||||
}
|
||||
|
||||
public void setXa(Xa xa) {
|
||||
this.xa = xa;
|
||||
}
|
||||
|
||||
/**
|
||||
* XA Specific datasource settings.
|
||||
*/
|
||||
public static class Xa {
|
||||
|
||||
private String dataSourceClassName;
|
||||
|
||||
private Map<String, String> properties = new LinkedHashMap<String, String>();
|
||||
|
||||
public String getDataSourceClassName() {
|
||||
return this.dataSourceClassName;
|
||||
}
|
||||
|
||||
public void setDataSourceClassName(String dataSourceClassName) {
|
||||
this.dataSourceClassName = dataSourceClassName;
|
||||
}
|
||||
|
||||
public Map<String, String> getProperties() {
|
||||
return this.properties;
|
||||
}
|
||||
|
||||
public void setProperties(Map<String, String> properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* 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.jdbc;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Enumeration of common database drivers.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Maciej Walkowiak
|
||||
* @since 1.2.0
|
||||
*/
|
||||
enum DatabaseDriver {
|
||||
|
||||
/**
|
||||
* Unknown type.
|
||||
*/
|
||||
UNKNOWN(null),
|
||||
|
||||
/**
|
||||
* Apache Derby.
|
||||
*/
|
||||
DERBY("org.apache.derby.jdbc.EmbeddedDriver"),
|
||||
|
||||
/**
|
||||
* H2.
|
||||
*/
|
||||
H2("org.h2.Driver", "org.h2.jdbcx.JdbcDataSource"),
|
||||
|
||||
/**
|
||||
* HyperSQL DataBase.
|
||||
*/
|
||||
HSQLDB("org.hsqldb.jdbc.JDBCDriver", "org.hsqldb.jdbc.pool.JDBCXADataSource"),
|
||||
|
||||
/**
|
||||
* SQL Lite.
|
||||
*/
|
||||
SQLITE("org.sqlite.JDBC"),
|
||||
|
||||
/**
|
||||
* MySQL.
|
||||
*/
|
||||
MYSQL("com.mysql.jdbc.Driver", "org.mysql.jdbc.MySQLDataSource"),
|
||||
|
||||
/**
|
||||
* Maria DB.
|
||||
*/
|
||||
MARIADB("org.mariadb.jdbc.Driver", "org.mariadb.jdbc.MySQLDataSource"),
|
||||
|
||||
/**
|
||||
* Google App Engine.
|
||||
*/
|
||||
GOOGLE("com.google.appengine.api.rdbms.AppEngineDriver"),
|
||||
|
||||
/**
|
||||
* Oracle
|
||||
*/
|
||||
ORACLE("oracle.jdbc.OracleDriver", "oracle.jdbc.xa.OracleXADataSource"),
|
||||
|
||||
/**
|
||||
* Postres
|
||||
*/
|
||||
POSTGRESQL("org.postgresql.Driver", "org.postgresql.xa.PGXADataSource"),
|
||||
|
||||
/**
|
||||
* JTDS
|
||||
*/
|
||||
JTDS("net.sourceforge.jtds.jdbc.Driver"),
|
||||
|
||||
/**
|
||||
* SQL Server
|
||||
*/
|
||||
SQLSERVER("com.microsoft.sqlserver.jdbc.SQLServerDriver");
|
||||
|
||||
private final String driverClassName;
|
||||
|
||||
private final String xaDataSourceClassName;
|
||||
|
||||
private DatabaseDriver(String driverClassName) {
|
||||
this(driverClassName, null);
|
||||
}
|
||||
|
||||
private DatabaseDriver(String driverClassName, String xaDataSourceClassName) {
|
||||
this.driverClassName = driverClassName;
|
||||
this.xaDataSourceClassName = xaDataSourceClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the driverClassName or {@code null}
|
||||
*/
|
||||
public String getDriverClassName() {
|
||||
return this.driverClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the xaDataSourceClassName or {@code null}
|
||||
*/
|
||||
public String getXaDataSourceClassName() {
|
||||
return this.xaDataSourceClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a {@link DatabaseDriver} for the given URL.
|
||||
* @param url JDBC URL
|
||||
* @return driver class name or {@link #UNKNOWN} if not found
|
||||
*/
|
||||
public static DatabaseDriver fromJdbcUrl(String url) {
|
||||
if (StringUtils.hasLength(url)) {
|
||||
Assert.isTrue(url.startsWith("jdbc"), "URL must start with 'jdbc'");
|
||||
String urlWithoutPrefix = url.substring("jdbc".length()).toLowerCase();
|
||||
for (DatabaseDriver driver : values()) {
|
||||
String prefix = ":" + driver.name().toLowerCase() + ":";
|
||||
if (driver != UNKNOWN && urlWithoutPrefix.startsWith(prefix)) {
|
||||
return driver;
|
||||
}
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
}
|
|
@ -36,7 +36,8 @@ import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
|
|||
* @since 1.2.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
|
||||
@AutoConfigureBefore({ XADataSourceAutoConfiguration.class,
|
||||
DataSourceAutoConfiguration.class })
|
||||
@ConditionalOnClass(DataSource.class)
|
||||
@ConditionalOnProperty(prefix = DataSourceProperties.PREFIX, name = "jndi-name")
|
||||
@EnableConfigurationProperties(DataSourceProperties.class)
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* 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.jdbc;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import javax.sql.XADataSource;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.jta.JtaAutoConfiguration;
|
||||
import org.springframework.boot.bind.RelaxedDataBinder;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.jta.XADataSourceWrapper;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link DataSource} with XA.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Josh Long
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
|
||||
@AutoConfigureAfter(JtaAutoConfiguration.class)
|
||||
@EnableConfigurationProperties(DataSourceProperties.class)
|
||||
@ConditionalOnClass({ DataSource.class, TransactionManager.class })
|
||||
@ConditionalOnBean(XADataSourceWrapper.class)
|
||||
@ConditionalOnMissingBean(DataSource.class)
|
||||
public class XADataSourceAutoConfiguration implements BeanClassLoaderAware {
|
||||
|
||||
@Autowired
|
||||
private XADataSourceWrapper wrapper;
|
||||
|
||||
@Autowired
|
||||
private DataSourceProperties properties;
|
||||
|
||||
@Autowired(required = false)
|
||||
private XADataSource xaDataSource;
|
||||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties(prefix = DataSourceProperties.PREFIX)
|
||||
public DataSource dataSource() throws Exception {
|
||||
XADataSource xaDataSource = this.xaDataSource;
|
||||
if (xaDataSource == null) {
|
||||
xaDataSource = createXaDataSource();
|
||||
}
|
||||
return this.wrapper.wrapDataSource(xaDataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
private XADataSource createXaDataSource() {
|
||||
String className = this.properties.getXa().getDataSourceClassName();
|
||||
if (!StringUtils.hasLength(className)) {
|
||||
className = DatabaseDriver.fromJdbcUrl(this.properties.getUrl())
|
||||
.getXaDataSourceClassName();
|
||||
}
|
||||
Assert.state(StringUtils.hasLength(className),
|
||||
"No XA DataSource class name specified");
|
||||
XADataSource dataSource = createXaDataSourceInstance(className);
|
||||
bindXaProperties(dataSource, this.properties);
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
private XADataSource createXaDataSourceInstance(String className) {
|
||||
try {
|
||||
Class<?> dataSourceClass = ClassUtils.forName(className, this.classLoader);
|
||||
Object instance = BeanUtils.instantiate(dataSourceClass);
|
||||
Assert.isInstanceOf(XADataSource.class, instance);
|
||||
return (XADataSource) instance;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(
|
||||
"Unable to create XADataSource instance from '" + className + "'");
|
||||
}
|
||||
}
|
||||
|
||||
private void bindXaProperties(XADataSource target, DataSourceProperties properties) {
|
||||
MutablePropertyValues values = new MutablePropertyValues();
|
||||
values.add("user", this.properties.getUsername());
|
||||
values.add("password", this.properties.getPassword());
|
||||
values.add("url", this.properties.getUrl());
|
||||
values.addPropertyValues(properties.getXa().getProperties());
|
||||
new RelaxedDataBinder(target).withAlias("user", "username").bind(values);
|
||||
}
|
||||
|
||||
}
|
|
@ -20,6 +20,7 @@ import javax.jms.ConnectionFactory;
|
|||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnJndi;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -29,6 +30,7 @@ import org.springframework.jms.annotation.JmsBootstrapConfiguration;
|
|||
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
|
||||
import org.springframework.jms.config.JmsListenerConfigUtils;
|
||||
import org.springframework.jms.support.destination.DestinationResolver;
|
||||
import org.springframework.jms.support.destination.JndiDestinationResolver;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
/**
|
||||
|
@ -67,6 +69,18 @@ class JmsAnnotationDrivenConfiguration {
|
|||
@EnableJms
|
||||
@ConditionalOnMissingBean(name = JmsListenerConfigUtils.JMS_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
|
||||
protected static class EnableJmsConfiguration {
|
||||
}
|
||||
|
||||
@ConditionalOnJndi
|
||||
protected static class JndiConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public DestinationResolver destinationResolver() {
|
||||
JndiDestinationResolver resolver = new JndiDestinationResolver();
|
||||
resolver.setFallbackToDynamicDestination(true);
|
||||
return resolver;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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 javax.jms.ConnectionFactory;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnJndi;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jndi.JndiLocatorDelegate;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for JMS provided from JNDI.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureBefore(JmsAutoConfiguration.class)
|
||||
@ConditionalOnMissingBean(ConnectionFactory.class)
|
||||
@ConditionalOnJndi("java:/JmsXA")
|
||||
public class JndiConnectionFactoryAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public ConnectionFactory connectionFactory() throws NamingException {
|
||||
return new JndiLocatorDelegate().lookup("java:/JmsXA", ConnectionFactory.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -19,19 +19,16 @@ package org.springframework.boot.autoconfigure.jms.activemq;
|
|||
import javax.jms.ConnectionFactory;
|
||||
|
||||
import org.apache.activemq.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.transport.vm.VMTransportFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.boot.autoconfigure.jta.JtaAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} to integrate with an ActiveMQ
|
||||
|
@ -39,67 +36,16 @@ import org.springframework.core.type.AnnotatedTypeMetadata;
|
|||
* embedded broker.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureBefore(JmsAutoConfiguration.class)
|
||||
@AutoConfigureAfter(JtaAutoConfiguration.class)
|
||||
@ConditionalOnClass({ ConnectionFactory.class, ActiveMQConnectionFactory.class })
|
||||
@ConditionalOnMissingBean(ConnectionFactory.class)
|
||||
@EnableConfigurationProperties(ActiveMQProperties.class)
|
||||
@Import({ ActiveMQXAConnectionFactoryConfiguration.class, ActiveMQConnectionFactoryConfiguration.class })
|
||||
public class ActiveMQAutoConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(VMTransportFactory.class)
|
||||
@Conditional(EmbeddedBrokerCondition.class)
|
||||
@Import(ActiveMQConnectionFactoryConfiguration.class)
|
||||
protected static class EmbeddedBroker {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Conditional(NonEmbeddedBrokerCondition.class)
|
||||
@Import(ActiveMQConnectionFactoryConfiguration.class)
|
||||
protected static class NetworkBroker {
|
||||
}
|
||||
|
||||
static abstract class BrokerTypeCondition extends SpringBootCondition {
|
||||
private final boolean embedded;
|
||||
|
||||
BrokerTypeCondition(boolean embedded) {
|
||||
this.embedded = embedded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
String brokerUrl = ActiveMQProperties.determineBrokerUrl(context
|
||||
.getEnvironment());
|
||||
boolean match = brokerUrl.contains("vm://");
|
||||
boolean outcome = (match == this.embedded);
|
||||
return new ConditionOutcome(outcome, buildMessage(brokerUrl, outcome));
|
||||
}
|
||||
|
||||
protected String buildMessage(String brokerUrl, boolean outcome) {
|
||||
String brokerType = this.embedded ? "Embedded" : "Network";
|
||||
String detected = outcome ? "detected" : "not detected";
|
||||
return brokerType + " ActiveMQ broker " + detected + " - brokerUrl '"
|
||||
+ brokerUrl + "'";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class EmbeddedBrokerCondition extends BrokerTypeCondition {
|
||||
|
||||
EmbeddedBrokerCondition() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class NonEmbeddedBrokerCondition extends BrokerTypeCondition {
|
||||
|
||||
NonEmbeddedBrokerCondition() {
|
||||
super(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,27 +18,34 @@ package org.springframework.boot.autoconfigure.jms.activemq;
|
|||
|
||||
import javax.jms.ConnectionFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.apache.activemq.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.pool.PooledConnectionFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Creates a {@link ConnectionFactory} based on {@link ActiveMQProperties}.
|
||||
* Configuration for ActiveMQ {@link ConnectionFactory}.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(ActiveMQProperties.class)
|
||||
@ConditionalOnMissingBean(ConnectionFactory.class)
|
||||
class ActiveMQConnectionFactoryConfiguration {
|
||||
|
||||
@Autowired
|
||||
private ActiveMQProperties properties;
|
||||
|
||||
@Bean
|
||||
public ConnectionFactory jmsConnectionFactory() {
|
||||
return this.properties.createConnectionFactory();
|
||||
public ConnectionFactory jmsConnectionFactory(ActiveMQProperties properties) {
|
||||
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
|
||||
properties).createConnectionFactory(ActiveMQConnectionFactory.class);
|
||||
if (properties.isPooled()) {
|
||||
PooledConnectionFactory pool = new PooledConnectionFactory();
|
||||
pool.setConnectionFactory(connectionFactory);
|
||||
return pool;
|
||||
}
|
||||
return connectionFactory;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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.activemq;
|
||||
|
||||
import org.apache.activemq.ActiveMQConnectionFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Factory to create a {@link ActiveMQConnectionFactory} instance from properties defined
|
||||
* in {@link ActiveMQProperties}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
class ActiveMQConnectionFactoryFactory {
|
||||
|
||||
private static final String DEFAULT_EMBEDDED_BROKER_URL = "vm://localhost?broker.persistent=false";
|
||||
|
||||
private static final String DEFAULT_NETWORK_BROKER_URL = "tcp://localhost:61616";
|
||||
|
||||
private final ActiveMQProperties properties;
|
||||
|
||||
public ActiveMQConnectionFactoryFactory(ActiveMQProperties properties) {
|
||||
Assert.notNull(properties, "Properties must not be null");
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public <T extends ActiveMQConnectionFactory> T createConnectionFactory(
|
||||
Class<T> factoryClass) {
|
||||
try {
|
||||
return doCreateConnectionFactory(factoryClass);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Unable to create "
|
||||
+ "ActiveMQConnectionFactory", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends ActiveMQConnectionFactory> T doCreateConnectionFactory(
|
||||
Class<T> factoryClass) throws Exception {
|
||||
String brokerUrl = determineBrokerUrl();
|
||||
String user = this.properties.getUser();
|
||||
String password = this.properties.getPassword();
|
||||
if (StringUtils.hasLength(user) && StringUtils.hasLength(password)) {
|
||||
return factoryClass.getConstructor(String.class, String.class, String.class)
|
||||
.newInstance(user, password, brokerUrl);
|
||||
}
|
||||
return factoryClass.getConstructor(String.class).newInstance(brokerUrl);
|
||||
}
|
||||
|
||||
String determineBrokerUrl() {
|
||||
if (this.properties.getBrokerUrl() != null) {
|
||||
return this.properties.getBrokerUrl();
|
||||
}
|
||||
if (this.properties.isInMemory()) {
|
||||
return DEFAULT_EMBEDDED_BROKER_URL;
|
||||
}
|
||||
return DEFAULT_NETWORK_BROKER_URL;
|
||||
}
|
||||
|
||||
}
|
|
@ -16,15 +16,7 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.jms.activemq;
|
||||
|
||||
import javax.jms.ConnectionFactory;
|
||||
|
||||
import org.apache.activemq.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.pool.PooledConnectionFactory;
|
||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertyResolver;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Configuration properties for ActiveMQ
|
||||
|
@ -35,10 +27,6 @@ import org.springframework.util.StringUtils;
|
|||
@ConfigurationProperties(prefix = "spring.activemq")
|
||||
public class ActiveMQProperties {
|
||||
|
||||
public static final String DEFAULT_EMBEDDED_BROKER_URL = "vm://localhost?broker.persistent=false";
|
||||
|
||||
public static final String DEFAULT_NETWORK_BROKER_URL = "tcp://localhost:61616";
|
||||
|
||||
private String brokerUrl;
|
||||
|
||||
private boolean inMemory = true;
|
||||
|
@ -93,52 +81,4 @@ public class ActiveMQProperties {
|
|||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link ConnectionFactory} from these properties.
|
||||
*/
|
||||
public ConnectionFactory createConnectionFactory() {
|
||||
ConnectionFactory connectionFactory = createActiveMQConnectionFactory();
|
||||
if (isPooled()) {
|
||||
PooledConnectionFactory pool = new PooledConnectionFactory();
|
||||
pool.setConnectionFactory(connectionFactory);
|
||||
return pool;
|
||||
}
|
||||
return connectionFactory;
|
||||
}
|
||||
|
||||
private ConnectionFactory createActiveMQConnectionFactory() {
|
||||
String brokerUrl = determineBrokerUrl();
|
||||
if (StringUtils.hasLength(this.user) && StringUtils.hasLength(this.password)) {
|
||||
return new ActiveMQConnectionFactory(this.user, this.password, brokerUrl);
|
||||
}
|
||||
return new ActiveMQConnectionFactory(brokerUrl);
|
||||
}
|
||||
|
||||
String determineBrokerUrl() {
|
||||
return determineBrokerUrl(this.brokerUrl, this.inMemory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the broker url to use for the specified {@link Environment}. If no broker
|
||||
* url is specified through configuration, a default broker is provided, that is
|
||||
* {@value #DEFAULT_EMBEDDED_BROKER_URL} if the {@code inMemory} flag is {@code null}
|
||||
* or {@code true}, {@value #DEFAULT_NETWORK_BROKER_URL} otherwise.
|
||||
* @param environment the environment to extract configuration from
|
||||
* @return the broker url to use
|
||||
*/
|
||||
public static String determineBrokerUrl(Environment environment) {
|
||||
PropertyResolver resolver = new RelaxedPropertyResolver(environment,
|
||||
"spring.activemq.");
|
||||
String brokerUrl = resolver.getProperty("brokerUrl");
|
||||
Boolean inMemory = resolver.getProperty("inMemory", Boolean.class);
|
||||
return determineBrokerUrl(brokerUrl, inMemory);
|
||||
}
|
||||
|
||||
private static String determineBrokerUrl(String brokerUrl, Boolean inMemory) {
|
||||
if (brokerUrl != null) {
|
||||
return brokerUrl;
|
||||
}
|
||||
boolean embedded = inMemory == null || inMemory;
|
||||
return (embedded ? DEFAULT_EMBEDDED_BROKER_URL : DEFAULT_NETWORK_BROKER_URL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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.activemq;
|
||||
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.apache.activemq.ActiveMQXAConnectionFactory;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Configuration for ActiveMQ XA {@link ConnectionFactory}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(TransactionManager.class)
|
||||
@ConditionalOnBean(XAConnectionFactoryWrapper.class)
|
||||
@ConditionalOnMissingBean(ConnectionFactory.class)
|
||||
class ActiveMQXAConnectionFactoryConfiguration {
|
||||
|
||||
@Bean
|
||||
public ConnectionFactory jmsConnectionFactory(ActiveMQProperties properties,
|
||||
XAConnectionFactoryWrapper wrapper) throws Exception {
|
||||
ActiveMQXAConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
|
||||
properties).createConnectionFactory(ActiveMQXAConnectionFactory.class);
|
||||
return wrapper.wrapConnectionFactory(connectionFactory);
|
||||
}
|
||||
|
||||
}
|
|
@ -16,48 +16,25 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.jms.hornetq;
|
||||
|
||||
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.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
|
||||
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;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} to integrate with an HornetQ 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.
|
||||
* {@link EnableAutoConfiguration Auto-configuration} to integrate with an HornetQ 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 Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @since 1.1.0
|
||||
* @see HornetQProperties
|
||||
*/
|
||||
|
@ -65,151 +42,9 @@ import org.springframework.util.ClassUtils;
|
|||
@AutoConfigureBefore(JmsAutoConfiguration.class)
|
||||
@ConditionalOnClass({ ConnectionFactory.class, HornetQJMSClient.class })
|
||||
@EnableConfigurationProperties(HornetQProperties.class)
|
||||
@Import({ HornetQEmbeddedServerConfiguration.class,
|
||||
HornetQXAConnectionFactoryConfiguration.class,
|
||||
HornetQConnectionFactoryConfiguration.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, start an
|
||||
* embedded server unless it has been explicitly disabled, connect 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(), this.properties.getEmbedded()
|
||||
.generateTransportParameters());
|
||||
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<String, Object> params = new HashMap<String, Object>();
|
||||
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)
|
||||
@ConditionalOnExpression("${spring.hornetq.embedded.enabled:true}")
|
||||
static class EmbeddedServerConfiguration {
|
||||
|
||||
@Autowired
|
||||
private HornetQProperties properties;
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<HornetQConfigurationCustomizer> configurationCustomizers;
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<JMSQueueConfiguration> queuesConfiguration;
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<TopicConfiguration> 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();
|
||||
customize(configuration);
|
||||
server.setConfiguration(configuration);
|
||||
server.setJmsConfiguration(jmsConfiguration);
|
||||
server.setRegistry(new HornetQNoOpBindingRegistry());
|
||||
return server;
|
||||
}
|
||||
|
||||
private void customize(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());
|
||||
addTopics(configuration, this.properties.getEmbedded().getTopics());
|
||||
return configuration;
|
||||
}
|
||||
|
||||
private <T> void addAll(List<T> 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 addTopics(JMSConfiguration configuration, String[] topics) {
|
||||
for (String topic : topics) {
|
||||
configuration.getTopicConfigurations().add(
|
||||
new TopicConfigurationImpl(topic, "/topic/" + topic));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.hornetq;
|
||||
|
||||
import javax.jms.ConnectionFactory;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.hornetq.jms.client.HornetQConnectionFactory;
|
||||
import org.hornetq.jms.server.embedded.EmbeddedJMS;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Configuration for HornetQ {@link ConnectionFactory}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(ConnectionFactory.class)
|
||||
class HornetQConnectionFactoryConfiguration {
|
||||
|
||||
private static Log logger = LogFactory
|
||||
.getLog(HornetQEmbeddedServerConfiguration.class);
|
||||
|
||||
// Ensure JMS is setup before XA
|
||||
@Autowired(required = false)
|
||||
private EmbeddedJMS embeddedJMS;
|
||||
|
||||
@Bean
|
||||
public ConnectionFactory jmsConnectionFactory(HornetQProperties properties) {
|
||||
if (this.embeddedJMS != null && logger.isDebugEnabled()) {
|
||||
logger.debug("Using embdedded HornetQ broker");
|
||||
}
|
||||
return new HornetQConnectionFactoryFactory(properties)
|
||||
.createConnectionFactory(HornetQConnectionFactory.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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.hornetq;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hornetq.api.core.TransportConfiguration;
|
||||
import org.hornetq.api.core.client.HornetQClient;
|
||||
import org.hornetq.api.core.client.ServerLocator;
|
||||
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.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Factory to create a {@link HornetQConnectionFactory} instance from properties defined
|
||||
* in {@link HornetQProperties}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.2.0
|
||||
*/
|
||||
class HornetQConnectionFactoryFactory {
|
||||
|
||||
static final String EMBEDDED_JMS_CLASS = "org.hornetq.jms.server.embedded.EmbeddedJMS";
|
||||
|
||||
private final HornetQProperties properties;
|
||||
|
||||
public HornetQConnectionFactoryFactory(HornetQProperties properties) {
|
||||
Assert.notNull(properties, "Properties must not be null");
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public <T extends HornetQConnectionFactory> T createConnectionFactory(
|
||||
Class<T> factoryClass) {
|
||||
try {
|
||||
return doCreateConnectionFactory(factoryClass);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Unable to create "
|
||||
+ "HornetQConnectionFactory", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends HornetQConnectionFactory> T doCreateConnectionFactory(
|
||||
Class<T> factoryClass) throws Exception {
|
||||
HornetQMode mode = this.properties.getMode();
|
||||
if (mode == null) {
|
||||
mode = deduceMode();
|
||||
}
|
||||
if (mode == HornetQMode.EMBEDDED) {
|
||||
return createEmbeddedConnectionFactory(factoryClass);
|
||||
}
|
||||
return createNativeConnectionFactory(factoryClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 <T extends HornetQConnectionFactory> T createEmbeddedConnectionFactory(
|
||||
Class<T> factoryClass) throws Exception {
|
||||
try {
|
||||
TransportConfiguration transportConfiguration = new TransportConfiguration(
|
||||
InVMConnectorFactory.class.getName(), this.properties.getEmbedded()
|
||||
.generateTransportParameters());
|
||||
ServerLocator serviceLocator = HornetQClient
|
||||
.createServerLocatorWithoutHA(transportConfiguration);
|
||||
return factoryClass.getConstructor(ServerLocator.class).newInstance(
|
||||
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 <T extends HornetQConnectionFactory> T createNativeConnectionFactory(
|
||||
Class<T> factoryClass) throws Exception {
|
||||
Map<String, Object> params = new HashMap<String, Object>();
|
||||
params.put(TransportConstants.HOST_PROP_NAME, this.properties.getHost());
|
||||
params.put(TransportConstants.PORT_PROP_NAME, this.properties.getPort());
|
||||
TransportConfiguration transportConfiguration = new TransportConfiguration(
|
||||
NettyConnectorFactory.class.getName(), params);
|
||||
Constructor<T> constructor = factoryClass.getConstructor(boolean.class,
|
||||
TransportConfiguration[].class);
|
||||
return constructor.newInstance(false,
|
||||
new TransportConfiguration[] { transportConfiguration });
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* 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.hornetq;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
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.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 HornetQ server.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(name = HornetQConnectionFactoryFactory.EMBEDDED_JMS_CLASS)
|
||||
@ConditionalOnProperty(prefix = "spring.hornetq.embedded", name = "enabled", havingValue = "true", matchIfMissing = true)
|
||||
class HornetQEmbeddedServerConfiguration {
|
||||
|
||||
@Autowired
|
||||
private HornetQProperties properties;
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<HornetQConfigurationCustomizer> configurationCustomizers;
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<JMSQueueConfiguration> queuesConfiguration;
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<TopicConfiguration> 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();
|
||||
customize(configuration);
|
||||
server.setConfiguration(configuration);
|
||||
server.setJmsConfiguration(jmsConfiguration);
|
||||
server.setRegistry(new HornetQNoOpBindingRegistry());
|
||||
return server;
|
||||
}
|
||||
|
||||
private void customize(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());
|
||||
addTopics(configuration, this.properties.getEmbedded().getTopics());
|
||||
return configuration;
|
||||
}
|
||||
|
||||
private <T> void addAll(List<T> 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 addTopics(JMSConfiguration configuration, String[] topics) {
|
||||
for (String topic : topics) {
|
||||
configuration.getTopicConfigurations().add(
|
||||
new TopicConfigurationImpl(topic, "/topic/" + topic));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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.hornetq;
|
||||
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.hornetq.jms.client.HornetQXAConnectionFactory;
|
||||
import org.hornetq.jms.server.embedded.EmbeddedJMS;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Configuration for HornetQ XA {@link ConnectionFactory}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(ConnectionFactory.class)
|
||||
@ConditionalOnClass(TransactionManager.class)
|
||||
@ConditionalOnBean(XAConnectionFactoryWrapper.class)
|
||||
class HornetQXAConnectionFactoryConfiguration {
|
||||
|
||||
private static Log logger = LogFactory
|
||||
.getLog(HornetQEmbeddedServerConfiguration.class);
|
||||
|
||||
// Ensure JMS is setup before XA
|
||||
@Autowired(required = false)
|
||||
private EmbeddedJMS embeddedJMS;
|
||||
|
||||
@Bean
|
||||
public ConnectionFactory jmsConnectionFactory(HornetQProperties properties,
|
||||
XAConnectionFactoryWrapper wrapper) throws Exception {
|
||||
if (this.embeddedJMS != null && logger.isDebugEnabled()) {
|
||||
logger.debug("Using embdedded HornetQ broker with XA");
|
||||
}
|
||||
return wrapper.wrapConnectionFactory(new HornetQConnectionFactoryFactory(
|
||||
properties).createConnectionFactory(HornetQXAConnectionFactory.class));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* 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.jta;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.transaction.TransactionManager;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationHome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.jta.XAConnectionFactoryWrapper;
|
||||
import org.springframework.boot.jta.XADataSourceWrapper;
|
||||
import org.springframework.boot.jta.atomikos.AtomikosDependsOnBeanFactoryPostProcessor;
|
||||
import org.springframework.boot.jta.atomikos.AtomikosProperties;
|
||||
import org.springframework.boot.jta.atomikos.AtomikosXAConnectionFactoryWrapper;
|
||||
import org.springframework.boot.jta.atomikos.AtomikosXADataSourceWrapper;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.jta.JtaTransactionManager;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.atomikos.icatch.config.UserTransactionService;
|
||||
import com.atomikos.icatch.config.UserTransactionServiceImp;
|
||||
import com.atomikos.icatch.jta.UserTransactionManager;
|
||||
|
||||
/**
|
||||
* JTA Configuration for <A href="http://www.atomikos.com/">Atomikos</a>.
|
||||
*
|
||||
* @author Josh Long
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(UserTransactionManager.class)
|
||||
@ConditionalOnMissingBean(PlatformTransactionManager.class)
|
||||
class AtomikosJtaConfiguration {
|
||||
|
||||
@Autowired
|
||||
private JtaProperties jtaProperties;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConfigurationProperties(prefix = JtaProperties.PREFIX)
|
||||
public AtomikosProperties atomikosProperties() {
|
||||
return new AtomikosProperties();
|
||||
}
|
||||
|
||||
@Bean(initMethod = "init", destroyMethod = "shutdownForce")
|
||||
@ConditionalOnMissingBean
|
||||
public UserTransactionService userTransactionService(
|
||||
AtomikosProperties atomikosProperties) {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("com.atomikos.icatch.log_base_dir", getLogBaseDir());
|
||||
properties.putAll(atomikosProperties.asProperties());
|
||||
return new UserTransactionServiceImp(properties);
|
||||
}
|
||||
|
||||
private String getLogBaseDir() {
|
||||
if (StringUtils.hasLength(this.jtaProperties.getLogDir())) {
|
||||
return this.jtaProperties.getLogDir();
|
||||
}
|
||||
File home = new ApplicationHome().getDir();
|
||||
return new File(home, "transaction-logs").getAbsolutePath();
|
||||
}
|
||||
|
||||
@Bean(initMethod = "init", destroyMethod = "close")
|
||||
@ConditionalOnMissingBean
|
||||
public UserTransactionManager atomikosTransactionManager(
|
||||
UserTransactionService userTransactionService) throws Exception {
|
||||
UserTransactionManager manager = new UserTransactionManager();
|
||||
manager.setStartupTransactionService(false);
|
||||
manager.setForceShutdown(true);
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public XADataSourceWrapper xaDataSourceWrapper() {
|
||||
return new AtomikosXADataSourceWrapper();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() {
|
||||
return new AtomikosXAConnectionFactoryWrapper();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public static AtomikosDependsOnBeanFactoryPostProcessor atomikosDependsOnBeanFactoryPostProcessor() {
|
||||
return new AtomikosDependsOnBeanFactoryPostProcessor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JtaTransactionManager transactionManager(UserTransaction userTransaction,
|
||||
TransactionManager transactionManager) {
|
||||
return new JtaTransactionManager(userTransaction, transactionManager);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* 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.jta;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationHome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.jta.XAConnectionFactoryWrapper;
|
||||
import org.springframework.boot.jta.XADataSourceWrapper;
|
||||
import org.springframework.boot.jta.bitronix.BitronixDependentBeanFactoryPostProcessor;
|
||||
import org.springframework.boot.jta.bitronix.BitronixXAConnectionFactoryWrapper;
|
||||
import org.springframework.boot.jta.bitronix.BitronixXADataSourceWrapper;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.jta.JtaTransactionManager;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import bitronix.tm.TransactionManagerServices;
|
||||
import bitronix.tm.jndi.BitronixContext;
|
||||
|
||||
/**
|
||||
* JTA Configuration for <A href="http://docs.codehaus.org/display/BTM/Home">Bitronix</A>.
|
||||
*
|
||||
* @author Josh Long
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(BitronixContext.class)
|
||||
@ConditionalOnMissingBean(PlatformTransactionManager.class)
|
||||
class BitronixJtaConfiguration {
|
||||
|
||||
@Autowired
|
||||
private JtaProperties jtaProperties;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConfigurationProperties(prefix = JtaProperties.PREFIX)
|
||||
public bitronix.tm.Configuration bitronixConfiguration(JtaProperties xxx) {
|
||||
bitronix.tm.Configuration config = TransactionManagerServices.getConfiguration();
|
||||
config.setServerId("spring-boot-jta-bitronix");
|
||||
File logBaseDir = getLogBaseDir();
|
||||
config.setLogPart1Filename(new File(logBaseDir, "part1.btm").getAbsolutePath());
|
||||
config.setLogPart2Filename(new File(logBaseDir, "part2.btm").getAbsolutePath());
|
||||
config.setDisableJmx(true);
|
||||
return config;
|
||||
}
|
||||
|
||||
private File getLogBaseDir() {
|
||||
if (StringUtils.hasLength(this.jtaProperties.getLogDir())) {
|
||||
return new File(this.jtaProperties.getLogDir());
|
||||
}
|
||||
File home = new ApplicationHome().getDir();
|
||||
return new File(home, "transaction-logs");
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TransactionManager bitronixTransactionManager(
|
||||
bitronix.tm.Configuration configuration) {
|
||||
// Inject configuration to force ordering
|
||||
return TransactionManagerServices.getTransactionManager();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public XADataSourceWrapper xaDataSourceWrapper() {
|
||||
return new BitronixXADataSourceWrapper();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() {
|
||||
return new BitronixXAConnectionFactoryWrapper();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public static BitronixDependentBeanFactoryPostProcessor atomikosDependsOnBeanFactoryPostProcessor() {
|
||||
return new BitronixDependentBeanFactoryPostProcessor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JtaTransactionManager transactionManager(TransactionManager transactionManager) {
|
||||
return new JtaTransactionManager(transactionManager);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.jta;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnJndi;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.jta.JtaTransactionManager;
|
||||
|
||||
/**
|
||||
* JTA Configuration for a JDNI managed {@link JtaTransactionManager}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnJndi({ JtaTransactionManager.DEFAULT_USER_TRANSACTION_NAME,
|
||||
"java:comp/TransactionManager", "java:appserver/TransactionManager",
|
||||
"java:pm/TransactionManager", "java:/TransactionManager" })
|
||||
@ConditionalOnMissingBean(PlatformTransactionManager.class)
|
||||
class JndiJtaConfiguration {
|
||||
|
||||
@Bean
|
||||
public JtaTransactionManager transactionManager() {
|
||||
return new JtaTransactionManager();
|
||||
}
|
||||
|
||||
}
|
|
@ -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.jta;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for JTA.
|
||||
*
|
||||
* @author Josh Long
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@ConditionalOnClass(javax.transaction.Transaction.class)
|
||||
@Import({ JndiJtaConfiguration.class, BitronixJtaConfiguration.class,
|
||||
AtomikosJtaConfiguration.class })
|
||||
@EnableConfigurationProperties(JtaProperties.class)
|
||||
public class JtaAutoConfiguration {
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.jta;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.transaction.jta.JtaTransactionManager;
|
||||
|
||||
/**
|
||||
* External configuration properties for a {@link JtaTransactionManager} created by
|
||||
* Spring. All {@literal spring.jta.} properties are also applied to the appropriate
|
||||
* vendor specific configuration.
|
||||
*
|
||||
* @author Josh Long
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = JtaProperties.PREFIX, ignoreUnknownFields = true)
|
||||
public class JtaProperties {
|
||||
|
||||
public static final String PREFIX = "spring.jta";
|
||||
|
||||
private String logDir;
|
||||
|
||||
public void setLogDir(String logDir) {
|
||||
this.logDir = logDir;
|
||||
}
|
||||
|
||||
public String getLogDir() {
|
||||
return this.logDir;
|
||||
}
|
||||
|
||||
}
|
|
@ -89,6 +89,8 @@ public class EntityManagerFactoryBuilder {
|
|||
|
||||
private Map<String, Object> properties = new HashMap<String, Object>();
|
||||
|
||||
private boolean jta;
|
||||
|
||||
private Builder(DataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
@ -142,6 +144,21 @@ public class EntityManagerFactoryBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure if using a JTA {@link DataSource}, i.e. if
|
||||
* {@link LocalContainerEntityManagerFactoryBean#setDataSource(DataSource)
|
||||
* setDataSource} or
|
||||
* {@link LocalContainerEntityManagerFactoryBean#setJtaDataSource(DataSource)
|
||||
* setJtaDataSource} should be called on the
|
||||
* {@link LocalContainerEntityManagerFactoryBean}.
|
||||
* @param jta if the data source is JTA
|
||||
* @return the builder for fluent usage
|
||||
*/
|
||||
public Builder jta(boolean jta) {
|
||||
this.jta = jta;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LocalContainerEntityManagerFactoryBean build() {
|
||||
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
|
||||
if (EntityManagerFactoryBuilder.this.persistenceUnitManager != null) {
|
||||
|
@ -153,7 +170,14 @@ public class EntityManagerFactoryBuilder {
|
|||
}
|
||||
entityManagerFactoryBean
|
||||
.setJpaVendorAdapter(EntityManagerFactoryBuilder.this.jpaVendorAdapter);
|
||||
entityManagerFactoryBean.setDataSource(this.dataSource);
|
||||
|
||||
if (this.jta) {
|
||||
entityManagerFactoryBean.setJtaDataSource(this.dataSource);
|
||||
}
|
||||
else {
|
||||
entityManagerFactoryBean.setDataSource(this.dataSource);
|
||||
}
|
||||
|
||||
entityManagerFactoryBean.setPackagesToScan(this.packagesToScan);
|
||||
entityManagerFactoryBean.getJpaPropertyMap().putAll(
|
||||
EntityManagerFactoryBuilder.this.properties.getProperties());
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.Map;
|
|||
import javax.persistence.EntityManager;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
|
@ -29,8 +30,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jta.JtaAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration.HibernateEntityManagerCondition;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -39,29 +41,30 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
|||
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
|
||||
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.springframework.transaction.jta.JtaTransactionManager;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Hibernate JPA.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Josh Long
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class,
|
||||
EnableTransactionManagement.class, EntityManager.class })
|
||||
@Conditional(HibernateEntityManagerCondition.class)
|
||||
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
|
||||
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, JtaAutoConfiguration.class })
|
||||
public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
private static final String JTA_PLATFORM = "hibernate.transaction.jta.platform";
|
||||
|
||||
@Autowired
|
||||
private JpaProperties properties;
|
||||
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
@Autowired
|
||||
private ConfigurableApplicationContext applicationContext;
|
||||
|
||||
@Override
|
||||
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
|
||||
return new HibernateJpaVendorAdapter();
|
||||
|
@ -74,6 +77,21 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration {
|
|||
return vendorProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customizeVendorProperties(Map<String, Object> vendorProperties) {
|
||||
super.customizeVendorProperties(vendorProperties);
|
||||
if (!vendorProperties.containsKey(JTA_PLATFORM)) {
|
||||
JtaTransactionManager jtaTransactionManager = getJtaTransactionManager();
|
||||
if (jtaTransactionManager != null) {
|
||||
vendorProperties.put(JTA_PLATFORM, new SpringJtaPlatform(
|
||||
jtaTransactionManager));
|
||||
}
|
||||
else {
|
||||
vendorProperties.put(JTA_PLATFORM, NoJtaPlatform.INSTANCE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class HibernateEntityManagerCondition extends SpringBootCondition {
|
||||
|
||||
private static String[] CLASS_NAMES = {
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;
|
|||
import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;
|
||||
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.jta.JtaTransactionManager;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
|
@ -71,6 +72,9 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware {
|
|||
@Autowired
|
||||
private JpaProperties jpaProperties;
|
||||
|
||||
@Autowired(required = false)
|
||||
private JtaTransactionManager jtaTransactionManager;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(PlatformTransactionManager.class)
|
||||
public PlatformTransactionManager transactionManager() {
|
||||
|
@ -103,14 +107,24 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware {
|
|||
@ConditionalOnMissingBean
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
|
||||
EntityManagerFactoryBuilder factoryBuilder) {
|
||||
Map<String, Object> vendorProperties = getVendorProperties();
|
||||
customizeVendorProperties(vendorProperties);
|
||||
return factoryBuilder.dataSource(this.dataSource).packages(getPackagesToScan())
|
||||
.properties(getVendorProperties()).build();
|
||||
.properties(vendorProperties).jta(isJta()).build();
|
||||
}
|
||||
|
||||
protected abstract AbstractJpaVendorAdapter createJpaVendorAdapter();
|
||||
|
||||
protected abstract Map<String, Object> getVendorProperties();
|
||||
|
||||
/**
|
||||
* Customize vendor properties before they are used. Allows for post processing (for
|
||||
* example to configure JTA specific settings).
|
||||
* @param vendorProperties the vendor properties to customize
|
||||
*/
|
||||
protected void customizeVendorProperties(Map<String, Object> vendorProperties) {
|
||||
}
|
||||
|
||||
protected EntityManagerFactoryBuilder.EntityManagerFactoryBeanCallback getVendorCallback() {
|
||||
return null;
|
||||
}
|
||||
|
@ -127,6 +141,20 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware {
|
|||
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jtaTransactionManager or {@code null}
|
||||
*/
|
||||
protected JtaTransactionManager getJtaTransactionManager() {
|
||||
return this.jtaTransactionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a JTA {@link PlatformTransactionManager} is being used.
|
||||
*/
|
||||
protected final boolean isJta() {
|
||||
return (this.jtaTransactionManager != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.apache.commons.logging.Log;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDatabaseConnection;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.orm.jpa.SpringNamingStrategy;
|
||||
import org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy;
|
||||
import org.springframework.orm.jpa.vendor.Database;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
|
|
@ -20,11 +20,14 @@ org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
|
|||
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
|
||||
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.hornetq.HornetQAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.jta.JtaAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchDataAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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.condition;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link OnJndiCondition}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class ConditionOnJndiTests {
|
||||
|
||||
private MockableOnJndi condition = new MockableOnJndi();
|
||||
|
||||
@Test
|
||||
public void jndiNotAvailable() {
|
||||
this.condition.setJndiAvailable(false);
|
||||
ConditionOutcome outcome = this.condition.getMatchOutcome(null, mockMetaData());
|
||||
assertThat(outcome.isMatch(), equalTo(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jndiLocationNotFound() {
|
||||
ConditionOutcome outcome = this.condition.getMatchOutcome(null,
|
||||
mockMetaData("java:/a"));
|
||||
assertThat(outcome.isMatch(), equalTo(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jndiLocationFound() {
|
||||
this.condition.setFoundLocation("java:/b");
|
||||
ConditionOutcome outcome = this.condition.getMatchOutcome(null,
|
||||
mockMetaData("java:/a", "java:/b"));
|
||||
assertThat(outcome.isMatch(), equalTo(true));
|
||||
}
|
||||
|
||||
private AnnotatedTypeMetadata mockMetaData(String... value) {
|
||||
AnnotatedTypeMetadata metadata = mock(AnnotatedTypeMetadata.class);
|
||||
Map<String, Object> attributes = new HashMap<String, Object>();
|
||||
attributes.put("value", value);
|
||||
given(metadata.getAnnotationAttributes(ConditionalOnJndi.class.getName()))
|
||||
.willReturn(attributes);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private static class MockableOnJndi extends OnJndiCondition {
|
||||
|
||||
private boolean jndiAvailable = true;
|
||||
|
||||
private String foundLocation;
|
||||
|
||||
@Override
|
||||
protected boolean isJndiAvailable() {
|
||||
return this.jndiAvailable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JndiLocator getJndiLocator(String[] locations) {
|
||||
return new JndiLocator(locations) {
|
||||
@Override
|
||||
public String lookupFirstLocation() {
|
||||
return MockableOnJndi.this.foundLocation;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void setJndiAvailable(boolean jndiAvailable) {
|
||||
this.jndiAvailable = jndiAvailable;
|
||||
}
|
||||
|
||||
public void setFoundLocation(String foundLocation) {
|
||||
this.foundLocation = foundLocation;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -20,47 +20,46 @@ import org.junit.Rule;
|
|||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link DriverClassNameProvider}.
|
||||
* Tests for {@link DatabaseDriver}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Maciej Walkowiak
|
||||
*/
|
||||
public class DriverClassNameProviderTests {
|
||||
|
||||
private DriverClassNameProvider provider = new DriverClassNameProvider();
|
||||
public class DatabaseDriverTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void classNameForKnownDatabase() {
|
||||
String driverClassName = this.provider
|
||||
.getDriverClassName("jdbc:postgresql://hostname/dbname");
|
||||
String driverClassName = DatabaseDriver.fromJdbcUrl(
|
||||
"jdbc:postgresql://hostname/dbname").getDriverClassName();
|
||||
assertEquals("org.postgresql.Driver", driverClassName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullForUnknownDatabase() {
|
||||
String driverClassName = this.provider
|
||||
.getDriverClassName("jdbc:unknowndb://hostname/dbname");
|
||||
public void nullClassNameForUnknownDatabase() {
|
||||
String driverClassName = DatabaseDriver.fromJdbcUrl(
|
||||
"jdbc:unknowndb://hostname/dbname").getDriverClassName();
|
||||
assertNull(driverClassName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failureOnNullJdbcUrl() {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("JdbcUrl must not be null");
|
||||
this.provider.getDriverClassName(null);
|
||||
public void unknownOnNullJdbcUrl() {
|
||||
assertThat(DatabaseDriver.fromJdbcUrl(null), equalTo(DatabaseDriver.UNKNOWN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failureOnMalformedJdbcUrl() {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("JdbcUrl must start with");
|
||||
this.provider.getDriverClassName("malformed:url");
|
||||
this.thrown.expectMessage("URL must start with");
|
||||
DatabaseDriver.fromJdbcUrl("malformed:url");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* 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.jdbc;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import javax.sql.XADataSource;
|
||||
|
||||
import org.hsqldb.jdbc.pool.JDBCXADataSource;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.jta.XADataSourceWrapper;
|
||||
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 static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link XADataSourceAutoConfiguration}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class XADataSourceAutoConfigurationTests {
|
||||
|
||||
@Test
|
||||
public void wrapExistingXaDataSource() throws Exception {
|
||||
ApplicationContext context = createContext(WrapExisting.class);
|
||||
context.getBean(DataSource.class);
|
||||
XADataSource source = context.getBean(XADataSource.class);
|
||||
MockXADataSourceWrapper wrapper = context.getBean(MockXADataSourceWrapper.class);
|
||||
assertThat(wrapper.getXaDataSource(), equalTo(source));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromUrl() throws Exception {
|
||||
ApplicationContext context = createContext(FromProperties.class,
|
||||
"spring.datasource.url:jdbc:hsqldb:mem:test",
|
||||
"spring.datasource.username:un");
|
||||
context.getBean(DataSource.class);
|
||||
MockXADataSourceWrapper wrapper = context.getBean(MockXADataSourceWrapper.class);
|
||||
JDBCXADataSource dataSource = (JDBCXADataSource) wrapper.getXaDataSource();
|
||||
assertNotNull(dataSource);
|
||||
assertThat(dataSource.getUrl(), equalTo("jdbc:hsqldb:mem:test"));
|
||||
assertThat(dataSource.getUser(), equalTo("un"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromClass() throws Exception {
|
||||
ApplicationContext context = createContext(
|
||||
FromProperties.class,
|
||||
"spring.datasource.xa.data-source-class:org.hsqldb.jdbc.pool.JDBCXADataSource",
|
||||
"spring.datasource.xa.properties.database-name:test");
|
||||
context.getBean(DataSource.class);
|
||||
MockXADataSourceWrapper wrapper = context.getBean(MockXADataSourceWrapper.class);
|
||||
JDBCXADataSource dataSource = (JDBCXADataSource) wrapper.getXaDataSource();
|
||||
assertNotNull(dataSource);
|
||||
assertThat(dataSource.getDatabaseName(), equalTo("test"));
|
||||
|
||||
}
|
||||
|
||||
private ApplicationContext createContext(Class<?> configuration, String... env) {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(context, env);
|
||||
context.register(configuration, XADataSourceAutoConfiguration.class);
|
||||
context.refresh();
|
||||
return context;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class WrapExisting {
|
||||
|
||||
@Bean
|
||||
public MockXADataSourceWrapper wrapper() {
|
||||
return new MockXADataSourceWrapper();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public XADataSource xaDataSource() {
|
||||
return mock(XADataSource.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class FromProperties {
|
||||
|
||||
@Bean
|
||||
public MockXADataSourceWrapper wrapper() {
|
||||
return new MockXADataSourceWrapper();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MockXADataSourceWrapper implements XADataSourceWrapper {
|
||||
|
||||
private XADataSource dataSource;
|
||||
|
||||
@Override
|
||||
public DataSource wrapDataSource(XADataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
return mock(DataSource.class);
|
||||
}
|
||||
|
||||
public XADataSource getXaDataSource() {
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -24,7 +24,6 @@ import org.junit.Test;
|
|||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQProperties;
|
||||
import org.springframework.boot.test.EnvironmentTestUtils;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -49,6 +48,10 @@ import static org.junit.Assert.assertTrue;
|
|||
*/
|
||||
public class JmsAutoConfigurationTests {
|
||||
|
||||
private static final String ACTIVEMQ_EMBEDDED_URL = "vm://localhost?broker.persistent=false";
|
||||
|
||||
private static final String ACTIVEMQ_NETWORK_URL = "tcp://localhost:61616";
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
@Test
|
||||
|
@ -61,7 +64,7 @@ public class JmsAutoConfigurationTests {
|
|||
.getBean(JmsMessagingTemplate.class);
|
||||
assertEquals(jmsTemplate.getConnectionFactory(), connectionFactory);
|
||||
assertEquals(jmsTemplate, messagingTemplate.getJmsTemplate());
|
||||
assertEquals(ActiveMQProperties.DEFAULT_EMBEDDED_BROKER_URL,
|
||||
assertEquals(ACTIVEMQ_EMBEDDED_URL,
|
||||
((ActiveMQConnectionFactory) jmsTemplate.getConnectionFactory())
|
||||
.getBrokerURL());
|
||||
assertTrue("listener container factory should be created by default",
|
||||
|
@ -158,7 +161,7 @@ public class JmsAutoConfigurationTests {
|
|||
assertNotNull(jmsTemplate);
|
||||
assertNotNull(connectionFactory);
|
||||
assertEquals(jmsTemplate.getConnectionFactory(), connectionFactory);
|
||||
assertEquals(ActiveMQProperties.DEFAULT_NETWORK_BROKER_URL,
|
||||
assertEquals(ACTIVEMQ_NETWORK_URL,
|
||||
((ActiveMQConnectionFactory) jmsTemplate.getConnectionFactory())
|
||||
.getBrokerURL());
|
||||
}
|
||||
|
@ -188,8 +191,7 @@ public class JmsAutoConfigurationTests {
|
|||
assertEquals(jmsTemplate.getConnectionFactory(), pool);
|
||||
ActiveMQConnectionFactory factory = (ActiveMQConnectionFactory) pool
|
||||
.getConnectionFactory();
|
||||
assertEquals(ActiveMQProperties.DEFAULT_EMBEDDED_BROKER_URL,
|
||||
factory.getBrokerURL());
|
||||
assertEquals(ACTIVEMQ_EMBEDDED_URL, factory.getBrokerURL());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -204,8 +206,7 @@ public class JmsAutoConfigurationTests {
|
|||
assertEquals(jmsTemplate.getConnectionFactory(), pool);
|
||||
ActiveMQConnectionFactory factory = (ActiveMQConnectionFactory) pool
|
||||
.getConnectionFactory();
|
||||
assertEquals(ActiveMQProperties.DEFAULT_NETWORK_BROKER_URL,
|
||||
factory.getBrokerURL());
|
||||
assertEquals(ACTIVEMQ_NETWORK_URL, factory.getBrokerURL());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -257,6 +258,7 @@ public class JmsAutoConfigurationTests {
|
|||
|
||||
@Configuration
|
||||
protected static class TestConfiguration2 {
|
||||
|
||||
@Bean
|
||||
ConnectionFactory connectionFactory() {
|
||||
return new ActiveMQConnectionFactory() {
|
||||
|
@ -265,10 +267,12 @@ public class JmsAutoConfigurationTests {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class TestConfiguration3 {
|
||||
|
||||
@Bean
|
||||
JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) {
|
||||
JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
|
||||
|
@ -280,6 +284,7 @@ public class JmsAutoConfigurationTests {
|
|||
|
||||
@Configuration
|
||||
protected static class TestConfiguration4 implements BeanPostProcessor {
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
|
@ -295,6 +300,7 @@ public class JmsAutoConfigurationTests {
|
|||
throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
|
|
@ -17,67 +17,50 @@
|
|||
package org.springframework.boot.autoconfigure.jms.activemq;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.test.EnvironmentTestUtils;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests for {@link ActiveMQProperties}.
|
||||
* Tests for {@link ActiveMQProperties} and ActiveMQConnectionFactoryFactory.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class ActiveMQPropertiesTests {
|
||||
|
||||
private static final String DEFAULT_EMBEDDED_BROKER_URL = "vm://localhost?broker.persistent=false";
|
||||
|
||||
private static final String DEFAULT_NETWORK_BROKER_URL = "tcp://localhost:61616";
|
||||
|
||||
private final ActiveMQProperties properties = new ActiveMQProperties();
|
||||
|
||||
private final StandardEnvironment environment = new StandardEnvironment();
|
||||
|
||||
@Test
|
||||
public void determineBrokerUrlDefault() {
|
||||
assertEquals(ActiveMQProperties.DEFAULT_EMBEDDED_BROKER_URL,
|
||||
ActiveMQProperties.determineBrokerUrl(this.environment));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void determineBrokerUrlVmBrokerUrl() {
|
||||
EnvironmentTestUtils.addEnvironment(this.environment,
|
||||
"spring.activemq.brokerUrl:vm://localhost?persistent=true");
|
||||
assertEquals("vm://localhost?persistent=true",
|
||||
ActiveMQProperties.determineBrokerUrl(this.environment));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void determineBrokerUrlInMemoryFlag() {
|
||||
EnvironmentTestUtils.addEnvironment(this.environment,
|
||||
"spring.activemq.inMemory:false");
|
||||
assertEquals(ActiveMQProperties.DEFAULT_NETWORK_BROKER_URL,
|
||||
ActiveMQProperties.determineBrokerUrl(this.environment));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBrokerUrlIsInMemoryByDefault() {
|
||||
assertEquals(ActiveMQProperties.DEFAULT_EMBEDDED_BROKER_URL,
|
||||
this.properties.determineBrokerUrl());
|
||||
assertEquals(DEFAULT_EMBEDDED_BROKER_URL, new ActiveMQConnectionFactoryFactory(
|
||||
this.properties).determineBrokerUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBrokerUrlUseExplicitBrokerUrl() {
|
||||
this.properties.setBrokerUrl("vm://foo-bar");
|
||||
assertEquals("vm://foo-bar", this.properties.determineBrokerUrl());
|
||||
assertEquals("vm://foo-bar",
|
||||
new ActiveMQConnectionFactoryFactory(this.properties)
|
||||
.determineBrokerUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBrokerUrlWithInMemorySetToFalse() {
|
||||
this.properties.setInMemory(false);
|
||||
assertEquals(ActiveMQProperties.DEFAULT_NETWORK_BROKER_URL,
|
||||
this.properties.determineBrokerUrl());
|
||||
assertEquals(DEFAULT_NETWORK_BROKER_URL, new ActiveMQConnectionFactoryFactory(
|
||||
this.properties).determineBrokerUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getExplicitBrokerUrlAlwaysWins() {
|
||||
this.properties.setBrokerUrl("vm://foo-bar");
|
||||
this.properties.setInMemory(false);
|
||||
assertEquals("vm://foo-bar", this.properties.determineBrokerUrl());
|
||||
assertEquals("vm://foo-bar",
|
||||
new ActiveMQConnectionFactoryFactory(this.properties)
|
||||
.determineBrokerUrl());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,11 +43,13 @@ import org.junit.Test;
|
|||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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;
|
||||
|
@ -183,10 +185,8 @@ public class HornetQAutoConfigurationTests {
|
|||
|
||||
@Test
|
||||
public void embeddedServiceWithCustomJmsConfiguration() {
|
||||
load(CustomJmsConfiguration.class, "spring.hornetq.embedded.queues=Queue1,Queue2"); // Ignored
|
||||
// with
|
||||
// custom
|
||||
// config
|
||||
// Ignored with custom config
|
||||
load(CustomJmsConfiguration.class, "spring.hornetq.embedded.queues=Queue1,Queue2");
|
||||
DestinationChecker checker = new DestinationChecker(this.context);
|
||||
checker.checkQueue("custom", true); // See CustomJmsConfiguration
|
||||
|
||||
|
@ -317,7 +317,7 @@ public class HornetQAutoConfigurationTests {
|
|||
String... environment) {
|
||||
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
||||
applicationContext.register(config);
|
||||
applicationContext.register(HornetQAutoConfiguration.class,
|
||||
applicationContext.register(HornetQAutoConfigurationWithoutXA.class,
|
||||
JmsAutoConfiguration.class);
|
||||
EnvironmentTestUtils.addEnvironment(applicationContext, environment);
|
||||
applicationContext.refresh();
|
||||
|
@ -417,4 +417,11 @@ public class HornetQAutoConfigurationTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(HornetQProperties.class)
|
||||
@Import({ HornetQEmbeddedServerConfiguration.class,
|
||||
HornetQConnectionFactoryConfiguration.class })
|
||||
protected static class HornetQAutoConfigurationWithoutXA {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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.jta;
|
||||
|
||||
import javax.transaction.TransactionManager;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.jta.XAConnectionFactoryWrapper;
|
||||
import org.springframework.boot.jta.XADataSourceWrapper;
|
||||
import org.springframework.boot.jta.atomikos.AtomikosDependsOnBeanFactoryPostProcessor;
|
||||
import org.springframework.boot.jta.atomikos.AtomikosProperties;
|
||||
import org.springframework.boot.jta.bitronix.BitronixDependentBeanFactoryPostProcessor;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.jta.JtaTransactionManager;
|
||||
|
||||
import com.atomikos.icatch.config.UserTransactionService;
|
||||
import com.atomikos.icatch.jta.UserTransactionManager;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link JtaAutoConfiguration}.
|
||||
*
|
||||
* @author Josh Long
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class JtaAutoConfigurationTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
@After
|
||||
public void closeContext() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customPatformTransactionManager() throws Exception {
|
||||
this.context = new AnnotationConfigApplicationContext(
|
||||
CustomTransactionManagerConfig.class, JtaAutoConfiguration.class);
|
||||
this.thrown.expect(NoSuchBeanDefinitionException.class);
|
||||
this.context.getBean(JtaTransactionManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void atomikosSanityCheck() throws Exception {
|
||||
this.context = new AnnotationConfigApplicationContext(JtaProperties.class,
|
||||
AtomikosJtaConfiguration.class);
|
||||
this.context.getBean(AtomikosProperties.class);
|
||||
this.context.getBean(UserTransactionService.class);
|
||||
this.context.getBean(UserTransactionManager.class);
|
||||
this.context.getBean(UserTransaction.class);
|
||||
this.context.getBean(XADataSourceWrapper.class);
|
||||
this.context.getBean(XAConnectionFactoryWrapper.class);
|
||||
this.context.getBean(AtomikosDependsOnBeanFactoryPostProcessor.class);
|
||||
this.context.getBean(JtaTransactionManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bitronixSanityCheck() throws Exception {
|
||||
this.context = new AnnotationConfigApplicationContext(JtaProperties.class,
|
||||
BitronixJtaConfiguration.class);
|
||||
this.context.getBean(bitronix.tm.Configuration.class);
|
||||
this.context.getBean(TransactionManager.class);
|
||||
this.context.getBean(XADataSourceWrapper.class);
|
||||
this.context.getBean(XAConnectionFactoryWrapper.class);
|
||||
this.context.getBean(BitronixDependentBeanFactoryPostProcessor.class);
|
||||
this.context.getBean(JtaTransactionManager.class);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class CustomTransactionManagerConfig {
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager transactionManager() {
|
||||
return mock(PlatformTransactionManager.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -17,11 +17,12 @@
|
|||
package org.springframework.boot.autoconfigure.orm.jpa;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform;
|
||||
import org.junit.After;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
@ -228,8 +229,10 @@ public abstract class AbstractJpaAutoConfigurationTests {
|
|||
factoryBean.setJpaVendorAdapter(adapter);
|
||||
factoryBean.setDataSource(dataSource);
|
||||
factoryBean.setPersistenceUnitName("manually-configured");
|
||||
factoryBean.setJpaPropertyMap(Collections.singletonMap("configured",
|
||||
"manually"));
|
||||
Map<String, Object> properties = new HashMap<String, Object>();
|
||||
properties.put("configured", "manually");
|
||||
properties.put("hibernate.transaction.jta.platform", NoJtaPlatform.INSTANCE);
|
||||
factoryBean.setJpaPropertyMap(properties);
|
||||
return factoryBean;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,8 @@
|
|||
<!-- Third Party -->
|
||||
<activemq.version>5.9.1</activemq.version>
|
||||
<aspectj.version>1.8.2</aspectj.version>
|
||||
<atomikos.version>3.9.3</atomikos.version>
|
||||
<bitronix.version>2.1.4</bitronix.version>
|
||||
<codahale-metrics.version>3.0.2</codahale-metrics.version>
|
||||
<commons-beanutils.version>1.9.2</commons-beanutils.version>
|
||||
<commons-collections.version>3.2.1</commons-collections.version>
|
||||
|
@ -85,6 +87,7 @@
|
|||
<jolokia.version>1.2.2</jolokia.version>
|
||||
<json-path.version>0.9.1</json-path.version>
|
||||
<jstl.version>1.2</jstl.version>
|
||||
<jta.version>1.1</jta.version>
|
||||
<junit.version>4.11</junit.version>
|
||||
<liquibase.version>3.0.8</liquibase.version>
|
||||
<log4j.version>1.2.17</log4j.version>
|
||||
|
@ -257,6 +260,21 @@
|
|||
<artifactId>spring-boot-starter-jetty</artifactId>
|
||||
<version>1.2.0.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
|
||||
<version>1.2.0.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jta-bitronix</artifactId>
|
||||
<version>1.2.0.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jta-arjuna</artifactId>
|
||||
<version>1.2.0.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-log4j</artifactId>
|
||||
|
@ -350,6 +368,21 @@
|
|||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.atomikos</groupId>
|
||||
<artifactId>transactions-jdbc</artifactId>
|
||||
<version>${atomikos.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.atomikos</groupId>
|
||||
<artifactId>transactions-jms</artifactId>
|
||||
<version>${atomikos.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.atomikos</groupId>
|
||||
<artifactId>transactions-jta</artifactId>
|
||||
<version>${atomikos.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.codahale.metrics</groupId>
|
||||
<artifactId>metrics-graphite</artifactId>
|
||||
|
@ -370,6 +403,11 @@
|
|||
<artifactId>metrics-servlets</artifactId>
|
||||
<version>${codahale-metrics.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.btm</groupId>
|
||||
<artifactId>btm</artifactId>
|
||||
<version>${bitronix.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.janino</groupId>
|
||||
<artifactId>janino</artifactId>
|
||||
|
@ -482,6 +520,11 @@
|
|||
<artifactId>jstl</artifactId>
|
||||
<version>${jstl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.transaction</groupId>
|
||||
<artifactId>jta</artifactId>
|
||||
<version>${jta.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jaxen</groupId>
|
||||
<artifactId>jaxen</artifactId>
|
||||
|
|
|
@ -205,6 +205,10 @@ content into your application; rather pick only the properties that you need.
|
|||
spring.jpa.hibernate.ddl-auto= # defaults to create-drop for embedded dbs
|
||||
spring.data.jpa.repositories.enabled=true # if spring data repository support is enabled
|
||||
|
||||
# JTA ({sc-spring-boot-autoconfigure}/jta/JtaAutoConfiguration.{sc-ext}[JtaAutoConfiguration])
|
||||
spring.jta.log-dir= # transaction log dir
|
||||
spring.jta.*= # technology specific configuration
|
||||
|
||||
# SOLR ({sc-spring-boot-autoconfigure}/solr/SolrProperties.{sc-ext}[SolrProperties}])
|
||||
spring.data.solr.host=http://127.0.0.1:8983/solr
|
||||
spring.data.solr.zkHost=
|
||||
|
|
|
@ -1874,6 +1874,83 @@ own beans:
|
|||
|
||||
|
||||
|
||||
[[boot-features-jta]]
|
||||
== Distributed Transactions with JTA
|
||||
Spring Boot supports distributed JTA transactions across multiple XA resources using
|
||||
either an http://www.atomikos.com/[Atomkos] or
|
||||
http://docs.codehaus.org/display/BTM/Home[Bitronix] embedded transaction manager. JTA
|
||||
transactions are also supported when deploying to a suitable Java EE Application Server.
|
||||
|
||||
When a JTA environment is detected, Spring's `JtaTransactionManager` will be used to manage
|
||||
transactions. Auto-configured JMS, DataSource and JPA beans will be upgraded to support
|
||||
XA transactions. You can use standard Spring idioms such as `@Transactional` to
|
||||
participate in a distributed transaction.
|
||||
|
||||
|
||||
|
||||
=== Using an Atomikos transaction manager
|
||||
Atomikos is a popular open source transaction manager which can be embedded into your
|
||||
Spring Boot application. You can use the `spring-boot-starter-jta-atomikos` Starter POM to
|
||||
pull in the appropriate Atomikos libraries. Spring Boot will auto-configure Atomikos and
|
||||
ensure that appropriate `depends-on` settings are applied to your Spring Beans for correct
|
||||
startup and shutdown ordering.
|
||||
|
||||
By default Atomikos transaction logs will be written to a `transaction-logs` folder in
|
||||
your application home directory (the directory in which your application jar file
|
||||
resides). You can customize this directory by setting a `spring.jta.log-dir` property in
|
||||
your `application.properties` file. Properties starting `spring.jta.` can also be used to
|
||||
customize the Atomikos `UserTransactionServiceIml`. See the
|
||||
{dc-spring-boot}/jta/atomikos/AtomikosProperties.{dc-ext}[`AtomikosProperties` javadoc]
|
||||
for complete details.
|
||||
|
||||
|
||||
|
||||
=== Using a Bitronix transaction manager
|
||||
Bitronix is another popular open source JTA transaction manager implementation. You can
|
||||
use the `spring-boot-starter-jta-bitronix` starter POM to add the appropriate Birtronix
|
||||
dependencies to your project. As with Atomikos, Spring Boot will automatically configure
|
||||
Bitronix and post-process your beans to ensure that startup and shutdown ordering is
|
||||
correct.
|
||||
|
||||
By default Bitronix transaction log files (`part1.btm` and `part2.btm`) will be written to
|
||||
a `transaction-logs` folder in your application home directory. You can customize this
|
||||
directory by using the `spring.jta.log-dir` property. Properties starting `spring.jta.`
|
||||
are also bound to the `bitronix.tm.Configuration` bean, allowing for complete
|
||||
customization. See the http://btm.codehaus.org/api/2.0.1/bitronix/tm/Configuration.html[Bitronix
|
||||
documentation] for details.
|
||||
|
||||
|
||||
|
||||
=== Using a Java EE managed transaction manager
|
||||
If you are packaging your Spring Boot application as a `war` or `ear` file and deploying
|
||||
it to a Java EE application server, you can use your application servers built-in
|
||||
transaction manager. Spring Boot will attempt to auto-configure a transaction manager by
|
||||
looking at common JNDI locations (`java:comp/UserTransaction`,
|
||||
`java:comp/TransactionManager` etc). If you are using a transaction service provided by
|
||||
your application server, you will generally also want to ensure that all resources are
|
||||
managed by the server and exposed over JNDI. Spring Boot will attempt to auto-configure
|
||||
JMS by looking for a `ConnectionFactory` at the JNDI path `java:/JmsXA` and you can use
|
||||
the <<boot-features-connecting-to-a-jndi-datasource, `spring.datasource.jndi-name` property>>
|
||||
to configure your `DataSource`.
|
||||
|
||||
|
||||
|
||||
=== Supporting an alternative embedded transaction manager
|
||||
The {sc-spring-boot}/jta/XAConnectionFactoryWrapper.{sc-ext}[`XAConnectionFactoryWrapper`]
|
||||
and {sc-spring-boot}/jta/XADataSourceWrapper.{sc-ext}[`XADataSourceWrapper`] interfaces
|
||||
can be used to support alternative embedded transaction managers. The interfaces are
|
||||
responsible for wrapping `XAConnectionFactory` and `XADataSource` beans and exposing them
|
||||
as regular `ConnectionFactory` and `DataSource` beans which will transparently enroll in
|
||||
the distributed transaction. DataSource and JMS auto-configuration will use JTA variants
|
||||
as long as you have a `JtaTransactionManager` bean and appropriate XA wrapper beans
|
||||
registered within your `ApplicationContext`
|
||||
|
||||
The {sc-spring-boot}/jta/BitronixXAConnectionFactoryWrapper.{sc-ext}[BitronixXAConnectionFactoryWrapper]
|
||||
and {sc-spring-boot}/jta/BitronixXADataSourceWrapper.{sc-ext}[BitronixXADataSourceWrapper]
|
||||
provide good examples of how to write XA wrappers.
|
||||
|
||||
|
||||
|
||||
[[boot-features-integration]]
|
||||
== Spring Integration
|
||||
Spring Integration provides abstractions over messaging and also other transports such as
|
||||
|
|
|
@ -255,6 +255,12 @@ and Hibernate.
|
|||
|`spring-boot-starter-jdbc`
|
||||
|JDBC Database support.
|
||||
|
||||
|`spring-boot-starter-jta-atomikos`
|
||||
|Support for JTA distributed transactions via Atomikos.
|
||||
|
||||
|`spring-boot-starter-jta-bitronix`
|
||||
|Support for JTA distributed transactions via Bitronix.
|
||||
|
||||
|`spring-boot-starter-mobile`
|
||||
|Support for `spring-mobile`
|
||||
|
||||
|
|
|
@ -38,6 +38,9 @@
|
|||
<module>spring-boot-sample-hornetq</module>
|
||||
<module>spring-boot-sample-integration</module>
|
||||
<module>spring-boot-sample-jetty</module>
|
||||
<module>spring-boot-sample-jta-atomikos</module>
|
||||
<module>spring-boot-sample-jta-bitronix</module>
|
||||
<module>spring-boot-sample-jta-jndi</module>
|
||||
<module>spring-boot-sample-liquibase</module>
|
||||
<module>spring-boot-sample-parent-context</module>
|
||||
<module>spring-boot-sample-profile</module>
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<!-- Your own application should inherit from spring-boot-starter-parent -->
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-samples</artifactId>
|
||||
<version>1.2.0.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-sample-jta-atomikos</artifactId>
|
||||
<name>Spring Boot Atomikos JTA Sample</name>
|
||||
<description>Spring Boot Atomikos JTA Sample</description>
|
||||
<url>http://projects.spring.io/spring-boot/</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>http://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jms</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-hornetq</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hornetq</groupId>
|
||||
<artifactId>hornetq-jms-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 sample.atomikos;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Account {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String username;
|
||||
|
||||
Account() {
|
||||
}
|
||||
|
||||
public Account(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 sample.atomikos;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface AccountRepository extends JpaRepository<Account, Long> {
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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 sample.atomikos;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jms.core.JmsTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class AccountService {
|
||||
|
||||
private final JmsTemplate jmsTemplate;
|
||||
|
||||
private final AccountRepository accountRepository;
|
||||
|
||||
@Autowired
|
||||
public AccountService(JmsTemplate jmsTemplate, AccountRepository accountRepository) {
|
||||
this.jmsTemplate = jmsTemplate;
|
||||
this.accountRepository = accountRepository;
|
||||
}
|
||||
|
||||
public void createAccountAndNotify(String username) {
|
||||
this.jmsTemplate.convertAndSend("accounts", username);
|
||||
this.accountRepository.save(new Account(username));
|
||||
if ("error".equals(username)) {
|
||||
throw new RuntimeException("Simulated error");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 sample.atomikos;
|
||||
|
||||
import org.springframework.jms.annotation.JmsListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class Messages {
|
||||
|
||||
@JmsListener(destination = "accounts")
|
||||
public void onMessage(String content) {
|
||||
System.out.println("----> " + content);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 sample.atomikos;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@EnableAutoConfiguration
|
||||
public class SampleAtomikosApplication {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ApplicationContext context = SpringApplication.run(
|
||||
SampleAtomikosApplication.class, args);
|
||||
AccountService service = context.getBean(AccountService.class);
|
||||
AccountRepository repository = context.getBean(AccountRepository.class);
|
||||
service.createAccountAndNotify("josh");
|
||||
System.out.println("Count is " + repository.count());
|
||||
try {
|
||||
service.createAccountAndNotify("error");
|
||||
}
|
||||
catch (Exception ex) {
|
||||
System.out.println(ex.getMessage());
|
||||
}
|
||||
System.out.println("Count is " + repository.count());
|
||||
Thread.sleep(100);
|
||||
((Closeable) context).close();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
spring.hornetq.mode=embedded
|
||||
spring.hornetq.embedded.enabled=true
|
||||
spring.hornetq.embedded.queues=accounts
|
||||
|
||||
logging.level.com.atomikos=WARN
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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 sample.atomikos;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.hamcrest.core.SubstringMatcher;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.test.OutputCapture;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Basic integration tests for demo application.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class SampleAtomikosApplicationTests {
|
||||
|
||||
@Rule
|
||||
public OutputCapture outputCapture = new OutputCapture();
|
||||
|
||||
@Test
|
||||
public void testTransactionRollback() throws Exception {
|
||||
SampleAtomikosApplication.main(new String[] {});
|
||||
String expected = "";
|
||||
expected += "----> josh\n";
|
||||
expected += "Count is 1\n";
|
||||
expected += "Simulated error\n";
|
||||
expected += "Count is 1\n";
|
||||
assertThat(this.outputCapture.toString(), containsString(expected));
|
||||
assertThat(this.outputCapture.toString(), containsStringOnce("---->"));
|
||||
}
|
||||
|
||||
private Matcher<? super String> containsStringOnce(String s) {
|
||||
return new SubstringMatcher(s) {
|
||||
|
||||
@Override
|
||||
protected String relationship() {
|
||||
return "containing once";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean evalSubstringOf(String s) {
|
||||
int i = 0;
|
||||
while (s.contains(this.substring)) {
|
||||
s = s.substring(s.indexOf(this.substring) + this.substring.length());
|
||||
i++;
|
||||
}
|
||||
return i == 1;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<!-- Your own application should inherit from spring-boot-starter-parent -->
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-samples</artifactId>
|
||||
<version>1.2.0.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-sample-jta-bitronix</artifactId>
|
||||
<name>Spring Boot Bitronix JTA Sample</name>
|
||||
<description>Spring Boot Bitronix JTA Sample</description>
|
||||
<url>http://projects.spring.io/spring-boot/</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>http://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jms</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jta-bitronix</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-hornetq</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hornetq</groupId>
|
||||
<artifactId>hornetq-jms-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 sample.bitronix;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Account {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String username;
|
||||
|
||||
Account() {
|
||||
}
|
||||
|
||||
public Account(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 sample.bitronix;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface AccountRepository extends JpaRepository<Account, Long> {
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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 sample.bitronix;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jms.core.JmsTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class AccountService {
|
||||
|
||||
private final JmsTemplate jmsTemplate;
|
||||
|
||||
private final AccountRepository accountRepository;
|
||||
|
||||
@Autowired
|
||||
public AccountService(JmsTemplate jmsTemplate, AccountRepository accountRepository) {
|
||||
this.jmsTemplate = jmsTemplate;
|
||||
this.accountRepository = accountRepository;
|
||||
}
|
||||
|
||||
public void createAccountAndNotify(String username) {
|
||||
this.jmsTemplate.convertAndSend("accounts", username);
|
||||
this.accountRepository.save(new Account(username));
|
||||
if ("error".equals(username)) {
|
||||
throw new RuntimeException("Simulated error");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 sample.bitronix;
|
||||
|
||||
import org.springframework.jms.annotation.JmsListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class Messages {
|
||||
|
||||
@JmsListener(destination = "accounts")
|
||||
public void onMessage(String content) {
|
||||
System.out.println("----> " + content);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 sample.bitronix;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@EnableAutoConfiguration
|
||||
public class SampleBitronixApplication {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ApplicationContext context = SpringApplication.run(
|
||||
SampleBitronixApplication.class, args);
|
||||
AccountService service = context.getBean(AccountService.class);
|
||||
AccountRepository repository = context.getBean(AccountRepository.class);
|
||||
service.createAccountAndNotify("josh");
|
||||
System.out.println("Count is " + repository.count());
|
||||
try {
|
||||
service.createAccountAndNotify("error");
|
||||
}
|
||||
catch (Exception ex) {
|
||||
System.out.println(ex.getMessage());
|
||||
}
|
||||
System.out.println("Count is " + repository.count());
|
||||
Thread.sleep(100);
|
||||
((Closeable) context).close();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
spring.hornetq.mode=embedded
|
||||
spring.hornetq.embedded.enabled=true
|
||||
spring.hornetq.embedded.queues=accounts
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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 sample.bitronix;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.hamcrest.core.SubstringMatcher;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.test.OutputCapture;
|
||||
|
||||
import sample.bitronix.SampleBitronixApplication;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Basic integration tests for demo application.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class SampleBitronixApplicationTests {
|
||||
|
||||
@Rule
|
||||
public OutputCapture outputCapture = new OutputCapture();
|
||||
|
||||
@Test
|
||||
public void testTransactionRollback() throws Exception {
|
||||
SampleBitronixApplication.main(new String[] {});
|
||||
String expected = "";
|
||||
expected += "----> josh\n";
|
||||
expected += "Count is 1\n";
|
||||
expected += "Simulated error\n";
|
||||
expected += "Count is 1\n";
|
||||
assertThat(this.outputCapture.toString(), containsString(expected));
|
||||
assertThat(this.outputCapture.toString(), containsStringOnce("---->"));
|
||||
}
|
||||
|
||||
private Matcher<? super String> containsStringOnce(String s) {
|
||||
return new SubstringMatcher(s) {
|
||||
|
||||
@Override
|
||||
protected String relationship() {
|
||||
return "containing once";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean evalSubstringOf(String s) {
|
||||
int i = 0;
|
||||
while (s.contains(this.substring)) {
|
||||
s = s.substring(s.indexOf(this.substring) + this.substring.length());
|
||||
i++;
|
||||
}
|
||||
return i == 1;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
## Introduction
|
||||
|
||||
This application is intended to run inside of a Java EE application server such as
|
||||
JBoss Wildfly. It demonstrates Spring Boot's auto-configuration defaulting for a
|
||||
container-managed `TransactionManager` and `DataSource`. This example unfortunately
|
||||
requires a fully configured Wildfly installation. You'll need to configure a PostgreSQL
|
||||
XA `DataSource` and an XA `ConnectionFactory` in the Java EE application server's
|
||||
JNDI machinery.
|
||||
|
||||
## Setup
|
||||
|
||||
### Postgres
|
||||
We will use postgres as the underlying database, v9.3.5 or above is recommend. Follow
|
||||
the installation instructions from http://www.postgresql.org/[postgresql.org] or use
|
||||
a package manager to install the appropriate binaries.
|
||||
|
||||
Once installed you will need to initialize and start the server.
|
||||
|
||||
[source,indent=0]
|
||||
----
|
||||
$ initdb /usr/local/var/postgres -E utf8
|
||||
$ pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start
|
||||
----
|
||||
|
||||
With the server running you can create a user and a database:
|
||||
|
||||
[source,indent=0]
|
||||
----
|
||||
$ createuser springboot
|
||||
$ createdb bootdemo
|
||||
----
|
||||
|
||||
Finally you can type `psql bootdemo` to configure a password:
|
||||
|
||||
[source,indent=0]
|
||||
----
|
||||
ALTER USER springboot WITH PASSWORD 'springboot';
|
||||
\q
|
||||
----
|
||||
|
||||
|
||||
### WildFly 8.1
|
||||
Download an install WildFly 8.1 from http://wildfly.org/downloads/[wildfly.org]. Once
|
||||
installed you will need to add a management user by running `$JBOSS_HOME/bin/add-user.sh`
|
||||
(see the WildFly documentation for details).
|
||||
|
||||
You will also need to add a postgresql module. The following commands setup the basic
|
||||
structure:
|
||||
|
||||
[source,indent=0]
|
||||
----
|
||||
$ cd $JBOSS_HOME
|
||||
mkdir -p modules/org/postgresql/main
|
||||
wget http://jdbc.postgresql.org/download/postgresql-9.3-1102.jdbc41.jar
|
||||
mv postgresql-9.3-1102.jdbc41.jar modules/org/postgresql/main
|
||||
----
|
||||
|
||||
You can then add the following to `$JBOSS_HOME/modules/org/postgresql/main/module.xml`:
|
||||
|
||||
[source,indent=0]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module xmlns="urn:jboss:module:1.0" name="org.postgresql">
|
||||
<resources>
|
||||
<resource-root path="postgresql-9.3-1102.jdbc41.jar"/>
|
||||
</resources>
|
||||
<dependencies>
|
||||
<module name="javax.api"/>
|
||||
<module name="javax.transaction.api"/>
|
||||
</dependencies>
|
||||
</module>
|
||||
----
|
||||
|
||||
## Configuration
|
||||
A custom WildFly configuration is required for the XA `DataSource` and `ConnectionFactory`
|
||||
elements. The `$JBOSS_HOME/standalone/configuration/standalone-full.xml` is a good
|
||||
starting point, copy this file to
|
||||
`$JBOSS_HOME/standalone/configuration/standalone-boot-demo.xml` then make the following
|
||||
changes.
|
||||
|
||||
### DataSource
|
||||
You need to register a PostgreSQL XA `Driver` and then configure an `xa-datasource`.
|
||||
|
||||
Here's a complete listing of the `xa-datasource` contribution to the `datasources`
|
||||
element, and the `driver` contribution to the `drivers` element to configure a PostgreSQL
|
||||
DB connection to localhost.
|
||||
https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6/html-single/Administration_and_Configuration_Guide/index.html#Install_a_JDBC_Driver_with_the_Management_Console[You can learn more from the documentation].
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,attributes"]
|
||||
----
|
||||
<datasources>
|
||||
...
|
||||
<xa-datasource
|
||||
jndi-name="java:jboss/datasources/bootdemo"
|
||||
pool-name="CrmXADS"
|
||||
enabled="true">
|
||||
<xa-datasource-property name="url">jdbc:postgresql://localhost:5432/crm</xa-datasource-property>
|
||||
<driver>postgres</driver>
|
||||
<xa-pool>
|
||||
<min-pool-size>10</min-pool-size>
|
||||
<max-pool-size>20</max-pool-size>
|
||||
<prefill>true</prefill>
|
||||
</xa-pool>
|
||||
<security>
|
||||
<user-name>springboot</user-name>
|
||||
<password>springboot</password>
|
||||
</security>
|
||||
</xa-datasource>
|
||||
<drivers>
|
||||
...
|
||||
<driver name="postgres" module="org.postgresql">
|
||||
<xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
|
||||
</driver>
|
||||
</drivers>
|
||||
</datasources>
|
||||
----
|
||||
|
||||
### JMS Destination
|
||||
You will also need to configure a `javax.jms.Destination` by contributing the following to
|
||||
the `hornetq-server` element:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,attributes"]
|
||||
----
|
||||
<jms-destinations>
|
||||
<jms-queue name="accounts">
|
||||
<entry name="java:/jms/queue/bootdemo"/>
|
||||
</jms-queue>
|
||||
...
|
||||
</jms-destinations>
|
||||
----
|
||||
|
||||
|
||||
## Running and deploying the sample
|
||||
Run Wildfly with the following command:
|
||||
|
||||
[source,indent=0]
|
||||
----
|
||||
$JBOSS_HOME/bin/standalone.sh -c standalone-boot-demo.xml
|
||||
----
|
||||
|
||||
Once running you can deploy the application by copying
|
||||
`target/spring-boot-sample-jta-jndi.war` to `$JBOSS_HOME/standalone/deployments`.
|
||||
|
||||
Open a browser to http://localhost:8080/spring-boot-sample-jta-jndi to trigger the
|
||||
sample. You should see the current count (it will increment by one on each refresh). If
|
||||
you check the logs you should see a `----> Josh` message and some counts. Notice how the
|
||||
`error` message triggers an exception with causes both the database insert and the JMS
|
||||
message to be rolled back.
|
|
@ -0,0 +1,61 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<!-- Your own application should inherit from spring-boot-starter-parent -->
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-samples</artifactId>
|
||||
<version>1.2.0.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-sample-jta-jndi</artifactId>
|
||||
<name>Spring Boot JNDI JTA Sample</name>
|
||||
<packaging>war</packaging>
|
||||
<description>Spring Boot JNDI JTA Sample</description>
|
||||
<url>http://projects.spring.io/spring-boot/</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>http://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jms</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.jms</groupId>
|
||||
<artifactId>jms-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<finalName>spring-boot-sample-jta-jndi</finalName>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 sample.jndi;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Account {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String username;
|
||||
|
||||
Account() {
|
||||
}
|
||||
|
||||
public Account(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 sample.jndi;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface AccountRepository extends CrudRepository<Account, Long> {
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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 sample.jndi;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jms.core.JmsTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class AccountService {
|
||||
|
||||
private final JmsTemplate jmsTemplate;
|
||||
|
||||
private final AccountRepository accountRepository;
|
||||
|
||||
@Autowired
|
||||
public AccountService(JmsTemplate jmsTemplate, AccountRepository accountRepository) {
|
||||
this.jmsTemplate = jmsTemplate;
|
||||
this.accountRepository = accountRepository;
|
||||
}
|
||||
|
||||
public void createAccountAndNotify(String username) {
|
||||
this.jmsTemplate.convertAndSend("java:/jms/queue/bootdemo", username);
|
||||
Account entity = new Account(username);
|
||||
this.accountRepository.save(entity);
|
||||
if ("error".equals(username)) {
|
||||
throw new RuntimeException("Simulated error");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 sample.jndi;
|
||||
|
||||
import org.springframework.jms.annotation.JmsListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class Messages {
|
||||
|
||||
@JmsListener(destination = "java:/jms/queue/bootdemo")
|
||||
public void onMessage(String content) {
|
||||
System.out.println("----> " + content);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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 sample.jndi;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan
|
||||
public class SampleJndiApplication {
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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 sample.jndi;
|
||||
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.context.web.SpringBootServletInitializer;
|
||||
|
||||
public class SampleJndiInitializer extends SpringBootServletInitializer {
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||
return application.sources(SampleJndiApplication.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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 sample.jndi;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class WebController {
|
||||
|
||||
private final AccountService service;
|
||||
|
||||
private final AccountRepository repository;
|
||||
|
||||
@Autowired
|
||||
public WebController(AccountService service, AccountRepository repository) {
|
||||
this.service = service;
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@RequestMapping("/")
|
||||
public String hello() {
|
||||
System.out.println("Count is " + this.repository.count());
|
||||
this.service.createAccountAndNotify("josh");
|
||||
try {
|
||||
this.service.createAccountAndNotify("error");
|
||||
}
|
||||
catch (Exception ex) {
|
||||
System.out.println(ex.getMessage());
|
||||
}
|
||||
long count = this.repository.count();
|
||||
System.out.println("Count is " + count);
|
||||
return "Count is " + count;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
spring.jpa.generate-ddl=true
|
||||
spring.datasource.jndi-name=java:jboss/datasources/bootdemo
|
||||
|
||||
# Workaround SPR-12118
|
||||
spring.jpa.open-in-view=false
|
|
@ -36,6 +36,8 @@
|
|||
<module>spring-boot-starter-integration</module>
|
||||
<module>spring-boot-starter-jdbc</module>
|
||||
<module>spring-boot-starter-jetty</module>
|
||||
<module>spring-boot-starter-jta-atomikos</module>
|
||||
<module>spring-boot-starter-jta-bitronix</module>
|
||||
<module>spring-boot-starter-logging</module>
|
||||
<module>spring-boot-starter-log4j</module>
|
||||
<module>spring-boot-starter-mobile</module>
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starters</artifactId>
|
||||
<version>1.2.0.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
|
||||
<name>Spring Boot Atomikos JTA Starter</name>
|
||||
<description>Spring Boot Atomikos JTA Starter</description>
|
||||
<url>http://projects.spring.io/spring-boot/</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>http://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.atomikos</groupId>
|
||||
<artifactId>transactions-jms</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.atomikos</groupId>
|
||||
<artifactId>transactions-jta</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.atomikos</groupId>
|
||||
<artifactId>transactions-jdbc</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starters</artifactId>
|
||||
<version>1.2.0.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-starter-jta-bitronix</artifactId>
|
||||
<name>Spring Boot Bitronix JTA Starter</name>
|
||||
<description>Spring Boot Bitronix JTA Starter</description>
|
||||
<url>http://projects.spring.io/spring-boot/</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>http://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>javax.jms</groupId>
|
||||
<artifactId>jms-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.transaction</groupId>
|
||||
<artifactId>jta</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.btm</groupId>
|
||||
<artifactId>btm</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -34,11 +34,31 @@
|
|||
<artifactId>logback-classic</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.atomikos</groupId>
|
||||
<artifactId>transactions-jms</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.atomikos</groupId>
|
||||
<artifactId>transactions-jta</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.atomikos</groupId>
|
||||
<artifactId>transactions-jdbc</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.jms</groupId>
|
||||
<artifactId>jms-api</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
|
@ -69,6 +89,11 @@
|
|||
<artifactId>tomcat-embed-jasper</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.btm</groupId>
|
||||
<artifactId>btm</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy</artifactId>
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.jta;
|
||||
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.jms.XAConnectionFactory;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
/**
|
||||
* Strategy interface used to wrap a JMS {@link XAConnectionFactory} enrolling it with a
|
||||
* JTA {@link TransactionManager}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public interface XAConnectionFactoryWrapper {
|
||||
|
||||
/**
|
||||
* Wrap the specific {@link XAConnectionFactory} and enroll it with a JTA
|
||||
* {@link TransactionManager}.
|
||||
* @param connectionFactory the connection factory to wrap
|
||||
* @return the wrapped connection factory
|
||||
*/
|
||||
ConnectionFactory wrapConnectionFactory(XAConnectionFactory connectionFactory)
|
||||
throws Exception;
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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.jta;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import javax.sql.XADataSource;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
/**
|
||||
* Strategy interface used to wrap a JMS {@link XADataSource} enrolling it with a JTA
|
||||
* {@link TransactionManager}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public interface XADataSourceWrapper {
|
||||
|
||||
/**
|
||||
* Wrap the specific {@link XADataSource} and enroll it with a JTA
|
||||
* {@link TransactionManager}.
|
||||
* @param dataSource the data source to wrap
|
||||
* @return the wrapped data source
|
||||
*/
|
||||
DataSource wrapDataSource(XADataSource dataSource) throws Exception;
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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.jta.atomikos;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Spring friendly version of {@link com.atomikos.jms.AtomikosConnectionFactoryBean}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class AtomikosConnectionFactoryBean extends
|
||||
com.atomikos.jms.AtomikosConnectionFactoryBean implements BeanNameAware,
|
||||
InitializingBean, DisposableBean {
|
||||
|
||||
private String beanName;
|
||||
|
||||
@Override
|
||||
public void setBeanName(String name) {
|
||||
this.beanName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (!StringUtils.hasLength(getUniqueResourceName())) {
|
||||
setUniqueResourceName(this.beanName);
|
||||
}
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
close();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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.jta.atomikos;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Spring friendly version of {@link com.atomikos.jdbc.AtomikosDataSourceBean}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class AtomikosDataSourceBean extends com.atomikos.jdbc.AtomikosDataSourceBean
|
||||
implements BeanNameAware, InitializingBean, DisposableBean {
|
||||
|
||||
private String beanName;
|
||||
|
||||
@Override
|
||||
public void setBeanName(String name) {
|
||||
this.beanName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (!StringUtils.hasLength(getUniqueResourceName())) {
|
||||
setUniqueResourceName(this.beanName);
|
||||
}
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
close();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* 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.jta.atomikos;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
import com.atomikos.icatch.jta.UserTransactionManager;
|
||||
|
||||
/**
|
||||
* {@link BeanFactoryPostProcessor} to automatically setup the recommended
|
||||
* {@link BeanDefinition#setDependsOn(String[]) dependsOn} settings for <a
|
||||
* href="http://www.atomikos.com/Documentation/SpringIntegration">correct Atomikos
|
||||
* ordering</a>.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class AtomikosDependsOnBeanFactoryPostProcessor implements
|
||||
BeanFactoryPostProcessor, Ordered {
|
||||
|
||||
private static final String[] NO_BEANS = {};
|
||||
|
||||
private int order = Ordered.LOWEST_PRECEDENCE;
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
|
||||
throws BeansException {
|
||||
String[] transactionManagers = beanFactory.getBeanNamesForType(
|
||||
UserTransactionManager.class, true, false);
|
||||
for (String transactionManager : transactionManagers) {
|
||||
addTransactionManagerDependencies(beanFactory, transactionManager);
|
||||
}
|
||||
addMessageDrivenContainerDependencies(beanFactory, transactionManagers);
|
||||
}
|
||||
|
||||
private void addTransactionManagerDependencies(
|
||||
ConfigurableListableBeanFactory beanFactory, String transactionManager) {
|
||||
BeanDefinition bean = beanFactory.getBeanDefinition(transactionManager);
|
||||
Set<String> dependsOn = new LinkedHashSet<String>(asList(bean.getDependsOn()));
|
||||
int initialSize = dependsOn.size();
|
||||
addDependencies(beanFactory, "javax.jms.ConnectionFactory", dependsOn);
|
||||
addDependencies(beanFactory, "javax.sql.DataSource", dependsOn);
|
||||
if (dependsOn.size() != initialSize) {
|
||||
bean.setDependsOn(dependsOn.toArray(new String[dependsOn.size()]));
|
||||
}
|
||||
}
|
||||
|
||||
private void addMessageDrivenContainerDependencies(
|
||||
ConfigurableListableBeanFactory beanFactory, String[] transactionManagers) {
|
||||
String[] messageDrivenContainers = getBeanNamesForType(beanFactory,
|
||||
"com.atomikos.jms.extra.MessageDrivenContainer");
|
||||
for (String messageDrivenContainer : messageDrivenContainers) {
|
||||
BeanDefinition bean = beanFactory.getBeanDefinition(messageDrivenContainer);
|
||||
Set<String> dependsOn = new LinkedHashSet<String>(asList(bean.getDependsOn()));
|
||||
dependsOn.addAll(asList(transactionManagers));
|
||||
bean.setDependsOn(dependsOn.toArray(new String[dependsOn.size()]));
|
||||
}
|
||||
}
|
||||
|
||||
private void addDependencies(ConfigurableListableBeanFactory beanFactory,
|
||||
String type, Set<String> dependsOn) {
|
||||
dependsOn.addAll(asList(getBeanNamesForType(beanFactory, type)));
|
||||
}
|
||||
|
||||
private String[] getBeanNamesForType(ConfigurableListableBeanFactory beanFactory,
|
||||
String type) {
|
||||
try {
|
||||
return beanFactory.getBeanNamesForType(Class.forName(type), true, false);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Ignore
|
||||
}
|
||||
return NO_BEANS;
|
||||
}
|
||||
|
||||
private List<String> asList(String[] array) {
|
||||
return (array == null ? Collections.<String> emptyList() : Arrays.asList(array));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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.jta.atomikos;
|
||||
|
||||
/**
|
||||
* Logging levels supported by Atomikos.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see AtomikosProperties
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public enum AtomikosLoggingLevel {
|
||||
|
||||
/**
|
||||
* Debug Level.
|
||||
*/
|
||||
DEBUG,
|
||||
|
||||
/**
|
||||
* Info Level.
|
||||
*/
|
||||
INFO,
|
||||
|
||||
/**
|
||||
* Warning Level.
|
||||
*/
|
||||
WARN
|
||||
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* 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.jta.atomikos;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Bean friendly variant of <a
|
||||
* href="http://www.atomikos.com/Documentation/JtaProperties">Atomikos configuration
|
||||
* properties</a>. Allows for setter based configuration and is amiable to relaxed data
|
||||
* binding.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see #asProperties()
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class AtomikosProperties {
|
||||
|
||||
private final Map<String, String> values = new TreeMap<String, String>();
|
||||
|
||||
/**
|
||||
* Specifies the transaction manager implementation that should be started. There is
|
||||
* no default value and this must be set. Generally,
|
||||
* {@literal com.atomikos.icatch.standalone.UserTransactionServiceFactory} is the
|
||||
* value you should set.
|
||||
* @param service the service
|
||||
*/
|
||||
public void setService(String service) {
|
||||
set("service", service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the maximum timeout (in milliseconds) that can be allowed for
|
||||
* transactions. Defaults to {@literal 300000}. This means that calls to
|
||||
* UserTransaction.setTransactionTimeout() with a value higher than configured here
|
||||
* will be max'ed to this value.
|
||||
* @param maxTimeout the max timeout
|
||||
*/
|
||||
public void setMaxTimeout(long maxTimeout) {
|
||||
set("max_timeout", maxTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* The default timeout for JTA transactions (optional, defaults to {@literal 10000}
|
||||
* ms).
|
||||
* @param defaultJtaTimeout the default JTA timeout
|
||||
*/
|
||||
public void setDefaultJtaTimeout(long defaultJtaTimeout) {
|
||||
set("default_jta_timeout", defaultJtaTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the maximum number of active transactions. Defaults to {@literal 50}. A
|
||||
* negative value means infinite amount. You will get an {@code IllegalStateException}
|
||||
* with error message "Max number of active transactions reached" if you call
|
||||
* {@code UserTransaction.begin()} while there are already n concurrent transactions
|
||||
* running, n being this value.
|
||||
* @param maxActivities the max activities
|
||||
*/
|
||||
public void setMaxActives(int maxActivities) {
|
||||
set("max_actives", maxActivities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies if disk logging should be enabled or not. Defaults to true. It is useful
|
||||
* for JUnit testing, or to profile code without seeing the transaction manager's
|
||||
* activity as a hot spot but this should never be disabled on production or data
|
||||
* integrity cannot be guaranteed.
|
||||
* @param enableLogging if logging is enabled
|
||||
*/
|
||||
public void setEnableLogging(boolean enableLogging) {
|
||||
set("enable_logging", enableLogging);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the transaction manager's unique name. Defaults to the machine's IP
|
||||
* address. If you plan to run more than one transaction manager against one database
|
||||
* you must set this property to a unique value or you might run into duplicate
|
||||
* transaction ID (XID) problems that can be quite subtle (example:
|
||||
* {@literal http://fogbugz.atomikos.com/default.asp?community.6.2225.7}). If multiple
|
||||
* instances need to use the same properties file then the easiest way to ensure
|
||||
* uniqueness for this property is by referencing a system property specified at VM
|
||||
* startup.
|
||||
* @param uniqueName the unique name
|
||||
*/
|
||||
public void setTransactionManagerUniqueName(String uniqueName) {
|
||||
set("tm_unique_name", uniqueName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies if subtransactions should be joined when possible. Defaults to true. When
|
||||
* false, no attempt to call {@code XAResource.start(TM_JOIN)} will be made for
|
||||
* different but related subtransctions. This setting has no effect on resource access
|
||||
* within one and the same transaction. If you don't use subtransactions then this
|
||||
* setting can be ignored.
|
||||
* @param serialJtaTransactions if serial JTA transaction are supported
|
||||
*/
|
||||
public void setSerialJtaTransactions(boolean serialJtaTransactions) {
|
||||
set("serial_jta_transactions", serialJtaTransactions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies whether VM shutdown should trigger forced shutdown of the transaction
|
||||
* core. Defaults to false.
|
||||
* @param forceShutdownOnVmExit
|
||||
*/
|
||||
public void setForceShutdownOnVmExit(boolean forceShutdownOnVmExit) {
|
||||
set("force_shutdown_on_vm_exit", forceShutdownOnVmExit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the transactions log file base name. Defaults to {@literal tmlog}. The
|
||||
* transactions logs are stored in files using this name appended with a number and
|
||||
* the extension {@literal .log}. At checkpoint, a new transactions log file is
|
||||
* created and the number is incremented.
|
||||
* @param logBaseName the log base name
|
||||
*/
|
||||
public void setLogBaseName(String logBaseName) {
|
||||
set("log_base_name", logBaseName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the directory in which the log files should be stored. Defaults to the
|
||||
* current working directory. This directory should be a stable storage like a SAN,
|
||||
* RAID or at least backed up location. The transactions logs files are as important
|
||||
* as the data themselves to guarantee consistency in case of failures.
|
||||
* @param logBaseDir the log base dir
|
||||
*/
|
||||
public void setLogBaseDir(String logBaseDir) {
|
||||
set("log_base_dir", logBaseDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the interval between checkpoints. A checkpoint reduces the log file size
|
||||
* at the expense of adding some overhead in the runtime. Defaults to {@literal 500}.
|
||||
* @param checkpointInterval the checkpoint interval
|
||||
*/
|
||||
public void setCheckpointInterval(long checkpointInterval) {
|
||||
set("checkpoint_interval", checkpointInterval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the console log level. Defaults to {@link AtomikosLoggingLevel#WARN}.
|
||||
* @param consoleLogLevel the console log level
|
||||
*/
|
||||
public void setConsoleLogLevel(AtomikosLoggingLevel consoleLogLevel) {
|
||||
set("console_log_level", consoleLogLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the directory in which to store the debug log files. Defaults to the
|
||||
* current working directory.
|
||||
* @param outputDir the output dir
|
||||
*/
|
||||
public void setOutputDir(String outputDir) {
|
||||
set("output_dir", outputDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the debug logs file name. Defaults to {@literal tm.out}.
|
||||
* @param consoleFileName the console file name
|
||||
*/
|
||||
public void setConsoleFileName(String consoleFileName) {
|
||||
set("console_file_name", consoleFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies how many debug logs files can be created. Defaults to {@literal 1}.
|
||||
* @param consoleFileCount the console file count
|
||||
*/
|
||||
public void setConsoleFileCount(int consoleFileCount) {
|
||||
set("console_file_count", consoleFileCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies how many bytes can be stored at most in debug logs files. Defaults to
|
||||
* {@literal -1}. Negative values means unlimited.
|
||||
* @param consoleFileLimit the console file limit
|
||||
*/
|
||||
public void setConsoleFileLimit(int consoleFileLimit) {
|
||||
set("console_file_limit", consoleFileLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies whether or not to use different (and concurrent) threads for two-phase
|
||||
* commit on the participating resources. Setting this to {@literal true} implies that
|
||||
* the commit is more efficient since waiting for acknowledgements is done in
|
||||
* parallel. Defaults to {@literal true}. If you set this to {@literal false}, then
|
||||
* commits will happen in the order that resources are accessed within the
|
||||
* transaction.
|
||||
* @param threadedTwoPhaseCommit if threaded two phase commits should be used
|
||||
*/
|
||||
public void setThreadedTwoPhaseCommit(boolean threadedTwoPhaseCommit) {
|
||||
set("threaded_2pc", threadedTwoPhaseCommit);
|
||||
}
|
||||
|
||||
private void set(String key, Object value) {
|
||||
set("com.atomikos.icatch.", key, value);
|
||||
}
|
||||
|
||||
private void set(String keyPrefix, String key, Object value) {
|
||||
if (value != null) {
|
||||
this.values.put(keyPrefix + key, value.toString());
|
||||
}
|
||||
else {
|
||||
this.values.remove(keyPrefix + key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the properties as a {@link Properties} object that can be used with
|
||||
* Atomikos.
|
||||
* @return the properties
|
||||
*/
|
||||
public Properties asProperties() {
|
||||
Properties properties = new Properties();
|
||||
properties.putAll(this.values);
|
||||
return properties;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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.jta.atomikos;
|
||||
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.jms.XAConnectionFactory;
|
||||
|
||||
import org.springframework.boot.jta.XAConnectionFactoryWrapper;
|
||||
|
||||
/**
|
||||
* {@link XAConnectionFactoryWrapper} that uses an {@link AtomikosConnectionFactoryBean}
|
||||
* to wrap a {@link XAConnectionFactory}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class AtomikosXAConnectionFactoryWrapper implements XAConnectionFactoryWrapper {
|
||||
|
||||
@Override
|
||||
public ConnectionFactory wrapConnectionFactory(XAConnectionFactory connectionFactory) {
|
||||
AtomikosConnectionFactoryBean bean = new AtomikosConnectionFactoryBean();
|
||||
bean.setXaConnectionFactory(connectionFactory);
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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.jta.atomikos;
|
||||
|
||||
import javax.sql.XADataSource;
|
||||
|
||||
import org.springframework.boot.jta.XADataSourceWrapper;
|
||||
|
||||
/**
|
||||
* {@link XADataSourceWrapper} that uses an {@link AtomikosDataSourceBean} to wrap a
|
||||
* {@link XADataSource}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class AtomikosXADataSourceWrapper implements XADataSourceWrapper {
|
||||
|
||||
@Override
|
||||
public AtomikosDataSourceBean wrapDataSource(XADataSource dataSource)
|
||||
throws Exception {
|
||||
AtomikosDataSourceBean bean = new AtomikosDataSourceBean();
|
||||
bean.setXaDataSource(dataSource);
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
|
@ -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.jta.bitronix;
|
||||
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* {@link BeanFactoryPostProcessor} to automatically register the recommended
|
||||
* {@link ConfigurableListableBeanFactory#registerDependentBean(String, String)
|
||||
* dependencies} for correct Bitronix shutdown ordering. With Bitronix it appears that
|
||||
* ConnectionFactory and DataSource beans must be shutdown before the
|
||||
* {@link TransactionManager}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class BitronixDependentBeanFactoryPostProcessor implements
|
||||
BeanFactoryPostProcessor, Ordered {
|
||||
|
||||
private static final String[] NO_BEANS = {};
|
||||
|
||||
private int order = Ordered.LOWEST_PRECEDENCE;
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
|
||||
throws BeansException {
|
||||
String[] transactionManagers = beanFactory.getBeanNamesForType(
|
||||
TransactionManager.class, true, false);
|
||||
for (String transactionManager : transactionManagers) {
|
||||
addTransactionManagerDependencies(beanFactory, transactionManager);
|
||||
}
|
||||
}
|
||||
|
||||
private void addTransactionManagerDependencies(
|
||||
ConfigurableListableBeanFactory beanFactory, String transactionManager) {
|
||||
for (String dependentBeanName : getBeanNamesForType(beanFactory,
|
||||
"javax.jms.ConnectionFactory")) {
|
||||
beanFactory.registerDependentBean(transactionManager, dependentBeanName);
|
||||
}
|
||||
for (String dependentBeanName : getBeanNamesForType(beanFactory,
|
||||
"javax.sql.DataSource")) {
|
||||
beanFactory.registerDependentBean(transactionManager, dependentBeanName);
|
||||
}
|
||||
}
|
||||
|
||||
private String[] getBeanNamesForType(ConfigurableListableBeanFactory beanFactory,
|
||||
String type) {
|
||||
try {
|
||||
return beanFactory.getBeanNamesForType(Class.forName(type), true, false);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Ignore
|
||||
}
|
||||
return NO_BEANS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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.jta.bitronix;
|
||||
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.jms.XAConnectionFactory;
|
||||
|
||||
import org.springframework.boot.jta.XAConnectionFactoryWrapper;
|
||||
|
||||
/**
|
||||
* {@link XAConnectionFactoryWrapper} that uses a Bitronix
|
||||
* {@link PoolingConnectionFactoryBean} to wrap a {@link XAConnectionFactory}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class BitronixXAConnectionFactoryWrapper implements XAConnectionFactoryWrapper {
|
||||
|
||||
@Override
|
||||
public ConnectionFactory wrapConnectionFactory(XAConnectionFactory connectionFactory) {
|
||||
PoolingConnectionFactoryBean pool = new PoolingConnectionFactoryBean();
|
||||
pool.setConnectionFactory(connectionFactory);
|
||||
return pool;
|
||||
}
|
||||
|
||||
}
|
|
@ -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.jta.bitronix;
|
||||
|
||||
import javax.sql.XADataSource;
|
||||
|
||||
import org.springframework.boot.jta.XADataSourceWrapper;
|
||||
|
||||
/**
|
||||
* {@link XADataSourceWrapper} that uses a Bitronix {@link PoolingDataSourceBean} to wrap
|
||||
* a {@link XADataSource}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class BitronixXADataSourceWrapper implements XADataSourceWrapper {
|
||||
|
||||
@Override
|
||||
public PoolingDataSourceBean wrapDataSource(XADataSource dataSource) throws Exception {
|
||||
PoolingDataSourceBean pool = new PoolingDataSourceBean();
|
||||
pool.setDataSource(dataSource);
|
||||
return pool;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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.jta.bitronix;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.XAConnection;
|
||||
import javax.jms.XAConnectionFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import bitronix.tm.resource.common.ResourceBean;
|
||||
import bitronix.tm.resource.common.XAStatefulHolder;
|
||||
import bitronix.tm.resource.jms.PoolingConnectionFactory;
|
||||
|
||||
/**
|
||||
* Spring friendly version of {@link PoolingConnectionFactory}. Provides sensible defaults
|
||||
* and also supports direct wrapping of a {@link XAConnectionFactory} instance.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Josh Long
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class PoolingConnectionFactoryBean extends PoolingConnectionFactory implements
|
||||
BeanNameAware, InitializingBean, DisposableBean {
|
||||
|
||||
private static ThreadLocal<PoolingConnectionFactoryBean> source = new ThreadLocal<PoolingConnectionFactoryBean>();
|
||||
|
||||
private String beanName;
|
||||
|
||||
private XAConnectionFactory connectionFactory;
|
||||
|
||||
public PoolingConnectionFactoryBean() {
|
||||
setMaxPoolSize(10);
|
||||
setTestConnections(true);
|
||||
setAutomaticEnlistingEnabled(true);
|
||||
setAllowLocalTransactions(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void init() {
|
||||
source.set(this);
|
||||
try {
|
||||
super.init();
|
||||
}
|
||||
finally {
|
||||
source.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanName(String name) {
|
||||
this.beanName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (!StringUtils.hasLength(getUniqueName())) {
|
||||
setUniqueName(this.beanName);
|
||||
}
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link XAConnectionFactory} directly, instead of calling
|
||||
* {@link #setClassName(String)}.
|
||||
* @param connectionFactory the connection factory to use
|
||||
*/
|
||||
public void setConnectionFactory(XAConnectionFactory connectionFactory) {
|
||||
this.connectionFactory = connectionFactory;
|
||||
setClassName(DirectXAConnectionFactory.class.getName());
|
||||
setDriverProperties(new Properties());
|
||||
}
|
||||
|
||||
protected final XAConnectionFactory getConnectionFactory() {
|
||||
return this.connectionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XAStatefulHolder createPooledConnection(Object xaFactory, ResourceBean bean)
|
||||
throws Exception {
|
||||
if (xaFactory instanceof DirectXAConnectionFactory) {
|
||||
xaFactory = ((DirectXAConnectionFactory) xaFactory).getConnectionFactory();
|
||||
}
|
||||
return super.createPooledConnection(xaFactory, bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link XAConnectionFactory} implementation that delegates to the
|
||||
* {@link ThreadLocal} {@link PoolingConnectionFactoryBean}.
|
||||
* @see PoolingConnectionFactoryBean#setConnectionFactory(XAConnectionFactory)
|
||||
*/
|
||||
public static class DirectXAConnectionFactory implements XAConnectionFactory {
|
||||
|
||||
private final XAConnectionFactory connectionFactory;
|
||||
|
||||
public DirectXAConnectionFactory() {
|
||||
this.connectionFactory = source.get().connectionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XAConnection createXAConnection() throws JMSException {
|
||||
return this.connectionFactory.createXAConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public XAConnection createXAConnection(String userName, String password)
|
||||
throws JMSException {
|
||||
return this.connectionFactory.createXAConnection(userName, password);
|
||||
}
|
||||
|
||||
public XAConnectionFactory getConnectionFactory() {
|
||||
return this.connectionFactory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* 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.jta.bitronix;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.sql.XAConnection;
|
||||
import javax.sql.XADataSource;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import bitronix.tm.resource.common.ResourceBean;
|
||||
import bitronix.tm.resource.common.XAStatefulHolder;
|
||||
import bitronix.tm.resource.jdbc.PoolingDataSource;
|
||||
|
||||
/**
|
||||
* Spring friendly version of {@link PoolingDataSource}. Provides sensible defaults and
|
||||
* also supports direct wrapping of a {@link XADataSource} instance.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Josh Long
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class PoolingDataSourceBean extends PoolingDataSource implements BeanNameAware,
|
||||
InitializingBean {
|
||||
|
||||
private static ThreadLocal<PoolingDataSourceBean> source = new ThreadLocal<PoolingDataSourceBean>();
|
||||
|
||||
private XADataSource dataSource;
|
||||
|
||||
private String beanName;
|
||||
|
||||
public PoolingDataSourceBean() {
|
||||
super();
|
||||
setMaxPoolSize(10);
|
||||
setAllowLocalTransactions(true);
|
||||
setEnableJdbc4ConnectionTest(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void init() {
|
||||
source.set(this);
|
||||
try {
|
||||
super.init();
|
||||
}
|
||||
finally {
|
||||
source.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanName(String name) {
|
||||
this.beanName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (!StringUtils.hasLength(getUniqueName())) {
|
||||
setUniqueName(this.beanName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link XADataSource} directly, instead of calling
|
||||
* {@link #setClassName(String)}.
|
||||
* @param dataSource the data source to use
|
||||
*/
|
||||
public void setDataSource(XADataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
setClassName(DirectXADataSource.class.getName());
|
||||
setDriverProperties(new Properties());
|
||||
}
|
||||
|
||||
protected final XADataSource getDataSource() {
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XAStatefulHolder createPooledConnection(Object xaFactory, ResourceBean bean)
|
||||
throws Exception {
|
||||
if (xaFactory instanceof DirectXADataSource) {
|
||||
xaFactory = ((DirectXADataSource) xaFactory).getDataSource();
|
||||
}
|
||||
return super.createPooledConnection(xaFactory, bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link XADataSource} implementation that delegates to the {@link ThreadLocal}
|
||||
* {@link PoolingDataSourceBean}.
|
||||
* @see PoolingDataSourceBean#setDataSource(XADataSource)
|
||||
*/
|
||||
public static class DirectXADataSource implements XADataSource {
|
||||
|
||||
private final XADataSource dataSource;
|
||||
|
||||
public DirectXADataSource() {
|
||||
this.dataSource = source.get().dataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter getLogWriter() throws SQLException {
|
||||
return this.dataSource.getLogWriter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public XAConnection getXAConnection() throws SQLException {
|
||||
return this.dataSource.getXAConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public XAConnection getXAConnection(String user, String password)
|
||||
throws SQLException {
|
||||
return this.dataSource.getXAConnection(user, password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogWriter(PrintWriter out) throws SQLException {
|
||||
this.dataSource.setLogWriter(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoginTimeout(int seconds) throws SQLException {
|
||||
this.dataSource.setLoginTimeout(seconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoginTimeout() throws SQLException {
|
||||
return this.dataSource.getLoginTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
||||
return this.dataSource.getParentLogger();
|
||||
}
|
||||
|
||||
public XADataSource getDataSource() {
|
||||
return this.dataSource;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support for the Java Transaction API.
|
||||
*/
|
||||
package org.springframework.boot.jta;
|
||||
|
|
@ -16,32 +16,17 @@
|
|||
|
||||
package org.springframework.boot.orm.jpa;
|
||||
|
||||
import org.hibernate.cfg.ImprovedNamingStrategy;
|
||||
import org.hibernate.cfg.NamingStrategy;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Hibernate {@link NamingStrategy} that follows Spring recommended naming conventions.
|
||||
* Naming conventions implemented here are identical to {@link ImprovedNamingStrategy}
|
||||
* with the exception that foreign key columns include the referenced column name.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see "http://stackoverflow.com/questions/7689206/ejb3namingstrategy-vs-improvednamingstrategy-foreign-key-naming"
|
||||
* @deprecated Since 1.2.0 in favor of
|
||||
* {@link org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy}
|
||||
*/
|
||||
public class SpringNamingStrategy extends ImprovedNamingStrategy {
|
||||
|
||||
@Override
|
||||
public String foreignKeyColumnName(String propertyName, String propertyEntityName,
|
||||
String propertyTableName, String referencedColumnName) {
|
||||
String name = propertyTableName;
|
||||
if (propertyName != null) {
|
||||
name = StringHelper.unqualify(propertyName);
|
||||
}
|
||||
Assert.state(StringUtils.hasLength(name),
|
||||
"Unable to generate foreignKeyColumnName");
|
||||
return columnName(name) + "_" + referencedColumnName;
|
||||
}
|
||||
@Deprecated
|
||||
public class SpringNamingStrategy extends
|
||||
org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy {
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.orm.jpa.hibernate;
|
||||
|
||||
import javax.transaction.TransactionManager;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform;
|
||||
import org.springframework.transaction.jta.JtaTransactionManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Generic Hibernate {@link AbstractJtaPlatform} implementation that simply resolves the
|
||||
* JTA {@link UserTransaction} and {@link TransactionManager} from the Spring-configured
|
||||
* {@link JtaTransactionManager} implementation.
|
||||
*
|
||||
* @author Josh Long
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class SpringJtaPlatform extends AbstractJtaPlatform {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final JtaTransactionManager transactionManager;
|
||||
|
||||
public SpringJtaPlatform(JtaTransactionManager transactionManager) {
|
||||
Assert.notNull(transactionManager, "TransactionManager must not be null");
|
||||
this.transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
protected boolean hasTransactionManager() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransactionManager locateTransactionManager() {
|
||||
return this.transactionManager.getTransactionManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UserTransaction locateUserTransaction() {
|
||||
return this.transactionManager.getUserTransaction();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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.orm.jpa.hibernate;
|
||||
|
||||
import org.hibernate.cfg.ImprovedNamingStrategy;
|
||||
import org.hibernate.cfg.NamingStrategy;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Hibernate {@link NamingStrategy} that follows Spring recommended naming conventions.
|
||||
* Naming conventions implemented here are identical to {@link ImprovedNamingStrategy}
|
||||
* with the exception that foreign key columns include the referenced column name.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see "http://stackoverflow.com/questions/7689206/ejb3namingstrategy-vs-improvednamingstrategy-foreign-key-naming"
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class SpringNamingStrategy extends ImprovedNamingStrategy {
|
||||
|
||||
@Override
|
||||
public String foreignKeyColumnName(String propertyName, String propertyEntityName,
|
||||
String propertyTableName, String referencedColumnName) {
|
||||
String name = propertyTableName;
|
||||
if (propertyName != null) {
|
||||
name = StringHelper.unqualify(propertyName);
|
||||
}
|
||||
Assert.state(StringUtils.hasLength(name),
|
||||
"Unable to generate foreignKeyColumnName");
|
||||
return columnName(name) + "_" + referencedColumnName;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.jta.atomikos;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link AtomikosConnectionFactoryBean}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class AtomikosConnectionFactoryBeanTests {
|
||||
|
||||
@Test
|
||||
public void beanMethods() throws Exception {
|
||||
MockAtomikosConnectionFactoryBean bean = spy(new MockAtomikosConnectionFactoryBean());
|
||||
bean.setBeanName("bean");
|
||||
bean.afterPropertiesSet();
|
||||
assertThat(bean.getUniqueResourceName(), equalTo("bean"));
|
||||
verify(bean).init();
|
||||
verify(bean, never()).close();
|
||||
bean.destroy();
|
||||
verify(bean).close();
|
||||
}
|
||||
|
||||
private static class MockAtomikosConnectionFactoryBean extends
|
||||
AtomikosConnectionFactoryBean {
|
||||
|
||||
@Override
|
||||
public synchronized void init() throws JMSException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.jta.atomikos;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.atomikos.jdbc.AtomikosSQLException;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link AtomikosDataSourceBean}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class AtomikosDataSourceBeanTests {
|
||||
|
||||
@Test
|
||||
public void beanMethods() throws Exception {
|
||||
MockAtomikosDataSourceBean bean = spy(new MockAtomikosDataSourceBean());
|
||||
bean.setBeanName("bean");
|
||||
bean.afterPropertiesSet();
|
||||
assertThat(bean.getUniqueResourceName(), equalTo("bean"));
|
||||
verify(bean).init();
|
||||
verify(bean, never()).close();
|
||||
bean.destroy();
|
||||
verify(bean).close();
|
||||
}
|
||||
|
||||
private static class MockAtomikosDataSourceBean extends AtomikosDataSourceBean {
|
||||
|
||||
@Override
|
||||
public synchronized void init() throws AtomikosSQLException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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.jta.atomikos;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.atomikos.icatch.jta.UserTransactionManager;
|
||||
import com.atomikos.jms.extra.MessageDrivenContainer;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link AtomikosDependsOnBeanFactoryPostProcessor}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class AtomikosDependsOnBeanFactoryPostProcessorTests {
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
@Test
|
||||
public void setsDependsOn() {
|
||||
this.context = new AnnotationConfigApplicationContext(Config.class);
|
||||
assertDependsOn("dataSource");
|
||||
assertDependsOn("connectionFactory");
|
||||
assertDependsOn("userTransactionManager", "dataSource", "connectionFactory");
|
||||
assertDependsOn("messageDrivenContainer", "userTransactionManager");
|
||||
this.context.close();
|
||||
}
|
||||
|
||||
private void assertDependsOn(String bean, String... expected) {
|
||||
BeanDefinition definition = this.context.getBeanDefinition(bean);
|
||||
if (definition.getDependsOn() == null) {
|
||||
assertTrue("No dependsOn expected for " + bean, expected.length == 0);
|
||||
return;
|
||||
}
|
||||
HashSet<String> dependsOn = new HashSet<String>(Arrays.asList(definition
|
||||
.getDependsOn()));
|
||||
assertThat(dependsOn, equalTo(new HashSet<String>(Arrays.asList(expected))));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
return mock(DataSource.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConnectionFactory connectionFactory() {
|
||||
return mock(ConnectionFactory.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserTransactionManager userTransactionManager() {
|
||||
return mock(UserTransactionManager.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageDrivenContainer messageDrivenContainer() {
|
||||
return mock(MessageDrivenContainer.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static AtomikosDependsOnBeanFactoryPostProcessor atomikosPostProcessor() {
|
||||
return new AtomikosDependsOnBeanFactoryPostProcessor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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.jta.atomikos;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for ;@link AtomikosProperties}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class AtomikosPropertiesTests {
|
||||
|
||||
private AtomikosProperties properties = new AtomikosProperties();
|
||||
|
||||
@Test
|
||||
public void testProperties() {
|
||||
this.properties.setService("service");
|
||||
this.properties.setMaxTimeout(1L);
|
||||
this.properties.setDefaultJtaTimeout(2L);
|
||||
this.properties.setMaxActives(3);
|
||||
this.properties.setEnableLogging(true);
|
||||
this.properties.setTransactionManagerUniqueName("uniqueName");
|
||||
this.properties.setSerialJtaTransactions(true);
|
||||
this.properties.setForceShutdownOnVmExit(true);
|
||||
this.properties.setLogBaseName("logBaseName");
|
||||
this.properties.setLogBaseDir("logBaseDir");
|
||||
this.properties.setCheckpointInterval(4);
|
||||
this.properties.setConsoleLogLevel(AtomikosLoggingLevel.WARN);
|
||||
this.properties.setOutputDir("outputDir");
|
||||
this.properties.setConsoleFileName("consoleFileName");
|
||||
this.properties.setConsoleFileCount(5);
|
||||
this.properties.setConsoleFileLimit(6);
|
||||
this.properties.setThreadedTwoPhaseCommit(true);
|
||||
|
||||
assertThat(this.properties.asProperties().size(), equalTo(17));
|
||||
assertProperty("com.atomikos.icatch.service", "service");
|
||||
assertProperty("com.atomikos.icatch.max_timeout", "1");
|
||||
assertProperty("com.atomikos.icatch.default_jta_timeout", "2");
|
||||
assertProperty("com.atomikos.icatch.max_actives", "3");
|
||||
assertProperty("com.atomikos.icatch.enable_logging", "true");
|
||||
assertProperty("com.atomikos.icatch.tm_unique_name", "uniqueName");
|
||||
assertProperty("com.atomikos.icatch.serial_jta_transactions", "true");
|
||||
assertProperty("com.atomikos.icatch.force_shutdown_on_vm_exit", "true");
|
||||
assertProperty("com.atomikos.icatch.log_base_name", "logBaseName");
|
||||
assertProperty("com.atomikos.icatch.log_base_dir", "logBaseDir");
|
||||
assertProperty("com.atomikos.icatch.checkpoint_interval", "4");
|
||||
assertProperty("com.atomikos.icatch.console_log_level", "WARN");
|
||||
assertProperty("com.atomikos.icatch.output_dir", "outputDir");
|
||||
assertProperty("com.atomikos.icatch.console_file_name", "consoleFileName");
|
||||
assertProperty("com.atomikos.icatch.console_file_count", "5");
|
||||
assertProperty("com.atomikos.icatch.console_file_limit", "6");
|
||||
assertProperty("com.atomikos.icatch.threaded_2pc", "true");
|
||||
}
|
||||
|
||||
private void assertProperty(String key, String value) {
|
||||
assertThat(this.properties.asProperties().getProperty(key), equalTo(value));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.jta.atomikos;
|
||||
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.jms.XAConnectionFactory;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link AtomikosXAConnectionFactoryWrapper}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class AtomikosXAConnectionFactoryWrapperTests {
|
||||
|
||||
@Test
|
||||
public void wrap() {
|
||||
XAConnectionFactory connectionFactory = mock(XAConnectionFactory.class);
|
||||
AtomikosXAConnectionFactoryWrapper wrapper = new AtomikosXAConnectionFactoryWrapper();
|
||||
ConnectionFactory wrapped = wrapper.wrapConnectionFactory(connectionFactory);
|
||||
assertThat(wrapped, instanceOf(AtomikosConnectionFactoryBean.class));
|
||||
assertThat(((AtomikosConnectionFactoryBean) wrapped).getXaConnectionFactory(),
|
||||
sameInstance(connectionFactory));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.jta.atomikos;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import javax.sql.XADataSource;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link AtomikosXADataSourceWrapper}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class AtomikosXADataSourceWrapperTests {
|
||||
|
||||
@Test
|
||||
public void wrap() throws Exception {
|
||||
XADataSource dataSource = mock(XADataSource.class);
|
||||
AtomikosXADataSourceWrapper wrapper = new AtomikosXADataSourceWrapper();
|
||||
DataSource wrapped = wrapper.wrapDataSource(dataSource);
|
||||
assertThat(wrapped, instanceOf(AtomikosDataSourceBean.class));
|
||||
assertThat(((AtomikosDataSourceBean) wrapped).getXaDataSource(),
|
||||
sameInstance(dataSource));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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.jta.bitronix;
|
||||
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import bitronix.tm.BitronixTransactionManager;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link BitronixDependentBeanFactoryPostProcessor}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class BitronixDependentBeanFactoryPostProcessorTests {
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
@Test
|
||||
public void setsDependsOn() {
|
||||
DefaultListableBeanFactory beanFactory = spy(new DefaultListableBeanFactory());
|
||||
this.context = new AnnotationConfigApplicationContext(beanFactory);
|
||||
this.context.register(Config.class);
|
||||
this.context.refresh();
|
||||
String name = "bitronixTransactionManager";
|
||||
verify(beanFactory).registerDependentBean(name, "dataSource");
|
||||
verify(beanFactory).registerDependentBean(name, "connectionFactory");
|
||||
this.context.close();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
return mock(DataSource.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConnectionFactory connectionFactory() {
|
||||
return mock(ConnectionFactory.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BitronixTransactionManager bitronixTransactionManager() {
|
||||
return mock(BitronixTransactionManager.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static BitronixDependentBeanFactoryPostProcessor bitronixPostProcessor() {
|
||||
return new BitronixDependentBeanFactoryPostProcessor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.jta.bitronix;
|
||||
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.jms.XAConnectionFactory;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link BitronixXAConnectionFactoryWrapper}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class BitronixXAConnectionFactoryWrapperTests {
|
||||
|
||||
@Test
|
||||
public void wrap() {
|
||||
XAConnectionFactory connectionFactory = mock(XAConnectionFactory.class);
|
||||
BitronixXAConnectionFactoryWrapper wrapper = new BitronixXAConnectionFactoryWrapper();
|
||||
ConnectionFactory wrapped = wrapper.wrapConnectionFactory(connectionFactory);
|
||||
assertThat(wrapped, instanceOf(PoolingConnectionFactoryBean.class));
|
||||
assertThat(((PoolingConnectionFactoryBean) wrapped).getConnectionFactory(),
|
||||
sameInstance(connectionFactory));
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue