package org.mockejb.test;

import java.util.Collection;

import javax.naming.*;
import com.mockrunner.mock.ejb.MockUserTransaction;

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

 * Demonstrates the use of JDBC and transactions with MockEJB. 
 * @author Alexander Ananiev
public class JdbcAndTransactionTest  extends OptionalCactusTestCase {

    // State of this test case. These variables are initialized by setUp method
    private SampleService sampleService;
    private SampleServiceHome sampleServiceHome;
    private Context context;

    // Aspect system used by this test
    private AspectSystem aspectSystem;

    private MockUserTransaction mockTransaction;

     * Constructor for JdbcTransactionTest.
     * @param name name of the test
    public JdbcAndTransactionTest(String name) {
     * Deploys and creates EJBs needed for our tests.
    public void setUp() throws Exception {

        aspectSystem =  AspectSystemFactory.getAspectSystem();
        // inside the app server use its InitialContext
        if ( isRunningOnServer() ) {
            context = new InitialContext( );
        // if the test runs outside of the app server
        else {
            // create the initial context that will be used for binding EJBs
            context = new InitialContext( );
            // Create an instance of the MockContainer
            MockContainer mockContainer = new MockContainer( context );

            /* Create deployment descriptor of our sample bean.
             * MockEjb does not support XML descriptors.
            SessionBeanDescriptor sampleBeanDescriptor = 
                new SessionBeanDescriptor( SampleService.JNDI_NAME, 
                SampleServiceHome.class, SampleService.class, SampleServiceBean.class );
            // Deploy operation simply creates Home and binds it to JNDI
            mockContainer.deploy( sampleBeanDescriptor );

            // StatelssSampleBean calls SampleHelperBean, so we need to deploy it too
            SessionBeanDescriptor helperBeanDescriptor = 
                new SessionBeanDescriptor( SampleServiceBean.HELPER_BEAN_JNDI_NAME, 
                SampleHelperHome.class, SampleHelper.class, SampleHelperBean.class );
            mockContainer.deploy( helperBeanDescriptor );

            /* Prepare the data source if we are not running in the app server.
             * We assume that the app server has the data source pre-configured.
             * You don't have to do it that way, the code will work in both cases, 
             * however it is "cleaner" to rely on the infrastructure provided by the 
             * app server for in-container testing. Also, the data source inside the 
             * app server may point to a completely different database. 

            // Instantiate DataSource implementation
            // You can use Jakarta DBCP
            //org.apache.commons.dbcp.BasicDataSource ds = new org.apache.commons.dbcp.BasicDataSource();
            // You can also use DataSource implementation that comes with MySQL driver
            com.mysql.jdbc.jdbc2.optional.MysqlDataSource ds = new com.mysql.jdbc.jdbc2.optional.MysqlDataSource();
            // Or, in case of Oracle driver:
            // oracle.jdbc.pool.OracleDataSource ds = oracle.jdbc.pool.OracleDataSource();
            // point to the database - we use the default MySql database.
            // add to the context
            context.rebind("java:comp/env/jdbc/SampleDataSource", ds);
            // we use MockTransaction outside of the app server            
            mockTransaction = new MockUserTransaction();
            context.rebind("javax.transaction.UserTransaction", mockTransaction );            

        // All EJBs are now deployed
        // To get the Sample bean we use the standard J2EE routine
        // Lookup the home
        SampleServiceHome sampleHome = (SampleServiceHome)context.lookup( SampleService.JNDI_NAME );
        // create the bean
        sampleService = sampleHome.create();


     * Performs the necessary cleanup by restoring the system properties that
     * were modified by MockContextFactory.setAsInitial().
     * This is needed in case if the test runs inside the container, so it would
     * not affect the tests that run after it.  
    public void tearDown() {

     * Tests EJB interaction with the database without transactions, i.e, 
     * the transactional policy is "Suppports".
    public void testJdbc() throws Exception {
        /* Read something from the database
         * We assume the existence of the "test_table" with a column "name".
        Collection values = sampleService.selectFromTable( "test_table", "name");
     * Demonstrates the use of transactions with MockEJB. 
     * Outside of the container, we use MockTransaction, inside we can rely on 
     * the real transaction support. Inside the container we can't really test much. 
    public void testTransactions() throws Exception {

        // it does not make sense to run this test on the server since we can't test much 
        if ( isRunningOnServer() ){
        // set our policy
        aspectSystem.add( new ClassPatternPointcut("org.mockejb.test"), 
            new TransactionManager( TransactionPolicy.REQUIRED ));
        Collection values = sampleService.selectFromTable( "test_table", "name");
        assertTrue( mockTransaction.wasBeginCalled() );
        assertTrue( mockTransaction.wasCommitCalled() );
        // Call the method that explicitly rolls back the transaction using ejb context        
        assertTrue( mockTransaction.wasBeginCalled() );
        assertTrue( mockTransaction.wasRollbackOnlyCalled() );
        assertTrue( mockTransaction.wasRollbackCalled() );

        // TODO: test other policies