001/* 002 * Copyright 2012-2018 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.jta.bitronix; 018 019import java.io.PrintWriter; 020import java.sql.SQLException; 021import java.sql.SQLFeatureNotSupportedException; 022import java.util.Properties; 023import java.util.logging.Logger; 024 025import javax.sql.XAConnection; 026import javax.sql.XADataSource; 027 028import bitronix.tm.resource.common.ResourceBean; 029import bitronix.tm.resource.common.XAStatefulHolder; 030import bitronix.tm.resource.jdbc.PoolingDataSource; 031 032import org.springframework.beans.factory.BeanNameAware; 033import org.springframework.beans.factory.InitializingBean; 034import org.springframework.boot.context.properties.ConfigurationProperties; 035import org.springframework.util.StringUtils; 036 037/** 038 * Spring friendly version of {@link PoolingDataSource}. Provides sensible defaults and 039 * also supports direct wrapping of a {@link XADataSource} instance. 040 * 041 * @author Phillip Webb 042 * @author Josh Long 043 * @author Andy Wilkinson 044 * @since 1.2.0 045 */ 046@SuppressWarnings("serial") 047@ConfigurationProperties(prefix = "spring.jta.bitronix.datasource") 048public class PoolingDataSourceBean extends PoolingDataSource 049 implements BeanNameAware, InitializingBean { 050 051 private static final ThreadLocal<PoolingDataSourceBean> source = new ThreadLocal<>(); 052 053 private XADataSource dataSource; 054 055 private String beanName; 056 057 public PoolingDataSourceBean() { 058 setMaxPoolSize(10); 059 setAllowLocalTransactions(true); 060 setEnableJdbc4ConnectionTest(true); 061 } 062 063 @Override 064 public synchronized void init() { 065 source.set(this); 066 try { 067 super.init(); 068 } 069 finally { 070 source.remove(); 071 } 072 } 073 074 @Override 075 public void setBeanName(String name) { 076 this.beanName = name; 077 } 078 079 @Override 080 public void afterPropertiesSet() throws Exception { 081 if (!StringUtils.hasLength(getUniqueName())) { 082 setUniqueName(this.beanName); 083 } 084 } 085 086 /** 087 * Set the {@link XADataSource} directly, instead of calling 088 * {@link #setClassName(String)}. 089 * @param dataSource the data source to use 090 */ 091 public void setDataSource(XADataSource dataSource) { 092 this.dataSource = dataSource; 093 setClassName(DirectXADataSource.class.getName()); 094 setDriverProperties(new Properties()); 095 } 096 097 protected final XADataSource getDataSource() { 098 return this.dataSource; 099 } 100 101 @Override 102 public XAStatefulHolder createPooledConnection(Object xaFactory, ResourceBean bean) 103 throws Exception { 104 if (xaFactory instanceof DirectXADataSource) { 105 xaFactory = ((DirectXADataSource) xaFactory).getDataSource(); 106 } 107 return super.createPooledConnection(xaFactory, bean); 108 } 109 110 @Override 111 public Logger getParentLogger() throws SQLFeatureNotSupportedException { 112 try { 113 return this.getParentLogger(); 114 } 115 catch (Exception ex) { 116 // Work around https://jira.codehaus.org/browse/BTM-134 117 return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); 118 } 119 } 120 121 /** 122 * A {@link XADataSource} implementation that delegates to the {@link ThreadLocal} 123 * {@link PoolingDataSourceBean}. 124 * 125 * @see PoolingDataSourceBean#setDataSource(XADataSource) 126 */ 127 public static class DirectXADataSource implements XADataSource { 128 129 private final XADataSource dataSource; 130 131 public DirectXADataSource() { 132 this.dataSource = source.get().dataSource; 133 } 134 135 @Override 136 public PrintWriter getLogWriter() throws SQLException { 137 return this.dataSource.getLogWriter(); 138 } 139 140 @Override 141 public XAConnection getXAConnection() throws SQLException { 142 return this.dataSource.getXAConnection(); 143 } 144 145 @Override 146 public XAConnection getXAConnection(String user, String password) 147 throws SQLException { 148 return this.dataSource.getXAConnection(user, password); 149 } 150 151 @Override 152 public void setLogWriter(PrintWriter out) throws SQLException { 153 this.dataSource.setLogWriter(out); 154 } 155 156 @Override 157 public void setLoginTimeout(int seconds) throws SQLException { 158 this.dataSource.setLoginTimeout(seconds); 159 } 160 161 @Override 162 public int getLoginTimeout() throws SQLException { 163 return this.dataSource.getLoginTimeout(); 164 } 165 166 @Override 167 public Logger getParentLogger() throws SQLFeatureNotSupportedException { 168 return this.dataSource.getParentLogger(); 169 } 170 171 public XADataSource getDataSource() { 172 return this.dataSource; 173 } 174 175 } 176 177}