package example.org.seasar.framework.ejb.tx;

import java.rmi.RemoteException;
import java.util.List;

import javax.ejb.ApplicationException;
import javax.ejb.EJBException;

import org.aopalliance.intercept.MethodInvocation;
import org.seasar.extension.tx.DefaultTransactionCallback;
import org.seasar.extension.tx.TransactionManagerAdapter;
import org.seasar.extension.tx.TxRule;

/**
 * @author glad
 * @see org.seasar.framework.ejb.tx.EJB3TransactionCallback
 */
public class ExampleTransactionCallback extends DefaultTransactionCallback {

    @SuppressWarnings("unchecked")
    public ExampleTransactionCallback(
            MethodInvocation methodInvocation, List txRules) {
        super(methodInvocation, txRules);
    }

    @Override
    protected void applyTxRule(
            final TransactionManagerAdapter adapter, final Throwable t) {
        final ApplicationException annotation
                = getApplicationExceptionAnnotation(t);
        if (annotation != null) {
            if (annotation.rollback()) {
                adapter.setRollbackOnly();
            }
            return;
        }
        for (int i = 0; i < txRules.size(); ++i) {
            final TxRule rule = (TxRule) txRules.get(i);
            if (rule.isAssignableFrom(t)) {
                rule.complete(adapter);
                return;
            }
        }
        if (isRollingBack(t)) {
            adapter.setRollbackOnly();
            // TODO 仕様的にどう処理するのが正しいか?
            throw newEJBException("transaction rolledback", t);
        }
    }

    protected ApplicationException getApplicationExceptionAnnotation(
            final Throwable throwable) {
        final Class<? extends Throwable> exceptionClass = throwable.getClass();
        return exceptionClass.getAnnotation(ApplicationException.class);
    }

    protected boolean isRollingBack(final Throwable throwable) {
        if (throwable instanceof RemoteException) {
            return true;
        }
        if (throwable instanceof RuntimeException) {
            return true;
        }
        if (throwable instanceof Exception) {
            return false;
        }
        return true;
    }

    protected EJBException newEJBException(String message, Throwable cause) {
        EJBException e = new EJBException(message);
        e.initCause(cause);
        return e;
    }

}
