/*
 * 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.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;

import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;

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

import org.objectweb.jonas.jtests.beans.relation.omb.AHomeRemote;
import org.objectweb.jonas.jtests.beans.relation.omb.ARemote;
import org.objectweb.jonas.jtests.beans.relation.omb.BHomeRemote;
import org.objectweb.jonas.jtests.beans.relation.omb.BRemote;

/**
 * For testing one-to-many bidirectional relationships
 * @author Helene Joanin
 */
public class G_Relation_ombEC2 extends A_Cmp2Util {


    private static String BEAN_HOME_A = "relation_omb_AHome";
    protected static AHomeRemote ahome = null;
    private static String BEAN_HOME_B = "relation_omb_BHome";
    protected static BHomeRemote bhome = null;

    static Hashtable a2b = new Hashtable();
    static String[][] b2a = {
        {"bs0", null},
        {"bs1_1", "as1"},
        {"bs2_1", "as2"},
        {"bs2_2", "as2"},
        {"bs2_3", "as2"},
        {"bs3", null},
        {"b0", null},
        {"b1_1", "a1"},
        {"b1_2", "a1"},
        {"b1_3", "a1"},
        {"b2_1", "a2"},
        {"b2_2", "a2"},
        {"b2_3", "a2"},
        {"b3_1", "a3"}};

    static {
        a2b.put("as0", new String[]{});
        a2b.put("as1", new String[]{"bs1_1"});
        a2b.put("as2", new String[]{"bs2_1", "bs2_2", "bs2_3"});
        a2b.put("a0", new String[]{});
        a2b.put("a1", new String[]{"b1_1", "b1_2", "b1_3"});
        a2b.put("a2", new String[]{"b2_1", "b2_2", "b2_3"});
        a2b.put("a3", new String[]{"b3_1"});
        a2b.put("ax0", new String[]{});

        // Translate the String[] to a Collection of String
        for (Iterator it = a2b.keySet().iterator(); it.hasNext();) {
            String aname = (String) (it.next());
            String[] tb = (String[]) a2b.get(aname);
            ArrayList col = new ArrayList(tb.length);
            for (int i = 0; i < tb.length; i++) {
                col.add(tb[i]);
            }
            a2b.put(aname, col);
        }
    }


    public G_Relation_ombEC2(String name) {
        super(name);
    }
  
    protected boolean isInit = false;

    protected void setUp() {
        super.setUp();
        boolean ok = false;
        int nbtry = 0;
        while (!ok && nbtry < 3) {
            if (!isInit) {
                // load bean if not loaded yet
                useBeans("omb", false);
                try {
                    ahome = (AHomeRemote) PortableRemoteObject.narrow(ictx.lookup(BEAN_HOME_A),
                                                                      AHomeRemote.class);
                    bhome = (BHomeRemote) PortableRemoteObject.narrow(ictx.lookup(BEAN_HOME_B),
                                                                      BHomeRemote.class);
                    assertNotNull(ahome);
                    assertNotNull(bhome);
                } catch (NamingException e) {
                    fail("Cannot get bean home: " + e.getMessage());
                }
                // check if tables have been initialized
                try {
                    ahome.findByPrimaryKey("a0");
                } catch (Exception e) {
                    try {
                        utx.begin();
                        bhome.create("bs0");
                        bhome.create("bs1_1");
                        bhome.create("bs2_1");
                        bhome.create("bs2_2");
                        bhome.create("bs2_3");
                        bhome.create("bs3");
                        bhome.create("b0");
                        bhome.create("b1_1");
                        bhome.create("b1_2");
                        bhome.create("b1_3");
                        bhome.create("b2_1");
                        bhome.create("b2_2");
                        bhome.create("b2_3");
                        bhome.create("b3_1");
                        ahome.create("as0");
                        ahome.create("as1").assignB((Collection) a2b.get("as1"));
                        ahome.create("as2").assignB((Collection) a2b.get("as2"));
                        ahome.create("a0");
                        ahome.create("a1").assignB((Collection) a2b.get("a1"));
                        ahome.create("a2").assignB((Collection) a2b.get("a2"));
                        ahome.create("a3").assignB((Collection) a2b.get("a3"));
                        ahome.create("ax0");
                    } catch (Exception i) {
                        fail("InitialState creation problem: " + i);
                    } finally {
                        try {
                            utx.commit();
                        } catch (Exception ii) {
                        }
                    }
                }
                isInit = true;
            }
            // Check that all is OK. Sometimes, a test has failed and has corrupted
            // the bean state in the database. We must unload and reload the bean then.
            nbtry++;
            try {
                if (initStateOK()) {
                    ok = true;
                }
            } catch (Exception e) {
            }
            if (!ok) {
                isInit = false;
                unloadBeans("omb");
            }
        }
    }

