Posts Tagged ‘WebSphere

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;
< 		}
<
< 	}
<
< }
21
Mar
10

Replacing Persistence Caching with In Memory DataGrids

Anyone that designed an enterprise system in Java with non-functional requirements that demanded tight response times faced the challenge of tuning the overall solution. If you are using Hibernate for persistence your first idea is to turn on Hibernate Caching but unfortunately it only Caches loads through Entity Id and sometimes you need to lookup through a secondary unique key. Another solution you might think is turning on Query Cache but as this post points out is more harmful to scalability and latency than you can ever imagine. Although Hibernate Docs and the post referenced above suggest that using @NaturalId annotation and Querying using Criteria API and a specially crafted Restriction through naturalId method would alleviate much of that problem it turns out that updates on related tables hugely undermines the improvements NaturalId queries may bring as this post suggest:

[…] Even though the objects are essentially static, the query cache takes the safe route and says any change to a related table invalidates any and all queries that reference that table. This makes sense, from a generic cache standpoint. […]

Source: Hibernate: Cache Queries the Natural Id Way
Add to this the fact that second level hibernate caches are data caches, not object caches so even on the best case of a cache miss you’d still have the cost of hydrating the object (as it is called on Hibernate terminology).

Object Caching

So, after giving up on all those previous attempts you’ll start considering taking the next obvious path: using/implementing an Object Caching. Have you noticed that I mentioned implementing? Yes, implementing. Now you’ll probably have to take care of the loading process in the case of cache misses, in fact you’ll be using a pattern called Side Caching.
But this can become a tedious code for maintaining and very prone to errors not to mention that implementing asynchronous write-behind won’t be an easy task.

In Memory DataGrids

Fortunately newer solutions marketed as In Memory DataGrids (or IMDG for short) provide an almost automagic way of plugging specially crafted classes that would be responsible for querying the underlying persistent storage on Cache misses, not to mention that they also provide improved partitioning and a great amount of other facilities usually not available on regular caches.
WebSphere eXtreme Scale Loaders and JBoss InfiniSpan CacheStore are examples of such specially crafted extensions for IMDGs. Those APIs also allow for updating the underlying storage (even asynchronously) with the changes that were passed to the in memory cache. One thing still missing (on different extents) on both solutions is the ability of querying the underlying store using a natural key. On eXtreme Scale there is already a framework for loading JPA entities but it lacks the ability of querying the underlying storage by anything different than the Cache Key that in those cases defaults to Entity Id (eXtreme Scale Query API is capable of querying the cache through any eXtreme Scale entity attribute but it only sees the data in memory). InfiniSpan on the other hand as of the 4.0.0 release does not provide anything similar to eXtreme Scale JPALoader or JPAEntityLoader it still sees the database (as on its JDBC Based CacheStore) as means of providing offloading and surviving reloads but never as means of querying data based on application defined format (eg.: application entities). Instead it uses its own format for storing data which limits its capability of loading from application storage in case of cache misses.

Querying IMDGs through Natural Keys

In summary, if you need to query through a natural key, in both cases you’ll need to roll your own Loader/CacheStore. And by querying through a natural key I mean something along the lines of what is described on Bill Burke’s EJB3 book:

The first way to define a primary-key class (and, for that matter, composite keys) is to use the @IdClass annotation. Your bean class
does not use this primary-key class internally, but it does use it to interact with the entity manager when finding a persisted object through
its primary key.
[…]
In your bean class, you designate one or more properties that make up your primary key, using the @Id annotation. These properties
must map exactly to properties in the @IdClass.

This way you can query the Cache using something in the lines of:

MyObjectNaturalKey key = new MyObjectNaturalKey("keyField1", "keyField2");
MyObject o = (MyObject) cache.get(key);

And you’ll have the guarantee that if this object exists either already on memory or in JPA EntityManager it’ll be returned.

Implementing a InfiniSpan CacheStore

Infinispan’s CacheStore interface has the following methods:

package org.infinispan.loaders;
public interface CacheStore extends CacheLoader {
   void store(InternalCacheEntry entry) throws CacheLoaderException;
   void fromStream(ObjectInput inputStream) throws CacheLoaderException;
   void toStream(ObjectOutput outputStream) throws CacheLoaderException;
   void clear() throws CacheLoaderException;
   boolean remove(Object key) throws CacheLoaderException;
   void removeAll(Set<Object> keys) throws CacheLoaderException;
   void purgeExpired() throws CacheLoaderException;
   void prepare(List<? extends Modification> modifications, GlobalTransaction tx, boolean isOnePhase) throws CacheLoaderException;
   void commit(GlobalTransaction tx) throws CacheLoaderException;
   void rollback(GlobalTransaction tx);
   public CacheStoreConfig getCacheStoreConfig();
}

