/******************************************************************************* * 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: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.xml; import java.util.Iterator; import java.util.List; import org.eclipse.persistence.tools.workbench.mappingsmodel.ProblemConstants; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.xml.MWEisDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWProxyIndirectionMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClassAttribute; import org.eclipse.persistence.tools.workbench.mappingsmodel.query.xml.MWEisInteraction; import org.eclipse.persistence.tools.workbench.mappingsmodel.query.xml.MWEisQueryManager; import org.eclipse.persistence.tools.workbench.mappingsmodel.query.xml.MWEisInteraction.ArgumentPair; import org.eclipse.persistence.tools.workbench.mappingsmodel.xml.MWXmlField; import org.eclipse.persistence.tools.workbench.utility.node.Node; import org.eclipse.persistence.eis.mappings.EISOneToOneMapping; import org.eclipse.persistence.internal.indirection.ProxyIndirectionPolicy; import org.eclipse.persistence.mappings.DatabaseMapping; import org.eclipse.persistence.oxm.XMLDescriptor; import org.eclipse.persistence.oxm.mappings.XMLDirectMapping; public final class MWEisOneToOneMapping extends MWEisReferenceMapping implements MWProxyIndirectionMapping { // **************** Variables ********************************************* private volatile boolean useDescriptorReadObjectInteraction; public final static String USE_DESCRIPTOR_READ_OBJECT_INTERACTION_PROPERTY = "useDescriptorReadObjectInteraction"; // **************** Constructors *************** /** Default constructor - for TopLink use only */ private MWEisOneToOneMapping() { super(); } public MWEisOneToOneMapping(MWEisDescriptor parent, MWClassAttribute attribute, String name) { super(parent, attribute, name); } // **************** Initialization **************************************** /** initialize persistent state */ protected void initialize(Node parent) { super.initialize(parent); this.useDescriptorReadObjectInteraction = true; } protected void initialize(MWClassAttribute attribute, String name) { super.initialize(attribute, name); if (!getInstanceVariable().isValueHolder() && getInstanceVariable().getType().isInterface()) { this.indirectionType = PROXY_INDIRECTION; } } /** * 1:1 mappings don't have a selection interaction when they * use the descriptor read object interaction */ protected boolean requiresSelectionInteraction() { return false; } // **************** Selection interaction ********************************* public boolean usesDescriptorReadObjectInteraction() { return this.useDescriptorReadObjectInteraction; } public void setUseDescriptorReadObjectInteraction(boolean useDescriptorReadObjectInteraction) { boolean old = this.useDescriptorReadObjectInteraction; this.useDescriptorReadObjectInteraction = useDescriptorReadObjectInteraction; if (old != useDescriptorReadObjectInteraction) { this.firePropertyChanged(USE_DESCRIPTOR_READ_OBJECT_INTERACTION_PROPERTY, old, useDescriptorReadObjectInteraction); // clear the selection interaction if the new value is true this.setSelectionInteraction(useDescriptorReadObjectInteraction ? null : new MWEisInteraction(this)); } } // **************** Convenience ******************************************* private MWEisInteraction referenceDescriptorReadInteraction() { return (this.referenceRootEisDescriptor() == null) ? null : ((MWEisQueryManager) this.referenceRootEisDescriptor().getQueryManager()).getReadObjectInteraction(); } // **************** MWXpathContext contract (for field pairs) ************* /** * Return true if a source field may use a collection xpath * @see MWEisReferenceMapping#sourceFieldMayUseCollectionXpath() */ public boolean sourceFieldMayUseCollectionXpath() { return false; } // *********** MWProxyIndirectionMapping implementation *********** public boolean usesProxyIndirection() { return getIndirectionType() == PROXY_INDIRECTION; } public void setUseProxyIndirection() { setIndirectionType(PROXY_INDIRECTION); } // **************** Morphing ********************************************** protected void initializeOn(MWMapping newMapping) { newMapping.initializeFromMWEisOneToOneMapping(this); } // ************** Problem handling **************************************** protected void addProblemsTo(List newProblems) { super.addProblemsTo(newProblems); this.checkFieldPairs(newProblems); this.checkReferenceDescriptorReadInteraction(newProblems); this.checkFieldPairsAndReadInteractionArguments(newProblems); this.addUsesIndirectionWhileMaintainsBiDirectionalRelationship(newProblems); } private void checkFieldPairs(List newProblems) { // the mapping must have field pairs unless // 1) there is a selection interaction specified -AND- // 2) the mapping is read only if ((this.isReadOnly() && this.getSelectionInteraction() == null) || this.xmlFieldPairsSize() == 0) { newProblems.add(this.buildProblem(ProblemConstants.MAPPING_1_TO_1_FIELD_PAIRS_NOT_SPECIFIED)); } } private void checkReferenceDescriptorReadInteraction(List newProblems) { // if the mapping does not specify a selection interaction, the reference descriptor must // have a read object interaction specified if ( this.usesDescriptorReadObjectInteraction() && this.referenceRootEisDescriptor() != null && this.referenceDescriptorReadInteraction().getFunctionName() == null ) { newProblems.add(this.buildProblem(ProblemConstants.MAPPING_REFERENCE_DESCRIPTOR_READ_INTERACTION_NOT_SPECIFIED)); } } private void checkFieldPairsAndReadInteractionArguments(List newProblems) { // if the selection interaction is not specified, each argument in the // reference descriptor's read interaction must correspond to a target key // in the field pairs. if (! this.usesDescriptorReadObjectInteraction() || this.referenceDescriptorReadInteraction() == null) { return; } for (Iterator stream = this.referenceDescriptorReadInteraction().inputArguments(); stream.hasNext(); ) { String argumentFieldName = ((ArgumentPair) stream.next()).getArgumentFieldName(); if (! this.hasCorrespondingTargetKey(argumentFieldName)) { newProblems.add(this.buildProblem(ProblemConstants.MAPPING_NONCORRESPONDING_TARGET_KEY, argumentFieldName)); } } } private void addUsesIndirectionWhileMaintainsBiDirectionalRelationship(List newProblems) { if (this.maintainsBidirectionalRelationship() && this.usesNoIndirection()) { newProblems.add(this.buildProblem(ProblemConstants.MAPPING_REFERENCE_MAINTAINS_BIDI_BUT_NO_INDIRECTION)); } } private boolean hasCorrespondingTargetKey(String argumentFieldName) { for (Iterator stream = this.xmlFieldPairs(); stream.hasNext(); ) { MWXmlField targetField = ((MWXmlFieldPair) stream.next()).getTargetXmlField(); if (targetField != null && targetField.getXpath().equals(argumentFieldName)) { return true; } } return false; } // **************** Runtime Conversion *************** protected DatabaseMapping buildRuntimeMapping() { return new EISOneToOneMapping(); } public DatabaseMapping runtimeMapping() { EISOneToOneMapping mapping = (EISOneToOneMapping) super.runtimeMapping(); for (Iterator stream = this.xmlFieldPairs(); stream.hasNext(); ) { ((MWXmlFieldPair) stream.next()).addRuntimeForeignKeyField(mapping); } if (usesProxyIndirection()) { mapping.setIndirectionPolicy(new ProxyIndirectionPolicy()); } return mapping; } // **************** TopLink methods *************************************** public static XMLDescriptor buildDescriptor() { XMLDescriptor descriptor = new XMLDescriptor(); descriptor.setJavaClass(MWEisOneToOneMapping.class); descriptor.getInheritancePolicy().setParentClass(MWEisReferenceMapping.class); XMLDirectMapping useDescriptorReadObjectInteractionMapping = (XMLDirectMapping) descriptor.addDirectMapping("useDescriptorReadObjectInteraction", "use-descriptor-read-object-interaction/text()"); useDescriptorReadObjectInteractionMapping.setNullValue(Boolean.FALSE); return descriptor; } }