001/** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.commons.dbcp2.managed; 019 020import javax.sql.ConnectionEvent; 021import javax.sql.ConnectionEventListener; 022import javax.sql.PooledConnection; 023import javax.sql.XAConnection; 024import javax.sql.XADataSource; 025import javax.transaction.TransactionManager; 026import javax.transaction.TransactionSynchronizationRegistry; 027import javax.transaction.xa.XAResource; 028 029import org.apache.commons.dbcp2.Utils; 030 031import java.sql.Connection; 032import java.sql.SQLException; 033import java.util.Objects; 034 035/** 036 * An implementation of XAConnectionFactory which uses a real XADataSource to obtain connections and XAResources. 037 * 038 * @since 2.0 039 */ 040public class DataSourceXAConnectionFactory implements XAConnectionFactory { 041 private final TransactionRegistry transactionRegistry; 042 private final XADataSource xaDataSource; 043 private String userName; 044 private char[] userPassword; 045 046 /** 047 * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections. 048 * The connections are enlisted into transactions using the specified transaction manager. 049 * 050 * @param transactionManager 051 * the transaction manager in which connections will be enlisted 052 * @param xaDataSource 053 * the data source from which connections will be retrieved 054 * @since 2.6.0 055 */ 056 public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource) { 057 this(transactionManager, xaDataSource, null, (char[]) null, null); 058 } 059 060 /** 061 * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections. 062 * The connections are enlisted into transactions using the specified transaction manager. 063 * 064 * @param transactionManager 065 * the transaction manager in which connections will be enlisted 066 * @param xaDataSource 067 * the data source from which connections will be retrieved 068 * @param userName 069 * the user name used for authenticating new connections or null for unauthenticated 070 * @param userPassword 071 * the password used for authenticating new connections 072 */ 073 public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource, 074 final String userName, final char[] userPassword) { 075 this(transactionManager, xaDataSource, userName, userPassword, null); 076 } 077 078 /** 079 * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections. 080 * The connections are enlisted into transactions using the specified transaction manager. 081 * 082 * @param transactionManager 083 * the transaction manager in which connections will be enlisted 084 * @param xaDataSource 085 * the data source from which connections will be retrieved 086 * @param userName 087 * the user name used for authenticating new connections or null for unauthenticated 088 * @param userPassword 089 * the password used for authenticating new connections 090 * @param transactionSynchronizationRegistry 091 * register with this TransactionSynchronizationRegistry 092 * @since 2.6.0 093 */ 094 public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource, 095 final String userName, final char[] userPassword, final TransactionSynchronizationRegistry transactionSynchronizationRegistry) { 096 Objects.requireNonNull(transactionManager, "transactionManager is null"); 097 Objects.requireNonNull(xaDataSource, "xaDataSource is null"); 098 099 // We do allow the transactionSynchronizationRegistry to be null for non-app server environments 100 101 this.transactionRegistry = new TransactionRegistry(transactionManager, transactionSynchronizationRegistry); 102 this.xaDataSource = xaDataSource; 103 this.userName = userName; 104 this.userPassword = userPassword; 105 } 106 107 /** 108 * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections. 109 * The connections are enlisted into transactions using the specified transaction manager. 110 * 111 * @param transactionManager 112 * the transaction manager in which connections will be enlisted 113 * @param xaDataSource 114 * the data source from which connections will be retrieved 115 * @param userName 116 * the user name used for authenticating new connections or null for unauthenticated 117 * @param userPassword 118 * the password used for authenticating new connections 119 */ 120 public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource, 121 final String userName, final String userPassword) { 122 this(transactionManager, xaDataSource, userName, Utils.toCharArray(userPassword), null); 123 } 124 125 /** 126 * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections. 127 * The connections are enlisted into transactions using the specified transaction manager. 128 * 129 * @param transactionManager 130 * the transaction manager in which connections will be enlisted 131 * @param xaDataSource 132 * the data source from which connections will be retrieved 133 * @param transactionSynchronizationRegistry 134 * register with this TransactionSynchronizationRegistry 135 */ 136 public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource, final TransactionSynchronizationRegistry transactionSynchronizationRegistry) { 137 this(transactionManager, xaDataSource, null, (char[]) null, transactionSynchronizationRegistry); 138 } 139 140 @Override 141 public Connection createConnection() throws SQLException { 142 // create a new XAConnection 143 XAConnection xaConnection; 144 if (userName == null) { 145 xaConnection = xaDataSource.getXAConnection(); 146 } else { 147 xaConnection = xaDataSource.getXAConnection(userName, Utils.toString(userPassword)); 148 } 149 150 // get the real connection and XAResource from the connection 151 final Connection connection = xaConnection.getConnection(); 152 final XAResource xaResource = xaConnection.getXAResource(); 153 154 // register the xa resource for the connection 155 transactionRegistry.registerConnection(connection, xaResource); 156 157 // The Connection we're returning is a handle on the XAConnection. 158 // When the pool calling us closes the Connection, we need to 159 // also close the XAConnection that holds the physical connection. 160 xaConnection.addConnectionEventListener(new ConnectionEventListener() { 161 162 @Override 163 public void connectionClosed(final ConnectionEvent event) { 164 final PooledConnection pc = (PooledConnection) event.getSource(); 165 pc.removeConnectionEventListener(this); 166 try { 167 pc.close(); 168 } catch (final SQLException e) { 169 System.err.println("Failed to close XAConnection"); 170 e.printStackTrace(); 171 } 172 } 173 174 @Override 175 public void connectionErrorOccurred(final ConnectionEvent event) { 176 connectionClosed(event); 177 } 178 }); 179 180 return connection; 181 } 182 183 @Override 184 public TransactionRegistry getTransactionRegistry() { 185 return transactionRegistry; 186 } 187 188 /** 189 * Gets the user name used to authenticate new connections. 190 * 191 * @return the user name or null if unauthenticated connections are used 192 * @deprecated Use {@link #getUserName()}. 193 */ 194 @Deprecated 195 public String getUsername() { 196 return userName; 197 } 198 199 /** 200 * Gets the user name used to authenticate new connections. 201 * 202 * @return the user name or null if unauthenticated connections are used 203 * @since 2.6.0 204 */ 205 public String getUserName() { 206 return userName; 207 } 208 209 public char[] getUserPassword() { 210 return userPassword; 211 } 212 213 public XADataSource getXaDataSource() { 214 return xaDataSource; 215 } 216 217 /** 218 * Sets the password used to authenticate new connections. 219 * 220 * @param userPassword 221 * the password used for authenticating the connection or null for unauthenticated. 222 * @since 2.4.0 223 */ 224 public void setPassword(final char[] userPassword) { 225 this.userPassword = userPassword; 226 } 227 228 /** 229 * Sets the password used to authenticate new connections. 230 * 231 * @param userPassword 232 * the password used for authenticating the connection or null for unauthenticated 233 */ 234 public void setPassword(final String userPassword) { 235 this.userPassword = Utils.toCharArray(userPassword); 236 } 237 238 /** 239 * Sets the user name used to authenticate new connections. 240 * 241 * @param userName 242 * the user name used for authenticating the connection or null for unauthenticated 243 */ 244 public void setUsername(final String userName) { 245 this.userName = userName; 246 } 247}