/*
 * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.testing.tests.jpa.inheritance;

import java.util.Collection;

import org.eclipse.persistence.annotations.BatchFetchType;
import org.eclipse.persistence.config.QueryHints;
import org.eclipse.persistence.expressions.ExpressionBuilder;
import org.eclipse.persistence.queries.UpdateAllQuery;
import org.eclipse.persistence.testing.framework.junit.JUnitTestCase;
import org.eclipse.persistence.testing.models.jpa.inheritance.InheritanceTableCreator;
import org.eclipse.persistence.jpa.JpaEntityManager;

import org.eclipse.persistence.testing.models.jpa.inheritance.Assassin;
import org.eclipse.persistence.testing.models.jpa.inheritance.Bomb;
import org.eclipse.persistence.testing.models.jpa.inheritance.ContractedPersonel;
import org.eclipse.persistence.testing.models.jpa.inheritance.DirectElimination;
import org.eclipse.persistence.testing.models.jpa.inheritance.DirectWeapon;
import org.eclipse.persistence.testing.models.jpa.inheritance.Elimination;
import org.eclipse.persistence.testing.models.jpa.inheritance.EliminationPK;
import org.eclipse.persistence.testing.models.jpa.inheritance.Gun;
import org.eclipse.persistence.testing.models.jpa.inheritance.IndirectElimination;
import org.eclipse.persistence.testing.models.jpa.inheritance.IndirectWeapon;
import org.eclipse.persistence.testing.models.jpa.inheritance.SocialClub;
import org.eclipse.persistence.testing.models.jpa.inheritance.SpecialAssassin;
import org.eclipse.persistence.testing.models.jpa.inheritance.Weapon;

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

import jakarta.persistence.LockModeType;
import jakarta.persistence.OptimisticLockException;
import jakarta.persistence.PersistenceException;
import jakarta.persistence.Query;
import jakarta.persistence.EntityManager;

public class TablePerClassInheritanceJUnitTest extends JUnitTestCase {
    private static Integer assassinId;
    private static Integer specialAssassinId;
    private static Integer socialClub1Id;
    private static Integer socialClub2Id;
    private static Integer socialClub3Id;
    private static Integer gunSerialNumber;
    private static EliminationPK directEliminationPK;
    private static EliminationPK indirectEliminationPK;

    public TablePerClassInheritanceJUnitTest() {
        super();
    }

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

    @Override
    public void setUp() {
        super.setUp();
        clearCache();
    }

    public static Test suite() {
        TestSuite suite = new TestSuite();
        suite.setName("TablePerClassInheritanceJUnitTestSuite");
        suite.addTest(new TablePerClassInheritanceJUnitTest("testSetup"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testCreateAssassinWithGun"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testValidateAssassinWithGun"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testValidateGunToAssassin"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testAddDirectElimination"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testValidateDirectElimination"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testAddIndirectElimination"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testValidateIndirectElimination"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testValidateAssassinWithBombAndEliminations"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testNamedQueryFindAllWeapons"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testNamedQueryFindAllWeaponsWhereDescriptionContainsSniper"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testCreateNewSocialClubsWithMembers"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testBatchFindAllWeapons"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testValidateSocialClub1Members"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testValidateSocialClub2Members"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testValidateSocialClub3Members"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testAssassinOptimisticLocking"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testSpecialAssassinOptimisticLocking"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testAssassinOptimisticLockingUsingEntityManagerAPI"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testGunOptimisticLocking"));
        suite.addTest(new TablePerClassInheritanceJUnitTest("testUpdateAllQuery"));
        return suite;
    }

    /**
     * The setup is done as a test, both to record its failure, and to allow execution in the server.
     */
    public void testSetup() {
        new InheritanceTableCreator().replaceTables(JUnitTestCase.getServerSession());
        clearCache();
    }

    public void testCreateAssassinWithGun() {
        EntityManager em = createEntityManager();
        Assassin assassin = null;
        try {
            beginTransaction(em);

            assassin = new Assassin();
            assassin.setName("Assassin1");

            assassin.getNicknames().add("Bonny");
            assassin.getNicknames().add("Clyde");

            Gun gun = new Gun();
            gun.setCaliber(50);
            gun.setDescription("Sniper rifle");
            gun.setModel("9-112");

            assassin.setWeapon(gun);

            em.persist(assassin);
            assassinId = assassin.getId();
            gunSerialNumber = gun.getSerialNumber();

            commitTransaction(em);
        } catch (Exception exception) {
            exception.printStackTrace();
            fail("Error persisting new assassin: " + exception.getMessage());
        } finally {
            closeEntityManager(em);
        }
        verifyObjectInCacheAndDatabase(assassin);
    }

    public void testValidateAssassinWithGun() {
        EntityManager em = createEntityManager();

        Assassin assassin = em.find(Assassin.class, assassinId);
        assertNotNull("The assassin could not be read back.", assassin);

        Weapon weapon = assassin.getWeapon();
        assertNotNull("The assassin's weapon was null", weapon);
        assertTrue("The assassin's weapon was not a direct weapon", weapon.isDirectWeapon());
        assertTrue("The assassin's weapon was not a gun", ((DirectWeapon) weapon).isGun());

        closeEntityManager(em);
    }

    public void testValidateGunToAssassin() {
        EntityManager em = createEntityManager();

        Gun gun = em.find(Gun.class, gunSerialNumber);
        assertNotNull("The gun could not be read back.", gun);

        Assassin assassin = gun.getAssassin();
        assertNotNull("The gun's assassin was null", assassin);
        assertTrue("The gun is currently not assigned to the correct assassin", assassin.getId().equals(assassinId));

        closeEntityManager(em);
    }

    public void testAddDirectElimination() {
        EntityManager em = createEntityManager();
        DirectElimination directElimination = null;
        try {
            beginTransaction(em);
            Assassin assassin = em.find(Assassin.class, assassinId);

            // Assassin already has a gun, therefore, correct weapon already set
            // for a direct elimination.
            directElimination = new DirectElimination();
            directElimination.setId(Long.valueOf(System.currentTimeMillis()).intValue());
            directElimination.setName("Joe Smuck");
            directElimination.setDescription("Because he has a big mouth");
            directElimination.setAssassin(assassin);
            em.persist(directElimination);
            directEliminationPK = directElimination.getPK();

            assassin.getEliminations().add(directElimination);

            commitTransaction(em);
        } catch (Exception e) {
            fail("Error adding new direct elimination: " + e.getMessage());
        } finally {
            closeEntityManager(em);
        }
        verifyObjectInCacheAndDatabase(directElimination);
    }

    public void testValidateDirectElimination() {
        EntityManager em = createEntityManager();

        Elimination directElimination = em.find(Elimination.class, directEliminationPK);
        assertNotNull("The direct elimination could not be read back.", directElimination);
        assertTrue("The elimination was not a direct elimination", directElimination.isDirectElimination());

        // Validate the weapon that was used for the direct elimination.
        DirectWeapon weapon = ((DirectElimination) directElimination).getDirectWeapon();
        assertNotNull("The direct elimination's weapon was null", weapon);
        assertTrue("The direct elimination's weapon was not a direct weapon", weapon.isDirectWeapon());
        assertTrue("The direct elimination's weapon was not a gun", weapon.isGun());

        closeEntityManager(em);
    }

    public void testAddIndirectElimination() {
        EntityManager em = createEntityManager();
        IndirectElimination indirectElimination = null;
        try {
            beginTransaction(em);

            Assassin assassin = em.find(Assassin.class, assassinId);

            Bomb bomb = new Bomb();
            bomb.setBombType(Bomb.BOMBTYPE.DIRTY);
            bomb.setDescription("Nasty blasty");
            em.persist(bomb);

            // Must set the correct weapon before an elimination.
            assassin.setWeapon(bomb);

            indirectElimination = new IndirectElimination();
            indirectElimination.setId(Long.valueOf(System.currentTimeMillis()).intValue());
            indirectElimination.setName("Jill Smuck");
            indirectElimination.setDescription("Because she has a big mouth");
            indirectElimination.setAssassin(assassin);
            em.persist(indirectElimination);
            indirectEliminationPK = indirectElimination.getPK();

            assassin.getEliminations().add(indirectElimination);

            commitTransaction(em);
        } catch (Exception e) {
            fail("Error adding new indirect elimination: " + e.getMessage());
        } finally {
            closeEntityManager(em);
        }
        verifyObjectInCacheAndDatabase(indirectElimination);
    }

    public void testValidateIndirectElimination() {
        EntityManager em = createEntityManager();

        Elimination indirectElimination = em.find(Elimination.class, indirectEliminationPK);
        assertNotNull("The indirect elimination could not be read back.", indirectElimination);
        assertTrue("The elimination was not an idirect elimination", indirectElimination.isIndirectElimination());

        // Validate the weapon that was used for the direct elimination.
        IndirectWeapon weapon = ((IndirectElimination) indirectElimination).getIndirectWeapon();
        assertNotNull("The indirect elimination's weapon was null", weapon);
        assertTrue("The indirect elimination's weapon was not an idirect weapon", weapon.isIndirectWeapon());
        assertTrue("The indirect elimination's weapon was not a bomb", weapon.isBomb());

        closeEntityManager(em);
    }

    public void testValidateAssassinWithBombAndEliminations() {
        EntityManager em = createEntityManager();

        Assassin assassin = em.find(Assassin.class, assassinId);
        assertNotNull("The assassin could not be read back.", assassin);
        assassin.getEliminations();
        assertFalse("The assassin didn't have any eliminations", assassin.getEliminations().isEmpty());

        Weapon weapon = assassin.getWeapon();
        assertNotNull("The assassin's weapon was null", weapon);
        assertTrue("The assassin's weapon was not an indirect weapon", weapon.isIndirectWeapon());
        assertTrue("The assassin's weapon was not a bomb", ((IndirectWeapon) weapon).isBomb());

        closeEntityManager(em);
    }

    // At this point no Weapon objects have been created only only real weapons.
    // So if the query returns an empty collection, something is not working.
    // We have create a gun and a bomb at this point ...
    public void testNamedQueryFindAllWeapons() {
        EntityManager em = createEntityManager();

        try {
            Query query = em.createNamedQuery("findAllWeapons");
            Collection<Weapon> weapons = query.getResultList();
            assertFalse("No weapons were returned", weapons.isEmpty());
            assertTrue("Expected weapon count of 2 not returned", weapons.size() == 2);
        } finally {
            closeEntityManager(em);
        }
    }

    // At this point no Weapon objects have been created only only real weapons.
    // So if the query returns an empty collection, something is not working.
    // We have create a gun and a bomb at this point ...
    public void testBatchFindAllWeapons() {
        EntityManager em = createEntityManager();

        try {
            Query query = em.createQuery("Select w from Weapon w");
            query.setHint(QueryHints.BATCH, "w.assassin");
            query.setHint(QueryHints.BATCH_TYPE, BatchFetchType.IN);
            Collection<Weapon> weapons = query.getResultList();
            for (Weapon weapon : weapons) {
                weapon.getAssassin();
            }
            assertFalse("No weapons were returned", weapons.isEmpty());
            assertTrue("Expected weapon count of 2 not returned", weapons.size() == 2);

            clearCache();
            em.clear();
            query = em.createQuery("Select w from Weapon w");
            query.setHint(QueryHints.BATCH, "w.assassin");
            query.setHint(QueryHints.BATCH_TYPE, BatchFetchType.EXISTS);
            weapons = query.getResultList();
            for (Weapon weapon : weapons) {
                weapon.getAssassin();
            }
            assertFalse("No weapons were returned", weapons.isEmpty());
            assertTrue("Expected weapon count of 2 not returned", weapons.size() == 2);

            clearCache();
            em.clear();
            query = em.createQuery("Select w from Weapon w");
            query.setHint(QueryHints.BATCH, "w.assassin");
            query.setHint(QueryHints.BATCH_TYPE, BatchFetchType.JOIN);
            weapons = query.getResultList();
            for (Weapon weapon : weapons) {
                weapon.getAssassin();
            }
            assertFalse("No weapons were returned", weapons.isEmpty());
            assertTrue("Expected weapon count of 2 not returned", weapons.size() == 2);

            clearCache();
            em.clear();
            query = em.createQuery("Select s from SocialClub s");
            query.setHint(QueryHints.BATCH, "s.members");
            query.setHint(QueryHints.BATCH_TYPE, BatchFetchType.IN);
            Collection<SocialClub> clubs = query.getResultList();
            for (SocialClub club : clubs) {
                club.getMembers().size();
            }

            clearCache();
            em.clear();
            query = em.createQuery("Select s from SocialClub s");
            query.setHint(QueryHints.BATCH, "s.members");
            query.setHint(QueryHints.BATCH_TYPE, BatchFetchType.JOIN);
            clubs = query.getResultList();
            for (SocialClub club : clubs) {
                club.getMembers().size();
            }

            clearCache();
            em.clear();
            query = em.createQuery("Select s from SocialClub s");
            query.setHint(QueryHints.BATCH, "s.members");
            query.setHint(QueryHints.BATCH_TYPE, BatchFetchType.EXISTS);
            clubs = query.getResultList();
            for (SocialClub club : clubs) {
                club.getMembers().size();
            }
        } finally {
            closeEntityManager(em);
        }
    }

    // At this point no Weapon objects have been created only only real weapons.
    // So if the query returns an empty collection, something is not working.
    // We have create a gun and a bomb at this point, and the gun is a sniper rifle.
    public void testNamedQueryFindAllWeaponsWhereDescriptionContainsSniper() {
        EntityManager em = createEntityManager();

        try {
            Query query = em.createNamedQuery("findAllWeaponsContainingDescription");

            query.setParameter("description", "Sniper%");
            Collection<Weapon> weapons = query.getResultList();
            assertFalse("No weapons were returned", weapons.isEmpty());
            assertTrue("Expected weapon count of 1 not returned", weapons.size() == 1);
        } catch (Exception e) {
            e.printStackTrace();
            fail("Error issuing find all weapons query: " + e.getMessage());
        } finally {
            closeEntityManager(em);
        }
    }

    // Maybe test that setting this flag does not cause an error. Internally
    // it gets ignored.
    // ((ObjectLevelReadQuery)((EJBQueryImpl) query).getDatabaseQuery()).setShouldOuterJoinSubclasses(true);
    public void testCreateNewSocialClubsWithMembers() {
        EntityManager em = createEntityManager();
        SocialClub socialClub1 = null;
        SocialClub socialClub2 = null;
        SocialClub socialClub3 = null;
        try {
            beginTransaction(em);

            // Create some new clubs.
            socialClub1 = new SocialClub();
            socialClub1.setName("Jimmy's my name and killing is my game!");
            em.persist(socialClub1);
            socialClub1Id = socialClub1.getId();

            socialClub2 = new SocialClub();
            socialClub2.setName("Sharp shooting");
            em.persist(socialClub2);
            socialClub2Id = socialClub2.getId();

            socialClub3 = new SocialClub();
            socialClub3.setName("Precision explosions");
            em.persist(socialClub3);
            socialClub3Id = socialClub3.getId();

            // Create a couple new characters and add them to various clubs.
            ContractedPersonel contractedPersonel = new ContractedPersonel();
            contractedPersonel.setName("Hired Goon");
            em.persist(contractedPersonel);

            SpecialAssassin specialAssassin = new SpecialAssassin();
            specialAssassin.setName("IED Expert");
            em.persist(specialAssassin);
            specialAssassinId = specialAssassin.getId();

            Assassin assassin = em.find(Assassin.class, assassinId);

            socialClub1.addMember(assassin);
            socialClub1.addMember(contractedPersonel);
            socialClub1.addMember(specialAssassin);

            socialClub2.addMember(assassin);
            socialClub2.addMember(contractedPersonel);

            socialClub3.addMember(contractedPersonel);
            socialClub3.addMember(specialAssassin);

            commitTransaction(em);
        } finally {
            closeEntityManager(em);
        }
        verifyObjectInCacheAndDatabase(socialClub1);
        verifyObjectInCacheAndDatabase(socialClub2);
        verifyObjectInCacheAndDatabase(socialClub3);
    }

    public void testValidateSocialClub1Members() {
        EntityManager em = createEntityManager();

        SocialClub socialClub1 = createEntityManager().find(SocialClub.class, socialClub1Id);
        assertNotNull("The social club 1 could not be read back.", socialClub1);
        assertFalse("The member list was empty", socialClub1.getMembers().isEmpty());
        assertTrue("The member count was not the expected 3", socialClub1.getMembers().size() == 3);

        closeEntityManager(em);
    }

    public void testValidateSocialClub2Members() {
        EntityManager em = createEntityManager();

        SocialClub socialClub2 = createEntityManager().find(SocialClub.class, socialClub2Id);
        assertNotNull("The social club 1 could not be read back.", socialClub2);
        assertFalse("The member list was empty", socialClub2.getMembers().isEmpty());
        assertTrue("The member count was not the expected 2", socialClub2.getMembers().size() == 2);

        closeEntityManager(em);
    }

    public void testValidateSocialClub3Members() {
        EntityManager em = createEntityManager();

        SocialClub socialClub3 = createEntityManager().find(SocialClub.class, socialClub3Id);
        assertNotNull("The social club 1 could not be read back.", socialClub3);
        assertFalse("The member list was empty", socialClub3.getMembers().isEmpty());
        assertTrue("The member count was not the expected 2", socialClub3.getMembers().size() == 2);

        closeEntityManager(em);
    }

    // Tested for an Assassin and a SpecialAssasin
    protected void optimisticLockTestOnAssassin(Integer id) {
        // Cannot create parallel entity managers in the server.
        if (! isOnServer()) {
            EntityManager em1 = createEntityManager();
            EntityManager em2 = createEntityManager();

            em1.getTransaction().begin();
            em2.getTransaction().begin();

            RuntimeException caughtException = null;

            try {
                Assassin assassin1 = em1.find(Assassin.class, id);
                Assassin assassin2 = em2.find(Assassin.class, id);

                assassin1.setName("Geezer");
                assassin2.setName("Guyzer");

                em1.getTransaction().commit();
                em2.getTransaction().commit();

                em1.close();
                em2.close();
            } catch (RuntimeException e) {
                if (em1.getTransaction().isActive()){
                    em1.getTransaction().rollback();
                }

                if (em2.getTransaction().isActive()){
                    em2.getTransaction().rollback();
                }

                if (e.getCause() instanceof jakarta.persistence.OptimisticLockException) {
                    caughtException = e;
                } else {
                    throw e;
                }
            } finally {
                em1.close();
                em2.close();
            }

            if (caughtException == null) {
                fail("Optimistic lock exception was not thrown.");
            }
        }
    }

    public void testAssassinOptimisticLocking() {
        optimisticLockTestOnAssassin(assassinId);
    }

    // Just being thorough ... special assassin uses a difference column
    // for versioning through an attribute override, but if it didn't work
    // we would have known long before now.
    public void testSpecialAssassinOptimisticLocking() {
        optimisticLockTestOnAssassin(specialAssassinId);
    }

    public void testAssassinOptimisticLockingUsingEntityManagerAPI() {
        // Cannot create parallel entity managers in the server.
        if (! isOnServer()) {
            EntityManager em = createEntityManager();
            beginTransaction(em);
            Assassin assassin = null;

            try {
                assassin = new Assassin();
                assassin.setName("OptLockAssassin");
                em.persist(assassin);
                commitTransaction(em);
            } catch (RuntimeException ex) {
                if (isTransactionActive(em)) {
                    rollbackTransaction(em);
                }

                closeEntityManager(em);
                throw ex;
            }

            EntityManager em2 = createEntityManager();
            Exception optimisticLockException = null;
            beginTransaction(em);

            try {
                assassin = em.find(Assassin.class, assassin.getId());
                em.lock(assassin, LockModeType.WRITE);
                beginTransaction(em2);

                try {
                    Assassin assassin2 = em2.find(Assassin.class, assassin.getId());
                    assassin2.setName("OptLockAssassin2");
                    commitTransaction(em2);
                    em2.close();
                } catch (RuntimeException ex) {
                    if (isTransactionActive(em2)) {
                        rollbackTransaction(em2);
                    }

                    closeEntityManager(em2);
                    throw ex;
                }

                try {
                    em.flush();
                } catch (PersistenceException exception) {
                    if (exception instanceof OptimisticLockException){
                        optimisticLockException = exception;
                    } else {
                        throw exception;
                    }
                }

                rollbackTransaction(em);
            } catch (RuntimeException ex) {
                if (isTransactionActive(em)){
                    rollbackTransaction(em);
                }

                closeEntityManager(em);
                throw ex;
            }

            try {
                beginTransaction(em);
                assassin = em.find(Assassin.class, assassin.getId());
                em.remove(assassin);
                commitTransaction(em);
            } catch (RuntimeException ex) {
                if (isTransactionActive(em)) {
                    rollbackTransaction(em);
                }

                closeEntityManager(em);
                throw ex;
            }

            assertFalse("Proper exception not thrown when EntityManager.lock(object, OPTIMISTIC) is used.", optimisticLockException == null);
        }
    }

    // Gun uses an ALL_COLUMNS optimistic locking policy.
    public void testGunOptimisticLocking() {
        // Cannot create parallel entity managers in the server.
        if (! isOnServer()) {
            EntityManager em1 = createEntityManager();
            EntityManager em2 = createEntityManager();

            em1.getTransaction().begin();
            em2.getTransaction().begin();

            RuntimeException caughtException = null;

            try {
                Gun gun1 = em1.find(Gun.class, gunSerialNumber);
                Gun gun2 = em2.find(Gun.class, gunSerialNumber);

                gun1.setCaliber(12);
                gun2.setCaliber(22);

                em1.getTransaction().commit();
                em2.getTransaction().commit();

                em1.close();
                em2.close();
            } catch (RuntimeException e) {
                if (em1.getTransaction().isActive()){
                    em1.getTransaction().rollback();
                }

                if (em2.getTransaction().isActive()){
                    em2.getTransaction().rollback();
                }

                if (e.getCause() instanceof jakarta.persistence.OptimisticLockException) {
                    caughtException = e;
                } else {
                    throw e;
                }
            } finally {
                em1.close();
                em2.close();
            }

            if (caughtException == null) {
                fail("Optimistic lock exception was not thrown.");
            }
        }
    }

    // Note: Update all for Table Per class only works with the one single
    // reference class. So it's not a full feature test.
    public void testUpdateAllQuery() {
        EntityManager em = createEntityManager();
        beginTransaction(em);
        try {
            ExpressionBuilder eb = new ExpressionBuilder();
            UpdateAllQuery updateQuery = new UpdateAllQuery(Assassin.class);
            updateQuery.addUpdate(eb.get("name"), "Generic Assassin Name");
            ((JpaEntityManager)em.getDelegate()).getServerSession().executeQuery(updateQuery);
            Assassin assassin = (Assassin) em.find(ContractedPersonel.class, assassinId);
            em.refresh(assassin);
            commitTransaction(em);
            assertTrue("Update all did not work", assassin.getName().equals("Generic Assassin Name"));
        } catch (Exception e) {
            e.printStackTrace();
            fail("Error issuing update all contracted personel query: " + e.getMessage());
        } finally {
            if (isTransactionActive(em)){
                rollbackTransaction(em);
            }
            closeEntityManager(em);
        }
    }

    /**
     * Commenting out this test. It didn't not work and well I'll leave it here
     * for now in case we pick this up again some other time.
     */
    /*
    public void testBatchQueryHint(){
        int id1 = 0;
        EntityManager em = createEntityManager();
        beginTransaction(em);

        Assassin assassin1 = new Assassin();
        assassin1.setName("Assassin1");
        Weapon weapon = new Weapon();
        weapon.setDescription("A generic weapon");
        weapon.setAssassin(assassin1);
        assassin1.setWeapon(weapon);
        em.persist(assassin1);

        //id1 = manager.getId();

        Assassin assassin2 = new Assassin();
        assassin2.setName("Assassin2");
        Poison poison = new Poison();
        poison.setDescription("A slow death poison");
        poison.setEffectTime(Poison.EFFECTTIME.PROLONGED);
        assassin2.setWeapon(poison);
        em.persist(assassin2);

        commitTransaction(em);
        em.clear();

        JpaQuery query = (JpaQuery) getEntityManagerFactory().createEntityManager().createQuery("SELECT a FROM Assassin a WHERE a.id > 0 order by a.name");
        query.setHint(QueryHints.BATCH, "a.weapon");
        query.setHint(QueryHints.BATCH, "a.eliminations");

        ReadAllQuery raq = (ReadAllQuery)query.getDatabaseQuery();
        List expressions = raq.getBatchReadAttributeExpressions();
        assertTrue(expressions.size() == 2);
        Expression exp = (Expression)expressions.get(0);
        assertTrue(exp.isQueryKeyExpression());
        assertTrue("Query key name was not weapon", exp.getName().equals("weapon"));
        exp = (Expression)expressions.get(1);
        assertTrue(exp.isQueryKeyExpression());
        assertTrue("Query key name was not eliminations", exp.getName().equals("eliminations"));

        List resultList = query.getResultList();
        Assassin assassin = (Assassin) resultList.get(0);
        assassin.getWeapon().hashCode();

        assassin = (Assassin) resultList.get(1);
        assassin.getWeapon().hashCode();
    }
    */
}

