/******************************************************************************* * 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.Collection; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Vector; import org.eclipse.persistence.tools.workbench.mappingsmodel.MWDataField; import org.eclipse.persistence.tools.workbench.mappingsmodel.ProblemConstants; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.xml.MWOXDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.xml.MWXmlDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWDescriptorHandle; import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWHandle; import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWHandle.NodeReferenceScrubber; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWAbstractReferenceMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWReferenceMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClassAttribute; import org.eclipse.persistence.tools.workbench.mappingsmodel.schema.MWSchemaContextComponent; import org.eclipse.persistence.tools.workbench.mappingsmodel.xml.MWXmlField; import org.eclipse.persistence.tools.workbench.mappingsmodel.xml.MWXmlNode; import org.eclipse.persistence.tools.workbench.mappingsmodel.xml.MWXpathContext; import org.eclipse.persistence.tools.workbench.mappingsmodel.xml.MWXpathSpec; import org.eclipse.persistence.tools.workbench.mappingsmodel.xml.SchemaChange; import org.eclipse.persistence.tools.workbench.utility.CollectionTools; import org.eclipse.persistence.tools.workbench.utility.iterators.CloneListIterator; import org.eclipse.persistence.tools.workbench.utility.node.Node; import org.eclipse.persistence.mappings.AggregateMapping; import org.eclipse.persistence.mappings.DatabaseMapping; import org.eclipse.persistence.mappings.ForeignReferenceMapping; import org.eclipse.persistence.oxm.XMLDescriptor; import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping; import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping; import org.eclipse.persistence.oxm.mappings.XMLObjectReferenceMapping; public abstract class MWAbstractXmlReferenceMapping extends MWAbstractReferenceMapping implements MWXpathContext, MWXmlReferenceMapping { private List<MWXmlFieldPair> xmlFieldPairs; // **************** Constructors ****************************************** /** * Default constructor, TopLink use only. */ protected MWAbstractXmlReferenceMapping() { super(); } MWAbstractXmlReferenceMapping(MWXmlDescriptor parent, MWClassAttribute attribute, String name) { super(parent, attribute, name); } // **************** Initialization **************************************** @Override protected void initialize() { super.initialize(); this.xmlFieldPairs = new Vector<MWXmlFieldPair>(); } @Override public void initializeFromMWXmlObjectReferenceMapping(MWXmlObjectReferenceMapping oldMapping) { super.initializeFromMWXmlObjectReferenceMapping(oldMapping); this.setReferenceDescriptor(oldMapping.getReferenceDescriptor()); } @Override public void initializeFromMWXmlCollectionReferenceMapping(MWXmlCollectionReferenceMapping oldMapping) { super.initializeFromMWXmlCollectionReferenceMapping(oldMapping); this.setReferenceDescriptor(oldMapping.getReferenceDescriptor()); } //********* model synchronization support ********* @Override protected void addChildrenTo(List children) { super.addChildrenTo(children); synchronized (this.xmlFieldPairs) { children.addAll(this.xmlFieldPairs); } } // **************** Model synchronization ********************************* /** @see MWXmlNode#resolveXpaths */ public void resolveXpaths() { for (Iterator stream = this.xmlFieldPairs(); stream.hasNext(); ) { ((MWXmlNode) stream.next()).resolveXpaths(); } } /** @see MWXmlNode#schemaChanged(SchemaChange) */ public void schemaChanged(SchemaChange change) { for (Iterator stream = this.xmlFieldPairs(); stream.hasNext(); ) { ((MWXmlNode) stream.next()).schemaChanged(change); } } // **************** TopLink methods *************************************** @SuppressWarnings("deprecation") public static XMLDescriptor buildDescriptor() { XMLDescriptor descriptor = new XMLDescriptor(); descriptor.setJavaClass(MWAbstractXmlReferenceMapping.class); descriptor.getInheritancePolicy().setParentClass(MWAbstractReferenceMapping.class); XMLCompositeCollectionMapping xpathFieldPairsListMapping = new XMLCompositeCollectionMapping(); xpathFieldPairsListMapping.setAttributeName("xmlFieldPairs"); xpathFieldPairsListMapping.setReferenceClass(MWXmlFieldPair.class); xpathFieldPairsListMapping.setXPath("xml-field-pairs/field-pair"); descriptor.addMapping(xpathFieldPairsListMapping); return descriptor; } // **************** MWXmlMapping contract ********************************* public MWSchemaContextComponent schemaContext() { return this.xmlDescriptor().getSchemaContext(); } public MWXmlField firstMappedXmlField() { MWXmlFieldPair firstFieldPair = xmlFieldPairAt(0); if (firstFieldPair != null && firstFieldPair.getSourceXmlField() != null && firstFieldPair.getSourceXmlField().isResolved()) { return firstFieldPair.getSourceXmlField(); } else { return null; } } @Override public void addWrittenFieldsTo(Collection writtenXpaths) { if (!this.isReadOnly()) { Iterator<MWXmlFieldPair> fielPairIter = xmlFieldPairs(); while (fielPairIter.hasNext()) { MWXmlField field = fielPairIter.next().getTargetXmlField(); if (!field.getXpath().equals("")) { writtenXpaths.add(field); } } } } // **************** MWXpathContext implementation ************************ public MWSchemaContextComponent schemaContext(MWXmlField xmlField) { return this.xmlDescriptor().getSchemaContext(); } public MWXpathSpec xpathSpec(MWXmlField xmlField) { return this.buildXpathSpec(); } protected MWXpathSpec buildXpathSpec() { return new MWXpathSpec() { public boolean mayUseCollectionData() { return false; } public boolean mayUseComplexData() { return false; } public boolean mayUseSimpleData() { return true; } }; } // **************** MWReferenceMapping contract *************************** public boolean descriptorIsValidReferenceDescriptor(MWDescriptor descriptor) { return true; } // **************** MWAbstractReferenceMapping contract ******************* @Override protected String referenceDescriptorInvalidProblemString() { return ProblemConstants.MAPPING_REFERENCE_DESCRIPTOR_NOT_ROOT; } public MWXmlDescriptor referenceDescriptor() { return (MWXmlDescriptor)getReferenceDescriptor(); } // **************** Convenience ******************************************* protected MWXmlDescriptor xmlDescriptor() { return (MWXmlDescriptor) this.getParent(); } // **************** Xml field pairs *************************************** public int xmlFieldPairsSize() { return this.xmlFieldPairs.size(); } public ListIterator<MWXmlFieldPair> xmlFieldPairs() { return new CloneListIterator(this.xmlFieldPairs); } public MWXmlFieldPair xmlFieldPairAt(int index) { if (index < this.xmlFieldPairsSize()) { return this.xmlFieldPairs.get(index); } return null; } public MWXmlFieldPair addFieldPair(String sourceXpath, String targetXpath) { MWXmlFieldPair xmlFieldPair = new MWXmlFieldPair(this, sourceXpath, targetXpath); this.addFieldPair(xmlFieldPair); return xmlFieldPair; } public void addFieldPair(MWXmlFieldPair xmlFieldPair) { this.addItemToList(this.xmlFieldPairsSize(), xmlFieldPair, this.xmlFieldPairs, XML_FIELD_PAIRS_LIST); } /** Builds an empty field pair, but does not add it */ public MWXmlFieldPair buildEmptyFieldPair() { return new MWXmlFieldPair(this); } public void removeXmlFieldPair(MWXmlFieldPair xmlFieldPair) { this.removeNodeFromList(this.xmlFieldPairs.indexOf(xmlFieldPair), this.xmlFieldPairs, XML_FIELD_PAIRS_LIST); } public void clearXmlFieldPairs() { this.clearList(this.xmlFieldPairs, XML_FIELD_PAIRS_LIST); } public boolean sourceFieldMayUseCollectionXpath() { return false; } @Override public DatabaseMapping runtimeMapping() { XMLObjectReferenceMapping runtimeMapping = (XMLObjectReferenceMapping) this.buildRuntimeMapping(); runtimeMapping.setAttributeName(this.getInstanceVariable().getName()); if (this.usesMethodAccessing()) { if (getGetMethod() != null) { runtimeMapping.setGetMethodName(this.getGetMethod().getName()); } if (getSetMethod() != null) { runtimeMapping.setSetMethodName(this.getSetMethod().getName()); } } runtimeMapping.setIsReadOnly(this.isReadOnly()); if (getReferenceDescriptor() != null) { runtimeMapping.setReferenceClassName(getReferenceDescriptor().getMWClass().getName()); } Iterator<MWXmlFieldPair> fieldpairsIter = this.xmlFieldPairs(); while (fieldpairsIter.hasNext()) { MWXmlFieldPair pair = fieldpairsIter.next(); runtimeMapping.addSourceToTargetKeyFieldAssociation(pair.getSourceXmlField().getXpath(), pair.getTargetXmlField().getXpath()); } return runtimeMapping; } //********************** Validation *************************************** @Override protected void addProblemsTo(List newProblems) { super.addProblemsTo(newProblems); checkXmlFieldPairsNotZero(newProblems); checkTargetPrimaryKey(newProblems); } protected void checkXmlFieldPairsNotZero(List newProblems) { if (this.xmlFieldPairsSize() <= 0) { newProblems.add(this.buildProblem(ProblemConstants.MAPPING_NO_XML_FIELD_PAIRS_SPECIFIED)); } } @Override protected void checkReferenceDescriptorCachIsolation(List newProblems) { // doesn't apply to OX projects } @Override protected void checkReferenceDescriptor(List newProblems) { MWDescriptor refDescriptor = this.getReferenceDescriptor(); if (refDescriptor == null) { newProblems.add(this.buildProblem(ProblemConstants.MAPPING_REFERENCE_DESCRIPTOR_NOT_SPECIFIED)); } else { if ( ! refDescriptor.isActive()) { newProblems.add(this.buildProblem(ProblemConstants.MAPPING_REFERENCE_DESCRIPTOR_IS_INACTIVE, this.getInstanceVariable().getName(), this.getReferenceDescriptor().getMWClass().shortName())); } this.checkReferenceDescriptorCachIsolation(newProblems); } } protected void checkTargetPrimaryKey(List newProblems) { Iterator<MWXmlFieldPair> fieldPairs = xmlFieldPairs(); while(fieldPairs.hasNext()) { MWXmlFieldPair pair = fieldPairs.next(); MWXmlField targetField = pair.getTargetXmlField(); MWOXDescriptor refDesc = (MWOXDescriptor)getReferenceDescriptor(); Collection pkFieldNames = new Vector(refDesc.primaryKeyPolicy().primaryKeysSize()); Iterator pkFieldIter = refDesc.primaryKeyPolicy().primaryKeys(); while (pkFieldIter.hasNext()) { pkFieldNames.add(((MWXmlField)pkFieldIter.next()).fieldName()); } if (pkFieldNames.contains(targetField.fieldName())) { continue; } else { newProblems.add(this.buildProblem(ProblemConstants.MAPPING_TARGET_NOT_PRIMARY_KEY_ON_REFERENCE_DESCRIPTOR, targetField.fieldName())); } } } }