org.eclipse.persistence.descriptors.changetracking.AttributeChangeTrackingPolicy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* 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.descriptors.changetracking;
import java.beans.PropertyChangeListener;
import java.util.*;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.internal.descriptors.changetracking.*;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.ChangeRecord;
import org.eclipse.persistence.internal.sessions.ObjectChangeSet;
import org.eclipse.persistence.internal.sessions.UnitOfWorkChangeSet;
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
import org.eclipse.persistence.internal.descriptors.*;
import org.eclipse.persistence.mappings.*;
import org.eclipse.persistence.queries.FetchGroup;
/**
* PUBLIC:
* An AttributeChangeTrackingPolicy allows change tracking at the attribute level of an
* object by implementing ChangeTracker. Objects with changed attributes will
* be processed in the UnitOfWork commit process to include any changes in the results of the
* commit. Unchanged objects will be ignored.
* @see DeferredChangeDetectionPolicy
* @see ObjectChangeTrackingPolicy
* @see ChangeTracker
*/
public class AttributeChangeTrackingPolicy extends ObjectChangeTrackingPolicy {
/**
* INTERNAL:
* PERF: Calculate change for the existing object, avoids check for new since already know.
* Avoid backup clone, as not used.
*/
@Override
public ObjectChangeSet calculateChangesForExistingObject(Object clone, UnitOfWorkChangeSet changeSet, UnitOfWorkImpl unitOfWork, ClassDescriptor descriptor, boolean shouldRaiseEvent) {
return calculateChanges(clone, null, false, changeSet, unitOfWork, descriptor, shouldRaiseEvent);
}
/**
* INTERNAL:
* Create ObjectChangeSet
*/
@Override
public ObjectChangeSet createObjectChangeSet(Object clone, Object backUp, org.eclipse.persistence.internal.sessions.UnitOfWorkChangeSet changeSet, boolean isNew, AbstractSession session, ClassDescriptor descriptor) {
ObjectChangeSet changes = null;
if (!isNew) {
AttributeChangeListener listener = (AttributeChangeListener)((ChangeTracker)clone)._persistence_getPropertyChangeListener();
if (listener != null){
changes = listener.getObjectChangeSet();
}
// The changes can be null if forceUpdate is used in CMP, so an empty change must be created.
if (changes != null) {
// PERF: Only merge the change set if merging into a new uow change set.
// merge the changeSet locally (ie the UOW's copy not the tracking policies copy) ; the local changeset will be returned.
if (changes.getUOWChangeSet() != changeSet) {
changes = changeSet.mergeObjectChanges(changes, (org.eclipse.persistence.internal.sessions.UnitOfWorkChangeSet)changes.getUOWChangeSet());
}
// check for deferred changes
if (changes.hasDeferredAttributes()){
//need to calculate the changes for these attributes.
for (Iterator iterator = changes.getDeferredSet().iterator(); iterator.hasNext();){
DatabaseMapping mapping = descriptor.getObjectBuilder().getMappingForAttributeName(iterator.next());
mapping.calculateDeferredChanges((ChangeRecord)changes.getChangesForAttributeNamed(mapping.getAttributeName()), session);
}
changes.getDeferredSet().clear();
}
} else {
changes = descriptor.getObjectBuilder().createObjectChangeSet(clone, changeSet, isNew, session);
}
} else {
changes = descriptor.getObjectBuilder().createObjectChangeSet(clone, changeSet, isNew, true, session);
// PERF: Do not create change records for new objects.
if (descriptor.shouldUseFullChangeSetsForNewObjects() || descriptor.isAggregateDescriptor()) {
FetchGroup fetchGroup = null;
if(descriptor.hasFetchGroupManager()) {
fetchGroup = descriptor.getFetchGroupManager().getObjectFetchGroup(clone);
}
List mappings = descriptor.getMappings();
int size = mappings.size();
for (int index = 0; index < size; index++) {
DatabaseMapping mapping = mappings.get(index);
if ((fetchGroup == null) || fetchGroup.containsAttributeInternal(mapping.getAttributeName())) {
changes.addChange(mapping.compareForChange(clone, null, changes, session));
}
}
}
}
// The following code deals with reads that force changes to the flag associated with optimistic locking.
if ((descriptor.usesOptimisticLocking()) && (changes.getId() != null)) {
changes.setOptimisticLockingPolicyAndInitialWriteLockValue(descriptor.getOptimisticLockingPolicy(), session);
}
return changes;
}
/**
* Used to track instances of the change policies without doing an instance of check
*/
@Override
public boolean isAttributeChangeTrackingPolicy(){
return true;
}
/**
* INTERNAL:
* Clear the change set in the change event listener.
*/
@Override
public void updateWithChanges(Object object, ObjectChangeSet changeSet, UnitOfWorkImpl uow, ClassDescriptor descriptor) {
clearChanges(object, uow, descriptor, false);
}
/**
* INTERNAL:
* In cases where a relationship with detached or new entities is merged into itself previous changes may have been recorded for
* the detached/new entity that need to be updated.
*/
@Override
public void updateListenerForSelfMerge(ObjectChangeListener listener, ForeignReferenceMapping mapping, Object source, Object target, UnitOfWorkImpl unitOfWork){
ChangeRecord record = (ChangeRecord) ((AttributeChangeListener)listener).getObjectChangeSet().getChangesForAttributeNamed(mapping.getAttributeName());
mapping.updateChangeRecordForSelfMerge(record, source, target, (UnitOfWorkChangeSet) ((AttributeChangeListener)listener).getObjectChangeSet().getUOWChangeSet(), unitOfWork);
}
/**
* INTERNAL:
* Clear the change set in the change event listener.
*/
@Override
public void revertChanges(Object clone, ClassDescriptor descriptor, UnitOfWorkImpl uow, Map cloneMapping, boolean forRefresh) {
clearChanges(clone, uow, descriptor, forRefresh);
cloneMapping.put(clone, clone);
}
/**
* INTERNAL:
* Assign ChangeListener to an aggregate object
*/
@Override
public void setAggregateChangeListener(Object parent, Object aggregate, UnitOfWorkImpl uow, ClassDescriptor descriptor, String mappingAttribute){
((ChangeTracker)aggregate)._persistence_setPropertyChangeListener(new AggregateAttributeChangeListener(descriptor, uow, (AttributeChangeListener)((ChangeTracker)parent)._persistence_getPropertyChangeListener(), mappingAttribute, aggregate));
// set change trackers for nested aggregates
Iterator i = descriptor.getMappings().iterator();
while (i.hasNext()){
DatabaseMapping mapping = i.next();
if (mapping.isAggregateObjectMapping()){
AggregateObjectMapping aggregateMapping = (AggregateObjectMapping)mapping;
Object nestedAggregate = aggregateMapping.getAttributeValueFromObject(aggregate);
if (nestedAggregate != null && nestedAggregate instanceof ChangeTracker){
descriptor.getObjectChangePolicy().setAggregateChangeListener(aggregate, nestedAggregate, uow, aggregateMapping.getReferenceDescriptor(), aggregateMapping.getAttributeName());
}
}
}
}
/**
* INTERNAL:
* Assign AttributeChangeListener to PropertyChangeListener
*/
@Override
public PropertyChangeListener setChangeListener(Object clone, UnitOfWorkImpl uow, ClassDescriptor descriptor) {
AttributeChangeListener listener = new AttributeChangeListener(descriptor, uow, clone);
((ChangeTracker)clone)._persistence_setPropertyChangeListener(listener);
return listener;
}
/**
* INTERNAL:
* Set the ObjectChangeSet on the Listener, initially used for aggregate support
*/
@Override
public void setChangeSetOnListener(ObjectChangeSet objectChangeSet, Object clone){
((AttributeChangeListener)((ChangeTracker)clone)._persistence_getPropertyChangeListener()).setObjectChangeSet(objectChangeSet);
}
/**
* INTERNAL:
* Only build backup clone
*/
@Override
public Object buildBackupClone(Object clone, ObjectBuilder builder, UnitOfWorkImpl uow) {
return clone;
}
}