| /* |
| * 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 org.eclipse.persistence.indirection.IndirectCollection; |
| import org.eclipse.persistence.internal.queries.ContainerPolicy; |
| |
| /** |
| * Abstract change record for collection type records that allow deferrable change detection. |
| * Used for change tracking when user sets entire collection. |
| */ |
| public abstract class DeferrableChangeRecord extends ChangeRecord { |
| |
| /** |
| * Used for change tracking when user sets entire collection. |
| */ |
| protected transient Object originalCollection; |
| |
| /** |
| * Used for change tracking when user sets entire collection. |
| */ |
| protected transient Object latestCollection; |
| |
| /** |
| * Defines if this change should be calculated at commit time using the two collections. |
| * This is used to handle collection replacement. |
| */ |
| protected boolean isDeferred = false; |
| |
| protected DeferrableChangeRecord() { |
| super(); |
| } |
| |
| protected DeferrableChangeRecord(ObjectChangeSet owner) { |
| this.owner = owner; |
| } |
| |
| /** |
| * Returns if this change should be calculated at commit time using the two collections. |
| * This is used to handle collection replacement. |
| */ |
| public boolean isDeferred() { |
| return isDeferred; |
| } |
| |
| /** |
| * Sets if this change should be calculated at commit time using the two collections. |
| * This is used to handle collection replacement. |
| */ |
| public void setIsDeferred(boolean isDeferred) { |
| this.isDeferred = isDeferred; |
| } |
| |
| /** |
| * Used for change tracking when user sets entire collection. |
| * This is the last collection that was set on the object. |
| */ |
| public Object getLatestCollection() { |
| return latestCollection; |
| } |
| |
| /** |
| * Used for change tracking when user sets entire collection. |
| * This is the original collection that was set on the object when it was cloned. |
| */ |
| public Object getOriginalCollection() { |
| return originalCollection; |
| } |
| |
| /** |
| * Used for change tracking when user sets entire collection. |
| * This is the last collection that was set on the object. |
| */ |
| public void setLatestCollection(Object latestCollection) { |
| this.latestCollection = latestCollection; |
| } |
| |
| /** |
| * Used for change tracking when user sets entire collection. |
| * This is the original collection that was set on the object when it was cloned. |
| */ |
| public void setOriginalCollection(Object originalCollection) { |
| this.originalCollection = originalCollection; |
| } |
| |
| /** |
| * Recreates the original state of currentCollection. |
| */ |
| abstract public void internalRecreateOriginalCollection(Object currentCollection, AbstractSession session); |
| |
| /** |
| * Clears info about added / removed objects set by change tracker. |
| * Called after the change info has been already used for creation of originalCollection. |
| * Also called to make sure there is no change info before comparison for change is performed |
| * (change info is still in the record after comparison for change is performed |
| * and may cause wrong results when the second comparison for change performed on the same change record). |
| */ |
| abstract public void clearChanges(); |
| |
| /** |
| * Recreates the original state of the collection. |
| */ |
| public void recreateOriginalCollection(Object currentCollection, AbstractSession session) { |
| if(currentCollection == null) { |
| this.setOriginalCollection(null); |
| return; |
| } |
| if(currentCollection instanceof IndirectCollection) { |
| // to avoid raising event when we add/remove elements from this collection later in this method. |
| setOriginalCollection(((IndirectCollection)currentCollection).getDelegateObject()); |
| } else { |
| setOriginalCollection(currentCollection); |
| } |
| internalRecreateOriginalCollection(this.originalCollection, session); |
| clearChanges(); |
| } |
| |
| /** |
| * ADVANCED: |
| * If the owning UnitOfWork has shouldChangeRecordKeepOldValue set to true, |
| * then return the old value of the attribute represented by this ChangeRecord. |
| */ |
| @Override |
| public Object getOldValue() { |
| if(this.originalCollection != null) { |
| return this.originalCollection; |
| } else { |
| if(getOwner() != null) { |
| Object obj = ((org.eclipse.persistence.internal.sessions.ObjectChangeSet)getOwner()).getUnitOfWorkClone(); |
| AbstractSession session = ((org.eclipse.persistence.internal.sessions.UnitOfWorkChangeSet)getOwner().getUOWChangeSet()).getSession(); |
| if(obj != null && session != null) { |
| Object currentCollection = this.mapping.getAttributeValueFromObject(obj); |
| ContainerPolicy cp = this.mapping.getContainerPolicy(); |
| Object cloneCurrentCollection = cp.containerInstance(cp.sizeFor(currentCollection)); |
| for (Object valuesIterator = cp.iteratorFor(currentCollection); cp.hasNext(valuesIterator);) { |
| Object member = cp.next(valuesIterator, session); |
| cp.addInto(cp.keyFromIterator(valuesIterator), member, cloneCurrentCollection , session); |
| } |
| return getOldValue(cloneCurrentCollection, session); |
| } |
| } |
| return null; |
| } |
| } |
| |
| public Object getOldValue(Object currentCollection, AbstractSession session) { |
| if(currentCollection != null) { |
| if(currentCollection instanceof IndirectCollection) { |
| currentCollection = ((IndirectCollection)currentCollection).getDelegateObject(); |
| } |
| internalRecreateOriginalCollection(currentCollection, session); |
| } |
| return currentCollection; |
| } |
| } |