| /* |
| * 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: |
| // 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<DatabaseField> ()); |
| 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) { |
| } |
| |
| } |