    /**
     * Check that we are in the same state as after the tables creation for thoses beans A and B
     * (ie if it is the initial state)
     */
    boolean initStateOK() throws Exception {
        boolean isOk = true;
        msgerror = new StringBuffer();
        // Check the relations A => B
        for (Enumeration ea = a2b.keys(); ea.hasMoreElements();) {
            String aname = (String) (ea.nextElement());
            ARemote a = ahome.findByPrimaryKey(aname);
            Collection colActual = a.retrieveB();
            Collection colExpected = (Collection) (a2b.get(aname));
            if (!isCollectionEqual(colExpected, colActual)) {
                isOk = false;
                msgerror = msgerror.append("\nWrong relation for " + aname
                                           + " (expected:" + colExpected
                                           + ", found:" + colActual + ")");
            }
        }
        // Check the relation B => A
        for (int i = 0; i < b2a.length; i++) {
            BRemote b = bhome.findByPrimaryKey(b2a[i][0]);
            String pkb = b.getId();
            String pka = b.retrieveA();
            if (b2a[i][1] == null && pka != null
                || b2a[i][1] != null && !b2a[i][1].equals(pka)) {
                isOk = false;
                msgerror = msgerror.append("\nWrong relation for " + pkb
                                           + " (expected:" + b2a[i][1]
                                           + ", found:" + pka + ")");
            }

        }
        return isOk;
    }


    /**
     * Check that the bean 'as0' has no relation.
     */
    public void tBasicGetEmptyA2B(int tx) throws Exception {
        Collection c = null;
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        ARemote a = ahome.findByPrimaryKey("as0");
        if (tx == TX_CONT) {
            c = a.retrieveBInNewTx();
        } else {
            c = a.retrieveB();
        }
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        // checking
        checkIsInitialState();
    }

    public void testBasicGetEmptyA2BTxNo() throws Exception {
        tBasicGetEmptyA2B(TX_NO);
    }
    public void testBasicGetEmptyA2BTxCall() throws Exception {
        tBasicGetEmptyA2B(TX_CALL);
    }
    public void testBasicGetEmptyA2BTxCont() throws Exception {
        tBasicGetEmptyA2B(TX_CONT);
    }
   

    /**
     * Check that the bean 'bs0' has no relation.
     */
    public void tBasicGetEmptyB2A(int tx) throws Exception {
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        String pka = null;
        BRemote b = bhome.findByPrimaryKey("bs0");
        if (tx == TX_CONT) {
            pka = b.retrieveAInNewTx();
        } else {
            pka = b.retrieveA();
        }
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        // checking
        checkIsInitialState();
    }
    public void testBasicGetEmptyB2ANoTx() throws Exception {
        tBasicGetEmptyB2A(TX_NO);
    }
    public void testBasicGetEmptyB2ATxCall() throws Exception {
        tBasicGetEmptyB2A(TX_CALL);
    }
    public void testBasicGetEmptyB2ATxCont() throws Exception {
        tBasicGetEmptyB2A(TX_CONT);
    }
  


