From 71519b08080107dae13867c760f224a2cde54b5b Mon Sep 17 00:00:00 2001 From: Pinaki Poddar Date: Fri, 13 Jun 2008 01:58:49 +0000 Subject: [PATCH] OPENJPA-610: Restored refresh() behavior for clean/new instances. git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@667312 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/openjpa/kernel/BrokerImpl.java | 59 +++++++-- .../TestDataCacheBehavesIdentical.java | 122 +++++++++++------- 2 files changed, 124 insertions(+), 57 deletions(-) diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java index 9f9879983..96d3596e9 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java @@ -2733,7 +2733,7 @@ public class BrokerImpl endOperation(); } } - + public void refreshAll(Collection objs, OpCallbacks call) { if (objs == null || objs.isEmpty()) return; @@ -2742,10 +2742,14 @@ public class BrokerImpl try { assertNontransactionalRead(); - for (Iterator itr = objs.iterator(); itr.hasNext();) { + for (Iterator itr = objs.iterator(); itr.hasNext();) gatherCascadeRefresh(itr.next(), call); - } - refreshInternal(_operating, call); + if (_operating.isEmpty()) + return; + if (_operating.size() == 1) + refreshInternal(_operating.iterator().next(), call); + else + refreshInternal(_operating, call); } finally { endOperation(); } @@ -2760,7 +2764,12 @@ public class BrokerImpl assertNontransactionalRead(); gatherCascadeRefresh(obj, call); - refreshInternal(_operating, call); + if (_operating.isEmpty()) + return; + if (_operating.size() == 1) + refreshInternal(_operating.iterator().next(), call); + else + refreshInternal(_operating, call); } finally { endOperation(); } @@ -2797,7 +2806,7 @@ public class BrokerImpl List exceps = null; try { // collect instances that need a refresh - Collection load = new ArrayList(objs.size()); + Collection load = null; StateManagerImpl sm; Object obj; for (Iterator itr = objs.iterator(); itr.hasNext();) { @@ -2812,9 +2821,11 @@ public class BrokerImpl continue; if (sm != null) { - if (sm.isDetached()) { + if (sm.isDetached()) throw newDetachedException(obj, "refresh"); - } else if (sm.beforeRefresh(true)) { + else if (sm.beforeRefresh(true)) { + if (load == null) + load = new ArrayList(objs.size()); load.add(sm); } } else if (assertPersistenceCapable(obj).pcIsDetached() @@ -2826,7 +2837,7 @@ public class BrokerImpl } // refresh all - if (!load.isEmpty()) { + if (load != null) { Collection failed = _store.loadAll(load, null, StoreManager.FORCE_LOAD_REFRESH, _fc, null); if (failed != null && !failed.isEmpty()) @@ -2868,6 +2879,36 @@ public class BrokerImpl throwNestedExceptions(exceps, false); } + /** + * Optimization for single-object refresh. + */ + protected void refreshInternal(Object obj, OpCallbacks call) { + try { + StateManagerImpl sm = getStateManagerImpl(obj, true); + if ((processArgument(OpCallbacks.OP_REFRESH, obj, sm, call) + & OpCallbacks.ACT_RUN) == 0) + return; + + if (sm != null) { + if (sm.isDetached()) + throw newDetachedException(obj, "refresh"); + else if (sm.beforeRefresh(false)) { + sm.load(_fc, StateManagerImpl.LOAD_FGS, null, null, false); + sm.afterRefresh(); + } + fireLifecycleEvent(sm.getManagedInstance(), null, + sm.getMetaData(), LifecycleEvent.AFTER_REFRESH); + } else if (assertPersistenceCapable(obj).pcIsDetached() + == Boolean.TRUE) + throw newDetachedException(obj, "refresh"); + } catch (OpenJPAException ke) { + throw ke; + } catch (RuntimeException re) { + throw new GeneralException(re); + } + } + + public void retrieveAll(Collection objs, boolean dfgOnly, OpCallbacks call) { if (objs == null || objs.isEmpty()) diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestDataCacheBehavesIdentical.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestDataCacheBehavesIdentical.java index e791df985..a2b151193 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestDataCacheBehavesIdentical.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestDataCacheBehavesIdentical.java @@ -19,10 +19,10 @@ package org.apache.openjpa.persistence.datacache; import javax.persistence.EntityManager; -import javax.persistence.EntityNotFoundException; import javax.persistence.LockModeType; import org.apache.openjpa.persistence.EntityManagerImpl; +import org.apache.openjpa.persistence.EntityNotFoundException; import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI; import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI; import org.apache.openjpa.persistence.StoreCache; @@ -54,7 +54,10 @@ public class TestDataCacheBehavesIdentical extends AbstractTestCase { private static final boolean WITH_DATACACHE = true; private static final boolean CONSISTENT = true; private static final boolean DIRTY = true; + private static final boolean REFRESH_FROM_DATACACHE = true; private static final LockModeType NOLOCK = null; + private static final Class ENTITY_NOT_FOUND_ERROR = EntityNotFoundException.class; + private static final Class NO_ERROR = null; private static final String MARKER_DATACACHE = "in DataCache"; private static final String MARKER_DATABASE = "in Database"; @@ -356,68 +359,66 @@ public class TestDataCacheBehavesIdentical extends AbstractTestCase { String getExpectedMarker(boolean useDataCache, LockModeType lock, boolean makeDirtyBeforeRefresh) { if (useDataCache) { -// return (lock != null && makeDirtyBeforeRefresh) return (lock != null) ? MARKER_DATABASE : MARKER_DATACACHE; } else { -// return (makeDirtyBeforeRefresh) ? MARKER_DATABASE : MARKER_CACHE; return MARKER_DATABASE; } } public void testDirtyRefreshWithNoLockHitsDatabase() { - verifyRefresh(WITH_DATACACHE, NOLOCK, DIRTY, false, MARKER_DATABASE); + verifyRefresh(WITH_DATACACHE, NOLOCK, DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATACACHE); } public void testDirtyRefreshWithNoLockHitsDataCache() { - verifyRefresh(WITH_DATACACHE, NOLOCK, DIRTY, true, MARKER_DATACACHE); + verifyRefresh(WITH_DATACACHE, NOLOCK, DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATACACHE); } - public void testCleanRefreshWithNoLockHitsDatabase() { - verifyRefresh(WITH_DATACACHE, NOLOCK, !DIRTY, false, MARKER_DATABASE); + public void testCleanRefreshWithNoLockDoesNotHitDatabase() { + verifyRefresh(WITH_DATACACHE, NOLOCK, !DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATACACHE); } public void testCleanRefreshWithNoLockHitsDataCache() { - verifyRefresh(WITH_DATACACHE, NOLOCK, !DIRTY, true, MARKER_DATACACHE); + verifyRefresh(WITH_DATACACHE, NOLOCK, !DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATACACHE); } public void testDirtyRefreshWithReadLockHitsDatabase() { - verifyRefresh(WITH_DATACACHE, LockModeType.READ, DIRTY, true, MARKER_DATABASE); - verifyRefresh(WITH_DATACACHE, LockModeType.READ, DIRTY, false, MARKER_DATABASE); + verifyRefresh(WITH_DATACACHE, LockModeType.READ, DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATABASE); + verifyRefresh(WITH_DATACACHE, LockModeType.READ, DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATABASE); } - public void testCleanRefreshWithReadLockHitsDatabase() { - verifyRefresh(WITH_DATACACHE, LockModeType.READ, !DIRTY, true, MARKER_DATABASE); - verifyRefresh(WITH_DATACACHE, LockModeType.READ, !DIRTY, false, MARKER_DATABASE); + public void testCleanRefreshWithReadLockDoesNotHitDatabase() { + verifyRefresh(WITH_DATACACHE, LockModeType.READ, !DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATACACHE); + verifyRefresh(WITH_DATACACHE, LockModeType.READ, !DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATACACHE); } public void testDirtyRefreshWithWriteLockHitsDatabase() { - verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, DIRTY, true, MARKER_DATABASE); - verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, DIRTY, false, MARKER_DATABASE); + verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATABASE); + verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATABASE); } - public void testCleanRefreshWithWriteLockHitsDatabase() { - verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, !DIRTY, true, MARKER_DATABASE); - verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, !DIRTY, false, MARKER_DATABASE); + public void testCleanRefreshWithWriteLockDoesNotHitDatabase() { + verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, !DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATACACHE); + verifyRefresh(WITH_DATACACHE, LockModeType.WRITE, !DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATACACHE); } public void testDirtyRefreshWithoutDataCacheAlwaysHitsDatabase() { - verifyRefresh(!WITH_DATACACHE, NOLOCK, DIRTY, true, MARKER_DATABASE); - verifyRefresh(!WITH_DATACACHE, LockModeType.READ, DIRTY, true, MARKER_DATABASE); - verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, DIRTY, true, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, NOLOCK, DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, LockModeType.READ, DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, DIRTY, REFRESH_FROM_DATACACHE, MARKER_DATABASE); - verifyRefresh(!WITH_DATACACHE, NOLOCK, DIRTY, false, MARKER_DATABASE); - verifyRefresh(!WITH_DATACACHE, LockModeType.READ, DIRTY, false, MARKER_DATABASE); - verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, DIRTY, false, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, NOLOCK, DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, LockModeType.READ, DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, DIRTY, !REFRESH_FROM_DATACACHE, MARKER_DATABASE); } - public void testCleanRefreshWithoutDataCacheAlwaysHitsDatabase() { - verifyRefresh(!WITH_DATACACHE, NOLOCK, !DIRTY, true, MARKER_DATABASE); - verifyRefresh(!WITH_DATACACHE, LockModeType.READ, !DIRTY, true, MARKER_DATABASE); - verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, !DIRTY, true, MARKER_DATABASE); + public void testCleanRefreshWithoutDataCacheDoesNotHitDatabase() { + verifyRefresh(!WITH_DATACACHE, NOLOCK, !DIRTY, REFRESH_FROM_DATACACHE, MARKER_CACHE); + verifyRefresh(!WITH_DATACACHE, LockModeType.READ, !DIRTY, REFRESH_FROM_DATACACHE, MARKER_CACHE); + verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, !DIRTY, REFRESH_FROM_DATACACHE, MARKER_CACHE); - verifyRefresh(!WITH_DATACACHE, NOLOCK, !DIRTY, false, MARKER_DATABASE); - verifyRefresh(!WITH_DATACACHE, LockModeType.READ, !DIRTY, false, MARKER_DATABASE); - verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, !DIRTY, false, MARKER_DATABASE); + verifyRefresh(!WITH_DATACACHE, NOLOCK, !DIRTY, !REFRESH_FROM_DATACACHE, MARKER_CACHE); + verifyRefresh(!WITH_DATACACHE, LockModeType.READ, !DIRTY, !REFRESH_FROM_DATACACHE, MARKER_CACHE); + verifyRefresh(!WITH_DATACACHE, LockModeType.WRITE, !DIRTY, !REFRESH_FROM_DATACACHE, MARKER_CACHE); } /** @@ -430,7 +431,7 @@ public class TestDataCacheBehavesIdentical extends AbstractTestCase { * @param lock */ public void verifyDeleteDetectionOnRefresh(boolean useDataCache, - LockModeType lock) { + boolean dirty, LockModeType lock, Class expectedExceptionType) { OpenJPAEntityManagerFactorySPI emf = (useDataCache) ? emfWithDataCache : emfWithoutDataCache; @@ -465,34 +466,59 @@ public class TestDataCacheBehavesIdentical extends AbstractTestCase { * */ em.getTransaction().begin(); - if (lock != null) - em.getFetchPlan().setReadLockMode(lock); + em.getFetchPlan().setReadLockMode(lock); + if (dirty) + pc.setName("Dirty Name"); try { em.refresh(pc); - fail("expected EntityNotFoundException for PObject:" + oid); - } catch (EntityNotFoundException ex) { - // we are good + if (expectedExceptionType != null) { + fail("expected " + expectedExceptionType.getSimpleName() + + " for PObject:" + oid); + } } catch (Exception ex) { - ex.printStackTrace(); - fail("expected EntityNotFoundException for PObject:" + oid); + boolean expectedException = expectedExceptionType != null && + expectedExceptionType.isAssignableFrom(ex.getClass()); + if (!expectedException) { + ex.printStackTrace(); + String error = (expectedExceptionType == null) + ? "no exception" : expectedExceptionType.getName(); + fail("expected " + error + " for PObject:" + oid); + } } finally { em.getTransaction().rollback(); } } - public void testDeleteIsDetectedOnRefreshWithLockWithActiveDataCache() { - verifyDeleteDetectionOnRefresh(WITH_DATACACHE, LockModeType.READ); - verifyDeleteDetectionOnRefresh(WITH_DATACACHE, LockModeType.WRITE); + public void testDeleteIsNotDetectedOnCleanRefreshWithoutLockWithDataCache() { + verifyDeleteDetectionOnRefresh(WITH_DATACACHE, !DIRTY, NOLOCK, NO_ERROR); } - public void testDeleteIsNotDetectedOnRefreshWithNoLockWithActiveDataCache() { - verifyDeleteDetectionOnRefresh(WITH_DATACACHE, NOLOCK); + public void testDeleteIsDetectedOnCleanRefreshWithLockWithDataCache() { + verifyDeleteDetectionOnRefresh(WITH_DATACACHE, !DIRTY, LockModeType.READ, ENTITY_NOT_FOUND_ERROR); + verifyDeleteDetectionOnRefresh(WITH_DATACACHE, !DIRTY, LockModeType.WRITE, ENTITY_NOT_FOUND_ERROR); + } + + public void testDeleteIsNotDetectedOnDirtyRefreshWithoutLockWithDataCache() { + verifyDeleteDetectionOnRefresh(WITH_DATACACHE, DIRTY, NOLOCK, NO_ERROR); } - public void testDeleteIsDetectedOnRefreshAlwaysWithoutDataCache() { - verifyDeleteDetectionOnRefresh(!WITH_DATACACHE, NOLOCK); - verifyDeleteDetectionOnRefresh(!WITH_DATACACHE, LockModeType.READ); - verifyDeleteDetectionOnRefresh(!WITH_DATACACHE, LockModeType.WRITE); + public void testDeleteIsDetectedOnDirtyRefreshWithLockWithDataCache() { + verifyDeleteDetectionOnRefresh(WITH_DATACACHE, DIRTY, LockModeType.READ, ENTITY_NOT_FOUND_ERROR); + verifyDeleteDetectionOnRefresh(WITH_DATACACHE, DIRTY, LockModeType.WRITE, ENTITY_NOT_FOUND_ERROR); + } + + public void testDeleteIsDetectedOnDirtyRefreshWitDataCache() { + verifyDeleteDetectionOnRefresh(WITH_DATACACHE, DIRTY, LockModeType.READ, ENTITY_NOT_FOUND_ERROR); + verifyDeleteDetectionOnRefresh(WITH_DATACACHE, DIRTY, LockModeType.WRITE, ENTITY_NOT_FOUND_ERROR); + } + + public void testDeleteIsDetectedOnCleanRefreshWithoutLockWithoutDataCache() { + verifyDeleteDetectionOnRefresh(!WITH_DATACACHE, !DIRTY, NOLOCK, ENTITY_NOT_FOUND_ERROR); + } + + public void testDeleteIsDetectedOnCleanRefreshWithLockWithoutDataCache() { + verifyDeleteDetectionOnRefresh(!WITH_DATACACHE, !DIRTY, LockModeType.READ, ENTITY_NOT_FOUND_ERROR); + verifyDeleteDetectionOnRefresh(!WITH_DATACACHE, !DIRTY, LockModeType.WRITE, ENTITY_NOT_FOUND_ERROR); } }