/******************************************************************************* * Copyright (c) 2011, 2015 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 v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * 03/23/2011-2.3 Guy Pelletier * - 337323: Multi-tenant with shared schema support (part 1) * 04/01/2011-2.3 Guy Pelletier * - 337323: Multi-tenant with shared schema support (part 2) * 04/21/2011-2.3 Guy Pelletier * - 337323: Multi-tenant with shared schema support (part 5) * 05/24/2011-2.3 Guy Pelletier * - 345962: Join fetch query when using tenant discriminator column fails. * 06/1/2011-2.3 Guy Pelletier * - 337323: Multi-tenant with shared schema support (part 9) * 06/30/2011-2.3.1 Guy Pelletier * - 341940: Add disable/enable allowing native queries * 09/09/2011-2.3.1 Guy Pelletier * - 356197: Add new VPD type to MultitenantType * 11/10/2011-2.4 Guy Pelletier * - 357474: Address primaryKey option from tenant discriminator column * 11/15/2011-2.3.2 Guy Pelletier * - 363820: Issue with clone method from VPDMultitenantPolicy * 14/05/2012-2.4 Guy Pelletier * - 376603: Provide for table per tenant support for multitenant applications * 22/05/2012-2.4 Guy Pelletier * - 380008: Multitenant persistence units with a dedicated emf should force tenant property specification up front. * 01/06/2011-2.3 Guy Pelletier * - 371453: JPA Multi-Tenancy in Bidirectional OneToOne Relation throws ArrayIndexOutOfBoundsException * 08/11/2012-2.5 Guy Pelletier * - 393867: Named queries do not work when using EM level Table Per Tenant Multitenancy. * 20/11/2012-2.5 Guy Pelletier * - 394524: Invalid query key [...] in expression ******************************************************************************/ package org.eclipse.persistence.testing.tests.jpa.advanced.multitenant; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.NamedQuery; import javax.persistence.Persistence; import javax.persistence.Query; import javax.persistence.TypedQuery; import junit.framework.*; import org.eclipse.persistence.queries.SQLCall; import org.eclipse.persistence.sessions.DatabaseSession; import org.eclipse.persistence.sessions.Session; import org.eclipse.persistence.sessions.server.ServerSession; import org.eclipse.persistence.testing.framework.junit.JUnitTestCase; import org.eclipse.persistence.testing.framework.junit.JUnitTestCaseHelper; import org.eclipse.persistence.config.EntityManagerProperties; import org.eclipse.persistence.config.PersistenceUnitProperties; import org.eclipse.persistence.config.QueryHints; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.internal.helper.Helper; import org.eclipse.persistence.internal.jpa.EJBQueryImpl; import org.eclipse.persistence.internal.sessions.AbstractSession; import org.eclipse.persistence.jpa.JpaEntityManager; import org.eclipse.persistence.jpa.JpaHelper; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Address; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.AdvancedMultiTenantTableCreator; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Boss; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Candidate; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Capo; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Card; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Contract; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.MafiaFamily; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Mafioso; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Mason; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Party; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.PhoneNumber; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Reward; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Riding; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Soldier; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.SubCapo; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.SubTask; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Supporter; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.SupporterInfo; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.SupporterInfoSub; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Task; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Trowel; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Underboss; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Card; import org.eclipse.persistence.testing.models.jpa.advanced.multitenant.Envelope; public class AdvancedMultiTenantJunitTest extends JUnitTestCase { public String MULTI_TENANT_VPD_PU; public String MULTI_TENANT_PU; public String MULTI_TENANT_PU_123; public String MULTI_TENANT_TABLE_PER_TENANT_PU; public String MULTI_TENANT_TABLE_PER_TENANT_C_PU; public static long candidateAId; public static long supporter1Id; public static long supporter2Id; public static int ridingId; public static int partyId; public static int masonId; public static int family707; public static int family007; public static int family123; public static int capo123Id; public static int soldier123Id; public static List<Integer> family707Mafiosos = new ArrayList<Integer>(); public static List<Integer> family707Contracts = new ArrayList<Integer>(); public static List<Integer> family007Mafiosos = new ArrayList<Integer>(); public static List<Integer> family007Contracts = new ArrayList<Integer>(); public static List<Integer> family123Mafiosos = new ArrayList<Integer>(); public static List<Integer> family123Contracts = new ArrayList<Integer>(); public AdvancedMultiTenantJunitTest() { super(); } public AdvancedMultiTenantJunitTest(String name) { super(name); } public void setUp() {} public static Test suite() { TestSuite suite = new TestSuite(); suite.setName("AdvancedMultiTenantJunitTest"); suite.addTest(new AdvancedMultiTenantJunitTest("testSetup")); suite.addTest(new AdvancedMultiTenantJunitTest("testCreateMafiaFamily707")); suite.addTest(new AdvancedMultiTenantJunitTest("testCreateMafiaFamily007")); suite.addTest(new AdvancedMultiTenantJunitTest("testCreateEMF123WithoutAllTenantPropertiesSet")); suite.addTest(new AdvancedMultiTenantJunitTest("testCreateMafiaFamily123")); suite.addTest(new AdvancedMultiTenantJunitTest("testValidateMafiaFamily707")); suite.addTest(new AdvancedMultiTenantJunitTest("testValidateMafiaFamily007")); suite.addTest(new AdvancedMultiTenantJunitTest("testValidateMafiaFamily707and007WithSameEM")); suite.addTest(new AdvancedMultiTenantJunitTest("testValidateMafiaFamily123")); suite.addTest(new AdvancedMultiTenantJunitTest("testComplexMultitenantQueries")); suite.addTest(new AdvancedMultiTenantJunitTest("testVPDEMPerTenant")); suite.addTest(new AdvancedMultiTenantJunitTest("testMultitenantOneToOneReadObjectRead")); suite.addTest(new AdvancedMultiTenantJunitTest("testMultitenantPrimaryKeyWithIdClass")); suite.addTest(new AdvancedMultiTenantJunitTest("testTablePerTenantA")); suite.addTest(new AdvancedMultiTenantJunitTest("testTablePerTenantAQueries")); suite.addTest(new AdvancedMultiTenantJunitTest("testTablePerTenantB")); suite.addTest(new AdvancedMultiTenantJunitTest("testTablePerTenantBQueries")); suite.addTest(new AdvancedMultiTenantJunitTest("testTablePerTenantC")); suite.addTest(new AdvancedMultiTenantJunitTest("testTablePerTenantCQueries")); return suite; } public String getMULTI_TENANT_PU() { return "multi-tenant-shared-emf"; } public String getMULTI_TENANT_PU_123() { return "multi-tenant-123"; } public String getMULTI_TENANT_VPD_PU() { return "multi-tenant-vpd"; } public String getMULTI_TENANT_TABLE_PER_TENANT_PU() { return "multi-tenant-table-per-tenant"; } public String getMULTI_TENANT_TABLE_PER_TENANT_C_PU(){ return "multi-tenant-table-per-tenant-C"; } public EntityManager createSharedEMFEntityManager(){ return createEntityManager(getMULTI_TENANT_PU()); } public EntityManager create123EntityManager(){ return createEntityManager(getMULTI_TENANT_PU_123()); } public EntityManager createTenant123EntityManager(){ Map<String, String> properties = new HashMap<String, String>(); EntityManager em = null; //properties passed in createEntityManager() won't work on server since server side entity manager is injected, so we have "eclipselink.tenant-id" in server persistence.xml if (! isOnServer()) { properties.putAll(JUnitTestCaseHelper.getDatabaseProperties(getMULTI_TENANT_PU_123())); properties.put(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, "123"); em = createEntityManager(getMULTI_TENANT_PU_123(), properties); }else{ em = create123EntityManager(); } return em; } public EntityManager createVPDEntityManager(){ return createEntityManager(getMULTI_TENANT_VPD_PU()); } public EntityManager createTableTenantEntityManager(){ return createEntityManager(getMULTI_TENANT_TABLE_PER_TENANT_PU()); } public EntityManager createTableTenantCEntityManager(){ return createEntityManager(getMULTI_TENANT_TABLE_PER_TENANT_C_PU()); } /** * The setup is done as a test, both to record its failure, and to allow execution in the server. */ public void testSetup() { new AdvancedMultiTenantTableCreator().replaceTables(((org.eclipse.persistence.jpa.JpaEntityManager) createSharedEMFEntityManager()).getServerSession()); } public void testTablePerTenantA() { EntityManager em = createTableTenantEntityManager(); try { beginTransaction(em); // Valid to set the table per tenant qualifier now. em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, "A"); Candidate candidateA = new Candidate(); candidateA.setName("CA"); candidateA.addHonor("Raised most money"); candidateA.addHonor("Highest win margin"); candidateA.setSalary(9999999); Supporter supporter1 = new Supporter(); supporter1.setName("Supporter1a"); SupporterInfo supporter1Info = new SupporterInfo(); supporter1Info.setDescription("Supporter1aDesc"); SupporterInfoSub supporter1InfoSub = new SupporterInfoSub(); supporter1InfoSub.setSubDescription("Supporter1aSubDesc"); supporter1Info.setSubInfo(supporter1InfoSub); supporter1.setInfo(supporter1Info); candidateA.addSupporter(supporter1); Supporter supporter2 = new Supporter(); supporter2.setName("Supporter2a"); SupporterInfo supporter2Info = new SupporterInfo(); supporter2Info.setDescription("Supporter2aDesc"); SupporterInfoSub supporter2InfoSub = new SupporterInfoSub(); supporter2InfoSub.setSubDescription("Supporter2aSubDesc"); supporter2Info.setSubInfo(supporter2InfoSub); supporter2.setInfo(supporter2Info); candidateA.addSupporter(supporter2); Supporter supporter3 = new Supporter(); supporter3.setName("Supporter3a"); SupporterInfo supporter3Info = new SupporterInfo(); supporter3Info.setDescription("Supporter3aDesc"); SupporterInfoSub supporter3InfoSub = new SupporterInfoSub(); supporter3InfoSub.setSubDescription("Supporter3aSubDesc"); supporter3Info.setSubInfo(supporter3InfoSub); supporter3.setInfo(supporter3Info); candidateA.addSupporter(supporter3); Party party = new Party(); party.setName("Conservatives"); party.addCandidate(candidateA); Riding riding = new Riding(); riding.setName("Ottawa"); candidateA.setRiding(riding); // Persist our objects. em.persist(party); em.persist(candidateA); em.persist(supporter1); em.persist(supporter2); em.persist(supporter3); em.persist(riding); Mason mason = new Mason(); mason.setName("FromTenantA"); mason.addAward(Helper.timestampFromDate(Helper.dateFromYearMonthDate(2009, 1, 1)), "Best pointer"); mason.addAward(Helper.timestampFromDate(Helper.dateFromYearMonthDate(2010, 5, 9)), "Least screw-ups"); Trowel trowel = new Trowel(); trowel.setType("Pointing"); mason.setTrowel(trowel); trowel.setMason(mason); em.persist(mason); em.persist(trowel); // Grab any id's for verification. candidateAId = candidateA.getId(); ridingId = riding.getId(); partyId = party.getId(); supporter1Id = supporter1.getId(); supporter2Id = supporter2.getId(); masonId = mason.getId(); commitTransaction(em); } catch (RuntimeException e) { throw e; } finally { if (isTransactionActive(em)){ rollbackTransaction(em); } closeEntityManager(em); } } public void testTablePerTenantAQueries() { EntityManager em = createTableTenantEntityManager(); try { beginTransaction(em); em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, "A"); List resultsFromNamedQuery = em.createNamedQuery("Supporter.findAll").getResultList(); List resultsFromDynamicQuery = em.createQuery("SELECT s FROM Supporter s ORDER BY s.id DESC").getResultList(); assertTrue("Incorrect number of supporters returned from named query.", resultsFromNamedQuery.size() == 3); assertTrue("Incorrect number of supporters returned from dynamic query.", resultsFromDynamicQuery.size() == 3); // Test some more complex joining queries. List<Supporter> results = em.createNamedQuery("Supporter.findBySupporterInfo").setParameter("desc", "Supporter1aDesc").getResultList(); assertFalse("No results returned.", results == null); assertTrue("Single result not returned.", results.size() == 1); assertTrue("Didn't return supporter1a", results.get(0).getName().equals("Supporter1a")); results = em.createNamedQuery("Supporter.findBySupporterInfoSub").setParameter("subDesc", "Supporter3aSubDesc").getResultList(); assertFalse("No results returned.", results == null); assertTrue("Single result not returned.", results.size() == 1); assertTrue("Didn't return supporter3a", results.get(0).getName().equals("Supporter3a")); commitTransaction(em); } catch (RuntimeException e) { throw e; } finally { if (isTransactionActive(em)){ rollbackTransaction(em); } closeEntityManager(em); } } public void testTablePerTenantB() { EntityManager em = createTableTenantEntityManager(); try { beginTransaction(em); // Valid to set the table per tenant qualifier now. em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, "B"); // Should not find these ... assertNull("CandidateA was found from tenant B.", em.find(Candidate.class, candidateAId)); assertNull("Supporter1 was found from tenant B.", em.find(Supporter.class, supporter1Id)); assertNull("Supporter2 was found from tenant B.", em.find(Supporter.class, supporter2Id)); assertNull("Mason was found from tenant B.", em.find(Mason.class, masonId)); // Should find these ... Riding riding = em.find(Riding.class, ridingId); assertNotNull("Riding was not found from tenant B", riding); Party party = em.find(Party.class, partyId); assertNotNull("Party was not found from tenant B", party); // TODO: can't do this (would have to initialize the mapping from party again to the new descriptor. // future implementation maybe. //assertTrue("Party had candidates", party.getCandidates().isEmpty()); Candidate candidateB = new Candidate(); candidateB.setName("CB"); candidateB.setSalary(100); em.persist(candidateB); commitTransaction(em); em.clear(); clearCache(getMULTI_TENANT_TABLE_PER_TENANT_PU()); beginTransaction(em); // Valid to set the table per tenant qualifier now. em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, "B"); Candidate candidateBRefreshed = em.find(Candidate.class, candidateB.getId()); assertNull("Candidate B has a Party when he shouldn't have.", candidateBRefreshed.getParty()); assertNull("Candidate B has a Riding when he shouldn't have.", candidateBRefreshed.getRiding()); assertTrue("Candidate B had supporters when he shouldn't have.", candidateBRefreshed.getSupporters().isEmpty()); assertTrue("Candidate B had honors when he shouldn't have.", candidateBRefreshed.getHonors().isEmpty()); assertTrue("Candidate B had the incorrect salary.", candidateBRefreshed.getSalary() == 100); commitTransaction(em); } catch (RuntimeException e) { if (isTransactionActive(em)){ rollbackTransaction(em); } throw e; } finally { closeEntityManager(em); } } public void testTablePerTenantBQueries() { EntityManager em = createTableTenantEntityManager(); try { beginTransaction(em); em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, "B"); List resultsFromNamedQuery = em.createNamedQuery("Supporter.findAll").getResultList(); List resultsFromDynamicQuery = em.createQuery("SELECT s FROM Supporter s ORDER BY s.id DESC").getResultList(); assertTrue("Incorrect number of supporters returned from named query.", resultsFromNamedQuery.isEmpty()); assertTrue("Incorrect number of supporters returned from dynamic query.", resultsFromDynamicQuery.isEmpty()); commitTransaction(em); } catch (RuntimeException e) { throw e; } finally { if (isTransactionActive(em)){ rollbackTransaction(em); } closeEntityManager(em); } } public void testTablePerTenantC() { // Tenant is set in the persistence.xml file. EntityManager em = createTableTenantCEntityManager(); try { beginTransaction(em); Candidate candidate = new Candidate(); candidate.setName("C"); candidate.addHonor("Raised most money"); candidate.addHonor("Highest win margin"); candidate.setSalary(9999999); Supporter supporter1 = new Supporter(); supporter1.setName("Supporter1c"); candidate.addSupporter(supporter1); Supporter supporter2 = new Supporter(); supporter2.setName("Supporter2c"); candidate.addSupporter(supporter2); Party party = new Party(); party.setName("Conservatives"); party.addCandidate(candidate); Riding riding = new Riding(); riding.setName("Ottawa"); candidate.setRiding(riding); // Persist our objects. em.persist(party); em.persist(candidate); em.persist(supporter2); em.persist(supporter1); em.persist(riding); Mason mason = new Mason(); mason.setName("FromTenantC"); mason.addAward(Helper.timestampFromDate(Helper.dateFromYearMonthDate(2009, 1, 1)), "Best pointer"); mason.addAward(Helper.timestampFromDate(Helper.dateFromYearMonthDate(2010, 5, 9)), "Least screw-ups"); Trowel trowel = new Trowel(); trowel.setType("Pointing"); mason.setTrowel(trowel); trowel.setMason(mason); em.persist(mason); em.persist(trowel); // Grab any id's for verification. candidateAId = candidate.getId(); ridingId = riding.getId(); partyId = party.getId(); supporter1Id = supporter1.getId(); supporter2Id = supporter2.getId(); masonId = mason.getId(); commitTransaction(em); } catch (RuntimeException e) { throw e; } finally { if (isTransactionActive(em)){ rollbackTransaction(em); } closeEntityManager(em); } } public void testTablePerTenantCQueries() { EntityManager em = createTableTenantCEntityManager(); try { beginTransaction(em); List resultsFromNamedQuery = em.createNamedQuery("Supporter.findAll").getResultList(); List resultsFromDynamicQuery = em.createQuery("SELECT s FROM Supporter s ORDER BY s.id DESC").getResultList(); assertTrue("Incorrect number of supporters returned from named query.", resultsFromNamedQuery.size() == 2); assertTrue("Incorrect number of supporters returned from dynamic query.", resultsFromDynamicQuery.size() == 2); commitTransaction(em); } catch (RuntimeException e) { throw e; } finally { if (isTransactionActive(em)){ rollbackTransaction(em); } closeEntityManager(em); } } public void testCreateMafiaFamily707() { EntityManager em = createSharedEMFEntityManager(); try { beginTransaction(em); //on server side, you have to set the em properties after transaction begins em.setProperty("tenant.id", "707"); em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, "707"); MafiaFamily family = new MafiaFamily(); family.setName("Gonzo"); family.setRevenue(10000000.00); family.addTag("firstTag"); family.addTag("secondTag"); family.addTag("thirdTag"); Boss boss = new Boss(); boss.setFirstName("707"); boss.setLastName("Boss"); boss.setGender(Mafioso.Gender.Male); Underboss underboss = new Underboss(); underboss.setFirstName("Under"); underboss.setLastName("Boss"); underboss.setGender(Mafioso.Gender.Male); Capo capo1 = new Capo(); capo1.setFirstName("Capo"); capo1.setLastName("Giggaloo"); capo1.setGender(Mafioso.Gender.Female); Capo capo2 = new Capo(); capo2.setFirstName("Capo"); capo2.setLastName("CrazyGlue"); capo2.setGender(Mafioso.Gender.Male); Soldier soldier1 = new Soldier(); soldier1.setFirstName("Soldier"); soldier1.setLastName("One"); soldier1.setGender(Mafioso.Gender.Female); Soldier soldier2 = new Soldier(); soldier2.setFirstName("Soldier"); soldier2.setLastName("Two"); soldier2.setGender(Mafioso.Gender.Male); Soldier soldier3 = new Soldier(); soldier3.setFirstName("Soldier"); soldier3.setLastName("Three"); soldier3.setGender(Mafioso.Gender.Male); Soldier soldier4 = new Soldier(); soldier4.setFirstName("Soldier"); soldier4.setLastName("Four"); soldier4.setGender(Mafioso.Gender.Male); Soldier soldier5 = new Soldier(); soldier5.setFirstName("Soldier"); soldier5.setLastName("Four"); soldier5.setGender(Mafioso.Gender.Female); Contract contract1 = new Contract(); contract1.setDescription("Whack 007 family boss"); Contract contract2 = new Contract(); contract2.setDescription("Acquire fully-automatic guns"); Contract contract3 = new Contract(); contract3.setDescription("Steal some money"); // Populate the relationships. contract1.addSoldier(soldier1); contract1.addSoldier(soldier5); contract2.addSoldier(soldier1); contract2.addSoldier(soldier3); contract2.addSoldier(soldier5); contract3.addSoldier(soldier2); contract3.addSoldier(soldier3); contract3.addSoldier(soldier4); contract3.addSoldier(soldier5); boss.setUnderboss(underboss); capo1.setUnderboss(underboss); capo2.setUnderboss(underboss); capo1.addSoldier(soldier1); capo1.addSoldier(soldier2); capo2.addSoldier(soldier3); capo2.addSoldier(soldier4); capo2.addSoldier(soldier5); underboss.addCapo(capo1); underboss.addCapo(capo2); family.addMafioso(boss); family.addMafioso(underboss); family.addMafioso(capo1); family.addMafioso(capo2); family.addMafioso(soldier1); family.addMafioso(soldier2); family.addMafioso(soldier3); family.addMafioso(soldier4); family.addMafioso(soldier5); // Will cascade through the whole family. em.persist(family); // Store the ids to verify family707 = family.getId(); family707Mafiosos.add(boss.getId()); family707Mafiosos.add(underboss.getId()); family707Mafiosos.add(capo1.getId()); family707Mafiosos.add(capo2.getId()); family707Mafiosos.add(soldier1.getId()); family707Mafiosos.add(soldier2.getId()); family707Mafiosos.add(soldier3.getId()); family707Mafiosos.add(soldier4.getId()); family707Mafiosos.add(soldier5.getId()); family707Contracts.add(contract1.getId()); family707Contracts.add(contract2.getId()); family707Contracts.add(contract3.getId()); commitTransaction(em); } catch (RuntimeException e) { if (isTransactionActive(em)){ rollbackTransaction(em); } throw e; } finally { closeEntityManager(em); } } public void testCreateMafiaFamily007() { EntityManager em = createSharedEMFEntityManager(); try { beginTransaction(em); //on server side, you have to set the em properties after transaction begins em.setProperty("tenant.id", "007"); em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, "007"); MafiaFamily family = new MafiaFamily(); family.setName("Bond"); family.setRevenue(987654321.03); family.addTag("tag1"); family.addTag("tag2"); family.addTag("tag3"); family.addTag("tag4"); family.addTag("tag5"); Boss boss = new Boss(); boss.setFirstName("007"); boss.setLastName("Boss"); boss.setGender(Mafioso.Gender.Female); Underboss underboss = new Underboss(); underboss.setFirstName("Second"); underboss.setLastName("InCommand"); underboss.setGender(Mafioso.Gender.Female); Capo capo1 = new Capo(); capo1.setFirstName("Capo"); capo1.setLastName("Lubey"); capo1.setGender(Mafioso.Gender.Male); Capo capo2 = new Capo(); capo2.setFirstName("Capo"); capo2.setLastName("Greasy"); capo2.setGender(Mafioso.Gender.Female); Soldier soldier1 = new Soldier(); soldier1.setFirstName("First"); soldier1.setLastName("Grunt"); soldier1.setGender(Mafioso.Gender.Male); Soldier soldier2 = new Soldier(); soldier2.setFirstName("Second"); soldier2.setLastName("Grunt"); soldier2.setGender(Mafioso.Gender.Female); Soldier soldier3 = new Soldier(); soldier3.setFirstName("Third"); soldier3.setLastName("Grunt"); soldier3.setGender(Mafioso.Gender.Female); Soldier soldier4 = new Soldier(); soldier4.setFirstName("Fourth"); soldier4.setLastName("Grunt"); soldier4.setGender(Mafioso.Gender.Female); Soldier soldier5 = new Soldier(); soldier5.setFirstName("Fifth"); soldier5.setLastName("Grunt"); soldier5.setGender(Mafioso.Gender.Male); Soldier soldier6 = new Soldier(); soldier6.setFirstName("Sixth"); soldier6.setLastName("Grunt"); soldier6.setGender(Mafioso.Gender.Male); Soldier soldier7 = new Soldier(); soldier7.setFirstName("Seventh"); soldier7.setLastName("Grunt"); soldier7.setGender(Mafioso.Gender.Male); Contract contract1 = new Contract(); contract1.setDescription("Whack 707 family boss"); Contract contract2 = new Contract(); contract2.setDescription("Acquire semi-automatic guns"); Contract contract3 = new Contract(); contract3.setDescription("Set up new financing deals"); // Populate the relationships. contract1.addSoldier(soldier1); contract1.addSoldier(soldier5); contract2.addSoldier(soldier1); contract2.addSoldier(soldier3); contract2.addSoldier(soldier7); contract3.addSoldier(soldier2); contract3.addSoldier(soldier3); contract3.addSoldier(soldier4); contract3.addSoldier(soldier5); boss.setUnderboss(underboss); capo1.setUnderboss(underboss); capo2.setUnderboss(underboss); capo1.addSoldier(soldier1); capo1.addSoldier(soldier2); capo2.addSoldier(soldier3); capo2.addSoldier(soldier4); capo2.addSoldier(soldier5); capo2.addSoldier(soldier6); capo2.addSoldier(soldier7); underboss.addCapo(capo1); underboss.addCapo(capo2); family.addMafioso(boss); family.addMafioso(underboss); family.addMafioso(capo1); family.addMafioso(capo2); family.addMafioso(soldier1); family.addMafioso(soldier2); family.addMafioso(soldier3); family.addMafioso(soldier4); family.addMafioso(soldier5); family.addMafioso(soldier6); family.addMafioso(soldier7); // Will cascade through the whole family. em.persist(family); family007 = family.getId(); family007Mafiosos.add(boss.getId()); family007Mafiosos.add(underboss.getId()); family007Mafiosos.add(capo1.getId()); family007Mafiosos.add(capo2.getId()); family007Mafiosos.add(soldier1.getId()); family007Mafiosos.add(soldier2.getId()); family007Mafiosos.add(soldier3.getId()); family007Mafiosos.add(soldier4.getId()); family007Mafiosos.add(soldier5.getId()); family007Mafiosos.add(soldier6.getId()); family007Mafiosos.add(soldier7.getId()); family007Contracts.add(contract1.getId()); family007Contracts.add(contract2.getId()); family007Contracts.add(contract3.getId()); commitTransaction(em); } catch (RuntimeException e) { if (isTransactionActive(em)){ rollbackTransaction(em); } throw e; } finally { closeEntityManager(em); } } /** * This test is expected to fail. */ public void testCreateEMF123WithoutAllTenantPropertiesSet() { EntityManager em = null; boolean exceptionCaught = false; try { em = create123EntityManager(); } catch (RuntimeException e) { exceptionCaught = true; } finally { if (em != null) { closeEntityManager(em); } closeEntityManagerFactory(getMULTI_TENANT_PU_123()); } assertTrue("No exception received on a non shared emf without all tenant properties provided", exceptionCaught); } public void testCreateMafiaFamily123() { EntityManager em = createTenant123EntityManager(); try { beginTransaction(em); MafiaFamily family = new MafiaFamily(); family.setName("Galore"); family.setRevenue(4321.03); family.addTag("newtag1"); Boss boss = new Boss(); boss.setFirstName("Kitty"); boss.setLastName("Galore"); boss.setGender(Mafioso.Gender.Female); boss.addReward("Reward 1"); boss.addReward("Reward 2"); boss.setAddress(new Address("1st Street", "Ottawa", "Ontario", "Canada", "B1T 2Y1")); Underboss underboss = new Underboss(); underboss.setFirstName("Number2"); underboss.setLastName("Galore"); underboss.setGender(Mafioso.Gender.Male); underboss.addReward("Reward 3"); underboss.addReward("Reward 4"); underboss.setAddress(new Address("2nd Street", "Ottawa", "Ontario", "Canada", "B1T 2Y2")); Capo capo1 = new Capo(); capo1.setFirstName("Capo"); capo1.setLastName("Galore"); capo1.setGender(Mafioso.Gender.Male); capo1.setAddress(new Address("3rd Street", "Ottawa", "Ontario", "Canada", "B1T 2Y3")); Capo capo2 = new Capo(); capo2.setFirstName("Drill"); capo2.setLastName("Bit"); capo2.setGender(Mafioso.Gender.Male); capo2.setAddress(new Address("4th Street", "Ottawa", "Ontario", "Canada", "B1T 2Y4")); Soldier soldier1 = new Soldier(); soldier1.setFirstName("Grunt"); soldier1.setLastName("Galore"); soldier1.setGender(Mafioso.Gender.Male); soldier1.addReward("Reward 5"); soldier1.addReward("Reward 6"); soldier1.addReward("Reward 7"); soldier1.addReward("Reward 8"); soldier1.setAddress(new Address("5th Street", "Ottawa", "Ontario", "Canada", "B1T 2Y5")); Soldier soldier2 = new Soldier(); soldier2.setFirstName("Hammer"); soldier2.setLastName("Head"); soldier2.setGender(Mafioso.Gender.Male); soldier2.addReward("Reward 9"); soldier2.addReward("Reward 10"); soldier2.setAddress(new Address("6th Street", "Ottawa", "Ontario", "Canada", "B1T 2Y6")); Contract contract1 = new Contract(); contract1.setDescription("Whack all other family bosses"); Contract contract2 = new Contract(); contract2.setDescription("Pillage, pillage, pillage!"); // Populate the relationships. contract1.addSoldier(soldier1); contract2.addSoldier(soldier1); boss.setUnderboss(underboss); capo1.setUnderboss(underboss); capo1.addSoldier(soldier1); capo2.addSoldier(soldier2); underboss.addCapo(capo1); underboss.addCapo(capo2); family.addMafioso(boss); family.addMafioso(underboss); family.addMafioso(capo1); family.addMafioso(capo2); family.addMafioso(soldier1); family.addMafioso(soldier2); // Will cascade through the whole family. em.persist(family); capo123Id = capo1.getId(); soldier123Id = soldier1.getId(); family123 = family.getId(); family123Mafiosos.add(boss.getId()); family123Mafiosos.add(underboss.getId()); family123Mafiosos.add(capo1.getId()); family123Mafiosos.add(soldier1.getId()); family123Contracts.add(contract1.getId()); family123Contracts.add(contract2.getId()); commitTransaction(em); } catch (RuntimeException e) { if (isTransactionActive(em)){ rollbackTransaction(em); } throw e; } finally { closeEntityManager(em); } } public void testValidateMafiaFamily707() { EntityManager em = createSharedEMFEntityManager(); try { validateMafiaFamily707(em); } catch (RuntimeException e) { if (isTransactionActive(em)){ rollbackTransaction(em); } throw e; } finally { closeEntityManager(em); } } public void testValidateMafiaFamily007() { EntityManager em = createSharedEMFEntityManager(); try { validateMafiaFamily007(em); } catch (RuntimeException e) { if (isTransactionActive(em)){ rollbackTransaction(em); } throw e; } finally { closeEntityManager(em); } } public void testValidateMafiaFamily707and007WithSameEM() { EntityManager em = createSharedEMFEntityManager(); try { validateMafiaFamily707(em); validateMafiaFamily007(em); } catch (RuntimeException e) { if (isTransactionActive(em)){ rollbackTransaction(em); } throw e; } finally { closeEntityManager(em); } } public void testValidateMafiaFamily123() { EntityManager em = createTenant123EntityManager(); try { clearCache(getMULTI_TENANT_PU_123()); em.clear(); MafiaFamily family = em.find(MafiaFamily.class, family123); assertNotNull("The Mafia Family with id: " + family123 + ", was not found", family); assertTrue("The Mafia Family had an incorrect number of tags [" + family.getTags().size() + "], expected [1]", family.getTags().size() == 1); assertNull("The Mafia Family with id: " + family707 + ", was found (when it should not have been)", em.find(MafiaFamily.class, family707)); assertNull("The Mafia Family with id: " + family007 + ", was found (when it should not have been)", em.find(MafiaFamily.class, family007)); assertFalse("No mafiosos part of 123 family", family.getMafiosos().isEmpty()); // See if we can find any members of the other family. for (Integer id : family707Mafiosos) { assertNull("Found family 707 mafioso.", em.find(Mafioso.class, id)); } // Try a native sql query. Should get an exception since the // eclipselink.jdbc.allow-native-sql-queries property is set to // false for this PU. boolean exceptionCaught = false; List mafiaFamilies = null; try { mafiaFamilies = em.createNativeQuery("select * from JPA_MAFIA_FAMILY").getResultList(); } catch (Exception e) { exceptionCaught = true; } assertTrue("No exception was caught from issuing a native query.", exceptionCaught); exceptionCaught = false; try { mafiaFamilies = em.createNamedQuery("findSQLMafiaFamilies").getResultList(); } catch (Exception e) { exceptionCaught = true; } assertTrue("No exception was caught from issuing a named native query.", exceptionCaught); // Query directly for the boss from the other family. Boss otherBoss = em.find(Boss.class, family707Mafiosos.get(0)); assertNull("Found family 707 boss.", otherBoss); // See if we can find any contracts of the other family. for (Integer id : family707Contracts) { assertNull("Found family 707 contract. ", em.find(Contract.class, id)); } // Try a select named query List families = em.createNamedQuery("findAllMafiaFamilies").getResultList(); assertTrue("Incorrect number of families were returned [" + families.size() + "], expected [1]", families.size() == 1); } catch (RuntimeException e) { if (isTransactionActive(em)){ rollbackTransaction(em); } throw e; } finally { closeEntityManager(em); } } protected void validateMafiaFamily007(EntityManager em) { clearCache(getMULTI_TENANT_PU()); em.clear(); beginTransaction(em); em.setProperty("tenant.id", "007"); em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, "007"); MafiaFamily family = em.find(MafiaFamily.class, family007); assertNotNull("The Mafia Family with id: " + family007 + ", was not found", family); assertTrue("The Mafia Family had an incorrect number of tags [" + family.getTags().size() + "], expected [5]", family.getTags().size() == 5); assertNull("The Mafia Family with id: " + family707 + ", was found (when it should not have been)", em.find(MafiaFamily.class, family707)); assertNull("The Mafia Family with id: " + family123 + ", was found (when it should not have been)", em.find(MafiaFamily.class, family123)); assertFalse("No mafiosos part of 007 family", family.getMafiosos().isEmpty()); // See if we can find any members of the other family. for (Integer id : family707Mafiosos) { assertNull("Found family 707 mafioso.", em.find(Mafioso.class, id)); } // Query directly for the boss from the other family. Boss otherBoss = em.find(Boss.class, family707Mafiosos.get(0)); assertNull("Found family 707 boss.", otherBoss); // See if we can find any contracts of the other family. for (Integer id : family707Contracts) { assertNull("Found family 707 contract.", em.find(Contract.class, id)); } // Read and validate our contracts List<Contract> contracts = em.createNamedQuery("FindAllContracts").getResultList(); assertTrue("Incorrect number of contracts were returned [" + contracts.size() + "], expected[3]", contracts.size() == 3); for (Contract contract : contracts) { assertFalse("Contract description was voided.", contract.getDescription().equals("voided")); } // Try a select named query List families = em.createNamedQuery("findAllMafiaFamilies").getResultList(); assertTrue("Incorrect number of families were returned [" + families.size() + "], expected [1]", families.size() == 1); // Find our boss and make sure his name has not been compromised from the 707 family. Boss boss = em.find(Boss.class, family007Mafiosos.get(0)); assertFalse("The Boss name has been compromised", boss.getFirstName().equals("Compromised")); commitTransaction(em); } protected void validateMafiaFamily707(EntityManager em) { clearCache(getMULTI_TENANT_PU()); em.clear(); beginTransaction(em); em.setProperty("tenant.id", "707"); em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, "707"); MafiaFamily family = em.find(MafiaFamily.class, family707); assertNotNull("The Mafia Family with id: " + family707 + ", was not found", family); assertTrue("The Mafia Family had an incorrect number of tags [" + family.getTags().size() + "], expected [3]", family.getTags().size() == 3); assertNull("The Mafia Family with id: " + family007 + ", was found (when it should not have been)", em.find(MafiaFamily.class, family007)); assertNull("The Mafia Family with id: " + family123 + ", was found (when it should not have been)", em.find(MafiaFamily.class, family123)); assertFalse("No mafiosos part of 707 family", family.getMafiosos().isEmpty()); // See if we can find any members of the other family. for (Integer id : family007Mafiosos) { assertNull("Found family 007 mafioso.", em.find(Mafioso.class, id)); } // Query directly for the boss from the other family. Boss otherBoss = em.find(Boss.class, family007Mafiosos.get(0)); assertNull("Found family 007 boss.", otherBoss); // See if we can find any contracts of the other family. for (Integer id : family007Contracts) { assertNull("Found family 007 contract.", em.find(Contract.class, id)); } // Try deleting a contract from the 007 family. Query deleteQuery = em.createNamedQuery("DeleteContractByPrimaryKey"); deleteQuery.setParameter("id", family007Contracts.get(0)); int result = deleteQuery.executeUpdate(); assertTrue("Was able to delete a contract from the 007 family", result == 0); // Update all our contract descriptions to be 'voided' Query updateAllQuery = em.createNamedQuery("UpdateAllContractDescriptions"); updateAllQuery.executeUpdate(); // Need to check that tenant id column is present assertTrue("Tenant discriminator column not found in update all query", ((EJBQueryImpl) updateAllQuery).getDatabaseQuery().getCall().getSQLString().contains("TENANT_ID")); // Read and validate the contracts List<Contract> contracts = em.createNamedQuery("FindAllContracts").getResultList(); int contractNumber = contracts.size(); assertTrue("Incorrect number of contracts were returned [" + contracts.size() + "], expected [3]", contracts.size() == 3); for (Contract contract : contracts) { assertTrue("Contract description was not voided.", contract.getDescription().equals("voided")); } // See how many soldiers are returned from a jpql query List soldiers = em.createQuery("SELECT s from Soldier s").getResultList(); assertTrue("Incorrect number of soldiers were returned [" + soldiers.size() + "], expected [5]", soldiers.size() == 5); if(getServerSession(getMULTI_TENANT_PU()).getPlatform().isSymfoware()) { getServerSession(getMULTI_TENANT_PU()).logMessage("Test AdvancedMultiTenantJunitTest partially skipped for this platform, " +"which uses UpdateAll internally to check tenant-id when updating an entity using JOINED inheritance strategy. " +"Symfoware doesn't support UpdateAll/DeleteAll on multi-table objects (see rfe 298193)."); commitTransaction(em); return; } // We know what the boss's id is for the 007 family to try to update him from the 707 pu. // The 007 family is validated after this test. Query query = em.createNamedQuery("UpdateBossName"); query.setParameter("name", "Compromised"); query.setParameter("id", family007Mafiosos.get(0)); query.executeUpdate(); commitTransaction(em); } public void testComplexMultitenantQueries() { EntityManager em = createTenant123EntityManager(); try { clearCache(getMULTI_TENANT_PU_123()); em.clear(); // Try passing in a sub entity as a parameter. try { Query q = em.createQuery("SELECT s FROM Soldier s WHERE s.capo=?1"); SubCapo subCapo = new SubCapo(); subCapo.setId(capo123Id); q.setParameter(1, subCapo); List<Soldier> soldiers = q.getResultList(); assertTrue("Incorrect number of soldiers returned [" + soldiers.size() +"], expected [1]", soldiers.size() == 1); assertTrue("Mafioso returned was not a soldier", soldiers.get(0).isSoldier()); assertTrue("Soldier returned was not the expected soldier", soldiers.get(0).getId() == soldier123Id); } catch (Exception e) { fail("Exception encountered on named parameter query (with tenant discriminator columns) : " + e); } // Try a join fetch try { TypedQuery<MafiaFamily> q = em.createQuery("SELECT m FROM MafiaFamily m ORDER BY m.id DESC", MafiaFamily.class); q.setHint(QueryHints.FETCH, "m.mafiosos"); q.getResultList(); } catch (Exception e) { fail("Exception encountered on join fetch query (with tenant discriminator columns): " + e); } // Try a nested join fetch try { TypedQuery<MafiaFamily> q = em.createQuery("SELECT f FROM MafiaFamily f ORDER BY f.id ASC", MafiaFamily.class); q.setHint(QueryHints.FETCH, "f.mafiosos.rewards"); q.getResultList(); } catch (Exception e) { fail("Exception encountered on nested join fetch query (with tenant discriminator columns): " + e); } // Try a batch fetch try { TypedQuery<MafiaFamily> query = em.createQuery("SELECT f FROM MafiaFamily f", MafiaFamily.class); query.setHint(QueryHints.BATCH, "f.mafiosos"); List<MafiaFamily> families = query.getResultList(); // Should only be one family assertTrue("Incorrect number of families returned [" + families.size() +"], expected [1]", families.size() == 1); int size = families.get(0).getMafiosos().size(); assertTrue("Incorrect number of mafiosos returned [" + size + "], expected [6]", size == 6); } catch (Exception e) { fail("Exception encountered on batch fetch query (with tenant discriminator columns): " + e); } // Try a multiple select try { Query query = em.createQuery("SELECT m.address, m.family FROM Mafioso m WHERE m.address.city = 'Ottawa' AND m.family.name LIKE 'Galore'", MafiaFamily.class); List results = query.getResultList(); int size = results.size(); assertTrue("Incorrect number of results returned [" + size + "], expected [6]", size == 6); } catch (Exception e) { fail("Exception encountered on mulitple select statement (with tenant discriminator columns): " + e); } // Try a delete all on single table (Contracts) try { beginTransaction(em); int contracts = em.createNamedQuery("FindAllContracts").getResultList().size(); int deletes = em.createNamedQuery("DeleteAllContracts").executeUpdate(); assertTrue("Incorrect number of contracts deleted [" + deletes + "], expected [" + contracts + "]", deletes == 2); commitTransaction(em); } catch (Exception e) { fail("Exception encountered on delete all query with single table (with tenant discriminator columns): " + e); } if(getServerSession(getMULTI_TENANT_PU_123()).getPlatform().isSymfoware()) { getServerSession(getMULTI_TENANT_PU_123()).logMessage("Test AdvancedMultiTenantJunitTest partially skipped for this platform, " +"Symfoware doesn't support UpdateAll/DeleteAll on multi-table objects (see rfe 298193)."); } else { // Try a delete all on multiple table (MafiaFamily) try { beginTransaction(em); List<MafiaFamily> allFamilies = em.createNamedQuery("findAllMafiaFamilies").getResultList(); int families = allFamilies.size(); assertTrue("More than one family was found ["+ families +"]", families == 1); Query deleteQuery = em.createNamedQuery("DeleteAllMafiaFamilies"); deleteQuery.setHint(QueryHints.ALLOW_NATIVE_SQL_QUERY, true); int deletes = deleteQuery.executeUpdate(); assertTrue("Incorrect number of families deleted [" + deletes + "], expected [" + families + "]", deletes == 1); commitTransaction(em); } catch (Exception e) { fail("Exception encountered on delete all query with multiple table (with tenant discriminator columns): " + e); } } } finally { if (isTransactionActive(em)){ rollbackTransaction(em); } closeEntityManager(em); } // Some verification of what was deleted. EntityManager em007 = createSharedEMFEntityManager(); try { List<MafiaFamily> families = em007.createNativeQuery("select * from JPA_MAFIA_FAMILY", MafiaFamily.class).getResultList(); assertTrue("Incorrect number of families found through SQL [" + families.size() + "], expected [2]", families.size() == 2); // Clear out the shared cache with what we read through native SQL. clearCache(getMULTI_TENANT_PU()); em007.clear(); beginTransaction(em007); em007.setProperty("tenant.id", "007"); em007.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, "007"); MafiaFamily family = em007.find(MafiaFamily.class, family007); assertFalse("Family 007 tags were nuked in delete all query above!", family.getTags().isEmpty()); assertFalse("Family 007 revenue was nuked in delete all query above!", family.getRevenue() == null); commitTransaction(em007); } catch (Exception e) { fail("Exception caught: " + e); } finally { if (isTransactionActive(em007)) { rollbackTransaction(em007); } closeEntityManager(em007); } } /** * This test will try to DDL generate on deploy. Meaning once we try to * access the VPD PU we'll get an exception if we are not an oracle platform * so check before throwing an exception. * * VPD is currently supported only on Oracle. */ public void testVPDEMPerTenant() { EntityManager em1 = null; EntityManager em2 = null; try { em1 = createVPDEntityManager(); em1.setProperty("tenant.id", "bsmith@here.com"); em2 = createVPDEntityManager(); em2.setProperty("tenant.id", "gdune@there.ca"); testInsertTask(em1, "blah", false); testInsertTask(em2, "halb", false); assertTrue("Found more than one result", em1.createQuery("Select t from Task t").getResultList().size() == 1); assertTrue("Found more than one result", em2.createQuery("Select t from Task t").getResultList().size() == 1); Task task1 = testInsertTaskWithOneSubtask(em1, "Rock that Propsal", false, "Write Proposal", false); assertNotNull(em1.find(Task.class, task1.getId())); assertNull(em2.find(Task.class, task1.getId())); // negative test Task task3 = testInsertTask(em2, "mow lawn", true); assertNull(em1.find(Task.class, task3.getId())); // negative test assertNotNull(em2.find(Task.class, task3.getId())); SubTask task4 = testInsertSubTaskObject(em1, "SubTask Object Creation", true); assertNotNull(em1.find(SubTask.class, task4.getId())); assertNull(em2.find(SubTask.class, task4.getId())); // negative test } catch (RuntimeException e) { if (em1 != null && isTransactionActive(em1)){ rollbackTransaction(em1); } if (em2 != null && isTransactionActive(em2)){ rollbackTransaction(em2); } if (! getPlatform(getMULTI_TENANT_VPD_PU()).isOracle()) { warning("VPD tests currently run only on an Oracle platform"); } else { throw e; } } finally { if (em1 != null) { closeEntityManager(em1); } if (em2 != null) { closeEntityManager(em2); } } } public void testMultitenantPrimaryKeyWithIdClass() { EntityManager em = createSharedEMFEntityManager(); PhoneNumber number = new PhoneNumber();; number.setAreaCode("613"); number.setNumber("123-4567"); number.setType("Home"); try { beginTransaction(em); // On server side, you have to set the em properties after // transaction begins em.setProperty("tenant.id", "707"); em.persist(number); commitTransaction(em); // This should hit the cache. beginTransaction(em); em.setProperty("tenant.id", "707"); PhoneNumber refreshedNumber = em.find(PhoneNumber.class, number.buildPK()); rollbackTransaction(em); } catch (RuntimeException e) { if (isTransactionActive(em)){ rollbackTransaction(em); } throw e; } finally { closeEntityManager(em); } } public void testMultitenantOneToOneReadObjectRead() { EntityManager em = createSharedEMFEntityManager(); try { beginTransaction(em); em.setProperty("tenant.id", "371453"); Envelope envelope = new Envelope(); envelope.setColor("Red"); Card card = new Card(); card.setPrice(2.99); card.setColor("Yellow"); card.setPrintYear(2012); card.setOccasion("Sympathy"); card.setFrontCaption("Get well soon"); card.setInsideCaption("Here's to a speedy recovery"); card.setEnvelope(envelope); envelope.setCard(card); // Will cascade to the envelope em.persist(card); commitTransaction(em); em.clear(); clearCache(getMULTI_TENANT_PU()); beginTransaction(em); em.setProperty("tenant.id", "371453"); envelope = em.merge(envelope); commitTransaction(em); em.clear(); clearCache(getMULTI_TENANT_PU()); beginTransaction(em); em.setProperty("tenant.id", "371453"); card = em.merge(card); commitTransaction(em); } catch (RuntimeException e) { if (isTransactionActive(em)){ rollbackTransaction(em); } throw e; } finally { closeEntityManager(em); } } private Task testInsertTask(EntityManager em, String description, boolean isCompleted) { beginTransaction(em); Task task = new Task(); task.setDescription(description); task.setCompleted(isCompleted); em.persist(task); commitTransaction(em); return task; } private Task testInsertTaskWithOneSubtask(EntityManager em, String description, boolean isCompleted, String subtaskDesc, boolean isSubtaskCompleted) { beginTransaction(em); Task task = new Task(); Task subtask = new Task(); task.setDescription(description); task.setCompleted(isCompleted); subtask.setDescription(subtaskDesc); subtask.setCompleted(isSubtaskCompleted); task.addSubtask(subtask); em.persist(subtask); em.persist(task); commitTransaction(em); return task; } private SubTask testInsertSubTaskObject(EntityManager em, String description, boolean isCompleted) { beginTransaction(em); SubTask subTask = new SubTask(); subTask.setDescription(description); subTask.setCompleted(isCompleted); em.persist(subTask); commitTransaction(em); return subTask; } }