    /**
     * Check that the bean 'as1' has only one relation with 'bs1_1'.
     */
    public void tBasicGetOneA2B(int tx) throws Exception {

        Collection c = null;
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        ARemote a = ahome.findByPrimaryKey("as1");
        if (tx == TX_CONT) {
            c = a.retrieveBInNewTx();
        } else {
            c = a.retrieveB();
        }
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        // checking
        assertEquals("Relations size of: ", 1, c.size());
        String s = "bs1_1";
        assertTrue("Relation missing " + s + ": ", c.contains(s));
        checkIsInitialState();
    }

   
    /**
     * Check that the bean 'as2' has many relations with 'bs2_1', 'bs2_2', 'bs2_3'.
     */
    public void tBasicGetManyA2B(int tx) throws Exception {

        Collection c = null;
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        ARemote a = ahome.findByPrimaryKey("as2");
        if (tx == TX_CONT) {
            c = a.retrieveBInNewTx();
        } else {
            c = a.retrieveB();
        }
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        // checking
        assertEquals("Relations size of: ", 3, c.size());
        String s = "bs2_1";
        assertTrue("Relation missing " + s + ": ", c.contains(s));
        s = "bs2_2";
        assertTrue("Relation missing " + s + ": ", c.contains(s));
        s = "bs2_3";
        assertTrue("Relation missing " + s + ": ", c.contains(s));
        checkIsInitialState();
    }

 

    /**
     * Set a A2B relation to empty.
     * Before: as1 <-> bs1_1
     * After:  as1     bs1_1
     * Check also the assignement rules for relationships.
     */
    public void tCohSetEmptyA2B(int tx) throws Exception {
        ArrayList ce = new ArrayList();
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        ARemote a = ahome.findByPrimaryKey("as1");
        if (tx == TX_CONT) {
            a.assignBInNewTx(ce);
        } else {
            a.assignB(ce);
        }
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        if (tx != TX_RB) {
            // checking
            Collection ca = a.retrieveB();
            assertEquals("Relations size for as1 ", 0, ca.size());
            BRemote b = bhome.findByPrimaryKey("bs1_1");
            assertNull("Bad relation for bs1_1", b.retrieveA());
            // undo
            a.addInB("bs1_1");
        }
        checkIsInitialState();
    }

  

    /**
     * Set a A2B relation to empty by clearing the collection.
     * Before: as1 <-> bs1_1
     * After:  as1     bs1_1
     * Check also the assignement rules for relationships.
     */
    public void tCohClearA2B(int tx) throws Exception {
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        ARemote a = ahome.findByPrimaryKey("as1");
        if (tx == TX_CONT) {
            a.clearBInNewTx();
        } else {
            a.clearB();
        }
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        if (tx != TX_RB) {
            // checking
            Collection c = a.retrieveB();
            BRemote b = bhome.findByPrimaryKey("bs1_1");
            String r = b.retrieveA();
            assertEquals("Expected empty collection for as1 relation: ", 0, c.size());
            assertNull("Expected no relation for bs1_1", r);
            // undo
            b.assignA("as1");
        }
        checkIsInitialState();
    }

   
    /**
     * Set an empty A2B relation with 1 element.
     * This added element was'nt already in an other relation.
     * Before: as0     b0
     * After:  as0 <-> b0
     * Check also the assignement rules for relationships.
     */
    public void tCohSetOneA2B(int tx) throws Exception {
        ArrayList ce = new ArrayList();
        ce.add("b0");
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        ARemote a = ahome.findByPrimaryKey("as0");
        if (tx == TX_CONT) {
            a.assignBInNewTx(ce);
        } else {
            a.assignB(ce);
        }
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        if (tx != TX_RB) {
            // checking
            Collection ca = a.retrieveB();
            BRemote b = bhome.findByPrimaryKey("b0");
            String r = b.retrieveA();
            assertTrue("Bad relations for as0 (required:" + ce + ", found:" + ca
                       + ")", isCollectionEqual(ce, ca));
            assertEquals("Bad relation for b0: ", "as0", r);
            // undo
            a.assignB(new ArrayList());
        }
        checkIsInitialState();
    }

   


