From ee6f4acc3ff9ac43ea4e98579b478e55767aef24 Mon Sep 17 00:00:00 2001 From: Jody Grassel Date: Fri, 23 Aug 2013 14:11:17 +0000 Subject: [PATCH] OPENJPA-2414: FinderCache does not consider active Fetch Groups/FetchPlan added Fields git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@1516853 13f79535-47bb-0310-9956-ffa450edef68 --- .../openjpa/jdbc/kernel/FinderCacheImpl.java | 12 + .../kernel/DelegatingFetchConfiguration.java | 8 + .../openjpa/kernel/FetchConfiguration.java | 6 + .../kernel/FetchConfigurationImpl.java | 80 +- .../fetchgroups/TestFetchGroups.java | 1396 +++++++++++++++++ 5 files changed, 1494 insertions(+), 8 deletions(-) create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/fetchgroups/TestFetchGroups.java diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/FinderCacheImpl.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/FinderCacheImpl.java index d423b3d0b..15383c3d4 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/FinderCacheImpl.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/FinderCacheImpl.java @@ -107,6 +107,12 @@ public class FinderCacheImpl if (fetch.getReadLockLevel() != 0) { return null; } + + // FinderCache only operates with Default Fetch Plans + if (!fetch.isDefaultPUFetchGroupConfigurationOnly()) { + return null; + } + boolean ignore = isHinted(fetch, QueryHints.HINT_IGNORE_FINDER); boolean invalidate = isHinted(fetch, QueryHints.HINT_INVALIDATE_FINDER); if (invalidate) { @@ -144,6 +150,12 @@ public class FinderCacheImpl if (fetch.getReadLockLevel() != 0) { return null; } + + // FinderCache only operates with Default Fetch Plans + if (!fetch.isDefaultPUFetchGroupConfigurationOnly()) { + return null; + } + boolean recache = isHinted(fetch, QueryHints.HINT_RECACHE_FINDER); if (isExcluded(mapping)) { return recache ? put(mapping, select) : null; diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingFetchConfiguration.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingFetchConfiguration.java index 13dfc4fd8..4a7543259 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingFetchConfiguration.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingFetchConfiguration.java @@ -500,6 +500,14 @@ public class DelegatingFetchConfiguration } } + public boolean isDefaultPUFetchGroupConfigurationOnly() { + try { + return _fetch.isDefaultPUFetchGroupConfigurationOnly(); + } catch (RuntimeException re) { + throw translate(re); + } + } + public Object getHint(String name) { try { return _fetch.getHint(name); diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfiguration.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfiguration.java index a1f01cbb4..436703a43 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfiguration.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfiguration.java @@ -414,6 +414,12 @@ public interface FetchConfiguration */ public boolean isHintSet(String key); + /** + * Affirm if the Fetch Plan currently matches the Persistence Unit's configured default. + * + */ + public boolean isDefaultPUFetchGroupConfigurationOnly(); + /** * Root classes for recursive operations. This set is not thread safe. */ diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java index b0dacb6d2..0b9e30d99 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java @@ -145,6 +145,7 @@ public class FetchConfigurationImpl public Map hints = null; public boolean fetchGroupContainsDefault = false; public boolean fetchGroupContainsAll = false; + public boolean fetchGroupIsPUDefault = false; public boolean extendedPathLookup = false; public DataCacheRetrieveMode cacheRetrieveMode = DataCacheRetrieveMode.USE; public DataCacheStoreMode cacheStoreMode = DataCacheStoreMode.USE; @@ -186,8 +187,11 @@ public class FetchConfigurationImpl setFlushBeforeQueries(conf.getFlushBeforeQueriesConstant()); setLockTimeout(conf.getLockTimeout()); setQueryTimeout(conf.getQueryTimeout()); - clearFetchGroups(); - addFetchGroups(Arrays.asList(conf.getFetchGroupsList())); + + String[] fetchGroupList = conf.getFetchGroupsList(); + clearFetchGroups((fetchGroupList == null || fetchGroupList.length == 0)); + + addFetchGroups(Arrays.asList(fetchGroupList)); setMaxFetchDepth(conf.getMaxFetchDepth()); } @@ -339,6 +343,10 @@ public class FetchConfigurationImpl } public FetchConfiguration addFetchGroup(String name) { + return addFetchGroup(name, true); + } + + public FetchConfiguration addFetchGroup(String name, boolean recomputeIsDefault) { if (StringUtils.isEmpty(name)) throw new UserException(_loc.get("null-fg")); @@ -347,11 +355,15 @@ public class FetchConfigurationImpl if (_state.fetchGroups == null) _state.fetchGroups = new HashSet(); _state.fetchGroups.add(name); + if (FetchGroup.NAME_ALL.equals(name)) _state.fetchGroupContainsAll = true; else if (FetchGroup.NAME_DEFAULT.equals(name)) _state.fetchGroupContainsDefault = true; } finally { + if (recomputeIsDefault) { + verifyDefaultPUFetchGroups(); + } unlock(); } return this; @@ -361,11 +373,17 @@ public class FetchConfigurationImpl if (groups == null || groups.isEmpty()) return this; for (String group : groups) - addFetchGroup(group); + addFetchGroup(group, false); + + verifyDefaultPUFetchGroups(); return this; } public FetchConfiguration removeFetchGroup(String group) { + return removeFetchGroup(group, true); + } + + public FetchConfiguration removeFetchGroup(String group, boolean recomputeIsDefault) { lock(); try { if (_state.fetchGroups != null) { @@ -376,6 +394,9 @@ public class FetchConfigurationImpl _state.fetchGroupContainsDefault = false; } } finally { + if (recomputeIsDefault) { + verifyDefaultPUFetchGroups(); + } unlock(); } return this; @@ -386,8 +407,9 @@ public class FetchConfigurationImpl try { if (_state.fetchGroups != null && groups != null) for (String group : groups) - removeFetchGroup(group); + removeFetchGroup(group, false); } finally { + verifyDefaultPUFetchGroups(); unlock(); } return this; @@ -413,18 +435,53 @@ public class FetchConfigurationImpl _state.fetchGroups.add(FetchGroup.NAME_DEFAULT); // OPENJPA-2413 } } finally { + verifyDefaultPUFetchGroups(); unlock(); } return this; } public FetchConfiguration resetFetchGroups() { - clearFetchGroups(); + String[] fetchGroupList = _state.ctx.getConfiguration().getFetchGroupsList(); + clearFetchGroups((fetchGroupList == null || fetchGroupList.length == 0)); + if (_state.ctx != null) - addFetchGroups(Arrays.asList(_state.ctx.getConfiguration(). - getFetchGroupsList())); + addFetchGroups(Arrays.asList(fetchGroupList)); + + verifyDefaultPUFetchGroups(); + return this; } + + /** + * Determine if the current selection of FetchGroups is equivalent to the Configuration's default FetchGroups + */ + private void verifyDefaultPUFetchGroups() { + _state.fetchGroupIsPUDefault = false; + + if (_state.fields != null && !_state.fields.isEmpty()) { + return; + } + + if (_state.fetchGroups != null && _state.ctx != null) { + List defaultPUFetchGroups = Arrays.asList(_state.ctx.getConfiguration().getFetchGroupsList()); + if (_state.fetchGroups.size() != defaultPUFetchGroups.size()) { + return; + } + + for (String fetchGroupName : defaultPUFetchGroups) { + if (!_state.fetchGroups.contains(fetchGroupName)) { + return; + } + } + + _state.fetchGroupIsPUDefault = true; + } + } + + public boolean isDefaultPUFetchGroupConfigurationOnly() { + return _state.fetchGroupIsPUDefault; + } public Set getFields() { if (_state.fields == null) return Collections.emptySet(); @@ -444,6 +501,7 @@ public class FetchConfigurationImpl if (_state.fields == null) _state.fields = new HashSet(); _state.fields.add(field); + _state.fetchGroupIsPUDefault = false; } finally { unlock(); } @@ -468,8 +526,13 @@ public class FetchConfigurationImpl public FetchConfiguration removeField(String field) { lock(); try { - if (_state.fields != null) + if (_state.fields != null) { _state.fields.remove(field); + + if (_state.fields.size() == 0) { + verifyDefaultPUFetchGroups(); + } + } } finally { unlock(); } @@ -493,6 +556,7 @@ public class FetchConfigurationImpl if (_state.fields != null) _state.fields.clear(); } finally { + verifyDefaultPUFetchGroups(); unlock(); } return this; diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/fetchgroups/TestFetchGroups.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/fetchgroups/TestFetchGroups.java new file mode 100644 index 000000000..bce0eed3e --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/fetchgroups/TestFetchGroups.java @@ -0,0 +1,1396 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.openjpa.persistence.fetchgroups; + +import java.util.HashSet; + +import org.apache.openjpa.kernel.FetchConfiguration; +import org.apache.openjpa.persistence.FetchPlan; +import org.apache.openjpa.persistence.OpenJPAEntityManager; +import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory; +import org.apache.openjpa.persistence.test.SingleEMTestCase; + +public class TestFetchGroups extends SingleEMTestCase { + private static final int empPerMgr = 5; + private static final int mgrCount = 3; + private static final int empCount = mgrCount * empPerMgr; + + + private HashSet employeeSet = new HashSet(); + private HashSet managerSet = new HashSet(); + + private static final String empDescriptionFieldStr = + "org.apache.openjpa.persistence.fetchgroups.FGEmployee.description"; + + public void setUp() { + super.setUp(CLEAR_TABLES, + FGManager.class, FGDepartment.class, FGEmployee.class, FGAddress.class); + createEmployeeData(); + } + + /** + * Verify the "default" fetch plan that models JPA's expected eager/lazy fetch load behaviors. + */ + public void testDefaultFetchPlan001() { + OpenJPAEntityManager em = emf.createEntityManager(); + FetchPlan fp = em.getFetchPlan(); + assertNotNull(fp); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + + FetchConfiguration fetchCfg = ((org.apache.openjpa.persistence.EntityManagerImpl) em) + .getBroker() + .getFetchConfiguration(); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + + FGManager mgr = managerSet.iterator().next(); + assertNotNull(mgr); + + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.close(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + /** + * Verify that adding a FetchGroup to the fetch plan makes a normally JPA determined lazy loaded + * field to behave as an eagerly loaded field. + */ + public void testDefaultFetchPlan002() { + OpenJPAEntityManager em = emf.createEntityManager(); + FetchPlan fp = em.getFetchPlan(); + assertNotNull(fp); + + fp.addFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + + FetchConfiguration fetchCfg = ((org.apache.openjpa.persistence.EntityManagerImpl) em) + .getBroker() + .getFetchConfiguration(); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + FGManager mgr = managerSet.iterator().next(); + assertNotNull(mgr); + + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.close(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + /** + * Verify that adding a field to the fetch plan makes a normally JPA determined lazy loaded + * field to behave as an eagerly loaded field. + */ + public void testDefaultFetchPlan003() { + OpenJPAEntityManager em = emf.createEntityManager(); + FetchPlan fp = em.getFetchPlan(); + assertNotNull(fp); + + fp.addField(empDescriptionFieldStr); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFields().contains(empDescriptionFieldStr)); + + FetchConfiguration fetchCfg = ((org.apache.openjpa.persistence.EntityManagerImpl) em) + .getBroker() + .getFetchConfiguration(); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + FGManager mgr = managerSet.iterator().next(); + assertNotNull(mgr); + + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.close(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + + /** + * Verify the use of the "openjpa.FetchGroups" property when used to add a fetch group + * to the default fetch plan. Note when overriding that "default" must be included in the list. + */ + public void testPctxDefaultFetchPlan001() { + OpenJPAEntityManagerFactory emf2 = createNamedEMF(getPersistenceUnitName(), + FGManager.class, FGDepartment.class, FGEmployee.class, FGAddress.class, + "openjpa.FetchGroups", "default,DescFetchGroup"); + + OpenJPAEntityManager em = emf2.createEntityManager(); + FetchPlan fp = em.getFetchPlan(); + assertNotNull(fp); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + + FetchConfiguration fetchCfg = ((org.apache.openjpa.persistence.EntityManagerImpl) em) + .getBroker() + .getFetchConfiguration(); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + FGManager mgr = managerSet.iterator().next(); + assertNotNull(mgr); + + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.close(); + emf2.close(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + /** + * Verify the use of the "openjpa.FetchGroups" property - when a list not containing "default" + * is provided, then the PCtx's default fetch plan should not include it. This renders + * fields normally eagerly loaded as per JPA rules to behave as lazy loaded fields. + * + * Note that fetch groups are case sensitive, "default" != "Default". + */ + public void testPctxDefaultFetchPlan002() { + OpenJPAEntityManagerFactory emf2 = createNamedEMF(getPersistenceUnitName(), + FGManager.class, FGDepartment.class, FGEmployee.class, FGAddress.class, + "openjpa.FetchGroups", "Default,DescFetchGroup"); + + OpenJPAEntityManager em = emf2.createEntityManager(); + FetchPlan fp = em.getFetchPlan(); + assertNotNull(fp); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("Default")); // Not the same as "default" + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + + FetchConfiguration fetchCfg = ((org.apache.openjpa.persistence.EntityManagerImpl) em) + .getBroker() + .getFetchConfiguration(); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + FGManager mgr = managerSet.iterator().next(); + assertNotNull(mgr); + + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.close(); + emf2.close(); + + assertEquals(mgr.getId(), findMgr.getId()); // Identity is always loaded + assertNull(findMgr.getFirstName()); + assertNull(findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + /** + * Test clearFetchGroups(), which removes all fetch groups from the fetch plan and reactivates + * the "default" fetch plan. + * + * Note that the method does not place "default" back in the list of active fetch groups, OPENJPA-2413 + * was opened to note this behavior. + */ + public void testClearFetchGroups001() { + OpenJPAEntityManagerFactory emf2 = createNamedEMF(getPersistenceUnitName(), + FGManager.class, FGDepartment.class, FGEmployee.class, FGAddress.class, + "openjpa.FetchGroups", "Default,DescFetchGroup"); + + OpenJPAEntityManager em = emf2.createEntityManager(); + FetchPlan fp = em.getFetchPlan(); + assertNotNull(fp); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("Default")); // Not the same as "default" + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + + FetchConfiguration fetchCfg = ((org.apache.openjpa.persistence.EntityManagerImpl) em) + .getBroker() + .getFetchConfiguration(); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + fp.clearFetchGroups(); // OPENJPA-2413: now places "default" in the list of active fetch groups. + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + FGManager mgr = managerSet.iterator().next(); + assertNotNull(mgr); + + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.close(); + emf2.close(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + /** + * The resetFetchGroups() method restores the fetch plan's active fetch plans to + * the PCtx's configured default. + */ + public void testResetFetchGroups001() { + OpenJPAEntityManagerFactory emf2 = createNamedEMF(getPersistenceUnitName(), + FGManager.class, FGDepartment.class, FGEmployee.class, FGAddress.class, + "openjpa.FetchGroups", "Default,DescFetchGroup"); + + OpenJPAEntityManager em = emf2.createEntityManager(); + FetchPlan fp = em.getFetchPlan(); + assertNotNull(fp); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("Default")); // Not the same as "default" + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + + FetchConfiguration fetchCfg = ((org.apache.openjpa.persistence.EntityManagerImpl) em) + .getBroker() + .getFetchConfiguration(); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + + // OPENJPA-2413: now places "default" in the list of active fetch groups. + fp.clearFetchGroups(); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + // Reset to the PCtx default Fetch Plan + fp.resetFetchGroups(); + assertNotNull(fp); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("Default")); // Not the same as "default" + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + // Verify that the PCtx default fetch plan was properly restored. "default" should not be enabled + // since it was not listed by openjpa.FetchGroups. + FGManager mgr = managerSet.iterator().next(); + assertNotNull(mgr); + + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.close(); + emf2.close(); + + assertEquals(mgr.getId(), findMgr.getId()); // Identity is always loaded +// assertNull(findMgr.getFirstName()); // Commented out, for OPENJPA-2420 +// assertNull(findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + /** + * Baseline test for Finder Cache + */ + public void testFinderCache001() { + OpenJPAEntityManager em = emf.createEntityManager(); + + FetchPlan fp = em.getFetchPlan(); + assertNotNull(fp); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + + FetchConfiguration fetchCfg = ((org.apache.openjpa.persistence.EntityManagerImpl) em) + .getBroker() + .getFetchConfiguration(); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + FGManager mgr = managerSet.iterator().next(); + assertNotNull(mgr); + + { + // First find, to prime the Finder Cache + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + { + // Second find, should rely on the finder cache to reuse generated SQL. + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + em.close(); + } + + /** + * Only SQL generated by the PCtx's default fetch plan should be used by the finder cache, + * as it currently lacks the ability to distinguish fetch plan configuration in its key value. + * The PCtx's default fetch plan is the normal plan not modified by the "openjpa.FetchGroups" + * property. + * + * In this variant, a find using the default fetch plan is first executed to prime the finder cache. + * Finds operating under a modified fetch plan should not utilize sql stored in the finder cache. + */ + public void testFinderCache002() { + OpenJPAEntityManager em = emf.createEntityManager(); + + FetchPlan fp = em.getFetchPlan(); + assertNotNull(fp); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + + FetchConfiguration fetchCfg = ((org.apache.openjpa.persistence.EntityManagerImpl) em) + .getBroker() + .getFetchConfiguration(); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + FGManager mgr = managerSet.iterator().next(); + assertNotNull(mgr); + + { + // First find, to prime the Finder Cache + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + { + // Second find, should rely on the finder cache to reuse generated SQL. + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + // Add a fetch group to the fetch plan and verify expected behavior + fp.addFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + // Second find, should rely on the finder cache to reuse generated SQL. + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Remove the fetch group previously added, and verify expected behavior + fp.removeFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + // Add a fetch group to the fetch plan and verify expected behavior + fp.addFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + // Second find, should rely on the finder cache to reuse generated SQL. + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Reset the fetch plan, and verify expected behavior + fp.resetFetchGroups(); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + // Add a fetch group to the fetch plan and verify expected behavior + fp.addFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + // Second find, should rely on the finder cache to reuse generated SQL. + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Clear all fetch groups, and verify expected behavior + // OPENJPA-2413: now places "default" in the list of active fetch groups. + fp.clearFetchGroups(); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + em.close(); + } + + /** + * Only SQL generated by the PCtx's default fetch plan should be used by the finder cache, + * as it currently lacks the ability to distinguish fetch plan configuration in its key value. + * The PCtx's default fetch plan is the normal plan not modified by the "openjpa.FetchGroups" + * property. + * + * In this variant, a find using a modified fetch plan is first executed, which should not be added + * to the finder cache. + */ + public void testFinderCache003() { + OpenJPAEntityManager em = emf.createEntityManager(); + + FetchPlan fp = em.getFetchPlan(); + assertNotNull(fp); + + fp.addFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + + FetchConfiguration fetchCfg = ((org.apache.openjpa.persistence.EntityManagerImpl) em) + .getBroker() + .getFetchConfiguration(); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + + FGManager mgr = managerSet.iterator().next(); + assertNotNull(mgr); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Remove the "DescFetchGroup" fetch group, and verify expected behavior + fp.removeFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + // Restore the fetch group to the fetch plan and verify expected behavior + fp.addFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + // Second find, should rely on the finder cache to reuse generated SQL. + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Remove the "DescFetchGroup" fetch group, and verify expected behavior + fp.removeFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + // Restore the fetch group to the fetch plan and verify expected behavior + fp.addFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + // Second find, should rely on the finder cache to reuse generated SQL. + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Reset the fetch plan, and verify expected behavior + fp.resetFetchGroups(); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + // Restore the fetch group to the fetch plan and verify expected behavior + fp.addFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + // Second find, should rely on the finder cache to reuse generated SQL. + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Clear all fetch groups, and verify expected behavior + // OPENJPA-2413: now places "default" in the list of active fetch groups. + fp.clearFetchGroups(); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + em.close(); + } + + /** + * Only SQL generated by the PCtx's default fetch plan should be used by the finder cache, + * as it currently lacks the ability to distinguish fetch plan configuration in its key value. + * The PCtx's default fetch plan is modified by the "openjpa.FetchGroups" property. + * + */ + public void testFinderCache004() { + OpenJPAEntityManagerFactory emf2 = createNamedEMF(getPersistenceUnitName(), + FGManager.class, FGDepartment.class, FGEmployee.class, FGAddress.class, + "openjpa.FetchGroups", "default,DescFetchGroup"); + + OpenJPAEntityManager em = emf2.createEntityManager(); + FetchPlan fp = em.getFetchPlan(); + assertNotNull(fp); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + + FetchConfiguration fetchCfg = ((org.apache.openjpa.persistence.EntityManagerImpl) em) + .getBroker() + .getFetchConfiguration(); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + FGManager mgr = managerSet.iterator().next(); + assertNotNull(mgr); + + { + // First find, to prime the Finder Cache + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + { + // Second find, should rely on the finder cache to reuse generated SQL. + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Remove a fetch group to the fetch plan and verify expected behavior + fp.removeFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + // Second find, should rely on the finder cache to reuse generated SQL. + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + // Restore the fetch group previously removed, and verify expected behavior + fp.addFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Remove a fetch group to the fetch plan and verify expected behavior + fp.removeFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + // Second find, should rely on the finder cache to reuse generated SQL. + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + // Reset the fetch plan, and verify expected behavior + fp.resetFetchGroups(); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Clear all fetch groups, and verify expected behavior + // OPENJPA-2413: now places "default" in the list of active fetch groups. + fp.clearFetchGroups(); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + em.close(); + emf2.close(); + } + + /** + * Only SQL generated by the PCtx's default fetch plan should be used by the finder cache, + * as it currently lacks the ability to distinguish fetch plan configuration in its key value. + * The PCtx's default fetch plan is modified by the "openjpa.FetchGroups" property. + * + * In this variant, a find using a modified fetch plan is first executed, which should not be added + * to the finder cache. + */ + public void testFinderCache005() { + OpenJPAEntityManagerFactory emf2 = createNamedEMF(getPersistenceUnitName(), + FGManager.class, FGDepartment.class, FGEmployee.class, FGAddress.class, + "openjpa.FetchGroups", "default,DescFetchGroup"); + + OpenJPAEntityManager em = emf2.createEntityManager(); + FetchPlan fp = em.getFetchPlan(); + assertNotNull(fp); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + + FetchConfiguration fetchCfg = ((org.apache.openjpa.persistence.EntityManagerImpl) em) + .getBroker() + .getFetchConfiguration(); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + FGManager mgr = managerSet.iterator().next(); + assertNotNull(mgr); + + fp.removeFetchGroup("DescFetchGroup"); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + // Restore the "DescFetchGroup" fetch group, and verify expected behavior + fp.addFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Remove the "DescFetchGroup" fetch group, and verify expected behavior + fp.removeFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + // Reset the fetch plan, and verify expected behavior + fp.resetFetchGroups(); + assertNotNull(fp.getFetchGroups()); + assertEquals(2, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFetchGroups().contains("DescFetchGroup")); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Remove the "DescFetchGroup" fetch group, and verify expected behavior + fp.removeFetchGroup("DescFetchGroup"); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + // Clear all fetch groups, and verify expected behavior + // OPENJPA-2413: now places "default" in the list of active fetch groups. + fp.clearFetchGroups(); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + em.close(); + emf2.close(); + } + + /** + * Only SQL generated by the PCtx's default fetch plan should be used by the finder cache, + * as it currently lacks the ability to distinguish fetch plan configuration in its key value. + * The PCtx's default fetch plan is the normal plan not modified by the "openjpa.FetchGroups" + * property. + * + * In this variant, a find using the default fetch plan is first executed to prime the finder cache. + * Finds operating under a modified fetch plan should not utilize sql stored in the finder cache. + */ + public void testFinderCache006() { + OpenJPAEntityManager em = emf.createEntityManager(); + + FetchPlan fp = em.getFetchPlan(); + assertNotNull(fp); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + + FetchConfiguration fetchCfg = ((org.apache.openjpa.persistence.EntityManagerImpl) em) + .getBroker() + .getFetchConfiguration(); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + FGManager mgr = managerSet.iterator().next(); + assertNotNull(mgr); + + { + // First find, to prime the Finder Cache + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + { + // Second find, should rely on the finder cache to reuse generated SQL. + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + // Add a field to the fetch plan and verify expected behavior + fp.addField(empDescriptionFieldStr); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFields().contains(empDescriptionFieldStr)); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + // Second find, should rely on the finder cache to reuse generated SQL. + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Remove the field previously added, and verify expected behavior + fp.removeField(empDescriptionFieldStr); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + // Add a field to the fetch plan and verify expected behavior + fp.addField(empDescriptionFieldStr); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFields().contains(empDescriptionFieldStr)); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + // Second find, should rely on the finder cache to reuse generated SQL. + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Reset the fetch groups, and verify expected behavior (note the reset doesn't remove added fields!) + fp.resetFetchGroups(); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFields().contains(empDescriptionFieldStr)); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Clear all fetch groups, and verify expected behavior (note the reset doesn't remove added fields!) + // OPENJPA-2413: now places "default" in the list of active fetch groups. + fp.clearFetchGroups(); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFields().contains(empDescriptionFieldStr)); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Clear all fields, and verify expected behavior + fp.clearFields(); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFields().contains(empDescriptionFieldStr)); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + em.close(); + } + + /** + * Only SQL generated by the PCtx's default fetch plan should be used by the finder cache, + * as it currently lacks the ability to distinguish fetch plan configuration in its key value. + * The PCtx's default fetch plan is the normal plan not modified by the "openjpa.FetchGroups" + * property. + * + * In this variant, a find using a modified fetch plan is first executed, which should not be added + * to the finder cache. + */ + public void testFinderCache007() { + OpenJPAEntityManager em = emf.createEntityManager(); + + FetchPlan fp = em.getFetchPlan(); + assertNotNull(fp); + + fp.addField(empDescriptionFieldStr); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFields().contains(empDescriptionFieldStr)); + + FetchConfiguration fetchCfg = ((org.apache.openjpa.persistence.EntityManagerImpl) em) + .getBroker() + .getFetchConfiguration(); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + + FGManager mgr = managerSet.iterator().next(); + assertNotNull(mgr); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Remove the field, and verify expected behavior + fp.removeField(empDescriptionFieldStr); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + // Restore the field to the fetch plan and verify expected behavior + fp.addField(empDescriptionFieldStr); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFields().contains(empDescriptionFieldStr)); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + // Second find, should rely on the finder cache to reuse generated SQL. + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Remove the "DescFetchGroup" fetch group, and verify expected behavior + fp.removeField(empDescriptionFieldStr); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + // Restore the field to the fetch plan and verify expected behavior + fp.addField(empDescriptionFieldStr); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFields().contains(empDescriptionFieldStr)); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + // Second find, should rely on the finder cache to reuse generated SQL. + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Reset the fetch plan, and verify expected behavior (should not affect fields) + fp.resetFetchGroups(); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFetchGroups().contains("DescFetchGroup")); + assertTrue(fp.getFields().contains(empDescriptionFieldStr)); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Clear all fetch groups, and verify expected behavior (should not affect fields) + // OPENJPA-2413: now places "default" in the list of active fetch groups. + fp.clearFetchGroups(); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertTrue(fp.getFields().contains(empDescriptionFieldStr)); + assertFalse(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertEquals(mgr.getDescription(), findMgr.getDescription()); // Should not be lazy-loaded + } + + // Clear all fields, and verify expected behavior + fp.clearFields(); + assertNotNull(fp.getFetchGroups()); + assertEquals(1, fp.getFetchGroups().size()); + assertTrue(fp.getFetchGroups().contains("default")); + assertFalse(fp.getFields().contains(empDescriptionFieldStr)); + assertTrue(fetchCfg.isDefaultPUFetchGroupConfigurationOnly()); + + { + FGManager findMgr = em.find(FGManager.class, mgr.getId()); + em.clear(); + + assertEquals(mgr.getId(), findMgr.getId()); + assertEquals(mgr.getFirstName(), findMgr.getFirstName()); + assertEquals(mgr.getLastName(), findMgr.getLastName()); + assertNull(findMgr.getDescription()); // Should be lazy-loaded + } + + em.close(); + } + + private void createEmployeeData() { + OpenJPAEntityManager em = emf.createEntityManager(); + + employeeSet.clear(); + managerSet.clear(); + + int empIdIndex = 1; + + em.getTransaction().begin(); + + // Create Managers + for (int i = 1; i < mgrCount; i++) { + int id = empIdIndex++; + + FGAddress addr = createAddress(id); + em.persist(addr); + + FGDepartment dept = createDepartment(id); + em.persist(dept); + + FGManager mgr = new FGManager(); + mgr.setId(id); + mgr.setFirstName("First-" + id); + mgr.setLastName("Last-" + id); + mgr.setMData("MData-" + id); + mgr.setRating("Rating-" + id); + mgr.setDescription("Manager-" + id); + mgr.setAddress(addr); + mgr.setDept(dept); + + em.persist(mgr); + + managerSet.add(mgr); + } + + // Create Employees + for (int i = 1; i < empCount; i++) { + int id = empIdIndex++; + int mgrId = (id % empPerMgr) + 1; + + FGAddress addr = createAddress(id); + em.persist(addr); + + FGDepartment dept = createDepartment(id); + em.persist(dept); + + FGEmployee emp = new FGEmployee(); + emp.setId(id); + emp.setFirstName("First-" + id); + emp.setLastName("Last-" + id); + emp.setRating("Rating-" + id); + emp.setDescription("Employee-" + id); + emp.setAddress(addr); + emp.setDept(dept); + + em.persist(emp); + + employeeSet.add(emp); + } + + em.getTransaction().commit(); + + em.close(); + } + + private FGAddress createAddress(int id) { + FGAddress addr = new FGAddress(); + addr.setId(id); + addr.setStreet("Street-" + id); + addr.setCity("City-" + id); + addr.setState("State-" + id); + addr.setZip(id); + + return addr; + } + + private FGDepartment createDepartment(int id) { + FGDepartment dept = new FGDepartment(); + dept.setId(id); + dept.setName("Department-" + id); + + return dept; + } +}