Posts Tagged ‘UOW

27
Jun
10

Hibernate Isolater.doIsolatedWork WebSphere compliant implementation based on UOWManager.runUnderUOW

Recently I decided to deepen my investigation upon Spring WebSphereUowTransactionManager. I always thought it was a shame Hibernate wasn’t fully supported under WebSphere and decided to investigate it a little more since I had the impression that after my first investigation that resulted in my first attempt of extending current hibernate transaction lookup for WebSphere it would take only a little more effort.

Considerations for the Implementation

The first decision taken for the implementation was that it should have no compile-time dependency upon WebSphere as Hibernate original TransactionManager and TransactionManagerLookup. This resulted in having all the calls to UOWManager and UOWSynchronizationRegistry using reflection and hence we needed to pass a UOWAction instance to UOWManager.runUnderUOW I chose to use a Java Dynamic Proxy.

Changes to Hibernate and Implementation

Since I didn’t want to embed another inner class into Isolater.java I made the Delegate interface public instead of private. The last trick was to return my delegate in place of JtaDelegate when configured for WebSphere. I sincerely feel like a factory was a better option over here but I didn’t take any time to investigate where to plug it. The resulting code for Isolater is show below:

	public static void doIsolatedWork(IsolatedWork work, SessionImplementor session) throws HibernateException {
		boolean isJta = session.getFactory().getTransactionManager() != null;
		if ( isJta ) {
			if (session.getFactory().getTransactionManager() instanceof UOWTransactionManagerAdapter)
				new WebSphereUOWDelegate(session).delegateWork(work, true);
			else
				new JtaDelegate( session ).delegateWork( work, true );
		}
		else {
			new JdbcDelegate( session ).delegateWork( work, true );
		}
	}

	public static void doNonTransactedWork(IsolatedWork work, SessionImplementor session) throws HibernateException {
		boolean isJta = session.getFactory().getTransactionManager() != null;
		if ( isJta ) {
			if (session.getFactory().getTransactionManager() instanceof UOWTransactionManagerAdapter)
				new WebSphereUOWDelegate(session).delegateWork(work, false);
			else
				new JtaDelegate( session ).delegateWork( work, false );
		}
		else {
			new JdbcDelegate( session ).delegateWork( work, false );
		}
	}

	public static interface Delegate {
		public void delegateWork(IsolatedWork work, boolean transacted) throws HibernateException;
	}

The resulting Isolater.Delegate implementation for WebSphere delegates the doTheWork to a method on UOWTransactionManagerAdapter that creates the UOWAction proxy and carries it on to UOWManager.

	private void doTheWork(IsolatedWork work, UOWTransactionManagerAdapter transactionManager, boolean transacted) {
		try {
			// obtain our isolated connection
			Connection connection = session.getFactory().getConnectionProvider().getConnection();
			try {
				// do the actual work
				if (transacted)
					transactionManager.doIsolatedWork(work, connection, false, true);
				else
					transactionManager.doIsolatedWork(work, connection, false, false);
			}
			catch ( HibernateException e ) {
				throw e;
			}
			catch ( Exception e ) {
				throw new HibernateException( "Unable to perform isolated work", e );
			}
			finally {
				try {
					// no matter what, release the connection (handle)
					session.getFactory().getConnectionProvider().closeConnection( connection );
				}
				catch ( Throwable ignore ) {
					log.info( "Unable to release isolated connection [" + ignore + "]" );
				}
			}
		}
		catch ( SQLException sqle ) {
			throw JDBCExceptionHelper.convert(
					sqlExceptionConverter(),
					sqle,
					"unable to obtain isolated JDBC connection"
			);
		}
	}

A class implementing InvocationHandler is responsible for delegating the UOWAction implementation to the Hibernate IsolatedWork

static class UOWInvocationHandler implements InvocationHandler {

private IsolatedWork work;
private Connection connection;

public UOWInvocationHandler(IsolatedWork work, Connection connection) {
super();
this.work = work;
this.connection = connection;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
work.doWork(connection);
return void.class;
}

}

