blob: b0c95845b05fdac1059c4a718ac6e2fbfa80afb9 [file] [log] [blame]
/*
* 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:
// rbarkhouse - 2009-11-26 13:04:58 - 2.0 - initial implementation
package org.eclipse.persistence.oxm.mappings;
import java.util.Collection;
import java.util.Map;
import java.util.Vector;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.exceptions.DescriptorException;
import org.eclipse.persistence.internal.descriptors.DescriptorIterator;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.identitymaps.CacheKey;
import org.eclipse.persistence.internal.oxm.mappings.InverseReferenceMapping;
import org.eclipse.persistence.internal.oxm.record.XMLRecord;
import org.eclipse.persistence.internal.queries.CollectionContainerPolicy;
import org.eclipse.persistence.internal.queries.ContainerPolicy;
import org.eclipse.persistence.internal.queries.JoinedAttributeManager;
import org.eclipse.persistence.internal.queries.ListContainerPolicy;
import org.eclipse.persistence.internal.queries.MapContainerPolicy;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.ChangeRecord;
import org.eclipse.persistence.internal.sessions.MergeManager;
import org.eclipse.persistence.internal.sessions.ObjectChangeSet;
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
import org.eclipse.persistence.mappings.AggregateMapping;
import org.eclipse.persistence.mappings.AttributeAccessor;
import org.eclipse.persistence.mappings.ContainerMapping;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.queries.ObjectBuildingQuery;
import org.eclipse.persistence.queries.ObjectLevelReadQuery;
import org.eclipse.persistence.sessions.remote.DistributedSession;
/**
* This mapping is used to map a back-pointer. It represents the "opposite" of one of the
* following relationship mappings:<br><br>
*
* <ul>
* <li>XMLCompositeObjectMapping
* <li>XMLCompositeCollectionMapping
* <li>XMLObjectReferenceMapping
* <li>XMLCollectionReferenceMapping
* </ul>
*
* When configuring an XMLInverseReferenceMapping, the "mappedBy" field must be set to the
* field on the reference class that maps to this Descriptor. For example:<br><br>
*
* <code>
* // EMPLOYEE has a collection of PHONEs (phoneNumbers)<br>
* // PHONE has a back-pointer to EMPLOYEE (owningEmployee)<br><br>
*
* // EMPLOYEE Descriptor<br>
* XMLCompositeCollectionMapping phone = new XMLCompositeCollectionMapping();<br>
* phone.setReferenceClassName("org.example.PhoneNumber");<br>
* phone.setAttributeName("phoneNumbers");<br>
* ...<br><br>
*
* // PHONE Descriptor<br>
* XMLInverseReferenceMapping owningEmployee = new XMLInverseReferenceMapping();<br>
* owningEmployee.setReferenceClassName("org.example.Employee");<br>
* owningEmployee.setMappedBy("phoneNumbers");<br>
* owningEmployee.setAttributeName("owningEmployee");<br>
* ...<br>
* </code>
*/
public class XMLInverseReferenceMapping extends AggregateMapping implements InverseReferenceMapping<AbstractSession, AttributeAccessor, ContainerPolicy, ClassDescriptor, DatabaseField, DatabaseMapping, XMLRecord>, ContainerMapping {
private String mappedBy;
private ContainerPolicy containerPolicy;
private DatabaseMapping inlineMapping;
@Override
public boolean isXMLMapping() {
return true;
}
@Override
public void initialize(AbstractSession session) throws DescriptorException {
super.initialize(session);
setFields(new Vector<>());
if(inlineMapping != null){
inlineMapping.initialize(session);
}
}
@Override
public void preInitialize(AbstractSession session){
super.preInitialize(session);
if(inlineMapping != null){
inlineMapping.setDescriptor(this.descriptor);
inlineMapping.preInitialize(session);
}
}
@Override
public void postInitialize(AbstractSession session) throws DescriptorException {
// Get the corresponding mapping from the reference descriptor and set up the
// inverse mapping.
DatabaseMapping mapping = getReferenceDescriptor().getMappingForAttributeName(this.mappedBy);
if (mapping instanceof XMLInverseReferenceMapping) {
mapping = ((XMLInverseReferenceMapping)mapping).getInlineMapping();
}
if (mapping instanceof XMLCompositeCollectionMapping) {
XMLCompositeCollectionMapping oppositeMapping = (XMLCompositeCollectionMapping) mapping;
oppositeMapping.setInverseReferenceMapping(this);
}
if (mapping instanceof XMLCompositeObjectMapping) {
XMLCompositeObjectMapping oppositeMapping = (XMLCompositeObjectMapping) mapping;
oppositeMapping.setInverseReferenceMapping(this);
}
if (mapping instanceof XMLObjectReferenceMapping) {
XMLObjectReferenceMapping oppositeMapping = (XMLObjectReferenceMapping) mapping;
oppositeMapping.setInverseReferenceMapping(this);
}
if (mapping instanceof XMLChoiceObjectMapping) {
XMLChoiceObjectMapping oppositeMapping = (XMLChoiceObjectMapping) mapping;
Collection<XMLMapping> nestedMappings = oppositeMapping.getChoiceElementMappings().values();
for(XMLMapping next:nestedMappings) {
if(next instanceof XMLCompositeObjectMapping) {
XMLCompositeObjectMapping compositeMapping = ((XMLCompositeObjectMapping)next);
if(compositeMapping.getReferenceClass() == this.getDescriptor().getJavaClass() || this.getDescriptor().getJavaClass().isAssignableFrom(compositeMapping.getReferenceClass())) {
compositeMapping.setInverseReferenceMapping(this);
}
} else if(next instanceof XMLObjectReferenceMapping) {
XMLObjectReferenceMapping refMapping = ((XMLObjectReferenceMapping)next);
if(refMapping.getReferenceClass() == this.getDescriptor().getJavaClass()) {
refMapping.setInverseReferenceMapping(this);
}
}
}
}
if (mapping instanceof XMLChoiceCollectionMapping) {
XMLChoiceCollectionMapping oppositeMapping = (XMLChoiceCollectionMapping) mapping;
Collection<XMLMapping> nestedMappings = oppositeMapping.getChoiceElementMappings().values();
for(XMLMapping next:nestedMappings) {
if(next instanceof XMLCompositeCollectionMapping) {
XMLCompositeCollectionMapping compositeMapping = ((XMLCompositeCollectionMapping)next);
if(compositeMapping.getReferenceClass() == this.getDescriptor().getJavaClass() || this.getDescriptor().getJavaClass().isAssignableFrom(compositeMapping.getReferenceClass())) {
compositeMapping.setInverseReferenceMapping(this);
}
} else if(next instanceof XMLCollectionReferenceMapping) {
XMLCollectionReferenceMapping refMapping = ((XMLCollectionReferenceMapping)next);
if(refMapping.getReferenceClass() == this.getDescriptor().getJavaClass()) {
refMapping.setInverseReferenceMapping(this);
}
}
}
}
if(inlineMapping != null){
inlineMapping.postInitialize(session);
}
}
public String getMappedBy() {
return mappedBy;
}
@Override
public void setMappedBy(String mappedBy) {
this.mappedBy = mappedBy;
}
// == AggregateMapping methods ============================================
@Override
public void buildBackupClone(Object clone, Object backup, UnitOfWorkImpl unitOfWork) {
}
@Override
public void buildClone(Object original, CacheKey cacheKey, Object clone, Integer refreshCascade, AbstractSession cloningSession) {
}
@Override
public void buildCloneFromRow(AbstractRecord databaseRow,
JoinedAttributeManager joinManager, Object clone, CacheKey sharedCacheKey,
ObjectBuildingQuery sourceQuery, UnitOfWorkImpl unitOfWork,
AbstractSession executionSession) {
}
@Override
public void cascadePerformRemoveIfRequired(Object object,
UnitOfWorkImpl uow, Map visitedObjects) {
}
@Override
public void cascadeRegisterNewIfRequired(Object object, UnitOfWorkImpl uow,
Map visitedObjects) {
}
@Override
public ChangeRecord compareForChange(Object clone, Object backup,
ObjectChangeSet owner, AbstractSession session) {
return null;
}
@Override
public boolean compareObjects(Object firstObject, Object secondObject,
AbstractSession session) {
return false;
}
@Override
public void fixObjectReferences(Object object, Map objectDescriptors,
Map processedObjects, ObjectLevelReadQuery query,
DistributedSession session) {
}
@Override
public void iterate(DescriptorIterator iterator) {
}
@Override
public void mergeChangesIntoObject(Object target,
ChangeRecord changeRecord, Object source, MergeManager mergeManager, AbstractSession targetSession) {
}
@Override
public void mergeIntoObject(Object target, boolean isTargetUninitialized,
Object source, MergeManager mergeManager, AbstractSession targetSession) {
}
// == ContainerPolicy methods =============================================
@Override
public void setContainerPolicy(ContainerPolicy containerPolicy) {
this.containerPolicy = containerPolicy;
}
@Override
public ContainerPolicy getContainerPolicy() {
return this.containerPolicy;
}
@Override
public void useCollectionClass(Class concreteClass) {
this.containerPolicy = new CollectionContainerPolicy(concreteClass);
}
@Override
public void useCollectionClassName(String concreteClass) {
this.containerPolicy = new CollectionContainerPolicy(concreteClass);
}
@Override
public void useListClassName(String concreteClass) {
this.containerPolicy = new ListContainerPolicy(concreteClass);
}
@Override
public void useMapClass(Class concreteClass, String methodName) {
this.containerPolicy = new MapContainerPolicy(concreteClass);
}
@Override
public void useMapClassName(String concreteClass, String methodName) {
this.containerPolicy = new MapContainerPolicy(concreteClass);
}
@Override
public DatabaseMapping getInlineMapping() {
return inlineMapping;
}
@Override
public void setInlineMapping(DatabaseMapping inlineMapping) {
this.inlineMapping = inlineMapping;
}
@Override
public void writeSingleValue(Object value, Object object, XMLRecord record, AbstractSession session) {
}
}