/** * Redistribution and use of this software and associated documentation * ("Software"), with or without modification, are permitted provided * that the following conditions are met: * * 1. Redistributions of source code must retain copyright * statements and notices. Redistributions must also contain a * copy of this document. * * 2. Redistributions in binary form must reproduce the * above copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. The name "Exolab" must not be used to endorse or promote * products derived from this Software without prior written * permission of Exoffice Technologies. For written permission, * please contact info@exolab.org. * * 4. Products derived from this Software may not be called "Exolab" * nor may "Exolab" appear in their names without prior written * permission of Exoffice Technologies. Exolab is a registered * trademark of Exoffice Technologies. * * 5. Due credit should be given to the Exolab Project * (http://www.exolab.org/). * * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved. * * $Id: ClientConnection.java,v 1.2 2002/04/21 03:03:46 mark_matthews Exp $ */ package com.mysql.jdbc.xa; import java.util.*; import java.sql.*; /** * Encapsulates an application's view of an XA/pooled connection. * The XA connection is managed by the application server through it's * {@link javax.sql.XAConnection} interface. The underlying JDBC * connection is a standard JDBC connection. The application's * JDBC connection gives access to the underlying JDBC connection but * is managed by the application server. The application is given an * instance of this class and not the underlying connection directly. * * * @author Assaf Arkin * @version 1.0 * @see XAConnectionImpl * @see XADataSourceImpl * @see Connection */ final class ClientConnection implements Connection { /** * The pooled XA connection that created this client connection * and should be used to report closure and fatal errors. */ private XAConnectionImpl _xaConn; /** * This identifier was handed on to use when we were created by * {@link XAConnection}. If since then the XA connection was asked * to create another connection or was closed, our identifier will * no longer be valid and any call to {@link * XAConnection#getUnderlying} will throw an exception. Previously, * the XA connection would hold a reference to use and tell us to * terminate, but that prevented ClientConnection from being * finalized. */ private int _clientId; /** * Construct a new client connection to provide access to the * underlying JDBC connection (underlying) on behalf of * an XA/pooled connection (xaConn). The pooled connection * is required to notify of connection closure and fatal errors. * * @param xaConn The XA/pooled connection that created this * client connection * @param clientId A unique identifier handed to us by * {@link XAConnection} * @param underlying The underlying JDBC connection */ ClientConnection( XAConnectionImpl xaConn, int clientId ) { _xaConn = xaConn; _clientId = clientId; } public Statement createStatement() throws SQLException { try { return getUnderlying().createStatement(); } catch ( SQLException except ) { notifyError( except ); throw except; } } public Statement createStatement( int resultSetType, int resultSetConcurrency ) throws SQLException { try { return getUnderlying().createStatement( resultSetType, resultSetConcurrency ); } catch ( SQLException except ) { notifyError( except ); throw except; } } public PreparedStatement prepareStatement( String sql ) throws SQLException { try { return getUnderlying().prepareStatement( sql ); } catch ( SQLException except ) { notifyError( except ); throw except; } } public PreparedStatement prepareStatement( String sql, int resultSetType, int resultSetConcurrency ) throws SQLException { try { return getUnderlying().prepareStatement( sql, resultSetType, resultSetConcurrency ); } catch ( SQLException except ) { notifyError( except ); throw except; } } public CallableStatement prepareCall( String sql ) throws SQLException { try { return getUnderlying().prepareCall( sql ); } catch ( SQLException except ) { notifyError( except ); throw except; } } public CallableStatement prepareCall( String sql, int resultSetType, int resultSetConcurrency ) throws SQLException { try { return getUnderlying().prepareCall( sql, resultSetType, resultSetConcurrency ); } catch ( SQLException except ) { notifyError( except ); throw except; } } public String nativeSQL( String sql ) throws SQLException { try { return getUnderlying().nativeSQL( sql ); } catch ( SQLException except ) { notifyError( except ); throw except; } } public DatabaseMetaData getMetaData() throws SQLException { try { return getUnderlying().getMetaData(); } catch ( SQLException except ) { notifyError( except ); throw except; } } public void setCatalog( String catalog ) throws SQLException { try { getUnderlying().setCatalog( catalog ); } catch ( SQLException except ) { notifyError( except ); throw except; } } public String getCatalog() throws SQLException { try { return getUnderlying().getCatalog(); } catch ( SQLException except ) { notifyError( except ); throw except; } } public SQLWarning getWarnings() throws SQLException { try { return getUnderlying().getWarnings(); } catch ( SQLException except ) { notifyError( except ); throw except; } } public void clearWarnings() throws SQLException { try { getUnderlying().clearWarnings(); } catch ( SQLException except ) { notifyError( except ); throw except; } } public Map getTypeMap() throws SQLException { try { return getUnderlying().getTypeMap(); } catch ( SQLException except ) { notifyError( except ); throw except; } } public void setTypeMap( Map map ) throws SQLException { try { getUnderlying().setTypeMap( map ); } catch ( SQLException except ) { notifyError( except ); throw except; } } public void setAutoCommit( boolean autoCommit ) throws SQLException { // Cannot set auto-commit inside a transaction. if ( _xaConn.insideGlobalTx() ) throw new SQLException( "Cannot commit/rollback a connection managed by the transaction manager" ); try { getUnderlying().setAutoCommit( autoCommit ); } catch ( SQLException except ) { notifyError( except ); throw except; } } public boolean getAutoCommit() throws SQLException { try { return getUnderlying().getAutoCommit(); } catch ( SQLException except ) { notifyError( except ); throw except; } } public void commit() throws SQLException { // Cannot commit directly if we're inside a global transaction. if ( _xaConn.insideGlobalTx() ) throw new SQLException( "Cannot commit/rollback a connection managed by the transaction manager" ); // Cannot commit a read-only transaction. if ( isReadOnly() ) throw new SQLException( "Cannot commit/rollback a read-only transaction" ); // This only occurs if not inside a local transaction. try { getUnderlying().commit(); } catch ( SQLException except ) { notifyError( except ); throw except; } } public void rollback() throws SQLException { // Cannot commit directly if we're inside a global transaction. if ( _xaConn.insideGlobalTx() ) throw new SQLException( "Cannot commit/rollback a connection managed by the transaction manager" ); // This only occurs if not inside a local transaction. try { getUnderlying().rollback(); } catch ( SQLException except ) { notifyError( except ); throw except; } } public void setReadOnly( boolean readOnly ) throws SQLException { try { getUnderlying().setReadOnly( readOnly ); } catch ( SQLException except ) { notifyError( except ); throw except; } } public boolean isReadOnly() throws SQLException { try { return getUnderlying().isReadOnly(); } catch ( SQLException except ) { notifyError( except ); throw except; } } public void setTransactionIsolation( int level ) throws SQLException { try { getUnderlying().setTransactionIsolation( level ); } catch ( SQLException except ) { notifyError( except ); throw except; } } public int getTransactionIsolation() throws SQLException { try { return getUnderlying().getTransactionIsolation(); } catch ( SQLException except ) { notifyError( except ); throw except; } } public synchronized void close() throws SQLException { if ( _xaConn == null ) return; // Notify the XA connection that we are no longer going // to be used. Whether the underlying connection is released, // held until the transaction terminates, etc is not // a concern of us. _xaConn.notifyClose( _clientId ); _xaConn = null; } public synchronized boolean isClosed() { // Simple way of determining if this connection is closed. // The actual connection is never closed, it is pooled. return ( _xaConn == null ); } /** * Called by {@link XAConnectionImpl} to terminate this connection * by dissociating it from the underlying JDBC connection. * The application would call {@link #close} but {@link * XAConnectionImpl} cannot, since pooled connection requirements * will cause an inifinite loop. This method should not attempt * to notify either a closure or fatal error, but rather throw an * exception if it fails. */ /* Deprecated: see XAConnection._clientId void terminate() { _xaConn = null; } */ protected void finalize() throws Throwable { close(); } public String toString() { try { return getUnderlying().toString(); } catch ( SQLException except ) { return "XAConnection: Connection closed"; } } /** * Called when an exception is thrown by the underlying connection * to determine whether the exception is critical or not. If the * exception is critical, notifies the XA connection to forget * about this connection. * * @param except The exception thrown by the underlying * connection */ void notifyError( SQLException except ) { if ( _xaConn != null ) _xaConn.notifyError( _clientId, except ); } /** * Called to retrieve the underlying JDBC connection. Actual JDBC * operations are performed against it. Throws an SQLException if * this connection has been closed. */ Connection getUnderlying() throws SQLException { if ( _xaConn == null ) throw new SQLException( "This connection has been closed" ); // Must pass the client identifier so XAConnection can determine // whether we are still valid. If it tells us we're no longer // valid, we have little to do. try { return _xaConn.getUnderlying( _clientId ); } catch ( SQLException except ) { _xaConn = null; throw except; } } }