package org.mockejb.test;

import javax.jms.MessageListener;
import javax.naming.*;

import junit.framework.TestCase;

import org.mockejb.*;
import org.mockejb.interceptor.*;
import org.mockejb.jndi.*;


/**
 * Demonstrates MDB testing with MockEJB. 
 * This class provides an example of the integration test where session bean
 * sends a message to MDB and MDB calls another session bean. 
 * We use the capability of MockEJB JMS implementation to deliver messages 
 * synchronously to the receivers, so we don't need to mess with threads. 
 * This class relies on MockEJB and it won't run in the container. 
 *  
 * @author Alexander Ananiev
 * @author Dimitar Gospodinov
 */
public class MDBTest extends TestCase {

    // JNDI context and MockContainer instance used by all tests in this class  
    private MockContainer mockContainer;
    private Context context;    

    public MDBTest(String name) {
        super(name);
    }
    

    /**
     * Sets up our mock container, JNDI context and deploy the beans that we need.   
     */
    public void setUp() throws Exception  {

        // MockContextFactory becomes the primary JNDI provider            
        MockContextFactory.setAsInitial();
        context = new InitialContext();
        
        mockContainer = new MockContainer( context );
            
        // Create deployment descriptor of our sample session bean.
        // This session bean is used as a client for MDB.
        SessionBeanDescriptor sampleBeanDescriptor = 
            new SessionBeanDescriptor( SampleService.JNDI_NAME, 
            SampleServiceHome.class, SampleService.class, new SampleServiceBean() );
         
        mockContainer.deploy( sampleBeanDescriptor );
    }

    
    /**
     * Deploys MDB and uses session bean to send a message to MDB.
     */
    public void testMessageBean( ) throws Exception {
        
        /* Specify connection factory and destination that MDB will listen to.
         * We also provide an instance of MDB implementaion class.
         */
        MDBDescriptor sampleMDBDescriptor = 
            new MDBDescriptor( "SampleConnectionFactory", "SampleTopic", new SampleMessageBean() );
        // queue is the default, in this test we use topic
        sampleMDBDescriptor.setIsTopic( true );
        // This will create connection factory and destination, create MDB and set
        // it as the listener to the destination
        mockContainer.deploy( sampleMDBDescriptor );
        
        // We can bind the same MDB to the queue as well
        // Note that the connection factory must be different for queues and topics!
        mockContainer.deploy( new MDBDescriptor( "SampleQueueConnectionFactory", "SampleQueue", 
                new SampleMessageBean() ));
        
        /*
         * If you want to use some other JMS provider, you need to create the connection factory
         * and destination separately and bind them to JNDI directly. 
         * Here we use MockEJB JMS as an example, but in reality you can use mockrunner,
         * or any other JMS library (for this test though, the JMS provider must be synchronous). 
         */ 
        context.rebind( "AnotherSampleQueueConnectionFactory", new org.mockejb.jms.QueueConnectionFactoryImpl() );
        context.rebind( "AnotherSampleQueue", new org.mockejb.jms.MockQueue( "AnotherSampleQueue" ) );
        MDBDescriptor foreignProviderMDBDescriptor = 
            new MDBDescriptor( "AnotherSampleQueueConnectionFactory", "AnotherSampleQueue", 
                    new SampleMessageBean() );
        //Then method tell MockEJB not to create queues/factories
        foreignProviderMDBDescriptor.setIsAlreadyBound( true );
        mockContainer.deploy(foreignProviderMDBDescriptor);
        
        
        InvocationRecorder recorder = new InvocationRecorder();
        AspectSystem aspectSystem = AspectSystemFactory.getAspectSystem();
        // Set our custom interceptor so it would handle all calls to Sample interface (w/o subclasses)
        aspectSystem.add( new ClassPointcut( SampleService.class, false), recorder );        
        // Intercept MDB too
        aspectSystem.add( new ClassPointcut( MessageListener.class, false), recorder );        
        
        // Obtain the session bean
        SampleServiceHome sampleServiceHome = (SampleServiceHome)context.lookup( SampleService.JNDI_NAME );
        // create the bean
        SampleService sampleService = sampleServiceHome.create();
        
        // send messages        
        sampleService.sendMessage( "Test message" ); 

        // make sure that onMessage was called. 
        assertNotNull( recorder.findByTargetMethod( "SampleMessageBean.onMessage") );

        // validate the call to the session bean and its parameters 
        InvocationContext echoStringInvocation = recorder.findByTargetMethod( "echoString");
        // ok, it was indeed called
        assertNotNull(echoStringInvocation);
        // and the content of the message was indeed passed in            
        assertEquals( "Test message", echoStringInvocation.getParamVals()[0]);
        
    }
    
    
}