/*******************************************************************************
* 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;
}
}