org.eclipse.persistence.internal.indirection.UnitOfWorkQueryValueHolder 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, 2020 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.indirection;
import java.util.Collection;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.indirection.*;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
import org.eclipse.persistence.mappings.*;
/**
* UnitOfWorkQueryValueHolder wraps a database-stored object and
* implements behavior to access it. The object is read from
* the database by invoking a user-specified query.
* This value holder is used only in the unit of work.
*
* @author Sati
*/
public class UnitOfWorkQueryValueHolder extends UnitOfWorkValueHolder {
protected UnitOfWorkQueryValueHolder() {
super();
}
protected UnitOfWorkQueryValueHolder(ValueHolderInterface attributeValue, Object clone, DatabaseMapping mapping, UnitOfWorkImpl unitOfWork) {
super(attributeValue, clone, mapping, unitOfWork);
}
public UnitOfWorkQueryValueHolder(ValueHolderInterface attributeValue, Object clone, ForeignReferenceMapping mapping, AbstractRecord row, UnitOfWorkImpl unitOfWork) {
this(attributeValue, clone, mapping, unitOfWork);
this.row = row;
}
/**
* Backup the clone attribute value.
*/
@Override
protected Object buildBackupCloneFor(Object cloneAttributeValue) {
return this.mapping.buildBackupCloneForPartObject(cloneAttributeValue, null, null, getUnitOfWork());
}
/**
* Clone the original attribute value.
*/
@Override
public Object buildCloneFor(Object originalAttributeValue) {
Integer refreshCascade = null;
if (wrappedValueHolder instanceof QueryBasedValueHolder){
refreshCascade = ((QueryBasedValueHolder)getWrappedValueHolder()).getRefreshCascadePolicy();
}
Object clone = this.mapping.buildCloneForPartObject(originalAttributeValue, null, null, this.relationshipSourceObject, getUnitOfWork(), refreshCascade, true, true);
// Bug 414801
if (wrappedValueHolder.isInstantiated() && refreshCascade != null) {
((QueryBasedValueHolder)getWrappedValueHolder()).setRefreshCascadePolicy(null);
}
return clone;
}
/**
* Ensure that the backup value holder is populated.
*/
@Override
public void setValue(Object theValue) {
// Must force instantiation to be able to compare with the old value.
if (!this.isInstantiated) {
instantiate();
}
Object oldValue = getValue();
super.setValue(theValue);
updateForeignReferenceSet(theValue, oldValue);
}
/**
* INTERNAL:
* Here we now must check for bi-directional relationship.
* If the mapping has a relationship partner then we must maintain the original relationship.
* We only worry about ObjectReferenceMappings as the collections mappings will be handled by transparentIndirection
*/
public void updateForeignReferenceRemove(Object value) {
DatabaseMapping sourceMapping = this.getMapping();
if (sourceMapping == null) {
//mapping is a transient attribute. If it does not exist then we have been serialized
return;
}
if (sourceMapping.isPrivateOwned()) {
// don't null out backpointer on private owned relationship because it will cause an
// extra update.
return;
}
// ForeignReferenceMapping partner = (ForeignReferenceMapping)getMapping().getRelationshipPartner();
ForeignReferenceMapping partner = this.getRelationshipPartnerFor(value);
if (partner != null) {
if (value != null) {
Object unwrappedValue = partner.getDescriptor().getObjectBuilder().unwrapObject(value, getSession());
Object oldParent = partner.getRealAttributeValueFromObject(unwrappedValue, getSession());
Object sourceObject = getRelationshipSourceObject();
if (oldParent == null) {
// value has already been set
return;
}
// PERF: If the collection is not instantiated, then do not instantiated it.
if (partner.isCollectionMapping()) {
if ((!(oldParent instanceof IndirectContainer)) || ((IndirectContainer)oldParent).isInstantiated()) {
if (!partner.getContainerPolicy().contains(sourceObject, oldParent, getSession())) {
// value has already been set
return;
}
}
}
if (partner.isObjectReferenceMapping()) {
// Check if it's already been set to null
partner.setRealAttributeValueInObject(unwrappedValue, null);
} else if (partner.isCollectionMapping()) {
// If it is not in the collection then it has already been removed.
partner.getContainerPolicy().removeFrom(sourceObject, oldParent, getSession());
}
}
}
}
/**
* INTERNAL:
* Here we now must check for bi-directional relationship.
* If the mapping has a relationship partner then we must maintain the original relationship.
* We only worry about ObjectReferenceMappings as the collections mappings will be handled by transparentIndirection
*/
public void updateForeignReferenceSet(Object value, Object oldValue) {
if ((value != null) && (value instanceof Collection)) {
//I'm passing a collection into the valueholder not an object
return;
}
if (getMapping() == null) {
//mapping is a transient attribute. If it does not exist then we have been serialized
return;
}
// ForeignReferenceMapping partner = (ForeignReferenceMapping)getMapping().getRelationshipPartner();
ForeignReferenceMapping partner = this.getRelationshipPartnerFor(value);
if (partner != null) {
if (value != null) {
Object unwrappedValue = partner.getDescriptor().getObjectBuilder().unwrapObject(value, getSession());
Object oldParent = partner.getRealAttributeValueFromObject(unwrappedValue, getSession());
Object sourceObject = getRelationshipSourceObject();
Object wrappedSource = getMapping().getDescriptor().getObjectBuilder().wrapObject(sourceObject, getSession());
if (oldParent == sourceObject) {
// value has already been set
return;
}
// PERF: If the collection is not instantiated, then do not instantiated it.
if (partner.isCollectionMapping()) {
if ((!(oldParent instanceof IndirectContainer)) || ((IndirectContainer)oldParent).isInstantiated()) {
if (partner.getContainerPolicy().contains(sourceObject, oldParent, getSession())) {
// value has already been set
return;
}
}
}
// Set the Object that was referencing this value to reference null, or remove value from its collection
if (oldParent != null) {
if (getMapping().isObjectReferenceMapping()) {
if (!partner.isCollectionMapping()) {
// If the back pointer is a collection it's OK that I'm adding myself into the collection
getMapping().setRealAttributeValueInObject(oldParent, null);
}
} else if (getMapping().isCollectionMapping() && (!partner.isManyToManyMapping())) {
getMapping().getContainerPolicy().removeFrom(unwrappedValue, getMapping().getRealAttributeValueFromObject(oldParent, getSession()), getSession());
}
}
if (oldValue != null) {
// CR 3487
Object unwrappedOldValue = partner.getDescriptor().getObjectBuilder().unwrapObject(oldValue, getSession());
// if this object was referencing a different object reset the back pointer on that object
if (partner.isObjectReferenceMapping()) {
partner.setRealAttributeValueInObject(unwrappedOldValue, null);
} else if (partner.isCollectionMapping()) {
partner.getContainerPolicy().removeFrom(sourceObject, partner.getRealAttributeValueFromObject(unwrappedOldValue, getSession()), getSession());
}
}
// Now set the back reference of the value being passed in to point to this object
if (partner.isObjectReferenceMapping()) {
partner.setRealAttributeValueInObject(unwrappedValue, wrappedSource);
} else if (partner.isCollectionMapping()) {
partner.getContainerPolicy().addInto(wrappedSource, oldParent, getSession());
}
} else {
updateForeignReferenceRemove(oldValue);
}
}
}
/**
* Helper method to retrieve the relationship partner mapping. This will take inheritance
* into account and return the mapping associated with correct subclass if necessary. This
* is needed for EJB 2.0 inheritance
*/
private ForeignReferenceMapping getRelationshipPartnerFor(Object partnerObject) {
ForeignReferenceMapping partner = (ForeignReferenceMapping)getMapping().getRelationshipPartner();
if ((partner == null) || (partnerObject == null)) {
// no partner, nothing to do
return partner;
}
// if the target object is not an instance of the class type associated with the partner
// mapping, try and look up the same partner mapping but as part of the partnerObject's
// descriptor. Only check if inheritance is involved...
if (partner.getDescriptor().hasInheritance()) {
ClassDescriptor partnerObjectDescriptor = this.getSession().getDescriptor(partnerObject);
if (!(partner.getDescriptor().getJavaClass().isAssignableFrom(partnerObjectDescriptor.getJavaClass()))) {
return (ForeignReferenceMapping)partnerObjectDescriptor.getObjectBuilder().getMappingForAttributeName(partner.getAttributeName());
}
}
return partner;
}
}