org.eclipse.persistence.descriptors.changetracking.ObjectChangeTrackingPolicy 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.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import org.eclipse.persistence.internal.descriptors.ObjectBuilder;
import org.eclipse.persistence.internal.descriptors.changetracking.ObjectChangeListener;
import org.eclipse.persistence.internal.descriptors.changetracking.AggregateObjectChangeListener;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.FetchGroupManager;
import org.eclipse.persistence.exceptions.DescriptorException;
import org.eclipse.persistence.mappings.DatabaseMapping;
/**
* PUBLIC:
* A ObjectChangeTrackingPolicy allows an object to calculate for itself whether
* it should has changed by implementing ChangeTracker. Changed objects 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 ChangeTracker
*/
public class ObjectChangeTrackingPolicy extends DeferredChangeDetectionPolicy {
/**
* INTERNAL:
* This method is used to disable changetracking temporarily
*/
@Override
public void dissableEventProcessing(Object changeTracker) {
ObjectChangeListener listener = (ObjectChangeListener)((ChangeTracker)changeTracker)._persistence_getPropertyChangeListener();
if (listener != null) {
listener.ignoreEvents();
}
}
/**
* INTERNAL:
* This method is used to enable changetracking temporarily
*/
@Override
public void enableEventProcessing(Object changeTracker) {
ObjectChangeListener listener = (ObjectChangeListener)((ChangeTracker)changeTracker)._persistence_getPropertyChangeListener();
if (listener != null) {
listener.processEvents();
}
}
/**
* INTERNAL:
* Return true if the Object should be compared, false otherwise. In ObjectChangeTrackingPolicy or
* AttributeChangeTracking Policy this method will return true if the object is new, if the object
* is in the OptimisticReadLock list or if the listener.hasChanges() returns true.
* @param object the object that will be compared
* @param unitOfWork the active unitOfWork
* @param descriptor the descriptor for the current object
*/
@Override
public boolean shouldCompareExistingObjectForChange(Object object, UnitOfWorkImpl unitOfWork, ClassDescriptor descriptor) {
//PERF: Breakdown the logic to have the most likely scenario checked first
ObjectChangeListener listener = (ObjectChangeListener)((ChangeTracker)object)._persistence_getPropertyChangeListener();
if ((listener != null) && listener.hasChanges()) {
return true;
}
Boolean optimisticRead = null;
if (unitOfWork.hasOptimisticReadLockObjects()) {
optimisticRead = (Boolean)unitOfWork.getOptimisticReadLockObjects().get(object);
// Need to always compare/build change set for new objects and those that are being forced to
// updated (opt. read lock and forceUpdate)
if (optimisticRead != null) {
return true;
}
}
if ((descriptor.getCMPPolicy() != null) && descriptor.getCMPPolicy().getForceUpdate()) {
return true;
}
return false;
}
/**
* INTERNAL:
* This may cause a property change event to be raised to a listner in the case that a listener exists.
* If there is no listener then this call is a no-op
*/
@Override
public void raiseInternalPropertyChangeEvent(Object source, String propertyName, Object oldValue, Object newValue) {
ObjectChangeListener listener = (ObjectChangeListener)((ChangeTracker)source)._persistence_getPropertyChangeListener();
if (listener != null) {
listener.internalPropertyChange(new PropertyChangeEvent(source, propertyName, oldValue, newValue));
}
}
/**
* 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 AggregateObjectChangeListener((ObjectChangeListener)((ChangeTracker)parent)._persistence_getPropertyChangeListener(), mappingAttribute));
}
/**
* INTERNAL:
* Assign ObjectChangeListener to PropertyChangeListener
*/
@Override
public PropertyChangeListener setChangeListener(Object clone, UnitOfWorkImpl uow, ClassDescriptor descriptor) {
ObjectChangeListener listener = new ObjectChangeListener();
((ChangeTracker)clone)._persistence_setPropertyChangeListener(listener);
return listener;
}
/**
* INTERNAL:
* Clear the changes in the ObjectChangeListener
*/
@Override
public void clearChanges(Object clone, UnitOfWorkImpl uow, ClassDescriptor descriptor, boolean forRefresh) {
ObjectChangeListener listener = (ObjectChangeListener)((ChangeTracker)clone)._persistence_getPropertyChangeListener();
if (listener != null) {
listener.clearChanges(forRefresh);
} else {
listener = (ObjectChangeListener)setChangeListener(clone, uow, descriptor);
}
ObjectBuilder builder = descriptor.getObjectBuilder();
// Only relationship mappings need to be reset.
if (!builder.isSimple()) {
dissableEventProcessing(clone);
// Must also ensure the listener has been set on collections and aggregates.
FetchGroupManager fetchGroupManager = descriptor.getFetchGroupManager();
boolean isPartialObject = (fetchGroupManager != null) && fetchGroupManager.isPartialObject(clone);
List mappings = builder.getRelationshipMappings();
int size = mappings.size();
// Only cascade fetched mappings.
for (int index = 0; index < size; index++) {
DatabaseMapping mapping = mappings.get(index);
if (!isPartialObject || fetchGroupManager.isAttributeFetched(clone, mapping.getAttributeName())) {
mapping.setChangeListener(clone, listener, uow);
}
}
enableEventProcessing(clone);
}
}
/**
* INTERNAL:
* initialize the Policy
*/
@Override
public void initialize(AbstractSession session, ClassDescriptor descriptor) {
//3934266 If changePolicy is ObjectChangeTrackingPolicy or AttributeChangeTrackingPolicy, the class represented
//by the descriptor must implement ChangeTracker interface. Otherwise throw an exception.
Class> javaClass = descriptor.getJavaClass();
if (!ChangeTracker.class.isAssignableFrom(javaClass)) {
session.getIntegrityChecker().handleError(DescriptorException.needToImplementChangeTracker(descriptor));
}
}
/**
* Used to track instances of the change policies without doing an instance of check
*/
@Override
public boolean isDeferredChangeDetectionPolicy(){
return false;
}
/**
* Used to track instances of the change policies without doing an instance of check
*/
@Override
public boolean isObjectChangeTrackingPolicy() {
return true;
}
}