    /**
     * Set a null B2A relation with 1 element.
     * This element was'nt already in an other relation.
     * Before: b0     as0
     * After:  b0 <-> as0
     * Check also the assignement rules for relationships.
     */
    public void tCohSet1B2A(int tx) throws Exception {
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        BRemote b = bhome.findByPrimaryKey("b0");
        if (tx == TX_CONT) {
            b.assignAInNewTx("as0");
        } else {
            b.assignA("as0");
        }
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        // checking
        String r = b.retrieveA();
        ARemote a = ahome.findByPrimaryKey("as0");
        Collection ca = a.retrieveB();
        ArrayList ce = new ArrayList();
        ce.add("b0");
        if (tx != TX_RB) {
            assertEquals("Bad relation for b0: ", "as0", r);
            assertTrue("Bad relations for as0 (required:" + ce + ", found:" + ca
                       + ")", isCollectionEqual(ce, ca));
            // undo
            b.assignA(null);
        }
        checkIsInitialState();
    }

 


    /**
     * Add an element to a empty relation.
     * Same as tCohSetOneA2B except that we add the element in the collection
     * instead of we set directly the collection.
     * Before: as0     bs0
     * After:  as0 <-> bs0
     * Check also the assignement rules for relationships.
     */
    public void tCohAddOneA2B(int tx) throws Exception {
        ArrayList ce = new ArrayList();
        ce.add("bs0");
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        ARemote a = ahome.findByPrimaryKey("as0");
        if (tx == TX_CONT) {
            a.addInBInNewTx("bs0");
        } else {
            a.addInB("bs0");
        }
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        if (tx != TX_RB) {
            // checking
            Collection ca = a.retrieveB();
            BRemote b = bhome.findByPrimaryKey("bs0");
            String r = b.retrieveA();
            assertTrue("Bad relations for as0 (required:" + ce + ", found:" + ca
                       + ")", isCollectionEqual(ce, ca));
            assertEquals("Bad relation for bs0", "as0", r);
            // undo
            a.assignB(new ArrayList());
        }
        checkIsInitialState();
    }

 
    /**
     * Re-Set a relation with N element.
     * Before: as1 <-> bs1_1
     *                 bs0
     *                 bs3
     * After:          bs1_1
     *         as1 <-> bs0
     *         as1 <-> bs3
     */
    public void tCohSetMultiA2B(int tx) throws Exception {
        ArrayList ce = new ArrayList(2);
        ce.add("bs0");
        ce.add("bs3");
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        ARemote a = ahome.findByPrimaryKey("as1");
        Collection co = a.retrieveB();
        if (tx == TX_CONT) {
            a.assignBInNewTx(ce);
        } else {
            a.assignB(ce);
        }
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        if (tx != TX_RB) {
            // checking
            Collection ca = a.retrieveB();
            BRemote bs1_1 = bhome.findByPrimaryKey("bs1_1");
            BRemote bs0 = bhome.findByPrimaryKey("bs0");
            BRemote bs3 = bhome.findByPrimaryKey("bs3");
            assertTrue("Bad relations for as1 (required:" + ce + ", found:" + ca
                       + ")", isCollectionEqual(ce, ca));
            assertNull("Not null relation for bs1_1", bs1_1.retrieveA());
            assertEquals("Bad relation for bs0: ", "as1", bs0.retrieveA());
            assertEquals("Bad relation for bs3: ", "as1", bs3.retrieveA());
            // undo
            a.assignB(co);
        }
        checkIsInitialState();
    }

   


