/* JFox, the OpenSource J2EE Application Server
 *
 * Copyright (C) 2002 huihoo.com
 * Distributable under GNU LGPL license
 * See the GNU Lesser General Public License for more details.
 */

package org.jfox.ejb.plugin;

import java.util.Iterator;
import javax.transaction.NotSupportedException;
import javax.transaction.Status;
import javax.transaction.TransactionRequiredException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.ejb.SessionSynchronization;
import javax.ejb.EnterpriseBean;
import javax.ejb.EJBException;

import org.jfox.ejb.Bulk;
import org.jfox.ejb.Invocation;
import org.jfox.ejb.ContainerImpl;
import org.jfox.ejb.meta.SessionBeanDescriptor;
import org.jfox.ejb.meta.TransactionAttribute;
import org.jfox.ejb.EJBSynchronization;

/**
 *
 * @author <a href="mailto:young_yy@hotmail.com">Young Yang</a>
 */

public class T5_TransactionInvoker extends AbstractInvoker {
  private static TransactionManager tm = ContainerImpl.getInstance().getTransactionManager();

  public Object invokeBean(Bulk bulk, Invocation invocation, Iterator iter) throws Exception {
    logger.debug("invokeBean " + bulk + ", " + invocation);
    Transaction suspendedTrans = null;
    SessionBeanDescriptor meta = (SessionBeanDescriptor)bulk.getEJBDescriptor();

    // 事务同步
    EnterpriseBean bean = invocation.getBean();
    boolean isSync = bean instanceof SessionSynchronization ? true : false;
    if(isSync & meta.isStateless()) {
      throw new EJBException("only stateful session bean can implement javax.ejb.SessionSynchronization.");
    }

//    byte type = TransactionAttribute.getTransactionAttribute(meta.getTransactionType());
    byte type = meta.getMethodTransactionAttribute(invocation.getMethod());
    int status = tm.getStatus();

    /**
     * 由这个方法创建的事务,因为该方法可能集成其调用方法的事务,
     * 但是该方法不能 commit 该事务,而应该由其调用方法来 commit
     */
    boolean created = false;
    boolean toCommit = true;
    try {
      switch(type) {
        case TransactionAttribute.TX_NOT_SUPPORTED: {
          if(status != Status.STATUS_NO_TRANSACTION) {
            suspendedTrans = tm.suspend();
          }
          break;
        }
        case TransactionAttribute.TX_SUPPORTS: {
          break;
        }
        case TransactionAttribute.TX_REQUIRED: {
          if(status == Status.STATUS_NO_TRANSACTION) {
            tm.begin();
            // 事务同步
            if(isSync){
              EJBSynchronization ejbSync = new EJBSynchronization((SessionSynchronization)bean,tm.getTransaction());
              ejbSync.afterBegin();
            }
            created = true;
          }
          break;
        }
        case TransactionAttribute.TX_REQUIRES_NEW: {
          if(status != Status.STATUS_NO_TRANSACTION) {
            suspendedTrans = tm.suspend();
          }
          tm.begin();
          // 事务同步
          if(isSync){
            EJBSynchronization ejbSync = new EJBSynchronization((SessionSynchronization)bean,tm.getTransaction());
            tm.getTransaction().registerSynchronization(ejbSync);
            ejbSync.afterBegin();
          }
          created = true;
          break;
        }
        case TransactionAttribute.TX_MANDATORY: {
          if(status == Status.STATUS_NO_TRANSACTION) {
            throw new TransactionRequiredException("Transaction Required");
          }
          break;
        }
        case TransactionAttribute.TX_NEVER: {
          if(status != Status.STATUS_NO_TRANSACTION) {
            throw new NotSupportedException("Transaction Not Supported");
          }
          break;
        }
      }
      return super.invokeBean(bulk, invocation, iter);
    }
    catch(Exception e){
      toCommit = false;
      throw e;
    }
    finally {
      if(created == true) {
        if(toCommit) {
          tm.commit();
        }
        else {
          tm.rollback();
        }
      }
      else { // 如果没有新建事务,但是继承了事务并且当前线程抛出了异常,要标记当前事务为 rollback only
        if(toCommit == false && tm.getStatus() != Status.STATUS_NO_TRANSACTION) {
          tm.getTransaction().setRollbackOnly();
        }
      }
      if(suspendedTrans != null) {
        tm.resume(suspendedTrans);
      }
    }
  }

  public static void main(String[] args) {

  }
}