001/* 002 * Copyright 2012-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.autoconfigure.jdbc; 018 019import javax.sql.DataSource; 020import javax.sql.XADataSource; 021import javax.transaction.TransactionManager; 022 023import org.springframework.beans.BeanUtils; 024import org.springframework.beans.MutablePropertyValues; 025import org.springframework.beans.factory.BeanClassLoaderAware; 026import org.springframework.beans.factory.annotation.Autowired; 027import org.springframework.boot.autoconfigure.AutoConfigureBefore; 028import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 029import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 030import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 031import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 032import org.springframework.boot.bind.RelaxedDataBinder; 033import org.springframework.boot.context.properties.EnableConfigurationProperties; 034import org.springframework.boot.jdbc.DatabaseDriver; 035import org.springframework.boot.jta.XADataSourceWrapper; 036import org.springframework.context.annotation.Bean; 037import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 038import org.springframework.util.Assert; 039import org.springframework.util.ClassUtils; 040import org.springframework.util.StringUtils; 041 042/** 043 * {@link EnableAutoConfiguration Auto-configuration} for {@link DataSource} with XA. 044 * 045 * @author Phillip Webb 046 * @author Josh Long 047 * @since 1.2.0 048 */ 049@AutoConfigureBefore(DataSourceAutoConfiguration.class) 050@EnableConfigurationProperties(DataSourceProperties.class) 051@ConditionalOnClass({ DataSource.class, TransactionManager.class, 052 EmbeddedDatabaseType.class }) 053@ConditionalOnBean(XADataSourceWrapper.class) 054@ConditionalOnMissingBean(DataSource.class) 055public class XADataSourceAutoConfiguration implements BeanClassLoaderAware { 056 057 @Autowired 058 private XADataSourceWrapper wrapper; 059 060 @Autowired 061 private DataSourceProperties properties; 062 063 @Autowired(required = false) 064 private XADataSource xaDataSource; 065 066 private ClassLoader classLoader; 067 068 @Bean 069 public DataSource dataSource() throws Exception { 070 XADataSource xaDataSource = this.xaDataSource; 071 if (xaDataSource == null) { 072 xaDataSource = createXaDataSource(); 073 } 074 return this.wrapper.wrapDataSource(xaDataSource); 075 } 076 077 @Override 078 public void setBeanClassLoader(ClassLoader classLoader) { 079 this.classLoader = classLoader; 080 } 081 082 private XADataSource createXaDataSource() { 083 String className = this.properties.getXa().getDataSourceClassName(); 084 if (!StringUtils.hasLength(className)) { 085 className = DatabaseDriver.fromJdbcUrl(this.properties.determineUrl()) 086 .getXaDataSourceClassName(); 087 } 088 Assert.state(StringUtils.hasLength(className), 089 "No XA DataSource class name specified"); 090 XADataSource dataSource = createXaDataSourceInstance(className); 091 bindXaProperties(dataSource, this.properties); 092 return dataSource; 093 } 094 095 private XADataSource createXaDataSourceInstance(String className) { 096 try { 097 Class<?> dataSourceClass = ClassUtils.forName(className, this.classLoader); 098 Object instance = BeanUtils.instantiate(dataSourceClass); 099 Assert.isInstanceOf(XADataSource.class, instance); 100 return (XADataSource) instance; 101 } 102 catch (Exception ex) { 103 throw new IllegalStateException( 104 "Unable to create XADataSource instance from '" + className + "'"); 105 } 106 } 107 108 private void bindXaProperties(XADataSource target, DataSourceProperties properties) { 109 MutablePropertyValues values = new MutablePropertyValues(); 110 values.add("user", this.properties.determineUsername()); 111 values.add("password", this.properties.determinePassword()); 112 values.add("url", this.properties.determineUrl()); 113 values.addPropertyValues(properties.getXa().getProperties()); 114 new RelaxedDataBinder(target).withAlias("user", "username").bind(values); 115 } 116 117}