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.xa.XAResource; 027 028import java.sql.Connection; 029import java.sql.SQLException; 030 031/** 032 * An implementation of XAConnectionFactory which uses a real XADataSource to obtain connections and XAResources. 033 * 034 * @author Dain Sundstrom 035 * @version $Id: DataSourceXAConnectionFactory.java 1649430 2015-01-04 21:29:32Z tn $ 036 * @since 2.0 037 */ 038public class DataSourceXAConnectionFactory implements XAConnectionFactory { 039 private final TransactionRegistry transactionRegistry; 040 private final XADataSource xaDataSource; 041 private String username; 042 private String password; 043 044 /** 045 * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database 046 * connections. The connections are enlisted into transactions using the specified transaction manager. 047 * 048 * @param transactionManager the transaction manager in which connections will be enlisted 049 * @param xaDataSource the data source from which connections will be retrieved 050 */ 051 public DataSourceXAConnectionFactory(TransactionManager transactionManager, XADataSource xaDataSource) { 052 this(transactionManager, xaDataSource, null, null); 053 } 054 055 /** 056 * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database 057 * connections. The connections are enlisted into transactions using the specified transaction manager. 058 * 059 * @param transactionManager the transaction manager in which connections will be enlisted 060 * @param xaDataSource the data source from which connections will be retrieved 061 * @param username the username used for authenticating new connections or null for unauthenticated 062 * @param password the password used for authenticating new connections 063 */ 064 public DataSourceXAConnectionFactory(TransactionManager transactionManager, XADataSource xaDataSource, String username, String password) { 065 if (transactionManager == null) { 066 throw new NullPointerException("transactionManager is null"); 067 } 068 if (xaDataSource == null) { 069 throw new NullPointerException("xaDataSource is null"); 070 } 071 072 this.transactionRegistry = new TransactionRegistry(transactionManager); 073 this.xaDataSource = xaDataSource; 074 this.username = username; 075 this.password = password; 076 } 077 078 /** 079 * Gets the username used to authenticate new connections. 080 * @return the user name or null if unauthenticated connections are used 081 */ 082 public String getUsername() { 083 return username; 084 } 085 086 /** 087 * Sets the username used to authenticate new connections. 088 * @param username the username used for authenticating the connection or null for unauthenticated 089 */ 090 public void setUsername(String username) { 091 this.username = username; 092 } 093 094 /** 095 * Sets the password used to authenticate new connections. 096 * @param password the password used for authenticating the connection or null for unauthenticated 097 */ 098 public void setPassword(String password) { 099 this.password = password; 100 } 101 102 @Override 103 public TransactionRegistry getTransactionRegistry() { 104 return transactionRegistry; 105 } 106 107 @Override 108 public Connection createConnection() throws SQLException { 109 // create a new XAConection 110 XAConnection xaConnection; 111 if (username == null) { 112 xaConnection = xaDataSource.getXAConnection(); 113 } else { 114 xaConnection = xaDataSource.getXAConnection(username, password); 115 } 116 117 // get the real connection and XAResource from the connection 118 Connection connection = xaConnection.getConnection(); 119 XAResource xaResource = xaConnection.getXAResource(); 120 121 // register the xa resource for the connection 122 transactionRegistry.registerConnection(connection, xaResource); 123 124 // The Connection we're returning is a handle on the XAConnection. 125 // When the pool calling us closes the Connection, we need to 126 // also close the XAConnection that holds the physical connection. 127 xaConnection.addConnectionEventListener(new ConnectionEventListener() { 128 129 @Override 130 public void connectionClosed(ConnectionEvent event) { 131 PooledConnection pc = (PooledConnection) event.getSource(); 132 pc.removeConnectionEventListener(this); 133 try { 134 pc.close(); 135 } catch (SQLException e) { 136 System.err.println("Failed to close XAConnection"); 137 e.printStackTrace(); 138 } 139 } 140 141 @Override 142 public void connectionErrorOccurred(ConnectionEvent event) { 143 connectionClosed(event); 144 } 145 }); 146 147 148 return connection; 149 } 150}