diff --git a/pom.xml b/pom.xml index 8980e73705..5486b3534f 100644 --- a/pom.xml +++ b/pom.xml @@ -147,12 +147,6 @@ 2.5 provided - - jta - jta - 1.0.1b - provided - commons-logging commons-logging diff --git a/src/main/java/com/alibaba/druid/pool/xa/DataSourceXAConnectionFactory.java b/src/main/java/com/alibaba/druid/pool/xa/DataSourceXAConnectionFactory.java deleted file mode 100644 index 9566a69f25..0000000000 --- a/src/main/java/com/alibaba/druid/pool/xa/DataSourceXAConnectionFactory.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 1999-2011 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.druid.pool.xa; - -import javax.sql.XAConnection; -import javax.sql.XADataSource; -import javax.transaction.TransactionManager; -import javax.transaction.xa.XAResource; -import java.sql.Connection; -import java.sql.SQLException; - -/** - * An implementation of XAConnectionFactory which uses a real XADataSource to obtain connections and XAResources. - * - * @author Dain Sundstrom - * @version $Revision$ - */ -public class DataSourceXAConnectionFactory implements XAConnectionFactory { - - protected TransactionRegistry transactionRegistry; - protected XADataSource xaDataSource; - protected String username; - protected String password; - - /** - * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections. - * The connections are enlisted into transactions using the specified transaction manager. - * - * @param transactionManager the transaction manager in which connections will be enlisted - * @param xaDataSource the data source from which connections will be retrieved - */ - public DataSourceXAConnectionFactory(TransactionManager transactionManager, XADataSource xaDataSource){ - this(transactionManager, xaDataSource, null, null); - } - - /** - * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections. - * The connections are enlisted into transactions using the specified transaction manager. - * - * @param transactionManager the transaction manager in which connections will be enlisted - * @param xaDataSource the data source from which connections will be retrieved - * @param username the username used for authenticating new connections or null for unauthenticated - * @param password the password used for authenticating new connections - */ - public DataSourceXAConnectionFactory(TransactionManager transactionManager, XADataSource xaDataSource, String username, String password){ - if (transactionManager == null) throw new NullPointerException("transactionManager is null"); - if (xaDataSource == null) throw new NullPointerException("xaDataSource is null"); - - this.transactionRegistry = new TransactionRegistry(transactionManager); - this.xaDataSource = xaDataSource; - this.username = username; - this.password = password; - } - - /** - * Gets the username used to authenticate new connections. - * - * @return the user name or null if unauthenticated connections are used - */ - public String getUsername() { - return username; - } - - /** - * Sets the username used to authenticate new connections. - * - * @param username the username used for authenticating the connection or null for unauthenticated - */ - public void setUsername(String username) { - this.username = username; - } - - /** - * Sets the password used to authenticate new connections. - * - * @param password the password used for authenticating the connection or null for unauthenticated - */ - public void setPassword(String password) { - this.password = password; - } - - public TransactionRegistry getTransactionRegistry() { - return transactionRegistry; - } - - public Connection createConnection() throws SQLException { - // create a new XAConection - XAConnection xaConnection; - if (username == null) { - xaConnection = xaDataSource.getXAConnection(); - } else { - xaConnection = xaDataSource.getXAConnection(username, password); - } - - // get the real connection and XAResource from the connection - Connection connection = xaConnection.getConnection(); - XAResource xaResource = xaConnection.getXAResource(); - - // register the xa resource for the connection - transactionRegistry.registerConnection(connection, xaResource); - - return connection; - } -} diff --git a/src/main/java/com/alibaba/druid/pool/xa/DruidXADataSource.java b/src/main/java/com/alibaba/druid/pool/xa/DruidXADataSource.java deleted file mode 100644 index 68bd964104..0000000000 --- a/src/main/java/com/alibaba/druid/pool/xa/DruidXADataSource.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 1999-2011 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.druid.pool.xa; - -import java.sql.SQLException; - -import javax.sql.XADataSource; -import javax.transaction.TransactionManager; - -import com.alibaba.druid.pool.ConnectionFactory; -import com.alibaba.druid.pool.DruidDataSource; - -public class DruidXADataSource extends DruidDataSource { - - private static final long serialVersionUID = 1L; - - /** Transaction Registry */ - private TransactionRegistry transactionRegistry; - /** Transaction Manager */ - private transient TransactionManager transactionManager; - /** XA datasource class name */ - private String xaDataSource; - /** XA datasource instance */ - private XADataSource xaDataSourceInstance; - - /** - * Gets the XADataSource instance used by the XAConnectionFactory. - * - * @return the XADataSource - */ - public synchronized XADataSource getXaDataSourceInstance() { - return xaDataSourceInstance; - } - - /** - *

- * Sets the XADataSource instance used by the XAConnectionFactory. - *

- *

- * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first - * time one of the following methods is invoked: getConnection, setLogwriter, - * setLoginTimeout, getLoginTimeout, getLogWriter. - *

- * - * @param xaDataSourceInstance XADataSource instance - */ - public synchronized void setXaDataSourceInstance(XADataSource xaDataSourceInstance) { - this.xaDataSourceInstance = xaDataSourceInstance; - xaDataSource = xaDataSourceInstance == null ? null : xaDataSourceInstance.getClass().getName(); - } - - /** - * Gets the required transaction manager property. - * - * @return the transaction manager used to enlist connections - */ - public TransactionManager getTransactionManager() { - return transactionManager; - } - - /** - * Gets the transaction registry. - * - * @return the transaction registry associating XAResources with managed connections - */ - protected synchronized TransactionRegistry getTransactionRegistry() { - return transactionRegistry; - } - - /** - * Sets the required transaction manager property. - * - * @param transactionManager the transaction manager used to enlist connections - */ - public void setTransactionManager(TransactionManager transactionManager) { - this.transactionManager = transactionManager; - } - - /** - * Gets the optional XADataSource class name. - * - * @return the optional XADataSource class name - */ - public synchronized String getXADataSource() { - return xaDataSource; - } - - /** - * Sets the optional XADataSource class name. - * - * @param xaDataSource the optional XADataSource class name - */ - public synchronized void setXADataSource(String xaDataSource) { - this.xaDataSource = xaDataSource; - } - - protected ConnectionFactory createConnectionFactory() throws SQLException { - if (transactionManager == null) { - throw new SQLException("Transaction manager must be set before a connection can be created"); - } - - // If xa data source is not specified a DriverConnectionFactory is created and wrapped with a - // LocalXAConnectionFactory - if (xaDataSource == null) { - ConnectionFactory connectionFactory = super.createConnectionFactory(); - XAConnectionFactory xaConnectionFactory = new LocalXAConnectionFactory(getTransactionManager(), connectionFactory); - transactionRegistry = xaConnectionFactory.getTransactionRegistry(); - return xaConnectionFactory; - } - - // Create the XADataSource instance using the configured class name if it has not been set - if (xaDataSourceInstance == null) { - Class xaDataSourceClass = null; - try { - xaDataSourceClass = Class.forName(xaDataSource); - } catch (Throwable t) { - String message = "Cannot load XA data source class '" + xaDataSource + "'"; - throw (SQLException) new SQLException(message).initCause(t); - } - - try { - xaDataSourceInstance = (XADataSource) xaDataSourceClass.newInstance(); - } catch (Throwable t) { - String message = "Cannot create XA data source of class '" + xaDataSource + "'"; - throw (SQLException) new SQLException(message).initCause(t); - } - } - - // finally, create the XAConectionFactory using the XA data source - XAConnectionFactory xaConnectionFactory = new DataSourceXAConnectionFactory(getTransactionManager(), xaDataSourceInstance, username, password); - transactionRegistry = xaConnectionFactory.getTransactionRegistry(); - return xaConnectionFactory; - } - - /** - * Creates the PoolableConnectionFactory and attaches it to the connection pool. - * - * @param driverConnectionFactory JDBC connection factory created by {@link #createConnectionFactory()} - * @param statementPoolFactory statement pool factory (null if statement pooling is turned off) - * @param abandonedConfig abandoned connection tracking configuration (null if no tracking) - * @throws SQLException if an error occurs creating the PoolableConnectionFactory - */ - protected void createPoolableConnectionFactory(ConnectionFactory driverConnectionFactory) throws SQLException { - // PoolableConnectionFactory connectionFactory = null; - // try { - // connectionFactory = new PoolableManagedConnectionFactory((XAConnectionFactory) driverConnectionFactory, - // connectionPool, statementPoolFactory, - // validationQuery, validationQueryTimeout, - // connectionInitSqls, defaultReadOnly, - // defaultAutoCommit, defaultTransactionIsolation, - // defaultCatalog, abandonedConfig); - // validateConnectionFactory(connectionFactory); - // } catch (RuntimeException e) { - // throw e; - // } catch (Exception e) { - // throw (SQLException) new SQLException("Cannot create PoolableConnectionFactory (" + e.getMessage() + - // ")").initCause(e); - // } - throw new SQLException("TODO"); - } - -} diff --git a/src/main/java/com/alibaba/druid/pool/xa/LocalXAConnectionFactory.java b/src/main/java/com/alibaba/druid/pool/xa/LocalXAConnectionFactory.java deleted file mode 100644 index 464bba5235..0000000000 --- a/src/main/java/com/alibaba/druid/pool/xa/LocalXAConnectionFactory.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright 1999-2011 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.druid.pool.xa; - -import java.sql.Connection; -import java.sql.SQLException; - -import javax.transaction.TransactionManager; -import javax.transaction.xa.XAException; -import javax.transaction.xa.XAResource; -import javax.transaction.xa.Xid; - -import com.alibaba.druid.pool.ConnectionFactory; - -/** - * An implementation of XAConnectionFactory which manages non-XA connections in XA transactions. A non-XA connection - * commits and rolls back as part of the XA transaction, but is not recoverable since the connection does not implement - * the 2-phase protocol. - * - * @author Dain Sundstrom - * @version $Revision$ - */ -public class LocalXAConnectionFactory implements XAConnectionFactory { - - protected TransactionRegistry transactionRegistry; - protected ConnectionFactory connectionFactory; - - /** - * Creates an LocalXAConnectionFactory which uses the specified connection factory to create database connections. - * The connections are enlisted into transactions using the specified transaction manager. - * - * @param transactionManager the transaction manager in which connections will be enlisted - * @param connectionFactory the connection factory from which connections will be retrieved - */ - public LocalXAConnectionFactory(TransactionManager transactionManager, ConnectionFactory connectionFactory){ - if (transactionManager == null) { - throw new NullPointerException("transactionManager is null"); - } - - if (connectionFactory == null) { - throw new NullPointerException("connectionFactory is null"); - } - - this.transactionRegistry = new TransactionRegistry(transactionManager); - this.connectionFactory = connectionFactory; - } - - public TransactionRegistry getTransactionRegistry() { - return transactionRegistry; - } - - public Connection createConnection() throws SQLException { - // create a new connection - Connection connection = connectionFactory.createConnection(); - - // create a XAResource to manage the connection during XA transactions - XAResource xaResource = new LocalXAResource(connection); - - // register the xa resource for the connection - transactionRegistry.registerConnection(connection, xaResource); - - return connection; - } - - /** - * LocalXAResource is a fake XAResource for non-XA connections. When a transaction is started the connection - * auto-commit is turned off. When the connection is committed or rolled back, the commit or rollback method is - * called on the connection and then the original auto-commit value is restored.

The LocalXAResource also - * respects the connection read-only setting. If the connection is read-only the commit method will not be called, - * and the prepare method returns the XA_RDONLY.

It is assumed that the wrapper around a managed connection - * disables the setAutoCommit(), commit(), rollback() and setReadOnly() methods while a transaction is in progress. - */ - protected static class LocalXAResource implements XAResource { - - private final Connection connection; - private Xid currentXid; - private boolean originalAutoCommit; - - public LocalXAResource(Connection localTransaction){ - this.connection = localTransaction; - } - - /** - * Gets the current xid of the transaction branch associated with this XAResource. - * - * @return the current xid of the transaction branch associated with this XAResource. - */ - public synchronized Xid getXid() { - return currentXid; - } - - /** - * Signals that a the connection has been enrolled in a transaction. This method saves off the current auto - * commit flag, and then disables auto commit. The original auto commit setting is restored when the transaction - * completes. - * - * @param xid the id of the transaction branch for this connection - * @param flag either XAResource.TMNOFLAGS or XAResource.TMRESUME - * @throws XAException if the connection is already enlisted in another transaction, or if auto-commit could not - * be disabled - */ - public synchronized void start(Xid xid, int flag) throws XAException { - if (flag == XAResource.TMNOFLAGS) { - // first time in this transaction - - // make sure we aren't already in another tx - if (this.currentXid != null) { - throw new XAException("Already enlisted in another transaction with xid " + xid); - } - - // save off the current auto commit flag so it can be restored after the transaction completes - try { - originalAutoCommit = connection.getAutoCommit(); - } catch (SQLException ignored) { - // no big deal, just assume it was off - originalAutoCommit = true; - } - - // update the auto commit flag - try { - connection.setAutoCommit(false); - } catch (SQLException e) { - throw (XAException) new XAException("Count not turn off auto commit for a XA transaction").initCause(e); - } - - this.currentXid = xid; - } else if (flag == XAResource.TMRESUME) { - if (xid != this.currentXid) { - throw new XAException("Attempting to resume in different transaction: expected " + this.currentXid + ", but was " + xid); - } - } else { - throw new XAException("Unknown start flag " + flag); - } - } - - /** - * This method does nothing. - * - * @param xid the id of the transaction branch for this connection - * @param flag ignored - * @throws XAException if the connection is already enlisted in another transaction - */ - public synchronized void end(Xid xid, int flag) throws XAException { - if (xid == null) throw new NullPointerException("xid is null"); - if (!this.currentXid.equals(xid)) throw new XAException("Invalid Xid: expected " + this.currentXid + ", but was " + xid); - - // This notification tells us that the application server is done using this - // connection for the time being. The connection is still associated with an - // open transaction, so we must still wait for the commit or rollback method - } - - /** - * This method does nothing since the LocalXAConnection does not support two-phase-commit. This method will - * return XAResource.XA_RDONLY if the connection isReadOnly(). This assumes that the physical connection is - * wrapped with a proxy that prevents an application from changing the read-only flag while enrolled in a - * transaction. - * - * @param xid the id of the transaction branch for this connection - * @return XAResource.XA_RDONLY if the connection.isReadOnly(); XAResource.XA_OK otherwise - */ - public synchronized int prepare(Xid xid) { - // if the connection is read-only, then the resource is read-only - // NOTE: this assumes that the outer proxy throws an exception when application code - // attempts to set this in a transaction - try { - if (connection.isReadOnly()) { - // update the auto commit flag - connection.setAutoCommit(originalAutoCommit); - - // tell the transaction manager we are read only - return XAResource.XA_RDONLY; - } - } catch (SQLException ignored) { - // no big deal - } - - // this is a local (one phase) only connection, so we can't prepare - return XAResource.XA_OK; - } - - /** - * Commits the transaction and restores the original auto commit setting. - * - * @param xid the id of the transaction branch for this connection - * @param flag ignored - * @throws XAException if connection.commit() throws a SQLException - */ - public synchronized void commit(Xid xid, boolean flag) throws XAException { - if (xid == null) throw new NullPointerException("xid is null"); - if (!this.currentXid.equals(xid)) throw new XAException("Invalid Xid: expected " + this.currentXid + ", but was " + xid); - - try { - // make sure the connection isn't already closed - if (connection.isClosed()) { - throw new XAException("Conection is closed"); - } - - // A read only connection should not be committed - if (!connection.isReadOnly()) { - connection.commit(); - } - } catch (SQLException e) { - throw (XAException) new XAException().initCause(e); - } finally { - try { - connection.setAutoCommit(originalAutoCommit); - } catch (SQLException e) { - } - this.currentXid = null; - } - } - - /** - * Rolls back the transaction and restores the original auto commit setting. - * - * @param xid the id of the transaction branch for this connection - * @throws XAException if connection.rollback() throws a SQLException - */ - public synchronized void rollback(Xid xid) throws XAException { - if (xid == null) throw new NullPointerException("xid is null"); - if (!this.currentXid.equals(xid)) throw new XAException("Invalid Xid: expected " + this.currentXid + ", but was " + xid); - - try { - connection.rollback(); - } catch (SQLException e) { - throw (XAException) new XAException().initCause(e); - } finally { - try { - connection.setAutoCommit(originalAutoCommit); - } catch (SQLException e) { - } - this.currentXid = null; - } - } - - /** - * Returns true if the specified XAResource == this XAResource. - * - * @param xaResource the XAResource to test - * @return true if the specified XAResource == this XAResource; false otherwise - */ - public boolean isSameRM(XAResource xaResource) { - return this == xaResource; - } - - /** - * Clears the currently associated transaction if it is the specified xid. - * - * @param xid the id of the transaction to forget - */ - public synchronized void forget(Xid xid) { - if (xid != null && this.currentXid.equals(xid)) { - this.currentXid = null; - } - } - - /** - * Always returns a zero length Xid array. The LocalXAConnectionFactory can not support recovery, so no xids - * will ever be found. - * - * @param flag ignored since recovery is not supported - * @return always a zero length Xid array. - */ - public Xid[] recover(int flag) { - return new Xid[0]; - } - - /** - * Always returns 0 since we have no way to set a transaction timeout on a JDBC connection. - * - * @return always 0 - */ - public int getTransactionTimeout() { - return 0; - } - - /** - * Always returns false since we have no way to set a transaction timeout on a JDBC connection. - * - * @param transactionTimeout ignored since we have no way to set a transaction timeout on a JDBC connection - * @return always false - */ - public boolean setTransactionTimeout(int transactionTimeout) { - return false; - } - } - -} diff --git a/src/main/java/com/alibaba/druid/pool/xa/ManagedConnection.java b/src/main/java/com/alibaba/druid/pool/xa/ManagedConnection.java deleted file mode 100644 index dd170b5a5d..0000000000 --- a/src/main/java/com/alibaba/druid/pool/xa/ManagedConnection.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 1999-2011 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.druid.pool.xa; - -import java.sql.Connection; -import java.sql.SQLException; - -import com.alibaba.druid.pool.ConnectionHolder; -import com.alibaba.druid.pool.PoolableConnection; - -/** - * ManagedConnection is responsible for managing a database connection in a transactional environment (typically called - * "Container Managed"). A managed connection operates like any other connection when no global transaction (a.k.a. XA - * transaction or JTA Transaction) is in progress. When a global transaction is active a single physical connection to - * the database is used by all ManagedConnections accessed in the scope of the transaction. Connection sharing means - * that all data access during a transaction has a consistent view of the database. When the global transaction is - * committed or rolled back the enlisted connections are committed or rolled back. Typically upon transaction - * completion, a connection returns to the auto commit setting in effect before being enlisted in the transaction, but - * some vendors do not properly implement this. When enlisted in a transaction the setAutoCommit(), commit(), - * rollback(), and setReadOnly() methods throw a SQLException. This is necessary to assure that the transaction - * completes as a single unit. - * - * @author Dain Sundstrom - * @version $Revision$ - */ -@SuppressWarnings("unused") -public class ManagedConnection extends PoolableConnection { - - private final TransactionRegistry transactionRegistry; - private final boolean accessToUnderlyingConnectionAllowed; - private TransactionContext transactionContext; - private boolean isSharedConnection; - - public ManagedConnection(ConnectionHolder holder, TransactionRegistry transactionRegistry, boolean accessToUnderlyingConnectionAllowed) throws SQLException{ - super(holder); - this.transactionRegistry = transactionRegistry; - this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed; - updateTransactionStatus(); - } - - protected void checkOpen() throws SQLException { - super.checkOpen(); - updateTransactionStatus(); - } - - private void updateTransactionStatus() throws SQLException { - // // if there is a is an active transaction context, assure the transaction context hasn't changed - // if (transactionContext != null) { - // if (transactionContext.isActive()) { - // if (transactionContext != transactionRegistry.getActiveTransactionContext()) { - // throw new SQLException("Connection can not be used while enlisted in another transaction"); - // } - // return; - // } else { - // // transaction should have been cleared up by TransactionContextListener, but in - // // rare cases another lister could have registered which uses the connection before - // // our listener is called. In that rare case, trigger the transaction complete call now - // transactionComplete(); - // } - // } - // - // // the existing transaction context ended (or we didn't have one), get the active transaction context - // transactionContext = transactionRegistry.getActiveTransactionContext(); - // - // // if there is an active transaction context and it already has a shared connection, use it - // if (transactionContext != null && transactionContext.getSharedConnection() != null) { - // // A connection for the connection factory has already been enrolled - // // in the transaction, replace our delegate with the enrolled connection - // - // // return current connection to the pool - // Connection connection = getDelegateInternal(); - // setDelegate(null); - // if (connection != null) { - // try { - // pool.returnObject(connection); - // } catch (Exception ignored) { - // // whatever... try to invalidate the connection - // try { - // pool.invalidateObject(connection); - // } catch (Exception ignore) { - // // no big deal - // } - // } - // } - // - // // add a listener to the transaction context - // transactionContext.addTransactionContextListener(new CompletionListener()); - // - // // set our delegate to the shared connection - // setDelegate(transactionContext.getSharedConnection()); - // - // // remember that we are using a shared connection so it can be cleared after the - // // transaction completes - // isSharedConnection = true; - // } else { - // // if our delegate is null, create one - // if (getDelegateInternal() == null) { - // try { - // // borrow a new connection from the pool - // Connection connection = (Connection) pool.borrowObject(); - // setDelegate(connection); - // } catch (Exception e) { - // throw (SQLException) new SQLException("Unable to acquire a new connection from the pool").initCause(e); - // } - // } - // - // // if we have a transaction, out delegate becomes the shared delegate - // if (transactionContext != null) { - // // add a listener to the transaction context - // transactionContext.addTransactionContextListener(new CompletionListener()); - // - // // register our connection as the shared connection - // try { - // transactionContext.setSharedConnection(getDelegateInternal()); - // } catch (SQLException e) { - // // transaction is hosed - // transactionContext = null; - // throw e; - // } - // } - // } - throw new SQLException("TODO"); - } - - public void close() throws SQLException { - if (transactionContext == null) { - super.close(); - } - } - - /** - * Delegates to {@link ManagedConnection#transactionComplete()} for transaction completion events. - */ - protected class CompletionListener implements TransactionContextListener { - - public void afterCompletion(TransactionContext completedContext, boolean commited) { - if (completedContext == transactionContext) { - transactionComplete(); - } - } - } - - protected void transactionComplete() { - // transactionContext = null; - // - // // if we were using a shared connection, clear the reference now that the transaction has completed - // if (isSharedConnection) { - // // for now, just set the delegate to null, it will be created later if needed - // setDelegate(null); - // isSharedConnection = false; - // } - // - // // if this connection was closed during the transaction and there is still a delegate present close it - // Connection delegate = getDelegateInternal(); - // if (isClosed() && delegate != null) { - // try { - // setDelegate(null); - // - // // don't actually close the connection if in a transaction - // if (!delegate.isClosed()) { - // // don't use super.close() because it calls passivate() which marks the - // // the connection as closed without returning it to the pool - // delegate.close(); - // } - // } catch (SQLException ignored) { - // // not a whole lot we can do here as connection is closed - // // and this is a transaction callback so there is no - // // way to report the error - // } finally { - // _closed = true; - // } - // } - throw new RuntimeException("TODO"); - } - - // - // The following methods can't be used while enlisted in a transaction - // - - public void setAutoCommit(boolean autoCommit) throws SQLException { - if (transactionContext != null) { - throw new SQLException("Auto-commit can not be set while enrolled in a transaction"); - } - super.setAutoCommit(autoCommit); - } - - public void commit() throws SQLException { - if (transactionContext != null) { - throw new SQLException("Commit can not be set while enrolled in a transaction"); - } - super.commit(); - } - - public void rollback() throws SQLException { - if (transactionContext != null) { - throw new SQLException("Commit can not be set while enrolled in a transaction"); - } - super.rollback(); - } - - public void setReadOnly(boolean readOnly) throws SQLException { - if (transactionContext != null) { - throw new SQLException("Read-only can not be set while enrolled in a transaction"); - } - super.setReadOnly(readOnly); - } - - // - // Methods for accessing the delegate connection - // - - /** - * If false, getDelegate() and getInnermostDelegate() will return null. - * - * @return if false, getDelegate() and getInnermostDelegate() will return null - */ - public boolean isAccessToUnderlyingConnectionAllowed() { - return accessToUnderlyingConnectionAllowed; - } - - @Deprecated - public Connection getDelegate() { - if (isAccessToUnderlyingConnectionAllowed()) { - return getRawConnection(); - } else { - return null; - } - } - - @Deprecated - public Connection getInnermostDelegate() { - if (isAccessToUnderlyingConnectionAllowed()) { - return getRawConnection(); - } else { - return null; - } - } -} diff --git a/src/main/java/com/alibaba/druid/pool/xa/ManagedDataSource.java b/src/main/java/com/alibaba/druid/pool/xa/ManagedDataSource.java deleted file mode 100644 index d5b7939145..0000000000 --- a/src/main/java/com/alibaba/druid/pool/xa/ManagedDataSource.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 1999-2011 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.druid.pool.xa; - -import java.sql.Connection; -import java.sql.SQLException; - -/** - * The ManagedDataSource is a PoolingDataSource that creates ManagedConnections. - * - * @author Dain Sundstrom - * @version $Revision$ - */ -public class ManagedDataSource { - - private TransactionRegistry transactionRegistry; - - /** - * Creates an uninitialized datasource. Before this data source can be used a pool and transaction registry must be - * set. - */ - public ManagedDataSource(){ - } - - /** - * Creates a ManagedDataSource which obtains connections from the specified pool and manages them using the - * specified transaction registry. The TransactionRegistry must be the transaction registry obtained from the - * XAConnectionFactory used to create the connection pool. If not an error will occure when attempting to use the - * connection in a global transaction because the XAResource object associated with the connection will be - * unavailable. - * - * @param pool the connection pool - * @param transactionRegistry the transaction registry obtained from the XAConnectionFactory used to create the - * connection pool object factory - */ - public ManagedDataSource(TransactionRegistry transactionRegistry){ - this.transactionRegistry = transactionRegistry; - } - - /** - * Sets the transaction registry from the XAConnectionFactory used to create the pool. The transaction registry can - * only be set once using either a connector or this setter method. - * - * @param transactionRegistry the transaction registry acquired from the XAConnectionFactory used to create the pool - */ - public void setTransactionRegistry(TransactionRegistry transactionRegistry) { - if (this.transactionRegistry != null) throw new IllegalStateException("TransactionRegistry already set"); - if (transactionRegistry == null) throw new NullPointerException("TransactionRegistry is null"); - - this.transactionRegistry = transactionRegistry; - } - - public Connection getConnection() throws SQLException { - // if (_pool == null) throw new IllegalStateException("Pool has not been set"); - // if (transactionRegistry == null) throw new IllegalStateException("TransactionRegistry has not been set"); - // - // Connection connection = new ManagedConnection(_pool, transactionRegistry, - // isAccessToUnderlyingConnectionAllowed()); - // return connection; - throw new SQLException("TODO"); // TODO - } -} diff --git a/src/main/java/com/alibaba/druid/pool/xa/TransactionContext.java b/src/main/java/com/alibaba/druid/pool/xa/TransactionContext.java deleted file mode 100644 index e41c2c2d3f..0000000000 --- a/src/main/java/com/alibaba/druid/pool/xa/TransactionContext.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 1999-2011 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.druid.pool.xa; - -import javax.transaction.RollbackException; -import javax.transaction.Status; -import javax.transaction.Synchronization; -import javax.transaction.SystemException; -import javax.transaction.Transaction; -import javax.transaction.xa.XAResource; -import java.sql.Connection; -import java.sql.SQLException; -import java.lang.ref.WeakReference; - -/** - * TransactionContext represents the association between a single XAConnectionFactory and a Transaction. This context - * contains a single shared connection which should be used by all ManagedConnections for the XAConnectionFactory, the - * ability to listen for the transaction completion event, and a method to check the status of the transaction. - * - * @author Dain Sundstrom - * @version $Revision$ - */ -public class TransactionContext { - - private final TransactionRegistry transactionRegistry; - private final WeakReference transactionRef; - private Connection sharedConnection; - - /** - * Creates a TransactionContext for the specified Transaction and TransactionRegistry. The TransactionRegistry is - * used to obtain the XAResource for the shared connection when it is enlisted in the transaction. - * - * @param transactionRegistry the TransactionRegistry used to obtain the XAResource for the shared connection - * @param transaction the transaction - */ - public TransactionContext(TransactionRegistry transactionRegistry, Transaction transaction){ - if (transactionRegistry == null) throw new NullPointerException("transactionRegistry is null"); - if (transaction == null) throw new NullPointerException("transaction is null"); - this.transactionRegistry = transactionRegistry; - this.transactionRef = new WeakReference(transaction); - } - - /** - * Gets the connection shared by all ManagedConnections in the transaction. Specifically, connection using the same - * XAConnectionFactory from which the TransactionRegistry was obtained. - * - * @return the shared connection for this transaction - */ - public Connection getSharedConnection() { - return sharedConnection; - } - - /** - * Sets the shared connection for this transaction. The shared connection is enlisted in the transaction. - * - * @param sharedConnection the shared connection - * @throws SQLException if a shared connection is already set, if XAResource for the connection could not be found - * in the transaction registry, or if there was a problem enlisting the connection in the transaction - */ - public void setSharedConnection(Connection sharedConnection) throws SQLException { - if (this.sharedConnection != null) { - throw new IllegalStateException("A shared connection is alredy set"); - } - - // This is the first use of the connection in this transaction, so we must - // enlist it in the transaction - Transaction transaction = getTransaction(); - try { - XAResource xaResource = transactionRegistry.getXAResource(sharedConnection); - transaction.enlistResource(xaResource); - } catch (RollbackException e) { - // transaction was rolled back... proceed as if there never was a transaction - } catch (SystemException e) { - throw (SQLException) new SQLException("Unable to enlist connection the transaction").initCause(e); - } - - this.sharedConnection = sharedConnection; - } - - /** - * Adds a listener for transaction completion events. - * - * @param listener the listener to add - * @throws SQLException if a problem occurs adding the listener to the transaction - */ - public void addTransactionContextListener(final TransactionContextListener listener) throws SQLException { - try { - getTransaction().registerSynchronization(new Synchronization() { - - public void beforeCompletion() { - } - - public void afterCompletion(int status) { - listener.afterCompletion(TransactionContext.this, status == Status.STATUS_COMMITTED); - } - }); - } catch (RollbackException e) { - // JTA spec doesn't let us register with a transaction marked rollback only - // just ignore this and the tx state will be cleared another way. - } catch (Exception e) { - throw (SQLException) new SQLException("Unable to register transaction context listener").initCause(e); - } - } - - /** - * True if the transaction is active or marked for rollback only. - * - * @return true if the transaction is active or marked for rollback only; false otherwise - * @throws SQLException if a problem occurs obtaining the transaction status - */ - public boolean isActive() throws SQLException { - try { - Transaction transaction = (Transaction) this.transactionRef.get(); - if (transaction == null) { - return false; - } - int status = transaction.getStatus(); - return status == Status.STATUS_ACTIVE || status == Status.STATUS_MARKED_ROLLBACK; - } catch (SystemException e) { - throw (SQLException) new SQLException("Unable to get transaction status").initCause(e); - } - } - - private Transaction getTransaction() throws SQLException { - Transaction transaction = (Transaction) this.transactionRef.get(); - if (transaction == null) { - throw new SQLException("Unable to enlist connection because the transaction has been garbage collected"); - } - return transaction; - } -} diff --git a/src/main/java/com/alibaba/druid/pool/xa/TransactionContextListener.java b/src/main/java/com/alibaba/druid/pool/xa/TransactionContextListener.java deleted file mode 100644 index 3619f2b375..0000000000 --- a/src/main/java/com/alibaba/druid/pool/xa/TransactionContextListener.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 1999-2011 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.druid.pool.xa; - -/** - * A listener for transaction completion events. - * - * @author Dain Sundstrom - * @version $Revision$ - */ -public interface TransactionContextListener { - - /** - * Occurs after the transaction commits or rolls back. - * - * @param transactionContext the transaction context that completed - * @param commited true if the transaction committed; false otherwise - */ - void afterCompletion(TransactionContext transactionContext, boolean commited); -} diff --git a/src/main/java/com/alibaba/druid/pool/xa/TransactionRegistry.java b/src/main/java/com/alibaba/druid/pool/xa/TransactionRegistry.java deleted file mode 100644 index 0888005ca5..0000000000 --- a/src/main/java/com/alibaba/druid/pool/xa/TransactionRegistry.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 1999-2011 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.druid.pool.xa; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Map; -import java.util.WeakHashMap; - -import javax.transaction.Status; -import javax.transaction.SystemException; -import javax.transaction.Transaction; -import javax.transaction.TransactionManager; -import javax.transaction.xa.XAResource; - -/** - * TransactionRegistry tracks Connections and XAResources in a transacted environment for a single XAConnectionFactory. - *

The TransactionRegistry hides the details of transaction processing from the existing DBCP pooling code, and - * gives the ManagedConnection a way to enlist connections in a transaction, allowing for the maximal rescue of DBCP. - * - * @author Dain Sundstrom - * @version $Revision$ - */ -public class TransactionRegistry { - - private final TransactionManager transactionManager; - private final Map caches = new WeakHashMap(); - private final Map xaResources = new WeakHashMap(); - - /** - * Creates a TransactionRegistry for the specified transaction manager. - * - * @param transactionManager the transaction manager used to enlist connections - */ - public TransactionRegistry(TransactionManager transactionManager){ - this.transactionManager = transactionManager; - } - - /** - * Registers the association between a Connection and a XAResource. When a connection is enlisted in a transaction, - * it is actually the XAResource that is given to the transaction manager. - * - * @param connection the JDBC connection - * @param xaResource the XAResource which managed the connection within a transaction - */ - public synchronized void registerConnection(Connection connection, XAResource xaResource) { - if (connection == null) throw new NullPointerException("connection is null"); - if (xaResource == null) throw new NullPointerException("xaResource is null"); - xaResources.put(connection, xaResource); - } - - /** - * Gets the XAResource registered for the connection. - * - * @param connection the connection - * @return the XAResource registered for the connection; never null - * @throws SQLException if the connection does not have a registered XAResource - */ - public synchronized XAResource getXAResource(Connection connection) throws SQLException { - if (connection == null) throw new NullPointerException("connection is null"); - XAResource xaResource = (XAResource) xaResources.get(connection); - if (xaResource == null) { - throw new SQLException("Connection does not have a registered XAResource " + connection); - } - return xaResource; - } - - /** - * Gets the active TransactionContext or null if not Transaction is active. - * - * @return the active TransactionContext or null if not Transaction is active - * @throws SQLException if an error occurs while fetching the transaction - */ - public TransactionContext getActiveTransactionContext() throws SQLException { - Transaction transaction = null; - try { - transaction = transactionManager.getTransaction(); - - // was there a transaction? - if (transaction == null) { - return null; - } - - // is it active - int status = transaction.getStatus(); - if (status != Status.STATUS_ACTIVE && status != Status.STATUS_MARKED_ROLLBACK) { - return null; - } - } catch (SystemException e) { - throw (SQLException) new SQLException("Unable to determine current transaction ").initCause(e); - } - - // register the the context (or create a new one) - synchronized (this) { - TransactionContext cache = (TransactionContext) caches.get(transaction); - if (cache == null) { - cache = new TransactionContext(this, transaction); - caches.put(transaction, cache); - } - return cache; - } - } - - /** - * Unregisters a destroyed connection from {@link TransactionRegistry} - * - * @param connection - */ - public synchronized void unregisterConnection(Connection connection) { - xaResources.remove(connection); - } -} diff --git a/src/main/java/com/alibaba/druid/pool/xa/XAConnectionFactory.java b/src/main/java/com/alibaba/druid/pool/xa/XAConnectionFactory.java deleted file mode 100644 index d4e18a6027..0000000000 --- a/src/main/java/com/alibaba/druid/pool/xa/XAConnectionFactory.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 1999-2011 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.druid.pool.xa; - -import java.sql.Connection; -import java.sql.SQLException; - -import com.alibaba.druid.pool.ConnectionFactory; - -/** - * XAConnectionFactory is an extension of ConnectionFactory used to create connections in a transaction managed - * environment. The XAConnectionFactory opperates like a normal ConnectionFactory except an TransactionRegistry is - * provided from which the XAResource for a connection can be obtained. This allows the existing DBCP pool code to work - * with XAConnections and gives a the ManagedConnection a way to enlist a connection in the the transaction. - * - * @author Dain Sundstrom - * @author Rodney Waldhoff - * @version $Revision$ - */ -public interface XAConnectionFactory extends ConnectionFactory { - - /** - * Gets the TransactionRegistry for this connection factory which contains a the XAResource for every connection - * created by this factory. - * - * @return the transaction registry for this connection factory - */ - TransactionRegistry getTransactionRegistry(); - - /** - * Create a new {@link java.sql.Connection} in an implementation specific fashion.

An implementation can assume - * that the caller of this will wrap the connection in a proxy that protects access to the setAutoCommit, commit and - * rollback when enrolled in a XA transaction. - * - * @return a new {@link java.sql.Connection} - * @throws java.sql.SQLException if a database error occurs creating the connection - */ - Connection createConnection() throws SQLException; -} diff --git a/src/test/java/com/alibaba/druid/pool/TestOracle_DruidDataSource.java b/src/test/java/com/alibaba/druid/pool/TestOracle_DruidDataSource.java index ed5e40e7c0..ab6250db4f 100644 --- a/src/test/java/com/alibaba/druid/pool/TestOracle_DruidDataSource.java +++ b/src/test/java/com/alibaba/druid/pool/TestOracle_DruidDataSource.java @@ -35,8 +35,8 @@ public class TestOracle_DruidDataSource extends TestCase { dataSource.setFilters("stat"); dataSource.setExceptionSoter(OracleExceptionSorter.class.getName()); - final int COUNT = 100; - final int THREAD_COUNT = 1000; + final int COUNT = 100 * 100; + final int THREAD_COUNT = 10; final CountDownLatch startLatch = new CountDownLatch(1); final CountDownLatch endLatch = new CountDownLatch(THREAD_COUNT);