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.

Advertisements

5 Responses to “WebSphere UOW TransactionManagerLookup for Hibernate”


  1. 2 Peter
    May 30, 2010 at 2:29 pm

    Hi, nice effort and still pretty bad that Hibernate doesn’t have support for the UOWManaget as Spring does.
    However even this WebSphereUOWTransactionLookup still doesn’t bring the transaction suspend/resume to work which is quite problem if you perform updates/deletes on multiple tables etc. where Hibernate goes via utilization of temporary tables where you can easily get to the use of Hibernate Isolater which will attempt to suspend the current transaction and this never works with WebSphereExtendedJTATransactionLookup as well as with this WebSphereUOWTransactionLookup implementation.

    I think the http://opensource.atlassian.com/projects/hibernate/browse/HHH-5019 is pretty much about this.

    This would be great to have some solution for.

  2. 3 gonzalad
    March 6, 2013 at 8:40 am

    Hi rafaelri !

    Usefull post even after 3 years.
    I needed to update your class since I’m using Hibernate 4.0.1 (I had this error when using jBPM 5.4 with LocalTaskService and with CMT on WAS).

    To use it, I’ve this persistence.xml :

    org.hibernate.ejb.HibernatePersistence
    jdbc/Aws

    Here’s the update :

    package com.rfc.example.tx;

    import java.lang.reflect.Method;

    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.UserTransaction;
    import javax.transaction.xa.XAResource;

    import org.hibernate.HibernateException;
    import org.hibernate.service.jta.platform.internal.AbstractJtaPlatform;

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

    private static final long serialVersionUID = 6514686920271789210L;
    private static final String UOW_MANAGER_JNDI = “java:comp/websphere/UOWManager”;
    private static final String UOW_SYNCHRONIZATION_MANAGER_JNDI = “java:comp/websphere/UOWSynchronizationRegistry”;
    public static final String UT_NAME = “java:comp/UserTransaction”;

    @Override
    protected TransactionManager locateTransactionManager() {
    return new TransactionManagerAdapter();
    }

    @Override
    protected UserTransaction locateUserTransaction() {
    return (UserTransaction) jndiService().locate(UT_NAME);
    }

    public class TransactionManagerAdapter implements TransactionManager {

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

    private final Method getLocalIdMethod;

    @SuppressWarnings({ “unchecked”, “rawtypes” })
    private TransactionManagerAdapter() {
    try {
    uowManagerClass = Class.forName(“com.ibm.ws.uow.UOWManager”);
    setRollbackOnlyMethod = uowManagerClass.getMethod(
    “setRollbackOnly”, new Class[] {});

    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);
    }
    }

    /**
    * Lazily loaded because UOW_MANAGER_JNDI isn’t always available on
    * Hibernate startup (when
    * HibernatePersistence.createContainerEntityManagerFactory is called).
    */
    private Object getUowManager() {
    if (uowManager == null) {
    uowManager = jndiService().locate(UOW_MANAGER_JNDI);
    }
    return uowManager;
    }

    private Object getUowSynchronizationRegistry() {
    if (uowSynchronizationRegistry == null) {
    uowSynchronizationRegistry = jndiService().locate(UOW_SYNCHRONIZATION_MANAGER_JNDI);
    }
    return uowSynchronizationRegistry;
    }

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

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

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

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

    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(getUowManager(), 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() {
    extendedJTATransaction = jndiService().locate(
    “java:comp/websphere/ExtendedJTATransaction”);
    }

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

    try {
    registerSynchronizationMethod.invoke(
    getUowSynchronizationRegistry(),
    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(getUowManager(), new Object[] {});
    } catch (Exception e) {
    throw new HibernateException(e);
    }
    }
    }

    }

    /**
    * {@inheritDoc}
    */
    public Object getTransactionIdentifier(Transaction transaction) {
    // WebSphere, however, is not a sane JEE/JTA container…
    return new Integer(transaction.hashCode());
    }
    }


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


ClustrMaps

Blog Stats

  • 348,092 hits since aug'08

%d bloggers like this: