/******************************************************************************* * Copyright (c) 1998, 2015 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 v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * 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); } } 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; } 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 ============================================= public void setContainerPolicy(ContainerPolicy containerPolicy) { this.containerPolicy = containerPolicy; } public ContainerPolicy getContainerPolicy() { return this.containerPolicy; } public void useCollectionClass(Class concreteClass) { this.containerPolicy = new CollectionContainerPolicy(concreteClass); } public void useCollectionClassName(String concreteClass) { this.containerPolicy = new CollectionContainerPolicy(concreteClass); } public void useListClassName(String concreteClass) { this.containerPolicy = new ListContainerPolicy(concreteClass); } public void useMapClass(Class concreteClass, String methodName) { this.containerPolicy = new MapContainerPolicy(concreteClass); } public void useMapClassName(String concreteClass, String methodName) { this.containerPolicy = new MapContainerPolicy(concreteClass); } public DatabaseMapping getInlineMapping() { return inlineMapping; } public void setInlineMapping(DatabaseMapping inlineMapping) { this.inlineMapping = inlineMapping; } @Override public void writeSingleValue(Object value, Object object, XMLRecord record, AbstractSession session) { } }