If you need further explanation of what each method does, see its JavaDoc. InfiniSpan team suggests having a look on DummyInMemoryCacheStore in order to have a general idea of how should a CacheStore be implemented but still I have the feeling it misses an explanation of how InternalCacheEntries should be instantiated and in fact there is a factory class for it.
At last, if you need further information JBoss InfiniSpan Wiki has an overview of the builtin CacheStore classes.

Implementing an eXtreme Scale Loader

eXtreme Scale has plenty information on how to write a Loader as well. InfoCenter has two important pages: the first one presents a general overview on how to write a loader, the second one presents one important concept of eXtreme Scale: its tuples. If you implement a Loader that stores its data based on tuples you are free from having to have the stored classes (in case of custom application classes) in the same classloader as the container process.
WebSphere eXtreme Scale Wiki has a page dedicated to explaining how to write a Loader which presents the signature of a class that implements the Loader interface:

package com.ibm.websphere.objectgrid.plugins;
public interface Loader {
    static final SpecialValue KEY_NOT_FOUND;
    List get(TxID txid, List keyList, boolean forUpdate) throws LoaderException;
    void batchUpdate(TxID txid, LogSequence sequence) throws LoaderException, OptimisticCollisionException;
    void preloadMap(Session session, BackingMap backingMap) throws LoaderException;
}

Apart from the Wiki there’s a post on Billy New Port’s DevWebSphere blog
that has the source code available for what he calls the PureQuery Loader for eXtreme Scale. It is a loader capable of loading POJOs from SQL queries.
Finally if you need a starting guide for eXtreme Scale, have a look at ObjectGrid programming model guide and samples that although slighlty old is still a good starting guide for WebSphere eXtreme Scale.
Lastly I’d like to say that Packt Publishing book on eXtreme Scale is also a good reference for it.

05
Jan
10

Quartz Resource Adapter as an alternative to EJB Timers

Anyone developing a J2EE application probably faced the challenge of setting some fixed interval timers that need to be up upon application startup. This, in fact involves two challenges:

First one: J2EE provides no means of startup notification on EJB-Jars.

Second: EJB timers are persistent (they survive server restarts) and if you don’t cancel them upon application shutdown you’ll end up having lots of those timers.

So, wouldn’t it be fine if we had some mechanism of having a notification sent down from AppServer to our application in a timed manner? It’d be even better if we had some mechanism to specify the intervals using Unix Cron format.

Happily there is a simple solution: Quartz Resource Adapter from JBoss licensed as LGPL (as stated on its ra.xml) that makes it safely usable on commercial products. It comes packaged as a rar file on JBoss deploy directory as it seems to be used for JBoss internal purposes but nothing (or almost nothing) prevents you from using it into another AppServer.

By almost nothing I meant that as it is packaged on JBoss there is one quirk:

QuartzResourceAdapter.endpointActivation method does one trick to detect whether the endpoint configured is a stateless or stateful endpoint that renders it unusable on WebSphere for example (WebSphere prevents you from calling MessageEndpointFactory.createEndpoint from the Thread that invoked endpointActivation) and I am sincerely not sure whether this is something the spec enforces. I’ll paste the trick below:

 // allocate instance of endpoint to figure out its endpoint interface
      Class clazz = QuartzJob.class;
      MessageEndpoint tmpMe = endpointFactory.createEndpoint(null);
      if (tmpMe instanceof StatefulJob) clazz = StatefulQuartzJob.class;
      tmpMe.release();

And the best thing is that this trick can be safely replaced by two markup ActivationSpec classes, so we end up having the following code:

      // figure out endpoint interface through activationspec (WAS denies endpoint creation on main thread)
      Class clazz = null;
      if (spec instanceof QuartzStatelessActivationSpec) {
          clazz = QuartzJob.class;
      }
      else {
          clazz = StatefulQuartzJob.class;
      }

And the two markup classes:

package org.jboss.resource.adapter.quartz.inflow;

public class QuartzStatefulActivationSpec extends QuartzActivationSpec {

}
package org.jboss.resource.adapter.quartz.inflow;

public class QuartzStatelessActivationSpec extends QuartzActivationSpec {

}

