| /* |
| * Copyright (c) 1998, 2021 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 v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Oracle - initial API and implementation from Oracle TopLink |
| package org.eclipse.persistence.internal.sessions; |
| |
| import java.io.Serializable; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.IdentityHashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.persistence.descriptors.ClassDescriptor; |
| import org.eclipse.persistence.internal.identitymaps.CacheId; |
| import org.eclipse.persistence.internal.identitymaps.CacheKey; |
| import org.eclipse.persistence.mappings.DatabaseMapping; |
| import org.eclipse.persistence.queries.FetchGroup; |
| |
| /** |
| * <p> |
| * <b>Purpose</b>: This is the overall collection of changes. |
| * </p> |
| * <p> |
| * <b>Description</b>: It holds all of the object changes and |
| * all ObjectChanges, with the same classType and primary keys, referenced in a changeSet should be |
| * the same object. |
| * </p> |
| */ |
| public class UnitOfWorkChangeSet implements Serializable, org.eclipse.persistence.sessions.changesets.UnitOfWorkChangeSet { |
| |
| /** This is the collection of ObjectChanges held by this ChangeSet */ |
| // *** TODO fix transients *** */ |
| protected Map<Class<?>, Map<ObjectChangeSet, ObjectChangeSet>> objectChanges; |
| |
| // This collection holds the new objects which will have no real identity until inserted. |
| protected Map<Class<?>, Map<ObjectChangeSet, ObjectChangeSet>> newObjectChangeSets; |
| protected Map<Object, ObjectChangeSet> cloneToObjectChangeSet; |
| protected Map<ObjectChangeSet, Object> objectChangeSetToUOWClone; |
| protected Map<ObjectChangeSet, ObjectChangeSet> aggregateChangeSets; |
| protected Map<ObjectChangeSet, ObjectChangeSet> allChangeSets; |
| protected Map<ObjectChangeSet, ObjectChangeSet> deletedObjects; |
| |
| /** This attribute is set to true if a changeSet with changes has been added */ |
| protected boolean hasChanges; |
| protected boolean hasForcedChanges; |
| |
| /** |
| * Flag set when calling commitToDatabaseWithPreBuiltChangeSet |
| * so we are aware the UOW does not contain the changes from this change set. |
| */ |
| protected boolean isChangeSetFromOutsideUOW; |
| |
| /** Stores unit of work before it is serialized. */ |
| protected transient AbstractSession session; |
| |
| /** |
| * INTERNAL: |
| * Create a ChangeSet |
| */ |
| public UnitOfWorkChangeSet() { |
| } |
| |
| /** |
| * INTERNAL: |
| * Create a ChangeSet |
| */ |
| public UnitOfWorkChangeSet(AbstractSession session) { |
| this.session = session; |
| } |
| |
| /** |
| * Return the session. |
| * This only exists before serialization. |
| */ |
| public AbstractSession getSession() { |
| return session; |
| } |
| |
| /** |
| * INTERNAL: |
| * Set the session. |
| * This only exists before serialization. |
| */ |
| public void setSession(AbstractSession session) { |
| this.session = session; |
| } |
| |
| /** |
| * INTERNAL: |
| * Add the Deleted objects to the changeSet. |
| */ |
| public void addDeletedObjects(Map deletedObjects, AbstractSession session) { |
| Iterator enumtr = deletedObjects.keySet().iterator(); |
| while (enumtr.hasNext()) { |
| Object object = enumtr.next(); |
| this.addDeletedObject(object, session); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Add the Deleted object to the changeSet. |
| */ |
| public void addDeletedObject(Object object, AbstractSession session) { |
| //CR 4080 - must prevent aggregate objects added to DeletedObjects list |
| ClassDescriptor descriptor = session.getDescriptor(object); |
| if (!descriptor.isAggregateCollectionDescriptor()) { |
| ObjectChangeSet set = descriptor.getObjectBuilder().createObjectChangeSet(object, this, false, session); |
| |
| // needed for xml change set |
| set.setShouldBeDeleted(true); |
| getDeletedObjects().put(set, set); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Add to the changes for 'object' object to this changeSet. This method |
| * will not add to the lists that are used for identity lookups. |
| * The passed change set *must* either have changes or forced changes. |
| * @see #addObjectChangeSetForIdentity(ObjectChangeSet, Object) |
| * @param forceToNewObjectList - Any pre commit actions should pass in true |
| * since new objects have extra-handling. Anything post commit, pass in |
| * false. |
| */ |
| public void addObjectChangeSet(ObjectChangeSet objectChanges, AbstractSession session, boolean forceToNewObjectList) { |
| if (objectChanges != null) { |
| if (objectChanges.isNew() && forceToNewObjectList) { |
| // Add it to the new list (unless there is no force, that is, |
| // we are in a post commit and we can trust the cache key then) |
| // so we do not loose it as it may not have a valid primary key |
| // it will be moved to the standard list once it is inserted. |
| addNewObjectChangeSet(objectChanges, session); |
| getAllChangeSets().put(objectChanges, objectChanges); |
| } else { |
| // If this object change set has changes or forced changes then |
| // record this. Must be done for each change set added because |
| // some may not contain 'real' changes. This is the case for |
| // opt. read lock and forceUdpate. Keep the flags separate |
| // because we don't want to cache sync. a change set with no |
| // 'real' changes. |
| boolean objectChangeSetHasChanges = objectChanges.hasChanges(); |
| if (objectChangeSetHasChanges) { |
| this.setHasChanges(true); |
| this.hasForcedChanges = this.hasForcedChanges || objectChanges.hasForcedChanges(); |
| } else { |
| // Object change set doesn't have changes so it has to have |
| // forced changes. |
| this.hasForcedChanges = true; |
| } |
| |
| if (!objectChanges.isAggregate()) { |
| if (objectChangeSetHasChanges) { |
| // Each time I create a changeSet it is added to this |
| // list and when I compute a changeSet for this object |
| // I again add it to these lists so that before this |
| // UOWChangeSet is Serialized there is a copy of every |
| // changeSet which has changes affecting cache in |
| // allChangeSets. |
| getAllChangeSets().put(objectChanges, objectChanges); |
| } |
| |
| if (objectChanges.getId() != null) { |
| Map<ObjectChangeSet, ObjectChangeSet> map = getObjectChanges().get(objectChanges.getClassType()); |
| |
| if (map == null) { |
| map = new HashMap<>(); |
| getObjectChanges().put(objectChanges.getClassType(), map); |
| map.put(objectChanges, objectChanges); |
| } else { |
| map.put(objectChanges, objectChanges); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Add to the changes for 'object' object to this changeSet. This method will not |
| * add to the lists that are used for identity lookups. It is called specifically |
| * for new objects, and new object will be moved to the standard changes list by |
| * the QueryMechanism after insert. |
| * @see #addObjectChangeSetForIdentity(ObjectChangeSet, Object) |
| * @param objectChanges the new object change set |
| */ |
| protected void addNewObjectChangeSet(ObjectChangeSet objectChanges, AbstractSession session) { |
| Map<ObjectChangeSet, ObjectChangeSet> changeSetTable = getNewObjectChangeSets().get(objectChanges.getClassType(session)); |
| if (changeSetTable == null) { |
| // 2612538 - the default size of Map (32) is appropriate |
| changeSetTable = new IdentityHashMap<>(); |
| getNewObjectChangeSets().put(objectChanges.getClassType(session), changeSetTable); |
| } |
| changeSetTable.put(objectChanges, objectChanges); |
| this.hasChanges = true; |
| } |
| |
| /** |
| * INTERNAL: |
| * This method can be used find the equivalent changeset within this UnitOfWorkChangeSet |
| * Aggregates, and new objects without primaryKeys from serialized ChangeSets will not be found |
| * Which may result in duplicates, in the UnitOfWorkChangeSet. |
| */ |
| public ObjectChangeSet findObjectChangeSet(ObjectChangeSet changeSet, UnitOfWorkChangeSet mergeFromChangeSet) { |
| Map<ObjectChangeSet, ObjectChangeSet> changes = getObjectChanges().get(changeSet.getClassType()); |
| ObjectChangeSet potential = null; |
| if (changes != null) { |
| potential = changes.get(changeSet); |
| } |
| if (potential == null) { |
| potential = (ObjectChangeSet)getObjectChangeSetForClone(changeSet.getUnitOfWorkClone()); |
| } |
| return potential; |
| } |
| |
| /** |
| * INTERNAL: |
| * This method will be used during the merge process to either find an equivalent change set |
| * within this UnitOfWorkChangeSet or integrate that changeset into this UOW ChangeSet |
| */ |
| public ObjectChangeSet findOrIntegrateObjectChangeSet(ObjectChangeSet tofind, UnitOfWorkChangeSet mergeFromChangeSet) { |
| if (tofind == null) { |
| return tofind; |
| } |
| ObjectChangeSet localChangeSet = this.findObjectChangeSet(tofind, mergeFromChangeSet); |
| if (localChangeSet == null) {//not found locally then replace it with the one from the merging changeset |
| if (tofind.getDescriptor() == null) { |
| tofind.getClassType(this.session); |
| tofind.setDescriptor(this.session.getDescriptor(tofind.getClassType())); |
| } |
| localChangeSet = new ObjectChangeSet(tofind.getId(), tofind.getDescriptor(), tofind.getUnitOfWorkClone(), this, tofind.isNew()); |
| this.addObjectChangeSetForIdentity(localChangeSet, localChangeSet.getUnitOfWorkClone()); |
| } |
| return localChangeSet; |
| } |
| |
| /** |
| * INTERNAL" |
| * This method is used during the merge process to either find the existing ChangeSet or create a new one. |
| */ |
| public ObjectChangeSet findOrCreateLocalObjectChangeSet(Object entityClone, ClassDescriptor descriptor, boolean isNew){ |
| ObjectChangeSet changes = (ObjectChangeSet)this.getObjectChangeSetForClone(entityClone); |
| if (changes == null) { |
| if (descriptor.hasInheritance() && descriptor.getJavaClass() != entityClone.getClass()) { |
| descriptor = descriptor.getInheritancePolicy().getSubclassDescriptor(entityClone.getClass()); |
| } |
| if (descriptor.isAggregateDescriptor()) { |
| changes = new AggregateObjectChangeSet(CacheId.EMPTY, descriptor, entityClone, this, isNew); |
| } else { |
| changes = new ObjectChangeSet(descriptor.getObjectBuilder().extractPrimaryKeyFromObject(entityClone, session), descriptor, entityClone, this, isNew); |
| } |
| changes.setIsAggregate(descriptor.isDescriptorTypeAggregate()); |
| this.addObjectChangeSetForIdentity(changes, entityClone); |
| } |
| return changes; |
| } |
| |
| /** |
| * INTERNAL: |
| * Add change records to the lists used to maintain identity. This will not actually |
| * add the changes to 'object' to the change set. |
| * @see #addObjectChangeSet(ObjectChangeSet, AbstractSession, boolean) |
| * @param objectChanges prototype.changeset.ObjectChanges |
| */ |
| public void addObjectChangeSetForIdentity(ObjectChangeSet objectChanges, Object object) { |
| if ((objectChanges == null) || (object == null)) { |
| return; |
| } |
| |
| if (objectChanges.isAggregate()) { |
| getAggregateChangeSets().put(objectChanges, objectChanges); |
| } |
| |
| getObjectChangeSetToUOWClone().put(objectChanges, object); |
| getCloneToObjectChangeSet().put(object, objectChanges); |
| |
| } |
| |
| /** |
| * INTERNAL: |
| * Get the Aggregate list. Lazy initializes the map if required. |
| */ |
| public Map<ObjectChangeSet, ObjectChangeSet> getAggregateChangeSets() { |
| if (this.aggregateChangeSets == null) { |
| this.aggregateChangeSets = new IdentityHashMap<>(); |
| } |
| return this.aggregateChangeSets; |
| } |
| |
| /** |
| * INTERNAL: |
| * This method returns a reference to the collection. |
| */ |
| @Override |
| public Map<ObjectChangeSet, ObjectChangeSet> getAllChangeSets() { |
| if (this.allChangeSets == null) { |
| // 2612538 - the default size of Map (32) is appropriate |
| this.allChangeSets = new IdentityHashMap<>(); |
| } |
| return this.allChangeSets; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return a new UnitOfWorkChangeSet that only includes data require for the remote merge, |
| * for cache coordination. |
| * |
| * @param session current database session |
| */ |
| public UnitOfWorkChangeSet buildCacheCoordinationMergeChangeSet(AbstractSession session) { |
| //bug 4416412: Map sent instead of Vector |
| Map writableChangeSets = new IdentityHashMap(); |
| for (ObjectChangeSet changeSet : getAllChangeSets().values()) { |
| // navigate through the related change sets here and set their cache synchronization type as well |
| ClassDescriptor descriptor = changeSet.getDescriptor(); |
| int syncType = descriptor.getCachePolicy().getCacheSynchronizationType(); |
| |
| // Bug 486845 - ensure that any existing protected foreign keys are set |
| // in the changeSet for objects with protected cache isolation |
| if (descriptor.isProtectedIsolation()) { |
| CacheKey activeCacheKey = changeSet.getActiveCacheKey(); |
| if (activeCacheKey != null && activeCacheKey.hasProtectedForeignKeys()) { |
| changeSet.setProtectedForeignKeys(activeCacheKey.getProtectedForeignKeys().clone()); |
| } |
| } |
| |
| // Change sets for new objects will only be sent as part of the UnitOfWorkChangeSet |
| // if they are meant to be merged into the distributed cache. |
| // Note: New objects could still be sent if the are referred to by a change record. |
| if ((syncType != ClassDescriptor.DO_NOT_SEND_CHANGES) |
| && (!changeSet.isNew() || (syncType == ClassDescriptor.SEND_NEW_OBJECTS_WITH_CHANGES))) { |
| changeSet.unitOfWorkChangeSet.setSession(null); |
| writableChangeSets.put(changeSet, changeSet); |
| } |
| // bug 530681: ensureChanges(AbstractSession, ObjectChangeSet, ClassDescriptor) from ObjectChangeSet was moved here |
| if (changeSet.isNew() && ((changeSet.changes == null) || changeSet.changes.isEmpty() |
| || syncType != ClassDescriptor.SEND_NEW_OBJECTS_WITH_CHANGES)) { |
| ensureChanges(session, changeSet, descriptor); |
| } |
| } |
| Map sendableDeletedObjects = new IdentityHashMap(); |
| for (ObjectChangeSet changeSet : getDeletedObjects().keySet()) { |
| // navigate through the related change sets here and set their cache synchronization type as well |
| ClassDescriptor descriptor = changeSet.getDescriptor(); |
| int syncType = descriptor.getCacheSynchronizationType(); |
| |
| // Change sets for new objects will only be sent as part of the UnitOfWorkChangeSet |
| // if they are meant to be merged into the distributed cache. |
| // Note: New objects could still be sent if the are referred to by a change record. |
| if (syncType != ClassDescriptor.DO_NOT_SEND_CHANGES) { |
| changeSet.unitOfWorkChangeSet.setSession(null); |
| sendableDeletedObjects.put(changeSet, changeSet); |
| } |
| } |
| |
| // Do not write if nothing to write i.e. only does inserts |
| if (writableChangeSets.isEmpty() && sendableDeletedObjects.isEmpty()) { |
| return null; |
| } |
| UnitOfWorkChangeSet remoteChangeSet = new UnitOfWorkChangeSet(); |
| if (!writableChangeSets.isEmpty()) { |
| remoteChangeSet.allChangeSets = writableChangeSets; |
| } |
| if (!sendableDeletedObjects.isEmpty()) { |
| remoteChangeSet.deletedObjects = sendableDeletedObjects; |
| } |
| return remoteChangeSet; |
| } |
| |
| /** |
| * Ensure the change set is populated for cache coordination. |
| * |
| * @param session current database session |
| * @param changeSet change set to populate |
| * @param descriptor class (relational) descriptor related to the change set |
| */ |
| private void ensureChanges(final AbstractSession session, final ObjectChangeSet changeSet, final ClassDescriptor descriptor) { |
| FetchGroup fetchGroup = null; |
| if (descriptor.hasFetchGroupManager()) { |
| fetchGroup = descriptor.getFetchGroupManager().getObjectFetchGroup(changeSet.cloneObject); |
| } |
| for (DatabaseMapping mapping : descriptor.getMappings()) { |
| if (fetchGroup == null || fetchGroup.containsAttributeInternal(mapping.getAttributeName())) { |
| changeSet.addChange(mapping.compareForChange(changeSet.cloneObject, changeSet.cloneObject, changeSet, session)); |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Get the clone to object change hash table. Lazy initializes the map if required. |
| */ |
| public Map<Object, ObjectChangeSet> getCloneToObjectChangeSet() { |
| if (cloneToObjectChangeSet == null) { |
| cloneToObjectChangeSet = new IdentityHashMap(); |
| } |
| return cloneToObjectChangeSet; |
| } |
| |
| /** |
| * INTERNAL: |
| * This method returns the reference to the deleted objects from the changeSet. |
| */ |
| @Override |
| public Map<ObjectChangeSet, ObjectChangeSet> getDeletedObjects() { |
| if (this.deletedObjects == null) { |
| // 2612538 - the default size of Map (32) is appropriate |
| this.deletedObjects = new IdentityHashMap(); |
| } |
| return deletedObjects; |
| } |
| |
| /** |
| * INTERNAL: |
| * Returns the ObjectChanges held by this ChangeSet. |
| */ |
| public Map<Class<?>, Map<ObjectChangeSet, ObjectChangeSet>> getObjectChanges() { |
| if (objectChanges == null) { |
| objectChanges = new HashMap<>(); |
| } |
| return objectChanges; |
| } |
| |
| /** |
| * INTERNAL: |
| * Returns the set of classes corresponding to updated objects in objectChanges. |
| */ |
| public Set<ClassDescriptor> findUpdatedObjectsClasses() { |
| if (this.objectChanges == null || this.objectChanges.isEmpty()) { |
| return null; |
| } |
| HashSet<ClassDescriptor> updatedObjectsClasses = new HashSet<>(getObjectChanges().size()); |
| for (Map<ObjectChangeSet, ObjectChangeSet> objectChanges : getObjectChanges().values()) { |
| for (ObjectChangeSet changeSet : objectChanges.values()) { |
| // any change set will do |
| if(!changeSet.isNew()) { |
| // found updated object - add its class to the set |
| updatedObjectsClasses.add(changeSet.getDescriptor()); |
| // and go to the table corresponding to the next class |
| break; |
| } |
| } |
| } |
| return updatedObjectsClasses; |
| } |
| |
| /** |
| * ADVANCED: |
| * Get ChangeSet for a particular clone |
| * @return ObjectChangeSet the changeSet that represents a particular clone |
| */ |
| @Override |
| public org.eclipse.persistence.sessions.changesets.ObjectChangeSet getObjectChangeSetForClone(Object clone) { |
| if ((clone == null) || (this.cloneToObjectChangeSet == null)) { |
| return null; |
| } |
| return this.cloneToObjectChangeSet.get(clone); |
| } |
| |
| /** |
| * INTERNAL: |
| * This method returns a reference to the collection |
| * @return Map |
| */ |
| protected Map<ObjectChangeSet, Object> getObjectChangeSetToUOWClone() { |
| if (this.objectChangeSetToUOWClone == null) { |
| // 2612538 - the default size of Map (32) is appropriate |
| this.objectChangeSetToUOWClone = new IdentityHashMap<>(); |
| } |
| return objectChangeSetToUOWClone; |
| } |
| |
| /** |
| * ADVANCED: |
| * This method returns the Clone for a particular changeSet |
| * @return Object the clone represented by the changeSet |
| */ |
| @Override |
| public Object getUOWCloneForObjectChangeSet(org.eclipse.persistence.sessions.changesets.ObjectChangeSet changeSet) { |
| if ((changeSet == null) || (this.objectChangeSetToUOWClone == null)) { |
| return null; |
| } |
| return this.objectChangeSetToUOWClone.get(changeSet); |
| } |
| |
| /** |
| * INTERNAL: |
| * Returns true if the Unit Of Work change Set has changes |
| */ |
| @Override |
| public boolean hasChanges() { |
| // All of the object change sets were empty (none contained changes) |
| // The this.hasChanges variable is set in addObjectChangeSet |
| return (this.hasChanges || (this.deletedObjects != null) && (!this.deletedObjects.isEmpty())); |
| } |
| |
| /** |
| * INTERNAL: |
| * Returns true if any deleted objects. |
| * This should be used before accessing deleted object to avoid creation of map. |
| */ |
| public boolean hasDeletedObjects() { |
| return (this.deletedObjects != null) && (!this.deletedObjects.isEmpty()); |
| } |
| |
| /** |
| * INTERNAL: |
| * Set whether the Unit Of Work change Set has changes |
| */ |
| public void setHasChanges(boolean flag) { |
| this.hasChanges = flag; |
| } |
| |
| /** |
| * INTERNAL: |
| * Returns true if this uowChangeSet contains an objectChangeSet that has forced |
| * SQL changes. This is true whenever CMPPolicy.getForceUpdate() == true. |
| * @return boolean |
| */ |
| public boolean hasForcedChanges() { |
| return this.hasForcedChanges; |
| } |
| |
| /** |
| * INTERNAL: |
| * This method will be used to merge a change set into an UnitOfWorkChangeSet |
| * This method returns the local instance of the changeset |
| */ |
| public ObjectChangeSet mergeObjectChanges(ObjectChangeSet objectChangeSet, UnitOfWorkChangeSet mergeFromChangeSet) { |
| ObjectChangeSet localChangeSet = this.findOrIntegrateObjectChangeSet(objectChangeSet, mergeFromChangeSet); |
| if (localChangeSet != null) { |
| localChangeSet.mergeObjectChanges(objectChangeSet, this, mergeFromChangeSet); |
| } |
| return localChangeSet; |
| } |
| |
| /** |
| * INTERNAL: |
| * THis method will be used to merge another changeset into this changeset. The |
| * Main use of this method is for non-deferred writes and checkpointing so that |
| * the accumulated changes are collected and merged at the end of the transaction. |
| */ |
| public void mergeUnitOfWorkChangeSet(UnitOfWorkChangeSet mergeFromChangeSet, AbstractSession session, boolean postCommit) { |
| if (mergeFromChangeSet == null) { |
| return; |
| } |
| for (Map<ObjectChangeSet, ObjectChangeSet> objectChanges : mergeFromChangeSet.getObjectChanges().values()) { |
| for (ObjectChangeSet objectChangeSet : objectChanges.values()) { |
| objectChangeSet = mergeObjectChanges(objectChangeSet, mergeFromChangeSet); |
| addObjectChangeSet(objectChangeSet, session, !postCommit); |
| } |
| } |
| |
| //merging a serialized UnitOfWorkChangeSet can result in duplicate deletes |
| //if a delete for the same object already exists in this UOWChangeSet. |
| if (mergeFromChangeSet.hasDeletedObjects()) { |
| for (ObjectChangeSet objectChangeSet : mergeFromChangeSet.getDeletedObjects().values()) { |
| ObjectChangeSet localObjectChangeSet = findObjectChangeSet(objectChangeSet, mergeFromChangeSet); |
| if (localObjectChangeSet == null) { |
| localObjectChangeSet = objectChangeSet; |
| } |
| getDeletedObjects().put(localObjectChangeSet, localObjectChangeSet); |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Used to rehash the new objects back into the objectChanges list for serialization |
| * Assumes the transaction in in post commit stage. |
| */ |
| public void putNewObjectInChangesList(ObjectChangeSet objectChangeSet, AbstractSession session) { |
| // Must reset the cache key for new objects assigned in insert. |
| if (objectChangeSet.getId() == null) { |
| Object clone = objectChangeSet.getUnitOfWorkClone(); |
| objectChangeSet.setId(session.getDescriptor(clone.getClass()).getObjectBuilder().extractPrimaryKeyFromObject(clone, session, false)); |
| } |
| addObjectChangeSet(objectChangeSet, session, false); |
| removeObjectChangeSetFromNewList(objectChangeSet, session); |
| } |
| |
| /** |
| * INTERNAL: |
| * Used to remove a new object from the new objects list once it has been |
| * inserted and added to the objectChangesList |
| */ |
| public void removeObjectChangeSetFromNewList(ObjectChangeSet objectChangeSet, AbstractSession session) { |
| Map<ObjectChangeSet, ObjectChangeSet> table = getNewObjectChangeSets().get(objectChangeSet.getClassType(session)); |
| if (table != null) { |
| table.remove(objectChangeSet); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Add the changed Object's records to the ChangeSet. |
| */ |
| public void removeObjectChangeSet(ObjectChangeSet changeSet) { |
| if (changeSet == null) { |
| return; |
| } |
| Object object = getObjectChangeSetToUOWClone().get(changeSet); |
| if (changeSet.isAggregate()) { |
| getAggregateChangeSets().remove(changeSet); |
| } else { |
| Map<ObjectChangeSet, ObjectChangeSet> classChanges = getObjectChanges().get(object.getClass()); |
| if (classChanges != null) { |
| classChanges.remove(changeSet); |
| } |
| } |
| getObjectChangeSetToUOWClone().remove(changeSet); |
| if (object != null) { |
| getCloneToObjectChangeSet().remove(object); |
| } |
| getAllChangeSets().remove(changeSet); |
| } |
| |
| /** |
| * INTERNAL: |
| * Set the internal flag that tells that this change set was built outside this |
| * UOW and the changes it contains cannot be calculated from the contents of this UOW |
| */ |
| public void setIsChangeSetFromOutsideUOW(boolean isChangeSetFromOutsideUOW){ |
| this.isChangeSetFromOutsideUOW = isChangeSetFromOutsideUOW; |
| } |
| |
| /** |
| * INTERNAL: |
| * Get the internal flag that tells that this change set was built outside this |
| * UOW and the changes it contains cannot be calculated from the contents of this UOW |
| */ |
| public boolean isChangeSetFromOutsideUOW(){ |
| return isChangeSetFromOutsideUOW; |
| } |
| |
| /** |
| * INTERNAL: |
| * This method is used to set the map for cloneToObject reference. |
| */ |
| public void setCloneToObjectChangeSet(Map<Object, ObjectChangeSet> cloneToObjectChangeSet) { |
| this.cloneToObjectChangeSet = cloneToObjectChangeSet; |
| } |
| |
| /** |
| * INTERNAL: |
| * Sets the collection of ObjectChanges in the change Set. |
| */ |
| protected void setObjectChanges(Map objectChanges) { |
| this.objectChanges = objectChanges; |
| } |
| |
| /** |
| * INTERNAL: |
| * Sets the collection of ObjectChanges in the change Set. |
| */ |
| public void setAllChangeSets(Map allChangeSets) { |
| this.allChangeSets = allChangeSets; |
| } |
| |
| /** |
| * INTERNAL: |
| * Sets the collection of deleted objects. |
| */ |
| public void setDeletedObjects(Map deletedObjects) { |
| this.deletedObjects = deletedObjects; |
| } |
| |
| /** |
| * INTERNAL: |
| * This method is used to insert a new collection into the UOWChangeSet. |
| */ |
| public void setObjectChangeSetToUOWClone(Map<ObjectChangeSet, Object> objectChangeSetToUOWClone) { |
| this.objectChangeSetToUOWClone = objectChangeSetToUOWClone; |
| } |
| |
| /** |
| * INTERNAL: |
| * This method will return a reference to the new object change set collections. |
| */ |
| public Map<Class<?>, Map<ObjectChangeSet, ObjectChangeSet>> getNewObjectChangeSets() { |
| if (this.newObjectChangeSets == null) { |
| this.newObjectChangeSets = new HashMap<>(); |
| } |
| return this.newObjectChangeSets; |
| } |
| |
| } |