/*
 * JBoss, Home of Professional Open Source
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package org.jboss.cache.pojo.interceptors;

import org.jboss.aop.joinpoint.Invocation;
import org.jboss.aop.joinpoint.MethodInvocation;
import org.jboss.cache.pojo.PojoCacheException;

import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;

/**
 * Interceptor that handles registration of tx synchronization for rollback
 * operations.
 *
 * @author Ben Wang
 * @version $Id: PojoTxUndoSynchronizationInterceptor.java 3937 2007-05-30 06:08:03Z jgreene $
 */
public class PojoTxUndoSynchronizationInterceptor extends AbstractInterceptor
{
   // We stores the handler in thread local since the afterCompletion won't be
   // called untill tx.commit(). Note that this is static since it can be
   // recursive call to attach/detach.
   private static ThreadLocal synchronizationHandler_ = new ThreadLocal();

   public Object invoke(Invocation in) throws Throwable
   {
      if (!(in instanceof MethodInvocation))
      {
         throw new IllegalArgumentException("TxSyncrhonizationInterceptor.invoke(): invocation not MethodInvocation");
      }
      MethodInvocation invocation = (MethodInvocation) in;
      try
      {
         registerTxHandler(invocation);
         return invocation.invokeNext(); // proceed to next advice or actual call
      }
      finally
      {
      }
   }

   private void registerTxHandler(MethodInvocation invocation) throws PojoCacheException
   {
      try
      {
         // Need to have this in case of rollback
         PojoTxSynchronizationHandler handler = (PojoTxSynchronizationHandler) synchronizationHandler_.get();
         if (handler == null)
         {
            // First entry point for this transaction scope.
            Transaction tx = (Transaction) invocation.getMetaData(PojoTxInterceptor.TAG, PojoTxInterceptor.TX);
            if (tx == null)
            {
               throw new IllegalStateException("PojoCache.registerTxHanlder(). Can't have null tx handle.");
            }

            handler = new PojoTxSynchronizationHandler();

            log.debug("Registering PojoTxSynchronizationHandler for rollback if ncessary " + handler);
            // Register so we can rollback if necessary
            tx.registerSynchronization(handler);

            synchronizationHandler_.set(handler);
         }
      }
      catch (RollbackException e)
      {
         throw new PojoCacheException("PojoTxUndoSynchronizationInterceptor.registerTxHandler(): Exception: " + e);
      }
      catch (SystemException e)
      {
         throw new PojoCacheException("PojoTxUndoSynchronizationInterceptor.registerTxHandler(): Exception: " + e);
      }
   }

   public static PojoTxSynchronizationHandler getSynchronizationHandler()
   {
      return (PojoTxSynchronizationHandler) synchronizationHandler_.get();
   }

   public static void reset()
   {
      synchronizationHandler_.set(null);
   }
}
