/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2005 Bull S.A.
 * Contact: jonas-team@objectweb.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas.jtests.clients.jdbcra;

import java.util.Enumeration;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import javax.transaction.UserTransaction;

import junit.framework.Test;
import junit.framework.TestSuite;

import org.objectweb.jonas.jtests.beans.jdbcra.JdbcRA1;
import org.objectweb.jonas.jtests.beans.jdbcra.JdbcRA1Home;
import org.objectweb.jonas.jtests.beans.jdbcra.JdbcRA2;
import org.objectweb.jonas.jtests.beans.jdbcra.JdbcRA2Home;
import org.objectweb.jonas.jtests.util.JTestCase;

/**
 * JdbcRa tests on Jdbc Resource Adapter
 */

public class F_JdbcRATest extends JTestCase {

    private static UserTransaction utx = null;

    static Context ctx = null;

    // Lookup bean home

    protected static String BEAN_HOME1 = "JdbcRA1EBRHome";
    protected static JdbcRA1Home ra1home = null;

    protected static String BEAN_HOME2 = "JdbcRA2EBRHome";
    protected static JdbcRA2Home ra2home = null;

    Enumeration ra1list;
    static JdbcRA1 ra1acc;

    Enumeration ra2list;
    static JdbcRA2 ra2acc;

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

    protected void setUp() {
        super.setUp();

	// Get InitialContext

        try {

	// get JNDI initial context

        if (ctx == null) {
	    ctx = new InitialContext();
        }

	// We want to start transactions from client: get UserTransaction

        if (utx == null) {
	    utx = (UserTransaction) ctx.lookup("javax.transaction.UserTransaction");
        }

        if (ra1home == null && ra2home == null) {
	    useBeans("jdbcra", true);
        }

	// Connecting to ra1transHome thru JNDI

        if (ra1home == null) {
	    ra1home = (JdbcRA1Home)PortableRemoteObject.narrow(
							    ctx.lookup(BEAN_HOME1),
							    JdbcRA1Home.class);
        }

	// Connecting to ra2Home thru JNDI

        if (ra2home == null) {
	    ra2home = (JdbcRA2Home)PortableRemoteObject.narrow(
							    ctx.lookup(BEAN_HOME2),
							    JdbcRA2Home.class);
        }

        assertTrue (5 == 5);

	} catch (Exception e) {
	    fail("Cannot lookup UserTransaction in setUp: " +e);
        }
    }

    public void testRaCleanUpCommit() {

	// Clean up databases just in case there was a failure
        // in an earlier execution of these tests

        ra1acc = null;
        ra2acc = null;
        int dlaccno;

        try {

	    utx.begin();

	    // Removing accounts 201-205, 209 from First database

	    // Getting the list of existing accounts in First database

	    ra1list = ra1home.findAllAccounts();

	    while (ra1list.hasMoreElements()) {
                ra1acc = (JdbcRA1) ra1list.nextElement();
                dlaccno = ra1acc.getNumber();

                if ((dlaccno >= 201 && dlaccno <= 205) || dlaccno == 209) {
                    ra1acc.remove();
                }
            }

	    // Getting the list of existing accounts in Second database

	    ra2list = ra2home.findAllAccounts();

	    while (ra2list.hasMoreElements()) {
                ra2acc = (JdbcRA2) ra2list.nextElement();
                dlaccno = ra2acc.getNumber();

                if ((dlaccno >= 201 && dlaccno <= 205) || dlaccno == 209) {
                    ra2acc.remove();
                }
	    }

	    utx.commit();

            assertTrue (5 == 5);

	} catch (Exception e) {
            // Not an error, accounts previously removed by last test
            try {
                 utx.rollback();
            }
            catch (Exception f) {
                 assertTrue (5 == 5);
            }
	    assertTrue (5 == 5);
	}
    }

    public void testRaBatchInsert() {

	// Store five accounts using executeBatch

        ra1acc = null;
        ra2acc = null;

        String str1 = null;
        String str2 = null;

        try {

	    utx.begin();

	    // Store accounts 201-205 in First database

	    ra1acc = ra1home.create();

	    // Store accounts 201-205 in Second database

	    ra2acc = ra2home.create();

	    // Find account 203 created in First database

	    ra1acc = ra1home.findByNumber(203);

	    // Find account 203 created in Second database

	    ra2acc = ra2home.findByNumber(203);

	    utx.commit();

            assertEquals (String.valueOf(ra1acc.getBalance()),
                          String.valueOf(ra2acc.getBalance()));

	} catch (Exception e) {

            try {
                 utx.rollback();
	         fail("Cannot store accounts using batch" +e);

            }
            catch (Exception f) {
                 fail("Cannot rollback testRaBatchInsert: " +f);
            }
	}
    }

