package org.mockejb;

import java.io.Serializable;
import java.rmi.RemoteException;

import javax.ejb.*;
import org.apache.commons.logging.*;

import org.mockejb.interceptor.*;

/**
 * Performs exception logging and chaining according to the
 * EJB spec. Wraps system exceptions in RemoteException or EJBException. 
 * All runtime and transaction-related exceptions are considered system exceptions.
 * 
 * @see MockContainer#isSystemException(Throwable)
 *  
 * @author Alexander Ananiev
 */
public class EjbExceptionHandler  implements Aspect, Serializable {

    // logger for this class
    private static Log logger = LogFactory.getLog( EjbExceptionHandler.class.getName() );


    /**
     * Intercepts all EJB methods.
     * @see org.mockejb.interceptor.Aspect#getPointcut()
     */
    public Pointcut getPointcut(){
        
        return PointcutPair.or( new ClassPointcut( EJBObject.class, true), 
                new ClassPointcut( EJBLocalObject.class, true) );
    }
 
    /**
     * Performs exception translation according to the ejb spec rules.
     */
    public void intercept( InvocationContext invocationContext ) throws Exception {
        
        try {
            invocationContext.proceed();
        }
        catch ( Exception exception ){
            
            if ( MockContainer.isSystemException( exception ) ) {
                // According to the spec we must log the exception
                logger.error("\nException during invocation of "+
                        invocationContext.getTargetMethod(), exception);
                //exception.printStackTrace();
                               
                // All system exceptions must be wrapped in remote exceptions for remote objects
                // here we can use the service provided by MockEjbContext to determine if the bean is remote or local
                MockEjbContext ejbContext = 
                    (MockEjbContext) invocationContext.getPropertyValue( MockEjbContext.class.getName() );
                
                if ( ejbContext.isRemote() && 
                    !(exception instanceof RemoteException ) ) {
                    
                    throw new RemoteException( "System Error", exception );
                }
                if ( ! ejbContext.isRemote() && !(exception instanceof EJBException )) {  
                    throw new EJBException( exception );
                }
            }
        
            throw exception;                     
            
        }
            
    }
    
    /**
     * This class does not have state, so all instances of this class
     * are considered equal
     */
    public boolean equals( Object obj ){
        
        if ( obj instanceof EjbExceptionHandler) 
            return true;
        else
            return false;
        
    }

    public int hashCode() { 
        return this.getClass().hashCode(); 
    }    
    
    

}