DataSourceXAConnectionFactory.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.dbcp2.managed;

  18. import java.sql.Connection;
  19. import java.sql.SQLException;
  20. import java.util.Objects;

  21. import javax.sql.ConnectionEvent;
  22. import javax.sql.ConnectionEventListener;
  23. import javax.sql.PooledConnection;
  24. import javax.sql.XAConnection;
  25. import javax.sql.XADataSource;
  26. import javax.transaction.TransactionManager;
  27. import javax.transaction.TransactionSynchronizationRegistry;
  28. import javax.transaction.xa.XAResource;

  29. import org.apache.commons.dbcp2.Utils;

  30. /**
  31.  * An implementation of XAConnectionFactory which uses a real XADataSource to obtain connections and XAResources.
  32.  *
  33.  * @since 2.0
  34.  */
  35. public class DataSourceXAConnectionFactory implements XAConnectionFactory {

  36.     private static final class XAConnectionEventListener implements ConnectionEventListener {
  37.         @Override
  38.         public void connectionClosed(final ConnectionEvent event) {
  39.             final PooledConnection pc = (PooledConnection) event.getSource();
  40.             pc.removeConnectionEventListener(this);
  41.             try {
  42.                 pc.close();
  43.             } catch (final SQLException e) {
  44.                 System.err.println("Failed to close XAConnection");
  45.                 e.printStackTrace();
  46.             }
  47.         }

  48.         @Override
  49.         public void connectionErrorOccurred(final ConnectionEvent event) {
  50.             connectionClosed(event);
  51.         }
  52.     }

  53.     private final TransactionRegistry transactionRegistry;
  54.     private final XADataSource xaDataSource;
  55.     private String userName;
  56.     private char[] userPassword;

  57.     /**
  58.      * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections.
  59.      * The connections are enlisted into transactions using the specified transaction manager.
  60.      *
  61.      * @param transactionManager
  62.      *            the transaction manager in which connections will be enlisted
  63.      * @param xaDataSource
  64.      *            the data source from which connections will be retrieved
  65.      * @since 2.6.0
  66.      */
  67.     public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource) {
  68.         this(transactionManager, xaDataSource, null, (char[]) null, null);
  69.     }

  70.     /**
  71.      * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections.
  72.      * The connections are enlisted into transactions using the specified transaction manager.
  73.      *
  74.      * @param transactionManager
  75.      *            the transaction manager in which connections will be enlisted
  76.      * @param xaDataSource
  77.      *            the data source from which connections will be retrieved
  78.      * @param userName
  79.      *            the user name used for authenticating new connections or null for unauthenticated
  80.      * @param userPassword
  81.      *            the password used for authenticating new connections
  82.      */
  83.     public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource,
  84.             final String userName, final char[] userPassword) {
  85.         this(transactionManager, xaDataSource, userName, userPassword, null);
  86.     }

  87.     /**
  88.      * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections.
  89.      * The connections are enlisted into transactions using the specified transaction manager.
  90.      *
  91.      * @param transactionManager
  92.      *            the transaction manager in which connections will be enlisted
  93.      * @param xaDataSource
  94.      *            the data source from which connections will be retrieved
  95.      * @param userName
  96.      *            the user name used for authenticating new connections or null for unauthenticated
  97.      * @param userPassword
  98.      *            the password used for authenticating new connections
  99.      * @param transactionSynchronizationRegistry
  100.      *            register with this TransactionSynchronizationRegistry
  101.      * @since 2.6.0
  102.      */
  103.     public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource,
  104.             final String userName, final char[] userPassword, final TransactionSynchronizationRegistry transactionSynchronizationRegistry) {
  105.         Objects.requireNonNull(transactionManager, "transactionManager");
  106.         Objects.requireNonNull(xaDataSource, "xaDataSource");
  107.         // We do allow the transactionSynchronizationRegistry to be null for non-app server environments
  108.         this.transactionRegistry = new TransactionRegistry(transactionManager, transactionSynchronizationRegistry);
  109.         this.xaDataSource = xaDataSource;
  110.         this.userName = userName;
  111.         this.userPassword = Utils.clone(userPassword);
  112.     }

  113.     /**
  114.      * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections.
  115.      * The connections are enlisted into transactions using the specified transaction manager.
  116.      *
  117.      * @param transactionManager
  118.      *            the transaction manager in which connections will be enlisted
  119.      * @param xaDataSource
  120.      *            the data source from which connections will be retrieved
  121.      * @param userName
  122.      *            the user name used for authenticating new connections or null for unauthenticated
  123.      * @param userPassword
  124.      *            the password used for authenticating new connections
  125.      */
  126.     public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource,
  127.             final String userName, final String userPassword) {
  128.         this(transactionManager, xaDataSource, userName, Utils.toCharArray(userPassword), null);
  129.     }

  130.     /**
  131.      * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections.
  132.      * The connections are enlisted into transactions using the specified transaction manager.
  133.      *
  134.      * @param transactionManager
  135.      *            the transaction manager in which connections will be enlisted
  136.      * @param xaDataSource
  137.      *            the data source from which connections will be retrieved
  138.      * @param transactionSynchronizationRegistry
  139.      *            register with this TransactionSynchronizationRegistry
  140.      */
  141.     public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource, final TransactionSynchronizationRegistry transactionSynchronizationRegistry) {
  142.         this(transactionManager, xaDataSource, null, (char[]) null, transactionSynchronizationRegistry);
  143.     }

  144.     @Override
  145.     public Connection createConnection() throws SQLException {
  146.         // create a new XAConnection
  147.         final XAConnection xaConnection;
  148.         if (userName == null) {
  149.             xaConnection = xaDataSource.getXAConnection();
  150.         } else {
  151.             xaConnection = xaDataSource.getXAConnection(userName, Utils.toString(userPassword));
  152.         }
  153.         // get the real connection and XAResource from the connection
  154.         final Connection connection = xaConnection.getConnection();
  155.         final XAResource xaResource = xaConnection.getXAResource();
  156.         // register the XA resource for the connection
  157.         transactionRegistry.registerConnection(connection, xaResource);
  158.         // The Connection we're returning is a handle on the XAConnection.
  159.         // When the pool calling us closes the Connection, we need to
  160.         // also close the XAConnection that holds the physical connection.
  161.         xaConnection.addConnectionEventListener(new XAConnectionEventListener());

  162.         return connection;
  163.     }

  164.     @Override
  165.     public TransactionRegistry getTransactionRegistry() {
  166.         return transactionRegistry;
  167.     }

  168.     /**
  169.      * Gets the user name used to authenticate new connections.
  170.      *
  171.      * @return the user name or null if unauthenticated connections are used
  172.      * @deprecated Use {@link #getUserName()}.
  173.      */
  174.     @Deprecated
  175.     public String getUsername() {
  176.         return userName;
  177.     }

  178.     /**
  179.      * Gets the user name used to authenticate new connections.
  180.      *
  181.      * @return the user name or null if unauthenticated connections are used
  182.      * @since 2.6.0
  183.      */
  184.     public String getUserName() {
  185.         return userName;
  186.     }

  187.     /**
  188.      * Gets the user password.
  189.      *
  190.      * @return the user password.
  191.      */
  192.     public char[] getUserPassword() {
  193.         return Utils.clone(userPassword);
  194.     }

  195.     /**
  196.      * Gets the XA data source.
  197.      *
  198.      * @return the XA data source.
  199.      */
  200.     public XADataSource getXaDataSource() {
  201.         return xaDataSource;
  202.     }

  203.     /**
  204.      * Sets the password used to authenticate new connections.
  205.      *
  206.      * @param userPassword
  207.      *            the password used for authenticating the connection or null for unauthenticated.
  208.      * @since 2.4.0
  209.      */
  210.     public void setPassword(final char[] userPassword) {
  211.         this.userPassword = Utils.clone(userPassword);
  212.     }

  213.     /**
  214.      * Sets the password used to authenticate new connections.
  215.      *
  216.      * @param userPassword
  217.      *            the password used for authenticating the connection or null for unauthenticated
  218.      */
  219.     public void setPassword(final String userPassword) {
  220.         this.userPassword = Utils.toCharArray(userPassword);
  221.     }

  222.     /**
  223.      * Sets the user name used to authenticate new connections.
  224.      *
  225.      * @param userName
  226.      *            the user name used for authenticating the connection or null for unauthenticated
  227.      */
  228.     public void setUsername(final String userName) {
  229.         this.userName = userName;
  230.     }
  231. }