/*
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.aspects.tx;

import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import org.jboss.aop.advice.Interceptor;
import org.jboss.aop.joinpoint.Invocation;

/**
 * This interceptor handles transactions for AOP
 *
 * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
 * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
 * @version $Revision: 1.4.2.4 $
 */
public class TxInterceptor
{
   public static class Never implements Interceptor
   {
      protected TransactionManager tm;
      protected TxPolicy policy;

      public Never(TransactionManager tm, TxPolicy policy)
      {
         this.tm = tm;
         this.policy = policy;
      }

      public Object invoke(Invocation invocation) throws Throwable
      {
         if (tm.getTransaction() != null)
         {
            throw new IllegalStateException("Transaction present on server in Never call");
         } // end of if ()
         return policy.invokeInNoTx(invocation);
      }

      public String getName()
      {
         return this.getClass().getName();
      }
   }

   public static class NotSupported implements Interceptor
   {
      protected TransactionManager tm;
      protected TxPolicy policy;

      public NotSupported(TransactionManager tm, TxPolicy policy)
      {
         this.tm = tm;
         this.policy = policy;
      }

      public Object invoke(Invocation invocation)
              throws Throwable
      {
         Transaction tx = tm.getTransaction();
         if (tx != null)
         {
            tm.suspend();
            try
            {
               return policy.invokeInNoTx(invocation);
            }
            finally
            {
               tm.resume(tx);
            }

         }
         else
         {
            return policy.invokeInNoTx(invocation);
         }
      }

      public String getName()
      {
         return this.getClass().getName();
      }
   }

   public static class Supports implements Interceptor
   {
      protected TransactionManager tm;
      protected TxPolicy policy;

      public Supports(TransactionManager tm, TxPolicy policy)
      {
         this.tm = tm;
         this.policy = policy;
      }

      public Object invoke(Invocation invocation) throws Throwable
      {
         if (tm.getTransaction() == null)
         {
            return policy.invokeInNoTx(invocation);
         }
         else
         {
            return policy.invokeInCallerTx(invocation, tm.getTransaction());
         }
      }

      public String getName()
      {
         return this.getClass().getName();
      }
   }

   public static class Required implements Interceptor
   {
      protected TransactionManager tm;
      protected TxPolicy policy;

      public Required(TransactionManager tm, TxPolicy policy)
      {
         this.tm = tm;
         this.policy = policy;
      }

      public Object invoke(Invocation invocation) throws Throwable
      {
         Transaction tx = tm.getTransaction();
         if (tx == null)
         {
            return policy.invokeInOurTx(invocation, tm);
         }
         else
         {
            return policy.invokeInCallerTx(invocation, tx);
         }
      }

      public String getName()
      {
         return this.getClass().getName();
      }
   }

   public static class RequiresNew implements Interceptor
   {
      protected TransactionManager tm;
      protected TxPolicy policy;

      public RequiresNew(TransactionManager tm, TxPolicy policy)
      {
         this.tm = tm;
         this.policy = policy;
      }

      public String getName()
      {
         return this.getClass().getName();
      }

      public Object invoke(Invocation invocation) throws Throwable
      {
         Transaction tx = tm.getTransaction();
         if (tx != null)
         {
            tm.suspend();
            try
            {
               return policy.invokeInOurTx(invocation, tm);
            }
            finally
            {
               tm.resume(tx);
            }
         }
         else
         {
            return policy.invokeInOurTx(invocation, tm);
         }
      }
   }

   public static class Mandatory implements Interceptor
   {
      protected TransactionManager tm;
      protected TxPolicy policy;

      public Mandatory(TransactionManager tm, TxPolicy policy)
      {
         this.tm = tm;
         this.policy = policy;
      }

      public String getName()
      {
         return this.getClass().getName();
      }

      public Object invoke(Invocation invocation) throws Throwable
      {
         Transaction tx = tm.getTransaction();
         if (tx == null)
         {
            policy.throwMandatory(invocation);
         }
         return policy.invokeInCallerTx(invocation, tx);
      }

   }
}