    /**
     * Set a B2A relation with 1 element.
     * This element wasn't already in an other relation.
     * Before: bs1_1 <-> as1
     *                   as0
     * Change: bs1_1.assignA(as0);
     * After:  bs1_1 <-> as0
     *                   as1
     * Check also the assignement rules for relationships.
     *
     */
    public void tCohSet2B2A(int tx) throws Exception {
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        BRemote b = bhome.findByPrimaryKey("bs1_1");
        if (tx == TX_CONT) {
            b.assignAInNewTx("as0");
        } else {
            b.assignA("as0");
        }
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        if (tx != TX_RB) {
            // checking
            String r = b.retrieveA();
            assertEquals("Bad relation for bs1_1: ", "as0", r);
            ARemote as0 = ahome.findByPrimaryKey("as0");
            Collection cas0 = as0.retrieveB();
            ARemote as1 = ahome.findByPrimaryKey("as1");
            Collection cas1 = as1.retrieveB();
            ArrayList ce = new ArrayList();
            ce.add("bs1_1");
            assertTrue("Bad relations for as0 (required:" + ce + ", found:" + cas0
                       + ")", isCollectionEqual(ce, cas0));
            ce = new ArrayList();
            assertTrue("Bad relations for as1 (required:" + ce + ", found:" + cas1
                       + ")", isCollectionEqual(ce, cas1));
            // undo
            b.assignA("as1");
        }
        checkIsInitialState();
    }

   


    /**
     * Set a B2A relation with 1 element.
     * This element was already in an other relation.
     * Before: bs1_1 <-> as1
     *         b3_1  <-> a3
     * Change: bs1_1.assignA(b3_1.retrieveA())
     * After:  bs1_1 <-> a3
     *         b3_1  <->
     *                   as1
     * Check also the assignement rules for relationships.
     *
     * See Spec chapter 10.3.7.3, change example: b2m.setA(b1n.getA())
     */
    public void tCohSet3B2A(int tx) throws Exception {
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        BRemote bs1_1 = bhome.findByPrimaryKey("bs1_1");
        if (tx == TX_CONT) {
            bs1_1.assignAInNewTx("a3");
        } else {
            bs1_1.assignA("a3");
        }
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        if (tx != TX_RB) {
            // checking
            String rbs1_1 = bs1_1.retrieveA();
            ARemote as1 = ahome.findByPrimaryKey("as1");
            Collection cas1 = as1.retrieveB();
            ARemote a3 = ahome.findByPrimaryKey("a3");
            Collection ca3 = a3.retrieveB();
            assertEquals("Bad relation for bs1_1: ", "a3", rbs1_1);
            ArrayList ce = new ArrayList();
            ce.add("bs1_1");
            ce.add("b3_1");
            assertTrue("Bad relations for a3 (required:" + ce + ", found:" + ca3
                       + ")", isCollectionEqual(ce, ca3));
            ce = new ArrayList();
            assertTrue("Bad relations for as1 (required:" + ce + ", found:" + cas1
                       + ")", isCollectionEqual(ce, cas1));
            // undo
            bs1_1.assignA("as1");
        }
        checkIsInitialState();
    }



    /**
     * Remove an element in a relation.
     * Before: a3 <-> b3_1
     * Change: a3.retrieveB().remove(b3_1)
     * After:  a3     b3_1
     * See Spec chapter 10.3.7.3, change example: a1.getB().remove(b1n)
     */
    public void tCohRemoveInRelA2B(int tx) throws Exception {
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        ARemote a = ahome.findByPrimaryKey("a3");
        if (tx == TX_CONT) {
            a.removeFromBInNewTx("b3_1");
        } else {
            a.removeFromB("b3_1");
        }
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        if (tx != TX_RB) {
            // checking
            Collection ca = a.retrieveB();
            BRemote b = bhome.findByPrimaryKey("b3_1");
            String r = b.retrieveA();
            ArrayList ce = new ArrayList();
            assertTrue("Bad relations for a3: (required:" + ce + ", found:" + ca
                       + ")", isCollectionEqual(ce, ca));
            assertNull("Bad not null relation for b3_1", r);
            // undo
            a.addInB("b3_1");
        }
        // check to initial state
        checkIsInitialState();

    }

  

