persistence@glassfish.java.net

Fix for issue 1139 "cascade merge"

From: Wonseok Kim <guruwons_at_gmail.com>
Date: Fri, 22 Sep 2006 01:44:38 +0900

Hi, Tom

I'm investigating the issue 1139 "Cascade doesn't work when merging managed
entity"
https://glassfish.dev.java.net/issues/show_bug.cgi?id=1139

I don't know that there is anyone working on this. Now I'm trying to fix
this.

MergeManager.mergeChangesOfCloneIntoWorkingCopy(Object rmiClone) just
returns if the clone is already registred one.
So I modified it to traverse ForeignReferenceMapping mappings and trigger
mapping.mergeIntoObject() if cascade merge is required. See below diffs.
Some questions:
* Is calling mapping.mergeIntoObject() with same source and target okay?
* ObjectBuilder.mergeIntoObject() also triggers PostMergeEvent. Is this
required too for this type of cascade merge? (JPA doesn't require this
event, but TopLink?)

I tested the fix with an attached testcase and it worked well. Also there
was no entity-persistence-tests failure.

Please review and instruct me.

Index:
src/java/oracle/toplink/essentials/internal/sessions/MergeManager.java
===================================================================
RCS file:
/cvs/glassfish/entity-persistence/src/java/oracle/toplink/essentials/internal/sessions/MergeManager.java,v
retrieving revision 1.6
diff -c -r1.6 MergeManager.java
***
src/java/oracle/toplink/essentials/internal/sessions/MergeManager.java 20
Apr 2006 20:32:05 -0000 1.6
---
src/java/oracle/toplink/essentials/internal/sessions/MergeManager.java    21
Sep 2006 16:01:58 -0000
***************
*** 387,402 ****
          ClassDescriptor descriptor = getSession().getDescriptor(rmiClone);
          Object registeredObject =
registerObjectForMergeCloneIntoWorkingCopy(rmiClone);
-         if (registeredObject == rmiClone) {
-             //need to find better better fix.  prevents merging into
itself.
-             return rmiClone;
-         }
-
          boolean changeTracked = false;
          try {
              ObjectBuilder builder = descriptor.getObjectBuilder();
!             if (descriptor.usesVersionLocking()) {
                  VersionLockingPolicy policy = (VersionLockingPolicy)
descriptor.getOptimisticLockingPolicy();
                  if (policy.isStoredInObject()) {
                      Object currentValue =
builder.extractValueFromObjectForField(registeredObject,
policy.getWriteLockField(), session);
--- 387,397 ----
          ClassDescriptor descriptor = getSession().getDescriptor(rmiClone);
          Object registeredObject =
registerObjectForMergeCloneIntoWorkingCopy(rmiClone);
          boolean changeTracked = false;
          try {
              ObjectBuilder builder = descriptor.getObjectBuilder();
!             if (registeredObject != rmiClone &&
descriptor.usesVersionLocking()) {
                  VersionLockingPolicy policy = (VersionLockingPolicy)
descriptor.getOptimisticLockingPolicy();
                  if (policy.isStoredInObject()) {
                      Object currentValue =
builder.extractValueFromObjectForField(registeredObject,
policy.getWriteLockField(), session);
***************
*** 410,417 ****
              // Toggle change tracking during the merge.
              descriptor.getObjectChangePolicy
().dissableEventProcessing(registeredObject);
!             // Merge into the clone from the original, use clone as backup
as anything different should be merged.
!             builder.mergeIntoObject(registeredObject, false, rmiClone,
this);
          } finally {
              descriptor.getObjectChangePolicy
().enableEventProcessing(registeredObject);
          }
--- 405,425 ----
              // Toggle change tracking during the merge.
              descriptor.getObjectChangePolicy
().dissableEventProcessing(registeredObject);
!             if(registeredObject == rmiClone){
!                 // GF#1139 Cascade merge operations even if it's already
managed
!                 Vector mappings = descriptor.getMappings();
!                 for (int index = 0; index < mappings.size(); index++) {
!                     DatabaseMapping mapping =
(DatabaseMapping)mappings.get(index);
!                     if(mapping instanceof ForeignReferenceMapping
!                             &&
((ForeignReferenceMapping)mapping).shouldMergeCascadeParts(this)){
!                         mapping.mergeIntoObject(registeredObject, false,
rmiClone, this);
!                     }
!                 }
!
!             } else {
!                 // Merge into the clone from the original, use clone as
backup as anything different should be merged.
!                 builder.mergeIntoObject(registeredObject, false, rmiClone,
this);
!             }
          } finally {
              descriptor.getObjectChangePolicy
().enableEventProcessing(registeredObject);
          }
Thanks
-- 
Wonseok Kim
Senior Developer, TmaxSoft