org.eclipse.persistence.internal.sessions.DeferrableChangeRecord Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.eclipse.persistence.core Show documentation
Show all versions of org.eclipse.persistence.core Show documentation
EclipseLink build based upon Git transaction ecdf3c32c4
/*
* 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 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;
public DeferrableChangeRecord() {
super();
}
public 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.
*/
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;
}
}