Finally we have the doIsolatedWork method on UOWTransactionManagerAdapter

		public void doIsolatedWork(IsolatedWork work, Connection conn, boolean join, boolean global) throws SystemException, InvalidTransactionException, IllegalStateException {
			Object p = Proxy.newProxyInstance
	          (uowActionClass.getClassLoader(),
	                new Class[] { uowActionClass }, new UOWInvocationHandler(work, conn));
			try {
				runUnderUOWMethod.invoke(uowManager, new Object[]{global ? UOW_TYPE_GLOBAL_TRANSACTION : UOW_TYPE_LOCAL_TRANSACTION, Boolean.FALSE.booleanValue(),p});
			} catch (IllegalArgumentException e) {
				throw new HibernateException(e);
			} catch (IllegalAccessException e) {
				throw new HibernateException(e);
			} catch (InvocationTargetException e) {
				throw (HibernateException) e.getTargetException().getCause();
			}
		}

I still need to develop a test application for the Isolater.doNonTransactedWork method… if anyone knows how Hibernate triggers that flow and is willing to give a try, please let me know on the comments.
With a patched Hibernate you only need to configure the hibernate.cfg.xml with the following transaction.manager_lookup_class:

		   <property name="hibernate.transaction.manager_lookup_class">
		       org.hibernate.transaction.WebSphereUOWTransactionLookup
           </property>

I am providing a Diff for anyone willing to patch Hibernate and testing this implementation.

