Package com.atomikos.jdbc

Source Code of com.atomikos.jdbc.ConnectionProxy

/**
* Copyright (C) 2000-2010 Atomikos <info@atomikos.com>
*
* This code ("Atomikos TransactionsEssentials"), by itself,
* is being distributed under the
* Apache License, Version 2.0 ("License"), a copy of which may be found at
* http://www.atomikos.com/licenses/apache-license-2.0.txt .
* You may not use this file except in compliance with the License.
*
* While the License grants certain patent license rights,
* those patent license rights only extend to the use of
* Atomikos TransactionsEssentials by itself.
*
* This code (Atomikos TransactionsEssentials) contains certain interfaces
* in package (namespace) com.atomikos.icatch
* (including com.atomikos.icatch.Participant) which, if implemented, may
* infringe one or more patents held by Atomikos.
* It should be appreciated that you may NOT implement such interfaces;
* licensing to implement these interfaces must be obtained separately from Atomikos.
*
* 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.
*/

package com.atomikos.jdbc;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.atomikos.datasource.TransactionalResource;
import com.atomikos.datasource.xa.XAResourceTransaction;
import com.atomikos.icatch.CompositeTransaction;
import com.atomikos.icatch.CompositeTransactionManager;
import com.atomikos.icatch.jta.TransactionManagerImp;
import com.atomikos.icatch.system.Configuration;
import com.atomikos.logging.Logger;
import com.atomikos.logging.LoggerFactory;

/**
*
*
*
*
*
* A dynamic proxy to allow external pooling, and also to allow late enlisting
* of resources with transactions.
*/

class ConnectionProxy implements InvocationHandler
{
  private static final Logger LOGGER = LoggerFactory.createLogger(ConnectionProxy.class);

  private final static List NON_TRANSACTIONAL_METHOD_NAMES = Arrays.asList(new String[] {
      "equals",
      "hashCode",
      "notify",
      "notifyAll",
      "toString",
      "wait"
      });



  static Set getAllImplementedInterfaces ( Class clazz )
    {
        Set ret = null;

        if ( clazz.getSuperclass() != null ) {
          //if superclass exists: first add the superclass interfaces!!!
          ret = getAllImplementedInterfaces ( clazz.getSuperclass() );
        }
        else {
          //no superclass: start with empty set
          ret = new HashSet();
        }

        //add the interfaces in this class
        Class[] interfaces = clazz.getInterfaces();
        for ( int i = 0 ; i < interfaces.length ; i++ ) {
          ret.add ( interfaces[i] );
        }

        return ret;
    }

    static Object newInstance ( DTPPooledConnection pc , java.sql.Connection c ,
            TransactionalResource resource ) throws SQLException
    {
        Object ret = null;

        ConnectionProxy proxy = new ConnectionProxy ( c, resource, pc );

        Set interfaces = getAllImplementedInterfaces ( c.getClass() );
        Class[] interfaceClasses = ( Class[] ) interfaces.toArray ( new Class[0] );
        ret = java.lang.reflect.Proxy.newProxyInstance ( c.getClass ()
                .getClassLoader (), interfaceClasses, proxy );

        return ret;
    }

    private Connection wrapped_;
    private TransactionalResource resource_;
    private DTPPooledConnection pc_;

    private ConnectionProxy ( Connection wrapped ,
            TransactionalResource resource , DTPPooledConnection pc )
    {
        wrapped_ = wrapped;
        resource_ = resource;
        pc_ = pc;
    }

    /**
     * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
     *      java.lang.reflect.Method, java.lang.Object[])
     */
    public Object invoke ( Object o , Method m , Object[] args )
            throws Throwable
    {
        if (NON_TRANSACTIONAL_METHOD_NAMES.contains(m.getName())) {
          if ( LOGGER.isDebugEnabled() ) LOGGER.logDebug ("Calling non-transactional method '" + m.getName() + "' on connection proxy, bypassing enlistment");
          return m.invoke ( wrapped_, args );
        }

        Object ret = null;
        XAResourceTransaction restx = null;
        CompositeTransaction ct = null;
        CompositeTransactionManager ctm = null;
        ctm = Configuration.getCompositeTransactionManager ();
        boolean inTx = false;
        // false if resume should be called (first invocation in tx)

        if ( ctm != null )
            ct = ctm.getCompositeTransaction ();

        inTx = pc_.isInResourceTransaction ();
        if ( ct != null && ct.getProperty TransactionManagerImp.JTA_PROPERTY_NAME ) != null && !pc_.isDiscarded () ) {
            // only enlist if there is a NORMAL tx
            // AND if the pc is not yet discarded (i.e. closed event
            // without a new getConnection() event)
            if ( !inTx ) {
                // not yet enlisted
                // IMPORTANT: we should enlist ONLY ONCE,
                // since we don't have wrappers for each
                // type of dependent object (statements,...)
                // where the real action is
                // Also, for the same reason we can only
                // delist at close time, since that is the
                // earliest detectable moment in time
                // when all these dependent objects are no
                // longer accessible.
                // VITAL ASSERTION FOR THIS TO WORK:
                // after close, the ResourceTransaction association
                // of the pooled connection MUST be null, or the
                // same restx will be reused in different
                // JTA transactions!
                restx = (XAResourceTransaction) resource_
                        .getResourceTransaction ( ct );
                pc_.setResourceTransaction ( restx );
                restx.resume ();
                LOGGER
                        .logDebug ( "JDBC ConnectionProxy: using resource transaction: "
                                + restx.getXid () );

            }

        }

        try {
            if ( LOGGER.isDebugEnabled() ) LOGGER.logDebug ( "JDBC ConnectionProxy: delegating "
                    + m.getName () + " to connection " + wrapped_.toString () );
//            if ("close".equals(m.getName())) {
//
//            }
            ret = m.invoke ( wrapped_, args );
        } catch ( InvocationTargetException i ) {
            pc_.setInvalidated ();
            pc_.close ();
            if ( LOGGER.isDebugEnabled() ) LOGGER.logDebug (
                    "Exception in pooled connection - closing it", i );
            AtomikosSQLException.throwAtomikosSQLException ( i.getMessage() , i );
        } catch ( Exception e ) {
            String msg = "Exception in pooled connection: unexpected error - closing it";
            LOGGER.logWarning ( msg, e );
            pc_.setInvalidated ();
            pc_.close ();
            AtomikosSQLException.throwAtomikosSQLException ( e.getMessage() , e );
        }

        return ret;

    }

}
TOP

Related Classes of com.atomikos.jdbc.ConnectionProxy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.