    public void testRaSelectAll() {

        try {

	    // List existing Accounts

	    utx.begin();

	    // Getting the list of existing accounts in First database

	    ra1list = ra1home.findAllAccounts();

	    while (ra1list.hasMoreElements()) {
                ra1acc = (JdbcRA1) PortableRemoteObject.narrow(ra1list.nextElement(), JdbcRA1.class);
            }

	    // Getting the list of existing accounts in Second database

	    ra2list = ra2home.findAllAccounts();

	    while (ra2list.hasMoreElements()) {
                ra2acc = (JdbcRA2) PortableRemoteObject.narrow(ra2list.nextElement(), JdbcRA2.class);
	    }

	    utx.commit();

            assertTrue (5 == 5);

	} catch (Exception e) {

            try {
                 utx.rollback();
                 fail("Cannot retrieve all accounts: " +e);
            }
            catch (Exception f) {
                 fail("Cannot rollback testRaSelectAll: " +f);
            }
	}
    }

    public void testRaSelectOne() {

	// Find a second Account

	ra1acc = null;
        ra2acc = null;

        try {

	    // Finding an Account 202 in First database

	    ra1acc = ra1home.findByNumber(202);

	    // Finding an Account 202 in Second database

	    ra2acc = ra2home.findByNumber(202);

            assertEquals (ra1acc.getNumber(), ra2acc.getNumber());

	} catch (Exception e) {
	    fail("Cannot find account 202 " +e);
	}
    }

    public void testRaUpdateCommit() {

	// First transaction (committed):
	// transfert 100 from ra1acc to ra2acc

	// Starting a first transaction, that will be committed

        String str1 = null;
        String str2 = null;

	double value = 100;

        try {

	    utx.begin();

	    // Finding an Account 202 in First database

	    ra1acc = ra1home.findByNumber(202);

	    // Finding an Account 202 in Second database

	    ra2acc = ra2home.findByNumber(202);

	    // Deduct 100 from Account 202 in First database

	    ra1acc.setBalance(-value);

	    // Increment 100 to Account 202 in Second database

	    ra2acc.setBalance(value);

	    utx.commit();

            assertEquals (String.valueOf(ra1acc.getBalance() + 100),
                          String.valueOf(ra2acc.getBalance() - 100));

	} catch (Exception e) {

            try {
                 utx.rollback();
	         fail("Cannot update balance by 100 for account 202 " +e);

            }
            catch (Exception f) {
                 fail("Cannot rollback TestRaUpdateCommit: " +f);
            }
	}
    }

    public void testRaUpdateRollback() {

	// Start another transaction (rolled back):
	// transfert 20 from ra1acc to ra2acc

	// Starting a second transaction, that will be rolled back

        String str1 = null;
        String str2 = null;

	double value = 20;

        try {

	    utx.begin();

	    // Finding an Account 202 in First database

	    ra1acc = ra1home.findByNumber(202);

	    // Finding an Account 202 in Second database

	    ra2acc = ra2home.findByNumber(202);

	    // Deduct 20 from Account 202 in First database

	    ra1acc.setBalance(-value);

	    // Increment 20 to Account 202 in Second database

	    ra2acc.setBalance(value);

	    utx.rollback();

            assertEquals (String.valueOf(ra1acc.getBalance() + 100),
                          String.valueOf(ra2acc.getBalance() - 100));

	} catch (Exception e) {
            try {
                 utx.rollback();
	         fail("Cannot update balance by 20 for account 202 " +e);
            }
            catch (Exception f) {
                 fail("Cannot rollback testRaUpdateRollback: " +f);
            }
	}
    }

    public void testRaInsertCommit() {

	// Create a first Account

	ra1acc = null;
        ra2acc = null;

        try {

	    // Creating a new Account in First database

	    utx.begin();

	    ra1acc = ra1home.create(209, "John Smith", 100);

	    // Creating a new Account in Second database

	    ra2acc = ra2home.create(209, "John Smith", 100);

	    utx.commit();

            assertEquals (ra1acc.getNumber(), ra2acc.getNumber());

	} catch (Exception e) {
            try {
                 utx.rollback();
	         fail("Cannot create account 209: " +e);
            }
            catch (Exception f) {
                 fail("Cannot rollback testRaInsertCommit: " +f);
            }
	}
    }