    /**
     * Remove a bean B which is in a relation.
     * Before: a3 <-> b3_1
     * change: B.remove(b3_1)
     * After:  a3
     *
     */
    public void tCohRemoveB(int tx) throws Exception {
        if (tx == TX_CONT) {
            // The transaction attribute of the remove method is TX_SUPPORT,
            // so the transaction cannot be initiate by the container
            fail("Transaction cannot be initiate by the container for this test");
        }
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        bhome.remove("b3_1");
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        if (tx != TX_RB) {
            // checking
            ARemote a = ahome.findByPrimaryKey("a3");
            Collection ca = a.retrieveB();
            assertEquals("Wrong relations size for a3: (expected: 0 found:"
                         + ca.size(), 0, ca.size());
            // undo
            bhome.create("b3_1");
            a.addInBInNewTx("b3_1");
        }
        checkIsInitialState();
    }

    

    /**
     * Remove a bean B which is in a relation.
     * Same as tCohRemoveB except that the called remove method is on the bean
     * instead of the home.
     * Before: a3 <-> b3_1
     * change: B.remove(b3_1)
     * After:  a3
     *
     */
    public void tCohBeanRemoveB(int tx) throws Exception {
        if (tx == TX_CONT) {
            // The transaction attribute of the remove method is TX_SUPPORT,
            // so the transaction cannot be initiate by the container
            fail("Transaction cannot be initiate by the container for this test");
        }
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        BRemote b = bhome.findByPrimaryKey("b3_1");
        b.remove();
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        if (tx != TX_RB) {
            // checking
            ARemote a = ahome.findByPrimaryKey("a3");
            Collection ca = a.retrieveB();
            assertEquals("Wrong relations size for a3: (expected: 0 found:"
                         + ca.size(), 0, ca.size());
            // undo
            bhome.create("b3_1");
            a.addInBInNewTx("b3_1");
        }
        checkIsInitialState();
    }

  



    /**
     * Set a empty relation A2B with 1 element.
     * This added element was already in a other relation.
     * Before: a0
     *         a3 <-> b3_1
     * Change: a0.assignB({b3_1})
     * After:  a0 <-> b3_1
     *         a3
     */
    public void tCohSetOne2A2B(int tx) throws Exception {
        ArrayList ce = new ArrayList();
        ce.add("b3_1");
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        ARemote a = ahome.findByPrimaryKey("a0");
        if (tx == TX_CONT) {
            a.assignBInNewTx(ce);
        } else {
            a.assignB(ce);
        }
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        if (tx != TX_RB) {
            // checking
            Collection ca = a.retrieveB();
            ARemote a3 = ahome.findByPrimaryKey("a3");
            Collection ca3 = a3.retrieveB();
            BRemote b = bhome.findByPrimaryKey("b3_1");
            String r = b.retrieveA();
            assertTrue("Wrong relations a0 (required:" + ce + ", found:" + ca
                       + ")", isCollectionEqual(ce, ca));
            assertTrue("Wrong relations for b3_1" + ": found:" + ca3 ,
                       !ca3.contains("b3_1"));
            assertEquals("Bad relation for b3_1: ", "a0", r);
            // undo
            a.assignB(new ArrayList());
            a3.addInB("b3_1");
        }
        checkIsInitialState();
    }

   