And the ra.xml file for the RAR package gets changed from:

 <messagelistener>
               <messagelistener-type>org.quartz.Job</messagelistener-type>
               <activationspec>
                  <activationspec-class>org.jboss.resource.adapter.quartz.inflow.QuartzActivationSpec</activationspec-class>
                  <required-config-property>
                      <config-property-name>cronTrigger</config-property-name>
                  </required-config-property>
               </activationspec>
            </messagelistener>
            <messagelistener>
               <messagelistener-type>org.quartz.StatefulJob</messagelistener-type>
               <activationspec>
                  <activationspec-class>org.jboss.resource.adapter.quartz.inflow.QuartzActivationSpec</activationspec-class>
                  <required-config-property>
                      <config-property-name>cronTrigger</config-property-name>
                  </required-config-property>
               </activationspec>
            </messagelistener>

To:

 <messagelistener>
               <messagelistener-type>org.quartz.Job</messagelistener-type>
               <activationspec>
                  <activationspec-class>org.jboss.resource.adapter.quartz.inflow.QuartzStatelessActivationSpec</activationspec-class>
                  <required-config-property>
                      <config-property-name>cronTrigger</config-property-name>
                  </required-config-property>
               </activationspec>
            </messagelistener>
            <messagelistener>
               <messagelistener-type>org.quartz.StatefulJob</messagelistener-type>
               <activationspec>
                  <activationspec-class>org.jboss.resource.adapter.quartz.inflow.QuartzStatefulActivationSpec</activationspec-class>
                  <required-config-property>
                      <config-property-name>cronTrigger</config-property-name>
                  </required-config-property>
               </activationspec>
            </messagelistener>

Apart from this you’ll have to include jboss-common.jar (found on $JBOSS_HOME\lib) into the quartz-ra.rar file in the same level as quartz-ra.jar and quartz.jar.
Now you are done to install it into your application server and finally create your Activation Specs.
I am providing a PDF with Patched Quartz Resource Adapter for anyone willing to test on your preferred J2EE server and I also posted a message on JBoss AS Development forum to check whether they are interested in incorporating these changes.
Updates: It seems like this is going to get integrated into JBoss AS main code. I’ve submitted the patch as requested.

19
Dec
09

WebSphere eXtreme Scale 6 book

As already stated I’ve been invited to review WebSphere eXtreme Scale book from Packt Publishing. The book is an excellent choice for anyone interested in adopting WebSphere eXtreme Scale in a solution.

WebSphere eXtreme Scale

WebSphere eXtreme Scale Book

The book starts on chapter one with basic concepts about a data grid and ends up with a hello world like application.

On chapter two it starts to take a deeper dive into WebSphere eXtreme Scale concepts. The first one explored is the ObjectMap API which is composed by the ObjectMap and the BackingMap objects.

Chapter three is the one that specially took my attention since it presented me a feature I had no clue eXtreme Scale had: a JPA like implementation. This is one of the things that makes eXtreme Scale such a nice tool. By now you will probably be thinking: “but what is the difference of having this and eXtreme Scale acting as an ORM cache?”. In fact there’s a great deal of differences – first one: on an ORM solution you’re caching data that when “hydrated” (as Hibernate calls it – this article explains something about hibernate 2nd level cache) becomes objects, so, you still have the time lapse and the memory losses derived from hydrating objects on each request. Another major advantage is that ORM caches are usually invalidated upon some update scenarios which leads to reload of data.

Chapter four covers how to integrate a data grid with a database store. As the book states you’d need to integrate with a database backend to provide a richer and wider set of tools for report generation, to integrate with legacy application that still interact with database, etc.

Chapter five is dedicated to handling increased load. If you thought: “Do I still need to care about load increase?” the answer is “YES! For Sure!”. All and every software needs to be proper configured for increased load, by no means eXtreme Scale would be an exception and this chapter covers important topics of performing planning  for increased load.

Chapter six is devoted to keeping data available, so now it focus on replication and other important points.

Chapter seven (which is also freely available online) presents a rather different pattern of performing tasks in a distributed application – pushing the operation instead of pulling the data.

Chapter eight is dedicated to present some common patterns when using a data grid.

Chapter nine covers some facilities for Spring integration.

And finally chapter ten covers a complete example of a project that is built open eXtreme Scale.

One thing I’d like to see on the books next edition is the ability of replacing WebSphere’s Application Server DynaCache with an eXtreme Scale cache implementation. But it is no surprise for me that this was missing on book since they (the book and this feature) were released almost at the same time, invalidating any possibility of this being covered on the book.

In summary: this is a book I really recommend for anyone interested in picking a data grid solution for Java. It is also more recommended if you are already inclined to use an IBM solution and stick with eXtreme Scale.

16
Nov
09

WebSphere eXtreme Scale 6 book review

Anyone designing a high performance transaction processing system has already needed at least a caching solution for increasing response time on frequently used data. But sometimes these data might become bigger than usual, those are times when you need a sofisticate

