Open Source Repository

Home /hibernate/hibernate-3.2.7.ga | Repository Home



org/hibernate/transaction/WebSphereExtendedJTATransactionLookup.java
//$Id: WebSphereExtendedJTATransactionLookup.java 14394 2008-03-06 17:03:03Z cbredesen $
package org.hibernate.transaction;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Properties;

import javax.naming.NamingException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.xa.XAResource;

import org.hibernate.HibernateException;
import org.hibernate.util.NamingHelper;

/**
 * TransactionManagerLookup implementation intended for use with WebSphere
 * Application Server (WAS).
 <p/>
 * WAS, unlike every other app server on the planet, does not allow direct
 * access to the JTS TransactionManager.  Instead, for common transaction-
 * related tasks users must utilize a proprietary API known as
 * ExtendedJTATransaction.
 <p/>
 * Even more unfortunate, the exact TransactionManagerLookup to use inside of
 * WAS is highly dependent upon (1) WAS version as well as (2) the WAS
 * container in which Hibernate will be utilized.
 <p/>
 * WebSphereExtendedJTATransactionLookup is reported to work on WAS version 6
 * in any of the standard J2EE/JEE component containers.
 *
 @author Gavin King
 @author <a href="mailto:[email protected]>Jesper Udby</a>
 */
public class WebSphereExtendedJTATransactionLookup implements TransactionManagerLookup {

  public TransactionManager getTransactionManager(Properties props) {
    return new TransactionManagerAdapterprops );
  }

  public String getUserTransactionName() {
    return "java:comp/UserTransaction";
  }

  public static class TransactionManagerAdapter implements TransactionManager {
    private final Properties properties;
    private final Class synchronizationCallbackClass;
    private final Method registerSynchronizationMethod;
    private final Method getLocalIdMethod;
    private Object extendedJTATransaction;

    private TransactionManagerAdapter(Properties propsthrows HibernateException {
      this.properties = props;
      try {
        synchronizationCallbackClass = Class.forName"com.ibm.websphere.jtaextensions.SynchronizationCallback" );
        Class extendedJTATransactionClass = Class.forName"com.ibm.websphere.jtaextensions.ExtendedJTATransaction" );
        registerSynchronizationMethod = extendedJTATransactionClass.getMethod(
            "registerSynchronizationCallbackForCurrentTran",
            new Class[] { synchronizationCallbackClass }
        );
        getLocalIdMethod = extendedJTATransactionClass.getMethod"getLocalId"null );

      }
      catch ClassNotFoundException cnfe ) {
        throw new HibernateExceptioncnfe );
      }
      catch NoSuchMethodException nsme ) {
        throw new HibernateExceptionnsme );
      }
    }

    public void begin() throws NotSupportedException, SystemException {
      throw new UnsupportedOperationException();
    }

    public void commit() throws UnsupportedOperationException {
      throw new UnsupportedOperationException();
    }

    public int getStatus() throws SystemException {
      return getTransaction() == null ? Status.STATUS_NO_TRANSACTION : getTransaction().getStatus();
    }

    public Transaction getTransaction() throws SystemException {
      return new TransactionAdapterproperties );
    }

    public void resume(Transaction txnthrows UnsupportedOperationException {
      throw new UnsupportedOperationException();
    }

    public void rollback() throws UnsupportedOperationException {
      throw new UnsupportedOperationException();
    }

    public void setRollbackOnly() throws UnsupportedOperationException {
      throw new UnsupportedOperationException();
    }

    public void setTransactionTimeout(int ithrows UnsupportedOperationException {
      throw new UnsupportedOperationException();
    }

    public Transaction suspend() throws UnsupportedOperationException {
      throw new UnsupportedOperationException();
    }

    public class TransactionAdapter implements Transaction {

      private TransactionAdapter(Properties props) {
        try {
          if extendedJTATransaction == null ) {
            extendedJTATransaction = NamingHelper.getInitialContextprops )
                .lookup"java:comp/websphere/ExtendedJTATransaction" );
          }
        }
        catch (NamingException ne) {
          throw new HibernateException(ne);
        }
      }

      public void registerSynchronization(final Synchronization synchronization)
          throws RollbackException, IllegalStateException,
          SystemException {

        final InvocationHandler ih = new InvocationHandler() {

          public Object invoke(Object proxy, Method method, Object[] argsthrows Throwable {
            if "afterCompletion".equalsmethod.getName() ) ) {
              int status = args[2].equals(Boolean.TRUE?
                  Status.STATUS_COMMITTED :
                  Status.STATUS_UNKNOWN;
              synchronization.afterCompletion(status);
            }
            else if "beforeCompletion".equalsmethod.getName() ) ) {
              synchronization.beforeCompletion();
            }
            else if "toString".equalsmethod.getName() ) ) {
              return synchronization.toString();
            }
            return null;
          }

        };

        final Object synchronizationCallback = Proxy.newProxyInstance(
            getClass().getClassLoader(),
            new Class[] { synchronizationCallbackClass },
            ih
          );

        try {
          registerSynchronizationMethod.invoke(
              extendedJTATransaction,
              new Object[] { synchronizationCallback }
            );
        }
        catch (Exception e) {
          throw new HibernateException(e);
        }

      }

      public int hashCode() {
        return getLocalId().hashCode();
      }

      public boolean equals(Object other) {
        if !(other instanceof TransactionAdapter) ) return false;
        TransactionAdapter that = (TransactionAdapterother;
        return getLocalId().equalsthat.getLocalId() );
      }

      private Object getLocalId() throws HibernateException {
        try {
          return getLocalIdMethod.invokeextendedJTATransaction, null );
        }
        catch Exception e ) {
          throw new HibernateException);
        }
      }

      public void commit() throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
      }

      public boolean delistResource(XAResource resource, int ithrows UnsupportedOperationException {
        throw new UnsupportedOperationException();
      }

      public boolean enlistResource(XAResource resourcethrows UnsupportedOperationException {
        throw new UnsupportedOperationException();
      }

      public int getStatus() {
        return new Integer(0).equalsgetLocalId() ) ?
            Status.STATUS_NO_TRANSACTION : Status.STATUS_ACTIVE;
      }

      public void rollback() throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
      }

      public void setRollbackOnly() throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
      }
    }

  }

}