    public void testRaInsertRollback() {

	// Create a first Account

	ra1acc = null;
        ra2acc = null;

        try {

	    // Creating a new Account in First database

	    utx.begin();

	    ra1acc = ra1home.create(210, "Mike Smith", 100);

	    // Creating a new Account in Second database

	    ra2acc = ra2home.create(210, "Mike Smith", 100);

	    utx.rollback();

	} catch (Exception e) {
            try {
                 utx.rollback();
	         fail("Cannot create account 210: " +e);
            }
            catch (Exception f) {
                 fail("Cannot rollback testRaInsertCommit: " +f);
            }
	}

        try {

            ra1acc = ra1home.findByNumber(210);
            assertTrue (5 == 6);

        }
        catch (Exception g) {
            // Okay should not find 210 in ra1acc

            try {
                ra2acc = ra2home.findByNumber(210);
                assertTrue (5 == 6);
            }
            catch (Exception h) {
                // Okay should not find 210 ins ra2acc
                assertTrue (5 == 5);
            }
        }
    }

    public void testRaDeleteRollback() {

	// Delete account

        ra1acc = null;
        ra2acc = null;

        try {

	    utx.begin();

	    // Removing account 201 previously created in First database

	    ra1acc = ra1home.findByNumber(201);
            ra1acc.remove();

	    // Removing account 201 previously created in Second database

	    ra2acc = ra2home.findByNumber(201);
            ra2acc.remove();

	    utx.rollback();

            utx.begin();

	    // Finding an Account 201 in First database

	    ra1acc = ra1home.findByNumber(201);

	    // Finding an Account 201 in Second database

	    ra2acc = ra2home.findByNumber(201);

            utx.commit();

            assertEquals (ra1acc.getNumber(), ra2acc.getNumber());

	} catch (Exception e) {
            try {
                 utx.rollback();
	         fail("Cannot delete accounts 201-205, 209: " +e);
            }
            catch (Exception f) {
                 fail("Cannot rollback testRaDeleteCommit: " +f);
            }
	}
    }

    public void testRaDeleteCommit() {

	// Delete account

        ra1acc = null;
        ra2acc = null;

        try {

	    utx.begin();

	    // Removing account 201-205 previously created in First database

	    ra1acc = ra1home.findByNumber(201);
            ra1acc.remove();
	    ra1acc = ra1home.findByNumber(202);
            ra1acc.remove();
	    ra1acc = ra1home.findByNumber(203);
            ra1acc.remove();
	    ra1acc = ra1home.findByNumber(204);
            ra1acc.remove();
	    ra1acc = ra1home.findByNumber(205);
            ra1acc.remove();
	    ra1acc = ra1home.findByNumber(209);
            ra1acc.remove();

	    // Removing account 201-205 previously created in Second database

	    ra2acc = ra2home.findByNumber(201);
            ra2acc.remove();
	    ra2acc = ra2home.findByNumber(202);
            ra2acc.remove();
	    ra2acc = ra2home.findByNumber(203);
            ra2acc.remove();
	    ra2acc = ra2home.findByNumber(204);
            ra2acc.remove();
	    ra2acc = ra2home.findByNumber(205);
            ra2acc.remove();
	    ra2acc = ra2home.findByNumber(209);
            ra2acc.remove();

	    utx.commit();

            assertTrue (5 == 5);

	} catch (Exception e) {
            try {
                 utx.rollback();
	         fail("Cannot delete accounts 201-205, 209: " +e);
            }
            catch (Exception f) {
                 fail("Cannot rollback testRaDeleteCommit: " +f);
            }
	}
    }

    public static Test suite() {
        TestSuite ts = new TestSuite();
        ts.addTest(new F_JdbcRATest("testRaCleanUpCommit"));
        ts.addTest(new F_JdbcRATest("testRaBatchInsert"));
        ts.addTest(new F_JdbcRATest("testRaSelectAll"));
        ts.addTest(new F_JdbcRATest("testRaSelectOne"));
        ts.addTest(new F_JdbcRATest("testRaUpdateCommit"));
        ts.addTest(new F_JdbcRATest("testRaUpdateRollback"));
        ts.addTest(new F_JdbcRATest("testRaInsertCommit"));
        ts.addTest(new F_JdbcRATest("testRaInsertRollback"));
        ts.addTest(new F_JdbcRATest("testRaDeleteRollback"));
        ts.addTest(new F_JdbcRATest("testRaDeleteCommit"));
        return ts;
    }

    public static void main (String args[]) {

        String testtorun = null;

        // Get args

        for (int argn = 0; argn < args.length; argn++) {

            String s_arg = args[argn];
            Integer i_arg;

            if (s_arg.equals("-n")) {
                testtorun = args[++argn];
            }
        }

        if (testtorun == null) {
            junit.textui.TestRunner.run(suite());
        } else {
            junit.textui.TestRunner.run(new F_JdbcRATest(testtorun));
        }
    }
}
