Fix for bug 470161 - ServerSession links RepeatableWriteUnitOfWork via entity / IndirectList / QueryBasedValueHolder
- Added call to ValueHolder releaseWrappedValueHolder() in TransparentIndirectionPolicy getOriginalValueHolder() to release a wrapped valueholder when TransparentIndirectionPolicy is utilized
- Added test: testTransparentIndirectionValueHolderSessionReset to AdvancedJPAJunitTest
- LRG & JPA LRG on MySQL, Oracle = Pass

Reviewed-by: Gordon Yorke <gordon.yorke@oracle.com>
Reviewed-by: Lukas Jungmann <lukas.jungmann@oracle.com>
Signed-off-by: Lukas Jungmann <lukas.jungmann@oracle.com>
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/TransparentIndirectionPolicy.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/TransparentIndirectionPolicy.java
index be9509a..4c8f0a4 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/TransparentIndirectionPolicy.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/TransparentIndirectionPolicy.java
@@ -362,6 +362,10 @@
                     valueHolder = ((WrappingValueHolder)valueHolder).getWrappedValueHolder();
                 }
             }
+            // EL bug 470161
+            if ((valueHolder != null) && (valueHolder instanceof DatabaseValueHolder)) {
+                ((DatabaseValueHolder) valueHolder).releaseWrappedValueHolder(session);
+            }
             return valueHolder;
         } else {
             return container.getValueHolder();
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/advanced/AdvancedJPAJunitTest.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/advanced/AdvancedJPAJunitTest.java
index f37f225..9f52460 100644
--- a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/advanced/AdvancedJPAJunitTest.java
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/advanced/AdvancedJPAJunitTest.java
@@ -63,10 +63,12 @@
 import org.eclipse.persistence.descriptors.DescriptorEventAdapter;
 import org.eclipse.persistence.descriptors.invalidation.CacheInvalidationPolicy;
 import org.eclipse.persistence.descriptors.invalidation.TimeToLiveCacheInvalidationPolicy;
+import org.eclipse.persistence.indirection.IndirectCollection;
 import org.eclipse.persistence.internal.helper.ClassConstants;
 import org.eclipse.persistence.internal.helper.DatabaseField;
 import org.eclipse.persistence.internal.helper.DatabaseTable;
 import org.eclipse.persistence.internal.helper.Helper;
+import org.eclipse.persistence.internal.indirection.DatabaseValueHolder;
 import org.eclipse.persistence.history.AsOfClause;
 import org.eclipse.persistence.internal.jpa.EJBQueryImpl;
 import org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate;
@@ -237,6 +239,7 @@
         suite.addTest(new AdvancedJPAJunitTest("testAttributeOverrideToMultipleSameDefaultColumnName"));
         suite.addTest(new AdvancedJPAJunitTest("testJoinFetchWithRefreshOnRelatedEntity"));
         suite.addTest(new AdvancedJPAJunitTest("testSharedEmbeddedAttributeOverrides"));
+        suite.addTest(new AdvancedJPAJunitTest("testTransparentIndirectionValueHolderSessionReset"));
 
         if (!isJPA10()) {
             // These tests use JPA 2.0 entity manager API
@@ -3215,6 +3218,91 @@
             closeEntityManager(em);
         }
     }
+    
+    /**
+     * Bug 470161 - ServerSession links RepeatableWriteUnitOfWork via entity / IndirectList / QueryBasedValueHolder\
+     * 
+     * Through the UoW: Persist a new object, read an existing object in (building from rows, original not put in the
+     * shared cache), associate existing object with new object, commit. Previously, after the changes are merged 
+     * into the shared cache, the transparent collection on the existing object has a wrapped VH from the initial uow 
+     * query, which internally references the uow session, not the shared session.
+     */
+    public void testTransparentIndirectionValueHolderSessionReset() {
+        Employee emp = null;
+        Dealer dealer = null;
+        
+        // setup
+        EntityManager em = createEntityManager();
+        try {
+            beginTransaction(em);
+            dealer = new Dealer();
+            dealer.setFirstName("Angle");
+            dealer.setLastName("Bracket");
+            em.persist(dealer);
+            commitTransaction(em);
+        } finally {
+            closeEntityManager(em);
+            clearCache(); // start test with an empty cache
+        }
+        
+        // test
+        em = createEntityManager();
+        try {
+            beginTransaction(em);
+            
+            emp = new Employee();
+            emp.setFemale();
+            emp.setFirstName("Case");
+            emp.setLastName("Statement");
+            em.persist(emp);
+            
+            Query query = em.createQuery("select d from Dealer d where d.firstName = :firstName and d.lastName = :lastName");
+            query.setParameter("firstName", dealer.getFirstName());
+            query.setParameter("lastName", dealer.getLastName());
+            List<Dealer> resultsList = query.getResultList();
+            assertTrue("List returned should be non-empty", resultsList.size() > 0);
+            
+            Dealer dealerFound = resultsList.get(0);
+            emp.addDealer(dealerFound);
+            
+            commitTransaction(em);
+            
+            // verify valueholder configuration in shared cache
+            Session parentSession = JpaHelper.getServerSession(em.getEntityManagerFactory());
+            Dealer cachedDealer = (Dealer) parentSession.getIdentityMapAccessor().getFromIdentityMap(dealer);
+            assertNotNull("Dealer with id should be in the cache: " + dealer.getId(), cachedDealer);
+            
+            ClassDescriptor descriptor = parentSession.getDescriptor(Dealer.class);
+            DatabaseMapping mapping = descriptor.getMappingForAttributeName("customers");
+            IndirectCollection indirectCollection = (IndirectCollection) mapping.getAttributeValueFromObject(cachedDealer);
+            assertFalse("Collection VH should be uninstantiated", indirectCollection.isInstantiated());
+            
+            DatabaseValueHolder dbValueHolder = (DatabaseValueHolder) indirectCollection.getValueHolder();
+            assertFalse("Referenced VH should be uninstantiated", dbValueHolder.isInstantiated());
+            
+            Session vhSession = dbValueHolder.getSession();
+            assertSame("Dealer.customers VH session should reference the shared session", parentSession, vhSession);
+        } finally {
+            closeEntityManager(em);
+        }
+        
+        // reset
+        em = createEntityManager();
+        try {
+            beginTransaction(em);
+            emp = em.find(Employee.class, emp.getId());
+            if (emp != null) {
+                em.remove(emp);
+            }
+            dealer = em.find(Dealer.class, dealer.getId());
+            if (dealer != null) {
+                em.remove(dealer);
+            }
+            commitTransaction(em);
+        } finally {
+            closeEntityManager(em);
+        }
+    }
 
     protected int getVersion(EntityManager em, Dealer dealer) {
         Vector pk = new Vector(1);