Bug 530680: embedded element collection within an entity of protected isolation does not merged changes into clones correctly

Signed-off-by: Lukas Jungmann <lukas.jungmann@oracle.com>
Reviewed-by: WillD
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/mappings/AggregateCollectionMapping.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/mappings/AggregateCollectionMapping.java
index 19d9382..acb4bd3 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/mappings/AggregateCollectionMapping.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/mappings/AggregateCollectionMapping.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018 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.
@@ -17,6 +17,8 @@
  *       - 374688: JPA 2.1 Converter support
  *     02/11/2013-2.5 Guy Pelletier
  *       - 365931: @JoinColumn(name="FK_DEPT",insertable = false, updatable = true) causes INSERT statement to include this data value that it is associated with
+ *     02/14/2018-2.7.2 Lukas Jungmann
+ *       - 530680: embedded element collection within an entity of protected isolation does not merged changes into clones correctly
  ******************************************************************************/
 package org.eclipse.persistence.mappings;
 
@@ -2186,10 +2188,8 @@ public void loadAll(Object object, AbstractSession session, IdentityHashSet load
      */
     @Override
     public void mergeChangesIntoObject(Object target, ChangeRecord changeRecord, Object source, MergeManager mergeManager, AbstractSession targetSession) {
-        if (this.descriptor.getCachePolicy().isProtectedIsolation()){
-            if (!this.isCacheable && !targetSession.isProtectedSession()){
-                setAttributeValueInObject(target, this.indirectionPolicy.buildIndirectObject(new ValueHolder(null)));
-            }
+        if (this.descriptor.getCachePolicy().isProtectedIsolation() && !this.isCacheable && !targetSession.isProtectedSession()) {
+            setAttributeValueInObject(target, this.indirectionPolicy.buildIndirectObject(new ValueHolder(null)));
             return;
         }
         //Check to see if the target has an instantiated collection
@@ -2249,10 +2249,8 @@ public void mergeChangesIntoObject(Object target, ChangeRecord changeRecord, Obj
      */
     @Override
     public void mergeIntoObject(Object target, boolean isTargetUnInitialized, Object source, MergeManager mergeManager, AbstractSession targetSession) {
-        if (this.descriptor.getCachePolicy().isProtectedIsolation()) {
-            if (!this.isCacheable && !targetSession.isProtectedSession()){
-                setAttributeValueInObject(target, this.indirectionPolicy.buildIndirectObject(new ValueHolder(null)));
-            }
+        if (this.descriptor.getCachePolicy().isProtectedIsolation() && !this.isCacheable && !targetSession.isProtectedSession()) {
+            setAttributeValueInObject(target, this.indirectionPolicy.buildIndirectObject(new ValueHolder(null)));
             return;
         }
         if (isTargetUnInitialized) {
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/cacheable/CacheableRelationshipsEntity.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/cacheable/CacheableRelationshipsEntity.java
index b8645ee..d2c8c31 100644
--- a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/cacheable/CacheableRelationshipsEntity.java
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/cacheable/CacheableRelationshipsEntity.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018 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.
@@ -51,6 +51,8 @@ public class CacheableRelationshipsEntity {
 
     protected List<ProtectedEmbeddable> protectedEmbeddables;
 
+    protected List<SharedEmbeddable> sharedEmbeddables;
+
     @Id
     @GeneratedValue(strategy=TABLE, generator="CACHEABLE_TABLE_GENERATOR")
     public int getId() {
@@ -155,11 +157,30 @@ public void addProtectedEmbeddable(ProtectedEmbeddable protectedEmbeddable) {
         protectedEmbeddables.add(protectedEmbeddable);
     }
 
+    /* element collection with embeddable (true protected)*/
+    @ElementCollection
+    @CollectionTable(
+        name="CACHREL_SHAREDEMB",
+        joinColumns=@JoinColumn(name="ID")
+    )
+    public List<SharedEmbeddable> getSharedEmbeddables() {
+        return sharedEmbeddables;
+    }
+
+    public void setSharedEmbeddables(List<SharedEmbeddable> sharedEmbeddables) {
+        this.sharedEmbeddables = sharedEmbeddables;
+    }
+
+    public void addSharedEmbeddable(SharedEmbeddable sharedEmbeddables) {
+        this.sharedEmbeddables.add(sharedEmbeddables);
+    }
+
     public CacheableRelationshipsEntity() {
         cacheableFalses = new ArrayList<CacheableFalseEntity>();
         cacheableProtecteds = new ArrayList<CacheableProtectedEntity>();
         cacheableFalseDetails = new ArrayList<CacheableFalseDetail>();
         protectedEmbeddables = new ArrayList<ProtectedEmbeddable>();
+        sharedEmbeddables = new ArrayList<SharedEmbeddable>();
     }
 
 }
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/cacheable/CacheableTableCreator.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/cacheable/CacheableTableCreator.java
index cabd6b1..f729c56 100644
--- a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/cacheable/CacheableTableCreator.java
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/cacheable/CacheableTableCreator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018 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.
@@ -39,6 +39,7 @@ public CacheableTableCreator() {
         addTableDefinition(buildCACHEABLEREL_PROTECTEDTable());
         addTableDefinition(buildCACHEABLEREL_FALSEDETAILTable());
         addTableDefinition(buildCACHEABLEREL_PROTECTEMBEDDABLETable());
+        addTableDefinition(buildCACHEABLEREL_SHAREDEMBEDDABLETable());
         addTableDefinition(buildProductFalseTable());
         addTableDefinition(buildProductTrueTable());
     }
@@ -570,6 +571,34 @@ public static TableDefinition buildCACHEABLEREL_PROTECTEMBEDDABLETable() {
         return table;
     }
 
+    public static TableDefinition buildCACHEABLEREL_SHAREDEMBEDDABLETable() {
+        TableDefinition table = new TableDefinition();
+        table.setName("CACHREL_SHAREDEMB");
+
+        FieldDefinition fieldID = new FieldDefinition();
+        fieldID.setName("ID");
+        fieldID.setTypeName("NUMERIC");
+        fieldID.setSize(15);
+        fieldID.setShouldAllowNull(false);
+        fieldID.setIsPrimaryKey(false);
+        fieldID.setUnique(false);
+        fieldID.setIsIdentity(false);
+        fieldID.setForeignKeyFieldName("JPA_CACHEREL.ID");
+        table.addField(fieldID);
+
+        FieldDefinition fieldNAME = new FieldDefinition();
+        fieldNAME.setName("SE_NAME");
+        fieldNAME.setTypeName("VARCHAR");
+        fieldNAME.setSize(75);
+        fieldNAME.setShouldAllowNull(true);
+        fieldNAME.setIsPrimaryKey(false);
+        fieldNAME.setUnique(false);
+        fieldNAME.setIsIdentity(false);
+        table.addField(fieldNAME);
+
+        return table;
+    }
+
     /**
      * Build table for {@see org.eclipse.persistence.testing.models.jpa.cacheable.ProductFalse}
      * class.
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/cacheable/SharedEmbeddable.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/cacheable/SharedEmbeddable.java
index 08be185..054eede 100644
--- a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/cacheable/SharedEmbeddable.java
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/cacheable/SharedEmbeddable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018 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.
@@ -33,9 +33,17 @@
 @Embeddable
 @Cacheable(true)
 public class SharedEmbeddable {
-    @Column(name="SE_NAME")
+
     protected String name;
 
     public SharedEmbeddable() {}
 
+    @Column(name="SE_NAME")
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
 }
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/cacheable/CacheableModelJunitTest.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/cacheable/CacheableModelJunitTest.java
index 07bc762..ecc753b 100644
--- a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/cacheable/CacheableModelJunitTest.java
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/cacheable/CacheableModelJunitTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 1998, 2015 Oracle and/or its affiliates, IBM Corporation. All rights reserved.
+ * Copyright (c) 1998, 2018 Oracle and/or its affiliates, IBM Corporation. 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.
@@ -302,6 +302,9 @@ public static Test suite() {
 
             // Bug 408262
             suite.addTest(new CacheableModelJunitTest("testRefreshProtectedEntityInEarlyTransaction"));
+
+            // Bug 530680
+            suite.addTest(new CacheableModelJunitTest("testUpdateSharedElementCollection"));
         }
         return suite;
     }
@@ -1745,6 +1748,46 @@ public void testUpdateProtectedElementCollection(){
         }
     }
 
+    //Bug #530680
+    public void testUpdateSharedElementCollection() {
+        EntityManager em = createDSEntityManager();
+        beginTransaction(em);
+        try{
+            CacheableRelationshipsEntity cre = em.find(CacheableRelationshipsEntity.class, m_cacheableRelationshipsEntityId);
+            ServerSession session = em.unwrap(ServerSession.class);
+            SharedEmbeddable cem1 = new SharedEmbeddable();
+            cem1.setName("origName1");
+            SharedEmbeddable cem2 = new SharedEmbeddable();
+            cem2.setName("origName2");
+            cre.addSharedEmbeddable(cem1);
+            cre.addSharedEmbeddable(cem2);
+            commitTransaction(em);
+
+            CacheableRelationshipsEntity cachedCRE = (CacheableRelationshipsEntity) session.getIdentityMapAccessor().getFromIdentityMap(cre);
+            assertTrue("A shared ElementCollection relationship was not merged into the shared cache", cachedCRE.getSharedEmbeddables() != null && !cachedCRE.getSharedEmbeddables().isEmpty());
+
+            CacheableRelationshipsEntity cre2 = em.find(CacheableRelationshipsEntity.class, m_cacheableRelationshipsEntityId);
+            beginTransaction(em);
+            em.detach(cre2);
+            cre2.getSharedEmbeddables().remove(0);
+            em.merge(cre2);
+            commitTransaction(em);
+
+            session = em.unwrap(ServerSession.class);
+            CacheableRelationshipsEntity cachedCRE2 = (CacheableRelationshipsEntity) session.getIdentityMapAccessor().getFromIdentityMap(cre2);
+            assertEquals("Changes in shared ElementCollection relationship were not merged into the shared cache", 1, cachedCRE2.getSharedEmbeddables().size());
+
+            beginTransaction(em);
+            cre.getSharedEmbeddables().clear();
+            commitTransaction(em);
+        }finally{
+            if (isTransactionActive(em)){
+                rollbackTransaction(em);
+            }
+            closeEM(em);
+        }
+    }
+
     public void testIsolationBeforeEarlyTxBegin(){
         EntityManager em = createDSEntityManager();
         beginTransaction(em);