    /**
     * Add an element to a relation A2B already multiple.
     * The element was already in a relation.
     * Check also the assignement rules for relationships.
     * Before: a1 <-> b1_1
     *            <-> b1_2
     *            <-> b1_3
     *         a3 <-> b3_1
     * Change: a1.addInB(b3_1)
     * After:  a1 <-> b1_1
     *            <-> b1_2
     *            <-> b1_3
     *            <-> b3_1
     *         a3
     *
     * See Spec chapter 10.3.7.3, change example: a1.getB().add(b2m)
     *
     */
    public void tCohAddOneInMultiA2B(int tx) throws Exception {

        ArrayList ce = new ArrayList();
        ce.add("b1_1");
        ce.add("b1_2");
        ce.add("b1_3");
        String bAdded = "b3_1";
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        ARemote a = ahome.findByPrimaryKey("a1");
        if (tx == TX_CONT) {
            a.addInBInNewTx(bAdded);
        } else {
            a.addInB(bAdded);
        }
        ce.add(bAdded);
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        if (tx != TX_RB) {
            // checking
            Collection ca1 = a.retrieveB();
            ARemote a3 = ahome.findByPrimaryKey("a3");
            Collection ca3 = a3.retrieveB();
            assertTrue("Bad relations for a1 (required:" + ce + ", found:" + ca1 + ")",
                       isCollectionEqual(ce, ca1));
            ce = new ArrayList();
            assertTrue("Bad relations for a3 (required:" + ce + ", found:" + ca3 + ")",
                       isCollectionEqual(ce, ca3));
            BRemote b = bhome.findByPrimaryKey(bAdded);
            assertEquals("Bad relation for b3_1: ", "a1", b.retrieveA());
            // undo
            a3.addInB(bAdded);
        }

        checkIsInitialState();
    }

   
    /*
     * Set a relation to multiple.
     * All of element was already in an other relation.
     * Check also the assignement rules for relationships.
     * Before: a1 <-> b1_1
     *            <-> b1_2
     *            <-> b1_3
     *         a2 <-> b2_1
     *            <-> b2_2
     *            <-> b2_3
     * Change: a1.assignB(a2.retrieveB())
     * After:  a1 <-> b2_1
     *            <-> b2_2
     *            <-> b2_3
     *         a2
     *               b1_1
     *               b1_2
     *               b1_3
     *
     * Spec chapter 10.3.7.3, change example: a1.setB(a2.getB())
     *
     */
    public void tCohSetMultiBisA2B(int tx) throws Exception {
        if ((tx == TX_CALL) || (tx == TX_RB)) {
            utx.begin();
        }
        ARemote a1 = ahome.findByPrimaryKey("a1");
        Collection co1 = a1.retrieveB();
        ARemote a2 = ahome.findByPrimaryKey("a2");
        Collection co2 = a2.retrieveB();
        if (tx == TX_CONT) {
            a1.assignBInNewTx(co2);
        } else {
            a1.assignB(co2);
        }
        if (tx == TX_CALL) {
            utx.commit();
        } else if (tx == TX_RB) {
            utx.rollback();
        }
        if (tx != TX_RB) {
            // checking
            Collection ca1 = a1.retrieveB();
            assertTrue("Wrong relations for a1 (required:" + co2 + ", found:" + ca1 + ")", isCollectionEqual(co2, ca1));
            Collection ca2 = a2.retrieveB();
            assertEquals("Wrong relations size for a2: ", 0, ca2.size());
            BRemote b;
            b = bhome.findByPrimaryKey("b1_1");
            assertNull("Wrong not null relation for b1_1: ", b.retrieveA());
            b = bhome.findByPrimaryKey("b1_2");
            assertNull("Wrong not null relation for b1_2: ", b.retrieveA());
            b = bhome.findByPrimaryKey("b1_3");
            assertNull("Wrong not null relation for b1_3: ", b.retrieveA());
            b = bhome.findByPrimaryKey("b2_1");
            assertEquals("Wrong relation for b2_1: ", "a1", b.retrieveA());
            b = bhome.findByPrimaryKey("b2_2");
            assertEquals("Wrong relation for b2_2: ", "a1", b.retrieveA());
            b = bhome.findByPrimaryKey("b2_3");
            assertEquals("Wrong relation for b2_3: ", "a1", b.retrieveA());
            // Undo
            a1.assignB(co1);
            a2.assignB(co2);
        }
        checkIsInitialState();
    }

    

 

    public static Test suite() {
        return new TestSuite(G_Relation_ombEC2.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 G_Relation_ombEC2(testtorun));
        }
    }

}
