package org.mockejb;
import java.io.Serializable;
import java.lang.reflect.Method;
import javax.naming.*;
import javax.transaction.*;
import javax.ejb.*;
import org.apache.commons.logging.*;
import org.mockejb.interceptor.*;
public class TransactionManager implements Interceptor, Serializable {
private static Log logger = LogFactory.getLog( TransactionManager.class.getName() );
public final static
String USER_TRANSACTION_JNDI="javax.transaction.UserTransaction";
public final static
String POLICY_CONTEXT_KEY="transactionPolicy";
private static UserTransaction sharedUserTransaction;
private TransactionPolicy policy = TransactionPolicy.SUPPORTS;
public TransactionManager( TransactionPolicy policy ){
super();
setPolicy( policy );
}
public TransactionManager( ){
super();
}
public TransactionPolicy getPolicy() {
return policy;
}
public void setPolicy( TransactionPolicy policy ) {
this.policy = policy;
}
public void intercept( InvocationContext invocationContext ) throws Exception {
UserTransaction newTran = null;
TransactionPolicy thisCallPolicy =
(TransactionPolicy) invocationContext.getOptionalPropertyValue( POLICY_CONTEXT_KEY );
if ( thisCallPolicy == null)
thisCallPolicy = this.policy;
Method method = invocationContext.getTargetMethod();
if ( handlePolicy( thisCallPolicy, invocationContext.getTargetObject(),
method, invocationContext.getParamVals() ) ) {
newTran = getUserTransaction();
log( method, "Begin transaction" );
newTran.begin();
}
try {
invocationContext.proceed();
commitOrRollback( newTran );
}
catch( Exception exception ) {
if ( MockContainer.isSystemException( exception )) {
if ( newTran != null && ( newTran.getStatus()==Status.STATUS_ACTIVE ||
newTran.getStatus()==Status.STATUS_MARKED_ROLLBACK ) ) {
newTran.rollback();
log( method, "Rollback because of system exception" );
}
}
else {
try {
commitOrRollback( newTran );
}
catch ( RollbackException rollbackEx ) {
logger.error(
"There has been rollback exception trying to rollback the transaction set for rollback. Ignoring. ", rollbackEx);
}
}
throw exception;
}
}
private void commitOrRollback( UserTransaction tran ) throws
SystemException, RollbackException, HeuristicMixedException,
HeuristicRollbackException {
if ( tran != null ) {
if ( tran.getStatus()==Status.STATUS_ACTIVE ) {
tran.commit();
log( "Committing transaction" );
}
else if ( tran.getStatus()==Status.STATUS_MARKED_ROLLBACK ) {
tran.rollback();
log( "Rollling back transaction" );
}
}
}
protected boolean handlePolicy( TransactionPolicy policy, Object targetObj,
Method method, Object[] args) throws SystemException, NamingException {
boolean newTranRequired = false;
if ( policy == TransactionPolicy.REQUIRED ){
UserTransaction tran = getUserTransaction();
newTranRequired=( tran == null ||
tran.getStatus()==Status.STATUS_NO_TRANSACTION ||
tran.getStatus()==Status.STATUS_COMMITTED ||
tran.getStatus()==Status.STATUS_ROLLEDBACK ||
tran.getStatus()==Status.STATUS_UNKNOWN );
}
else if ( policy == TransactionPolicy.REQUIRED_NEW ){
newTranRequired = true;
}
else if ( policy == TransactionPolicy.MANDATORY ){
UserTransaction tran = getUserTransaction();
if ( tran==null ||
tran.getStatus()==Status.STATUS_NO_TRANSACTION ||
tran.getStatus()==Status.STATUS_COMMITTED ||
tran.getStatus()==Status.STATUS_ROLLEDBACK ||
tran.getStatus()==Status.STATUS_UNKNOWN ) {
throw new TransactionRequiredLocalException(
"Attempt to invoke method with Mandatory policy without transaction context");
}
}
else if ( policy == TransactionPolicy.NEVER ){
UserTransaction tran = getUserTransaction();
if ( tran != null ||
tran.getStatus()==Status.STATUS_ACTIVE ) {
throw new EJBException(
"Attempt to invoke method with Never policy inside transaction context");
}
}
return newTranRequired;
}
public static UserTransaction getUserTransaction() {
UserTransaction userTransaction = null;
if ( sharedUserTransaction != null ) {
userTransaction = sharedUserTransaction;
}
else {
try {
Context context = new InitialContext();
userTransaction = (UserTransaction) context.lookup( USER_TRANSACTION_JNDI );
}
catch ( NamingException namingEx ){
throw new MockEjbSystemException(
"Errors while trying to obtain javax.transaction.UserTransaction from JNDI", namingEx );
}
}
return userTransaction;
}
public void setUserTransaction( UserTransaction userTransaction ) {
sharedUserTransaction = userTransaction;
}
private void log( Method method, String message ){
log( message+" for \n"+method );
}
protected void log( String message ){
logger.debug(message);
}
public boolean equals( Object obj ){
if ( ! (obj instanceof ClassPatternPointcut) )
return false;
TransactionManager transactionManager = (TransactionManager) obj;
return ( this.policy == transactionManager.policy );
}
public int hashCode() {
return policy.hashCode();
}
}