diff -r -d -N src/org/hibernate/engine/transaction/Isolater.java ..\..\hib-orig\src/org/hibernate/engine/transaction/Isolater.java
40d39
< import org.hibernate.transaction.WebSphereUOWTransactionLookup.UOWTransactionManagerAdapter;
68,71c67
< 			if (session.getFactory().getTransactionManager() instanceof UOWTransactionManagerAdapter)
< 				new WebSphereUOWDelegate(session).delegateWork(work, true);
< 			else
< 				new JtaDelegate( session ).delegateWork( work, true );
---
> 			new JtaDelegate( session ).delegateWork( work, true );
89,92c85
< 			if (session.getFactory().getTransactionManager() instanceof UOWTransactionManagerAdapter)
< 				new WebSphereUOWDelegate(session).delegateWork(work, false);
< 			else
< 				new JtaDelegate( session ).delegateWork( work, false );
---
> 			new JtaDelegate( session ).delegateWork( work, false );
103c96
< 	public static interface Delegate {
---
> 	private static interface Delegate {
diff -r -d -N src/org/hibernate/engine/transaction/WebSphereUOWDelegate.java ..\..\hib-orig\src/org/hibernate/engine/transaction/WebSphereUOWDelegate.java
1,89d0
< package org.hibernate.engine.transaction;
<
< import java.sql.Connection;
< import java.sql.SQLException;
<
< import org.hibernate.HibernateException;
< import org.hibernate.engine.SessionImplementor;
< import org.hibernate.engine.transaction.Isolater.Delegate;
< import org.hibernate.exception.JDBCExceptionHelper;
< import org.hibernate.exception.SQLExceptionConverter;
< import org.hibernate.transaction.WebSphereUOWTransactionLookup.UOWTransactionManagerAdapter;
< import org.slf4j.Logger;
< import org.slf4j.LoggerFactory;
<
< /**
<  * An isolation delegate for WebSphere UOW-based transactions.  Essentially calls UOW for
<  * suspending any current transaction, does the work in a new transaction, and then
<  * resumes the initial transaction (if there was one).
<  */
< public class WebSphereUOWDelegate implements Delegate {
< 	private static final Logger log = LoggerFactory.getLogger( Isolater.class );
<
< 	private final SessionImplementor session;
<
< 	public WebSphereUOWDelegate(SessionImplementor session) {
< 		this.session = session;
< 	}
<
< 	public void delegateWork(IsolatedWork work, boolean transacted) throws HibernateException {
< 		UOWTransactionManagerAdapter transactionManager = (UOWTransactionManagerAdapter) session.getFactory().getTransactionManager();
<
< 		// then peform the requested work
< 		if ( transacted ) {
< 			doTheWorkInNewTransaction( work, transactionManager );
< 		}
< 		else {
< 			doTheWorkInNoTransaction( work,  transactionManager);
< 		}
< 	}
<
< 	private void doTheWorkInNewTransaction(IsolatedWork work, UOWTransactionManagerAdapter transactionManager) {
< 		doTheWork( work , transactionManager, true);
< 	}
<
< 	private void doTheWorkInNoTransaction(IsolatedWork work, UOWTransactionManagerAdapter transactionManager) {
< 		doTheWork( work , transactionManager, false);
< 	}
<
< 	private void doTheWork(IsolatedWork work, UOWTransactionManagerAdapter transactionManager, boolean transacted) {
< 		try {
< 			// obtain our isolated connection
< 			Connection connection = session.getFactory().getConnectionProvider().getConnection();
< 			try {
< 				// do the actual work
< 				if (transacted)
< 					transactionManager.doIsolatedWork(work, connection, false, true);
< 				else
< 					transactionManager.doIsolatedWork(work, connection, false, false);
< 			}
< 			catch ( HibernateException e ) {
< 				throw e;
< 			}
< 			catch ( Exception e ) {
< 				throw new HibernateException( "Unable to perform isolated work", e );
< 			}
< 			finally {
< 				try {
< 					// no matter what, release the connection (handle)
< 					session.getFactory().getConnectionProvider().closeConnection( connection );
< 				}
< 				catch ( Throwable ignore ) {
< 					log.info( "Unable to release isolated connection [" + ignore + "]" );
< 				}
< 			}
< 		}
< 		catch ( SQLException sqle ) {
< 			throw JDBCExceptionHelper.convert(
< 					sqlExceptionConverter(),
< 					sqle,
< 					"unable to obtain isolated JDBC connection"
< 			);
< 		}
< 	}
<
< 	private SQLExceptionConverter sqlExceptionConverter() {
< 		return session.getFactory().getSQLExceptionConverter();
< 	}
<
< }
diff -r -d -N src/org/hibernate/transaction/WebSphereUOWTransactionLookup.java ..\..\hib-orig\src/org/hibernate/transaction/WebSphereUOWTransactionLookup.java
1,304d0
< package org.hibernate.transaction;
<
< import java.lang.reflect.InvocationHandler;
< import java.lang.reflect.InvocationTargetException;
< import java.lang.reflect.Method;
< import java.lang.reflect.Proxy;
< import java.sql.Connection;
< import java.util.Properties;
<
< import javax.naming.NamingException;
< import javax.transaction.HeuristicMixedException;
< import javax.transaction.HeuristicRollbackException;
< import javax.transaction.InvalidTransactionException;
< 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.engine.transaction.IsolatedWork;
< import org.hibernate.transaction.WebSphereUOWTransactionLookup.UOWTransactionManagerAdapter.UOWTransactionAdapter;
< import org.hibernate.util.NamingHelper;
<
< /**
<  * @author rafaelri Support for proprietary interfaces for registering
<  *         synchronizations in WebSphere 6.1+
<  */
< public class WebSphereUOWTransactionLookup implements TransactionManagerLookup {
<
< 	private static final String UOW_MANAGER_JNDI = "java:comp/websphere/UOWManager";
< 	private static final String UOW_SYNCHRONIZATION_MANAGER_JNDI = "java:comp/websphere/UOWSynchronizationRegistry";
<
< 	public TransactionManager getTransactionManager(Properties props)
< 			throws HibernateException {
< 		return new UOWTransactionManagerAdapter(props);
< 	}
<
< 	public String getUserTransactionName() {
< 		return "java:comp/UserTransaction";
< 	}
<
< 	public static class UOWTransactionManagerAdapter implements TransactionManager {
< 		private final Object uowManager;
< 		private final Class uowManagerClass;
< 		private final Object uowSynchronizationRegistry;
< 		private final Class uowSynchronizationRegistryClass;
< 		private final Class uowActionClass;
< 		private final Method registerSynchronizationMethod;
< 		private final Method setRollbackOnlyMethod;
< 		private final Method setUOWTimeoutMethod;
< 		private final Method getUOWTimeoutMethod;
< 		private final Method runUnderUOWMethod;
< 		public final int UOW_TYPE_GLOBAL_TRANSACTION;
< 		public final int UOW_TYPE_LOCAL_TRANSACTION;
<
< 		private final Properties properties;
< 		private final Method getLocalIdMethod;
<
< 		private UOWTransactionManagerAdapter(Properties props) {
< 			this.properties = props;
< 			try {
< 				uowManager = NamingHelper.getInitialContext(props).lookup(
< 						UOW_MANAGER_JNDI);
< 				uowManagerClass = Class.forName("com.ibm.wsspi.uow.UOWManager");
< 				setRollbackOnlyMethod = uowManagerClass.getMethod(
< 						"setRollbackOnly", new Class[] {});
< 				uowActionClass = Class.forName("com.ibm.wsspi.uow.UOWAction");
< 				runUnderUOWMethod = uowManagerClass.getMethod("runUnderUOW",
< 						new Class[] {int.class, boolean.class, uowActionClass});
< 				setUOWTimeoutMethod = uowManagerClass.getMethod(
< 						"setUOWTimeout", new Class[] { int.class, int.class });
< 				getUOWTimeoutMethod = uowManagerClass.getMethod(
< 						"getUOWTimeout", new Class[] {});
<
< 				uowSynchronizationRegistry = NamingHelper.getInitialContext(
< 						props).lookup(UOW_SYNCHRONIZATION_MANAGER_JNDI);
< 				uowSynchronizationRegistryClass = Class
< 						.forName("com.ibm.websphere.uow.UOWSynchronizationRegistry");
<
< 				UOW_TYPE_LOCAL_TRANSACTION = uowSynchronizationRegistryClass.getDeclaredField("UOW_TYPE_LOCAL_TRANSACTION").getInt(null);
<
< 				UOW_TYPE_GLOBAL_TRANSACTION = uowSynchronizationRegistryClass.getDeclaredField("UOW_TYPE_GLOBAL_TRANSACTION").getInt(null);
<
< 				registerSynchronizationMethod = uowSynchronizationRegistryClass
< 						.getMethod("registerInterposedSynchronization",
< 								new Class[] { Synchronization.class });
< 				getLocalIdMethod = uowSynchronizationRegistryClass.getMethod(
< 						"getLocalUOWId", new Class[] {});
<
< 			} catch (ClassNotFoundException cnfe) {
< 				throw new HibernateException(cnfe);
< 			} catch (NoSuchMethodException nsme) {
< 				throw new HibernateException(nsme);
< 			} catch (NamingException ne) {
< 				throw new HibernateException(ne);
< 			} catch (IllegalArgumentException e) {
< 				throw new HibernateException(e);
< 			} catch (SecurityException e) {
< 				throw new HibernateException(e);
< 			} catch (IllegalAccessException e) {
< 				throw new HibernateException(e);
< 			} catch (NoSuchFieldException e) {
< 				throw new HibernateException(e);
< 			}
< 		}
<
< 		public void doIsolatedWork(IsolatedWork work, Connection conn, boolean join, boolean global) throws SystemException, InvalidTransactionException, IllegalStateException {
< 			Object p = Proxy.newProxyInstance
< 	          (uowActionClass.getClassLoader(),
< 	                new Class[] { uowActionClass }, new UOWInvocationHandler(work, conn));
< 			try {
< 				runUnderUOWMethod.invoke(uowManager, new Object[]{global ? UOW_TYPE_GLOBAL_TRANSACTION : UOW_TYPE_LOCAL_TRANSACTION, Boolean.FALSE.booleanValue(),p});
< 			} catch (IllegalArgumentException e) {
< 				throw new HibernateException(e);
< 			} catch (IllegalAccessException e) {
< 				throw new HibernateException(e);
< 			} catch (InvocationTargetException e) {
< 				throw (HibernateException) e.getTargetException().getCause();
< 			}
< 		}
<
< 		public void begin() throws NotSupportedException, SystemException {
< 			throw new UnsupportedOperationException();
< 		}
<
< 		public void commit() throws RollbackException, HeuristicMixedException,
< 				HeuristicRollbackException, SecurityException,
< 				IllegalStateException, SystemException {
< 			throw new UnsupportedOperationException();
< 		}
<
< 		public int getStatus() throws SystemException {
< 			throw new UnsupportedOperationException();
< 		}
<
< 		public Transaction getTransaction() throws SystemException {
< 			return new UOWTransactionAdapter(properties);
< 		}
<
< 		public void resume(Transaction txn) throws InvalidTransactionException,
< 				IllegalStateException, SystemException {
< 			throw new UnsupportedOperationException();
< 		}
<
< 		public void rollback() throws IllegalStateException, SecurityException,
< 				SystemException {
< 			throw new UnsupportedOperationException();
< 		}
<
< 		public void setRollbackOnly() throws IllegalStateException,
< 				SystemException {
< 			try {
< 				setRollbackOnlyMethod.invoke(uowManager, new Object[] {});
< 			} catch (IllegalArgumentException e) {
< 				throw new RuntimeException(e);
< 			} catch (IllegalAccessException e) {
< 				throw new RuntimeException(e);
< 			} catch (InvocationTargetException e) {
< 				// is there any way to better handle this???
< 				if (e.getTargetException() instanceof IllegalStateException)
< 					throw ((IllegalStateException) e.getTargetException());
< 				else if (e.getTargetException() instanceof SystemException)
< 					throw ((SystemException) e.getTargetException());
< 				else
< 					throw new RuntimeException(e.getTargetException());
< 			}
< 		}
<
< 		public void setTransactionTimeout(int i) throws SystemException {
< 			try {
< 				setUOWTimeoutMethod.invoke(uowManager, new Object[] {
< 						UOW_TYPE_GLOBAL_TRANSACTION,
< 						i });
< 			} catch (IllegalArgumentException e) {
< 				throw new RuntimeException(e);
< 			} catch (IllegalAccessException e) {
< 				throw new RuntimeException(e);
< 			} catch (InvocationTargetException e) {
< 				// is there any way to better handle this???
< 				if (e.getTargetException() instanceof IllegalStateException)
< 					throw ((IllegalStateException) e.getTargetException());
< 				else if (e.getTargetException() instanceof SystemException)
< 					throw ((SystemException) e.getTargetException());
< 				else
< 					throw new RuntimeException(e.getTargetException());
< 			}
< 		}
<
< 		public Transaction suspend() throws SystemException {
< 			throw new UnsupportedOperationException();
< 		}
<
< 		public class UOWTransactionAdapter implements Transaction {
<
< 			private Object localId;
<
< 			private UOWTransactionAdapter(Properties props) {
< 				try {
< 					localId = getLocalIdMethod.invoke(
< 							uowSynchronizationRegistry, new Object[] {});
< 				} catch (Exception e) {
< 					throw new HibernateException(e);
< 				}
< 			}
<
< 			public void registerSynchronization(
< 					final Synchronization synchronization)
< 					throws RollbackException, IllegalStateException,
< 					SystemException {
<
< 				try {
< 					registerSynchronizationMethod.invoke(
< 							uowSynchronizationRegistry,
< 							new Object[] { synchronization });
< 				} catch (Exception e) {
< 					throw new HibernateException(e);
< 				}
<
< 			}
<
< 			public int hashCode() {
< 				return getLocalId().hashCode();
< 			}
<
< 			public boolean equals(Object other) {
< 				if (!(other instanceof UOWTransactionAdapter))
< 					return false;
< 				UOWTransactionAdapter that = (UOWTransactionAdapter) other;
< 				return getLocalId().equals(that.getLocalId());
< 			}
<
< 			private Object getLocalId() {
< 				return localId;
< 			}
<
< 			public void commit() throws RollbackException,
< 					HeuristicMixedException, HeuristicRollbackException,
< 					SecurityException, IllegalStateException, SystemException {
< 				throw new UnsupportedOperationException();
< 			}
<
< 			public boolean delistResource(XAResource resource, int i)
< 					throws IllegalStateException, SystemException {
< 				throw new UnsupportedOperationException();
< 			}
<
< 			public boolean enlistResource(XAResource resource)
< 					throws RollbackException, IllegalStateException,
< 					SystemException {
< 				throw new UnsupportedOperationException();
< 			}
<
< 			public int getStatus() throws SystemException {
< 				return new Integer(0).equals(getLocalId()) ? Status.STATUS_NO_TRANSACTION
< 						: Status.STATUS_ACTIVE;
< 			}
<
< 			public void rollback() throws IllegalStateException,
< 					SystemException {
< 				throw new UnsupportedOperationException();
< 			}
<
< 			public void setRollbackOnly() throws IllegalStateException,
< 					SystemException {
< 				try {
< 					setRollbackOnlyMethod.invoke(uowManager, new Object[] {});
< 				} catch (Exception e) {
< 					throw new HibernateException(e);
< 				}
< 			}
< 		}
<
< 	}
<
< 	public Object getTransactionIdentifier(Transaction txn) {
< 		if (!(txn instanceof UOWTransactionAdapter))
< 			throw new IllegalStateException("Invalid Transaction class");
< 		UOWTransactionAdapter tx = (UOWTransactionAdapter) txn;
< 		return tx.localId;
< 	}
<
< 	static class UOWInvocationHandler implements InvocationHandler {
<
< 		private IsolatedWork work;
< 		private Connection connection;
<
< 		public UOWInvocationHandler(IsolatedWork work, Connection connection) {
< 			super();
< 			this.work = work;
< 			this.connection = connection;
< 		}
< 		public Object invoke(Object proxy, Method method, Object[] args)
< 				throws Throwable {
< 			work.doWork(connection);
< 			return void.class;
< 		}
<
< 	}
<
< }
23
Jan
09

WebSphere UOW TransactionManagerLookup for Hibernate

For those interested in experimenting the latest Transaction Management API from WebSphere (available on newer 6.0 and 6.1 versions), I’ll place the code here of a draft implementation I made (partly based on original WebSphereExtendedTransactionLookup, WebSphere documentations [1][2][3][4] and Spring’s Transaction Manager for WAS).
I hope someday it gets integrated into Hibernate mainstream code but while it isn’t I’ll place here so more people may test it and improve it (reducing the burden over Hibernate team).

package org.hibernate.transaction;

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

import javax.naming.NamingException;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.InvalidTransactionException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.xa.XAResource;

import org.hibernate.HibernateException;
import org.hibernate.util.NamingHelper;
import org.omg.CORBA.SystemException;

/**
 * @author rafaelri
 * Support for proprietary interfaces for registering synchronizations in WebSphere 6.1+
 */
public class WebSphereUOWTransactionLookup implements TransactionManagerLookup {

	private static final String UOW_MANAGER_JNDI = "java:comp/websphere/UOWManager";
	private static final String UOW_SYNCHRONIZATION_MANAGER_JNDI = "java:comp/websphere/UOWSynchronizationRegistry";
	public TransactionManager getTransactionManager(Properties props)
	throws HibernateException {
		return new TransactionManagerAdapter(props);
	}

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

	public static class TransactionManagerAdapter implements TransactionManager {

		private final Object uowManager;
		private final Class uowManagerClass;
		private final Object uowSynchronizationRegistry;
		private final Class uowSynchronizationRegistryClass;
		private final Method registerSynchronizationMethod;
		private final Method setRollbackOnlyMethod;

		private final Properties properties;
		private final Method getLocalIdMethod;

		private TransactionManagerAdapter(Properties props) {
			this.properties = props;
			try {
				uowManager = NamingHelper.getInitialContext(props).lookup( UOW_MANAGER_JNDI );
				uowManagerClass = Class.forName("com.ibm.wsspi.uow.UOWManager");
				setRollbackOnlyMethod = uowManagerClass.getMethod(
						"setRollbackOnly",
						new Class[] {}
					);

				uowSynchronizationRegistry = NamingHelper.getInitialContext(props).lookup( UOW_SYNCHRONIZATION_MANAGER_JNDI );
				uowSynchronizationRegistryClass = Class.forName("com.ibm.websphere.uow.UOWSynchronizationRegistry");

				registerSynchronizationMethod = uowSynchronizationRegistryClass.getMethod(
						"registerInterposedSynchronization",
						new Class[] { Synchronization.class }
					);
				Class extendedJTATransactionClass = Class.forName("com.ibm.websphere.jtaextensions.ExtendedJTATransaction");
				getLocalIdMethod = extendedJTATransactionClass.getMethod( "getLocalId", null );

			}
			catch (ClassNotFoundException cnfe) {
				throw new HibernateException(cnfe);
			}
			catch (NoSuchMethodException nsme) {
				throw new HibernateException(nsme);
			} catch (NamingException ne) {
				throw new HibernateException(ne);
			}
		}

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

		public void commit() throws RollbackException, HeuristicMixedException,
				HeuristicRollbackException, SecurityException,
				IllegalStateException, SystemException {
			throw new UnsupportedOperationException();
		}

		public int getStatus() throws SystemException {
			throw new UnsupportedOperationException();
		}

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

		public void resume(Transaction txn) throws  InvalidTransactionException,
				IllegalStateException, SystemException {
			throw new UnsupportedOperationException();
		}

		public void rollback() throws IllegalStateException, SecurityException,
				SystemException {
			throw new UnsupportedOperationException();
		}

		public void setRollbackOnly() throws IllegalStateException,
				SystemException {
			try {
				setRollbackOnlyMethod.invoke(
					uowManager,
					new Object[] { }
				);
			}
			catch (Exception e) {
				throw new HibernateException(e);
			}
		}

		public void setTransactionTimeout(int i) throws SystemException {
			throw new UnsupportedOperationException();
		}

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

		public class TransactionAdapter implements Transaction {

			private final Object extendedJTATransaction;

			private TransactionAdapter(Properties props) {
				try {
					extendedJTATransaction = NamingHelper.getInitialContext(props)
						.lookup("java:comp/websphere/ExtendedJTATransaction");

				}
				catch (NamingException ne) {
					throw new HibernateException(ne);
				}
			}

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

				try {
					registerSynchronizationMethod.invoke(
							uowSynchronizationRegistry,
							new Object[] { synchronization }
						);
				}
				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 = (TransactionAdapter) other;
				return getLocalId().equals( that.getLocalId() );
			}

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

			public void commit() throws RollbackException, HeuristicMixedException,
					HeuristicRollbackException, SecurityException,
					IllegalStateException, SystemException {
				throw new UnsupportedOperationException();
			}

			public boolean delistResource(XAResource resource, int i)
					throws IllegalStateException, SystemException {
				throw new UnsupportedOperationException();
			}

			public boolean enlistResource(XAResource resource)
					throws RollbackException, IllegalStateException,
					SystemException {
				throw new UnsupportedOperationException();
			}

			public int getStatus() throws SystemException {
				return new Integer(0).equals( getLocalId() ) ?
						Status.STATUS_NO_TRANSACTION : Status.STATUS_ACTIVE;
			}

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

			public void setRollbackOnly() throws IllegalStateException,
					SystemException {
				try {
					setRollbackOnlyMethod.invoke(
						uowManager,
						new Object[] { }
					);
				}
				catch (Exception e) {
					throw new HibernateException(e);
				}
			}
		}

	}

}

Please, if you use it and find any bugs, comments or suggestions, leave a comment on this post.

Update:

I’ve recently improved this implementation to support the Isolater.Delegate interface on WebSphere anyone interested please take a look at this post.




ClustrMaps

Blog Stats

  • 353,165 hits since aug'08

%d bloggers like this: