/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 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.entity;

import java.rmi.RemoteException;
import java.util.Enumeration;
import javax.ejb.CreateException;
import javax.ejb.DuplicateKeyException;
import javax.ejb.FinderException;
import javax.ejb.RemoveException;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.objectweb.jonas.jtests.beans.annuaire.Personne;
import org.objectweb.jonas.jtests.beans.annuaire.PersonneHome;
import org.objectweb.jonas.jtests.util.JTestCase;

/**
 * This is an advanced test suite for home interface on entity bean CMP.
 * Beans used: annuaire
 * @author Philippe Coq, Philippe Durieux (jonas team)
 */
public class F_AdvancedHomeInterface extends JTestCase {

    private static String BEAN_HOME = "annuairePersonneECHome";
    protected static PersonneHome ehome = null;
    String mynum = "638";
    String myname = "Philippe Durieux";

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

    protected void setUp() {
	super.setUp();
	if (ehome == null) {
	    useBeans("annuaire", true);
	    try {
		ehome = (PersonneHome) PortableRemoteObject.narrow(ictx.lookup(BEAN_HOME), PersonneHome.class);
	    } catch (NamingException e) {
		fail("Cannot get bean home");
	    }
	}
    }

    /**
     * test du findAll, returning an Enumeration.
     * Some of the beans are already in the database, some other are created.
     */
    public void testFindAllEnum() throws Exception {
	Enumeration enum = ehome.findAll();
	int count = 0;
	while (enum.hasMoreElements()) {
	    count++;
	    Personne p = (Personne) PortableRemoteObject.narrow(enum.nextElement(), Personne.class);
	}
	assertEquals(10, count);
	Personne p1 = ehome.create("Paul Morgan", "1234256");
	Personne p2 = ehome.create("Jean Richard", "1234356");
	Personne p3 = ehome.create("Jean-Paul Landry", "1234556");
	enum = ehome.findAll();
	count = 0;
	while (enum.hasMoreElements()) {
	    count++;
	    Personne p = (Personne) PortableRemoteObject.narrow(enum.nextElement(), Personne.class);
	}
	assertEquals(13, count);
	// cleaning
	p1.remove();
	p2.remove();
	p3.remove();
	enum = ehome.findAll();
	count = 0;
	while (enum.hasMoreElements()) {
	    count++;
	    Personne p = (Personne) PortableRemoteObject.narrow(enum.nextElement(), Personne.class);
	}
	assertEquals(10, count);
    }

    /**
     * test Create inside a Transaction.
     */
    public void testCreateInTx() throws Exception {
	utx.begin();
	ehome.create("Duke Ellington", "12235446");
	utx.commit();
	Personne p = ehome.findByNom("Duke Ellington");
	p.remove();
	utx.begin();
	ehome.create("Louis Armstrong", "12035446");
	utx.rollback();
	try {
	    ehome.findByNom("Louis Armstrong");
	    fail("Should not find it");
	} catch (FinderException e) {
	}
    }

    /**
     * test a simple Create inside a Transaction.
     */
    public void testSimpleCreateInTx() throws Exception {
	utx.begin();
	ehome.create("Mike", "12235846");
	utx.commit();
	Personne p = ehome.findByNom("Mike");
	p.remove();
    }

    /**
     * test a simple Remove
     * Find an instance already in database and remove it.
     */
    public void testSimpleRemove() throws Exception {
	Personne p = ehome.findByNom("Adriana Danes");
	p.remove();
	ehome.create("Adriana Danes", "777"); // cleaning
    }

    /**
     * Test Create + Business Method inside the same Tx
     */
    public void testCreateAndBusiness() throws Exception {
	String num = "00000001";
	Personne p = null;
	utx.begin();
	p = ehome.create("Lionel Hampton", "92235446");
	p.setNumero(num);
	utx.commit();
	assertTrue(num.equals(p.getNumero()));
	p.remove();		// cleaning
    }

    /**
     * Test remove(pk): create / find / remove(pk) / find
     */
    public void testRemovePk() throws Exception {
	Personne p = null;
	String newman = "Xavier Spengler";
	p = ehome.create(newman, "6");
	ehome.findByPrimaryKey(newman);
	ehome.remove(newman);
	try {
	    ehome.findByPrimaryKey(newman);
	    fail("Should not exist anymore");
	} catch (FinderException e) {
	}
    }

    /**
     * Test remove(pk) inside transaction: 
     * create / find / remove(pk) / find
     */
    public void testRemovePkInTx() throws Exception {
	Personne p = null;
	String newman = "Xavier Spengler";
	p = ehome.create(newman, "6");
	ehome.findByPrimaryKey(newman);
	utx.begin();
	ehome.remove(newman);
	utx.commit();
	try {
	    ehome.findByPrimaryKey(newman);
	    fail("Should not exist anymore");
	} catch (FinderException e) {
	}
    }

    /**
     * Test remove(pk) of a non-existent pk.
     */
    public void testRemovePkNonExistent() throws Exception {
	String man = "NonExistent";
	try {
	    ehome.remove(man);
	    fail("No RemoveException");
	} catch (RemoveException e) {
	}
    }

    /**
     * Test remove(pk) of a non-existent pk inside transaction.
     * (This is a knowned bug: TransactionRolledbackException instead of RemoveException)
     */
    public void testRemovePkNonExistentInTx() throws Exception {
	String man = "NonExistent";
	utx.begin();
	try {
	    ehome.remove(man);
	    fail("No RemoveException");
	} catch (RemoveException e) {
	} finally {
	    utx.commit();
	}
    }

    /**
     * Test bean.remove :
     * create / find / remove / find
     */
    public void testRemove() throws Exception {
	Personne p = null;
	String newman = "Jeannot";
	p = ehome.create(newman, "5");
	ehome.findByPrimaryKey(newman);
	p.remove();
	try {
	    ehome.findByPrimaryKey(newman);
	    fail("Should not exist anymore");
	} catch (FinderException e) {
	}
    }

    /**
     * Test bean.remove inside a tx:
     * create / find / remove / find
     */
    public void testRemoveInTx() throws Exception {
	Personne p = null;
	String newman = "Jeannot";
	p = ehome.create(newman, "5");
	ehome.findByPrimaryKey(newman);
	utx.begin();
	p.remove();
	utx.commit();
	try {
	    ehome.findByPrimaryKey(newman);
	    fail("Should not exist anymore");
	} catch (FinderException e) {
	}
    }

    /**
     * Test finder in transactions
     */
    public void testFinderInTx() throws Exception {
	Personne p = null;

	// FindByPrimaryKey
	for (int i = 0; i < 5; i++) {
	    utx.begin();
	    p = ehome.findByPrimaryKey(myname);
	    utx.commit();
	}
	assertTrue(p.getNumero().equals(mynum));

	// FindByNum
	for (int i = 0; i < 5; i++) {
	    utx.begin();
	    p = ehome.findByNom(myname);
	    utx.commit();
	}
	assertTrue(p.getNumero().equals(mynum));

	// FindAll
	for (int i = 0; i < 5; i++) {
	    utx.begin();
	    ehome.findAll();
	    utx.commit();
	}
    }

    /**
     * Test create + remove in transactions
     */
    public void testCreateRemoveInTx() throws Exception {
	for (int i = 0; i < 20; i++) {
	    utx.begin();
	    ehome.create("Eric Paire", "500");
	    ehome.remove("Eric Paire");
	    utx.commit();
	}
    }

    /** 
     * test 2 findByPrimaryKey in the same tx, with an update
     * between the 2 calls. We shall see the modifications, even before
     * the commit occurs.
     */
    public void testFindTwice() throws Exception {
	String num = "0032";
	utx.begin();
	Personne p = ehome.findByPrimaryKey(myname);
	p.setNumero(num);
	Personne p2 = ehome.findByPrimaryKey(myname);
	assertTrue(p2.getNumero().equals(num));
	utx.rollback();
	p = ehome.findByPrimaryKey(myname);
	assertTrue(p.getNumero().equals(mynum));
    }

    /**
     * Test DuplicateKeyException.
     * Create in an implicit tx
     */
    public void testDuplicateKeyTx() throws Exception {
	ehome.findByPrimaryKey(myname);
	try {
	    ehome.create(myname, "700");
	    ehome.create(myname, "700"); 
	    fail("DuplicateKeyException not raised");
	} catch (DuplicateKeyException e) {
	}
    }

    /**
     * Test DuplicateKeyException.
     * Create outside tx
     */
    public void testDuplicateKey() throws Exception {
	ehome.findByPrimaryKey(myname);
	try {
	    ehome.create(myname, "700", true);
	    fail("DuplicateKeyException not raised");
	} catch (DuplicateKeyException e) {
	}
    }

    /**
     * Verify that we can create an entity with a null name
     * 
     */
    public void testCreateNull() throws Exception {
	ehome.create("null", null);
	ehome.remove("null");	// cleaning
    }

    /**
     * Test many Create calls
     */
    public void testManyCreate() throws Exception {
	int nbCreate=20;
	for (int i=1; i<=nbCreate; i++) {
	    Personne p = ehome.create("manycreate"+i, "num"+i, true);
	}
	for (int i=1; i<=nbCreate; i++) {
	    ehome.remove("manycreate"+i);
	}
    }

    /**
     * Combination of other tests
     * This test the transaction isolation in entity bean container
     * this test must never hang
     */
    public void testIsolation() throws Exception {
	Personne p0 = null;
	Personne p1 = null;
	Personne p2 = null;
	Personne p3 = null;
	Personne p4 = null;
	Personne p5 = null;
	String n = null;
	String man1 = "Duke Ellington";
	String man2 = "Louis Armstrong";
	String man3 = "Lionel Hampton";
	String man4 = "Dexter Gordon";
	String man5 = "Bill Evans";

	// man1
	utx.begin();
	ehome.create(man1, "1");
	utx.commit();
	p1 = ehome.findByNom(man1);

	// man2
	utx.begin();
	ehome.create(man2, "2");
	utx.rollback();

	// man3
	utx.begin();
	p3 = ehome.create(man3, "3");
	p3.setNumero("33");
	utx.commit();
	assertTrue(p3.getNumero().equals("33"));

	// man4
	p4 = ehome.create(man4, "4");
	ehome.findByPrimaryKey(man4);
	ehome.remove(man4);
	p4 = ehome.create(man4, "44");
	ehome.findByPrimaryKey(man4);
	utx.begin();
	ehome.remove(man4);
	utx.commit();

	// man5
	p5 = ehome.create(man5, "5");
	ehome.findByPrimaryKey(man5);
	p5.remove();
	p5 = ehome.create(man5, "5");
	ehome.findByPrimaryKey(man5);
	utx.begin();
	p5.remove();
	utx.commit();

	// existing person
	for (int i = 0; i < 5; i++) {
	    utx.begin();
	    p0 = ehome.findByPrimaryKey(myname);
	    utx.commit();
	}
	assertTrue(p0.getNumero().equals(mynum));

	// findall
	for (int i = 0; i < 5; i++) {
	    utx.begin();
	    ehome.findAll();
	    utx.commit();
	}

	// create + remove
	for (int i = 0; i < 20; i++) {
	    utx.begin();
	    ehome.create(man2, "500");
	    ehome.remove(man2);
	    utx.commit();
	}

	// findByPrimaryKey twice
	utx.begin();
	p0 = ehome.findByPrimaryKey(myname);
	p0.setNumero("0");
	p2 = ehome.findByPrimaryKey(myname);
	assertTrue(p2.getNumero().equals("0"));
	utx.rollback();

	// cleaning
	p1.remove();
	p3.remove();
    }

    public static Test suite() {
	return new TestSuite(F_AdvancedHomeInterface.class);
    }

    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_AdvancedHomeInterface(testtorun));
	}
    }
}