WebSphere eXtreme Scale

WebSphere eXtreme Scale Book

solution, something that can automatically fetch data from a slower storage, offload when not necessary, split its contents between various nodes, …

If you require something like this then you’ll notice that you need a DataGrid solution.

By now you’ll be asking yourself why I am on that subject? Recently I’ve been kindly invited to review a book about IBM WebSphere eXtreme Scale from Packt Publishing.

Apart from this, I work on a project where we were already evaluating WebSphere eXtreme Scale as a replacement for WebSphere DynaCache.

If you are in a hurry and want to have a sneak peak on the book contents, take a look at the sample chapter (Chapter 7: “The DataGrid API”) available for free on Packt Publishing website.

03
May
09

WebSphere Concepts: Cell, Node, Cluster, Server…

Quick post… If you are not familiar with WebSphere at first you might get confused with its concepts: cell, deployment manager, node, node agent, cluster, server, …

First of all, lets start with the concept of a Cell:

A Cell is a virtual unit that is built of a Deployment Manager and one or more nodes. I guess a picture will help making things clearer:

WebSphere Cell

WebSphere Cell

But still there are a few concepts that need to be explained. The next obvious one is the Deployment Manager.

The Deployment Manager is a process (in fact it is an special WebSphere instance) responsible for managing the installation and maintenance of Applications, Connection Pools and other resources related to a J2EE environment. It is also responsible for centralizing user repositories for application and also for WebSphere authentication and authorization.

The Deployment Manager communicates with the Nodes through another special WebSphere process, the Node Agent.

The Node is another virtual unit that is built of a Node Agent and one or more Server instances.

The Node Agent it the process responsible for spawning and killing server processes and also responsible for configuration synchronization between the Deployment Manager and the Node. Extra care must be taken when changing security configurations for the cell, since communication between Deployment Manager and Node Agent is ciphered and secured when security is enabled, Node Agent needs to have configuration fully resynchronized when impacting changes are made to Cell security configuration.

Servers are regular Java process responsible for serving J2EE requests (eg.: serving JSP/JSF pages, serving EJB calls, consuming JMS queues, etc).

And to finish, Clusters are also virtual units that groups Servers so resources added to the Cluster are propagated to every Server that makes up the cluster, this will in fact affect usually more than a single Node instance.

Lets finish this post with another diagram to illustrate all those concepts.

WebSphere Concepts

WebSphere Concepts

28
Mar
09

WebSphere custom user repository

If you already used JBoss you probably used (or at least knew there is) the DatabaseServerLoginModule. But, if you happen to be using WebSphere things are a little bit different. WebSphere (I guess version 6 onwards) comes with the powerful concept of the federated repository. This feature allows multiples sources for authentication and authorization. The final layout inside WebSphere ressembles an LDAP tree, every Repository is suffixed with an identifier.

But, unfortunately, through the Web Administration interface you are limited to LDAP and the builtin FileBased WIM authentication.

Another thing that makes it even harder is that there isn’t much documentation about these extended repositories.

There is one post from IBM that suggests that there are alternatives:

The information used for the registry lookup is customizable and can be made totally flexible if a custom registry is developed using the WebSphere Application Server custom registry interface.

But still there isn’t a single link from this article that points out how to achieve this. If you get the key words in this phrase and risk a Google search you’d end up finding how to do this on WebSphere 4, that, by the way, was much limitted when compared to what is available on WebSphere 6.

Refining this search a little bit you’ll find what you are looking for, how to do this on WebSphere 6. But you’ll only take this approach if you are willing to roll your own adapter, but be advised that this tutorial won’t cover every steps you need and this is the content of another post. There is a complex interface that needs to be implemented in order to fulfill the requirements of an WebSphere Repository. The complexity is derived from the fact that all method in this interface is based on commonj.sdo.DataObject class and this class maps an XML to a Java Object hierarchy making for now this implementation almost a guessing game since there isn't much public information regarding this interface contract.

But, returning to the original objective of the post that was to guide on how to make WebSphere authenticate users against a database, setup the DBAdapter using the guide that is found on this page. If you want, check the list of WebSphere builtin adapters here.

The last step is to create the tables for the database as described on step 3 of this post. This post in fact describes various possibilities for user repositories available in WebSphere.

JBoss DatabaseServerLoginModule adantages over WebSphere approach are its simplicity and flexibility but on the other hand, WebSphere Federated Repositories present a much more robust approach for handling user databases.

I’ll try to post some tips on how to roll your own Repository in the next few days.




ClustrMaps

Blog Stats

  • 357,126 hits since aug'08

%d bloggers like this: