/******************************************************************************* * 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.descriptor.xml; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import java.util.List; import org.eclipse.persistence.tools.workbench.mappingsmodel.MWDataField; import org.eclipse.persistence.tools.workbench.mappingsmodel.ProblemConstants; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.InterfaceDescriptorCreationException; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWMappingDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWHandle; import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWNamedSchemaComponentHandle; import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWHandle.NodeReferenceScrubber; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWMappingFactory; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.xml.MWCompositeCollectionMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.xml.MWCompositeObjectMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.xml.MWXmlMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.xml.MWXmlMappingFactory; import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClass; import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClassAttribute; import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClassRefreshPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.project.xml.MWXmlProject; import org.eclipse.persistence.tools.workbench.mappingsmodel.schema.MWComplexTypeDefinition; import org.eclipse.persistence.tools.workbench.mappingsmodel.schema.MWElementDeclaration; import org.eclipse.persistence.tools.workbench.mappingsmodel.schema.MWModelGroupDefinition; import org.eclipse.persistence.tools.workbench.mappingsmodel.schema.MWNamedSchemaComponent; import org.eclipse.persistence.tools.workbench.mappingsmodel.schema.MWSchemaContextComponent; import org.eclipse.persistence.tools.workbench.mappingsmodel.schema.MWSimpleTypeDefinition; import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.ExternalClassNotFoundException; 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.SchemaChange; import org.eclipse.persistence.tools.workbench.utility.node.Node; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.mappings.foundation.AbstractCompositeCollectionMapping; import org.eclipse.persistence.mappings.foundation.AbstractCompositeDirectCollectionMapping; import org.eclipse.persistence.mappings.foundation.AbstractCompositeObjectMapping; import org.eclipse.persistence.mappings.foundation.AbstractDirectMapping; import org.eclipse.persistence.mappings.foundation.AbstractTransformationMapping; import org.eclipse.persistence.oxm.NamespaceResolver; import org.eclipse.persistence.oxm.XMLDescriptor; import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping; import org.eclipse.persistence.oxm.schema.XMLSchemaReference; public abstract class MWXmlDescriptor extends MWMappingDescriptor implements MWXmlNode { private MWNamedSchemaComponentHandle schemaContextHandle; public final static String SCHEMA_CONTEXT_PROPERTY = "schemaContext"; //TODO this only applies to root MWOxDescriptors and MWRootEisDescriptors private MWNamedSchemaComponentHandle defaultRootElementHandle; public final static String DEFAULT_ROOT_ELEMENT_PROPERTY = "defaultRootElement"; // **************** Constructors ****************************************** /** Default constructor - for TopLink use only. */ protected MWXmlDescriptor() { super(); } public MWXmlDescriptor(MWXmlProject project, MWClass type, String name) { super(project, type, name); } // **************** Initialization **************************************** protected void initialize(Node parent) { super.initialize(parent); this.schemaContextHandle = new MWNamedSchemaComponentHandle(this, this.buildSchemaContextScrubber()); this.defaultRootElementHandle = new MWNamedSchemaComponentHandle(this, this.buildDefaultRootElementScrubber()); } protected void initializeFromMWXmlDescriptor(MWXmlDescriptor oldDescriptor) { super.initializeFromMWMappingDescriptor(oldDescriptor); this.setSchemaContext(oldDescriptor.getSchemaContext()); this.setDefaultRootElement(oldDescriptor.getDefaultRootElement()); } // **************** Schema context **************************************** public MWSchemaContextComponent getSchemaContext() { return (MWSchemaContextComponent) this.schemaContextHandle.getComponent(); } public void setSchemaContext(MWSchemaContextComponent newContext) { MWSchemaContextComponent oldContext = this.getSchemaContext(); this.schemaContextHandle.setComponent(newContext); this.firePropertyChanged(SCHEMA_CONTEXT_PROPERTY, oldContext, newContext); this.setInitialDefaultRootElement(); this.resolveXpaths(); } // **************** Default root element ********************************** public abstract boolean isRootDescriptor(); public abstract boolean isEisDescriptor(); public MWElementDeclaration getDefaultRootElement() { return (MWElementDeclaration) this.defaultRootElementHandle.getComponent(); } public void setDefaultRootElement(MWElementDeclaration newDefaultRootElement) { MWElementDeclaration oldDefaultRootElement = this.getDefaultRootElement(); this.defaultRootElementHandle.setComponent(newDefaultRootElement); this.firePropertyChanged(DEFAULT_ROOT_ELEMENT_PROPERTY, oldDefaultRootElement, newDefaultRootElement); } /** set to an initial value, if it exists */ protected void setInitialDefaultRootElement() { if (this.getSchemaContext() instanceof MWElementDeclaration) { this.setDefaultRootElement((MWElementDeclaration) this.getSchemaContext()); } } //************** Mapping Creation ***************************************** public abstract MWMappingFactory mappingFactory(); public MWCompositeObjectMapping addCompositeObjectMapping(MWClassAttribute attribute) { MWCompositeObjectMapping mapping = ((MWXmlMappingFactory) mappingFactory()).createCompositeObjectMapping(this, attribute, attribute.getName()); addMapping(mapping); return mapping; } public MWCompositeCollectionMapping addCompositeCollectionMapping(MWClassAttribute attribute) { MWCompositeCollectionMapping mapping = ((MWXmlMappingFactory) mappingFactory()).createCompositeCollectionMapping(this, attribute, attribute.getName()); addMapping(mapping); return mapping; } //***************** Model synchronization ********************************* protected void addChildrenTo(List children) { super.addChildrenTo(children); children.add(this.schemaContextHandle); children.add(this.defaultRootElementHandle); } private NodeReferenceScrubber buildSchemaContextScrubber() { return new NodeReferenceScrubber() { public void nodeReferenceRemoved(Node node, MWHandle handle) { MWXmlDescriptor.this.setSchemaContext(null); } public String toString() { return "MWXmlDescriptor.buildSchemaContextScrubber()"; } }; } private NodeReferenceScrubber buildDefaultRootElementScrubber() { return new NodeReferenceScrubber() { public void nodeReferenceRemoved(Node node, MWHandle handle) { MWXmlDescriptor.this.setDefaultRootElement(null); } public String toString() { return "MWXmlDescriptor.buildDefaultRootElementtScrubber()"; } }; } protected void refreshClass(MWClassRefreshPolicy refreshPolicy) throws ExternalClassNotFoundException, InterfaceDescriptorCreationException { super.refreshClass(refreshPolicy); if (this.getMWClass().isInterface()) { throw new InterfaceDescriptorCreationException(getMWClass()); } } /** @see MWXmlNode#resolveXpaths() */ public void resolveXpaths() { ((MWXmlNode) this.getInheritancePolicy()).resolveXpaths(); ((MWXmlNode) this.getLockingPolicy()).resolveXpaths(); for (Iterator stream = this.mappings(); stream.hasNext(); ) { ((MWXmlNode) stream.next()).resolveXpaths(); } } /** @see MWXmlNode#schemaChanged(SchemaChange) */ public void schemaChanged(SchemaChange change) { if (this.getSchemaContext() == null || this.getSchemaContext().getSchema() != change.getSchema()) { return; } // The following policies may have xpath information ... ((MWXmlNode) this.getInheritancePolicy()).schemaChanged(change); ((MWXmlNode) this.getLockingPolicy()).schemaChanged(change); // ... and mappings always do. for (Iterator stream = this.mappings(); stream.hasNext(); ) { ((MWXmlNode) stream.next()).schemaChanged(change); } } //***************** Problem Handling ************************************** /** Check for any problems and add them to the specified collection. */ protected void addProblemsTo(List newProblems) { super.addProblemsTo(newProblems); this.addSchemaContextNotSpecifiedProblemTo(newProblems); this.addDefaultRootElementNotSpecifiedProblemTo(newProblems); } private void addSchemaContextNotSpecifiedProblemTo(List newProblems) { if (this.schemaContextIsRequired() && this.getSchemaContext() == null) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_NO_SCHEMA_CONTEXT_SPECIFIED)); } } public Collection allWritableMappingsForField(MWDataField field) { // Answer all mappings that map to the xml field with an xpath that maps to this same element/attribute Collection mappingsForField = new ArrayList(); for (Iterator mappings = this.mappings(); mappings.hasNext(); ) { MWMapping mapping = (MWMapping) mappings.next(); if (! mapping.isReadOnly()) { Collection writtenFields = new ArrayList(); mapping.addWrittenFieldsTo(writtenFields); for (Iterator writtenFieldIter = writtenFields.iterator(); writtenFieldIter.hasNext(); ) { MWXmlField writtenField = (MWXmlField) writtenFieldIter.next(); if (writtenField.getXpath().equals(((MWXmlField)field).getXpath())) { mappingsForField.add(mapping); } } } } if (! writableMappingsForField(field).isEmpty() && ! getInheritancePolicy().isRoot() && getInheritancePolicy().getParentDescriptor() != null) { for (Iterator stream = getInheritancePolicy().getParentDescriptor().writableMappingsForField(field).iterator(); stream.hasNext(); ) { // do not add mappings that are overwritten in this descriptor MWMapping nextInheritedMapping = (MWMapping) stream.next(); MWMapping inheritedMappingInThisDescriptor = mappingNamed(nextInheritedMapping.getName()); if (inheritedMappingInThisDescriptor == null) { mappingsForField.add(nextInheritedMapping); } } } return mappingsForField; } public Collection writableMappingsForField( MWDataField field ) { // Answer all mappings that map to the xml field Collection mappingsForField = new ArrayList(); for (Iterator mappings = mappings(); mappings.hasNext(); ) { MWMapping mapping = (MWMapping) mappings.next(); Collection writtenFields = new ArrayList(); mapping.addWrittenFieldsTo(writtenFields); for (Iterator writtenFieldIter = writtenFields.iterator(); writtenFieldIter.hasNext(); ) { MWXmlField writtenField = (MWXmlField)writtenFieldIter.next(); if (writtenField.getXpath().equals(((MWXmlField)field).getXpath())) { mappingsForField.add(mapping); } } } return mappingsForField; } /** default behavior - overridden in MWOXDescriptor */ protected boolean schemaContextIsRequired() { return true; } private void addDefaultRootElementNotSpecifiedProblemTo(List newProblems) { if (this.isRootDescriptor()) { if (this.getDefaultRootElement() == null) { newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_NO_DEFAULT_ROOT_ELEMENT_SPECIFIED)); } } } protected String multipleMappingsWriteFieldProblemResourceStringKey() { return ProblemConstants.DESCRIPTOR_MULTIPLE_MAPPINGS_WRITE_TO_XPATH; } // **************** Runtime conversion ************************************ public ClassDescriptor buildRuntimeDescriptor() { ClassDescriptor runtimeDescriptor = super.buildRuntimeDescriptor(); this.adjustRuntimeDescriptorRootProperties(runtimeDescriptor); return runtimeDescriptor; } protected void adjustRuntimeDescriptorRootProperties(ClassDescriptor runtimeDescriptor) { if (! this.isRootDescriptor()) { runtimeDescriptor.descriptorIsAggregate(); } } protected Comparator orderedMappingComparator() { return new Comparator() { public int compare(Object o1, Object o2) { MWXmlField xmlField1 = ((MWXmlMapping) o1).firstMappedXmlField(); MWXmlField xmlField2 = ((MWXmlMapping) o2).firstMappedXmlField(); return MWXmlField.compareSchemaOrder(xmlField1, xmlField2); } }; } protected XMLSchemaReference runtimeSchemaReference() { MWSchemaContextComponent context = this.getSchemaContext(); if (context != null) { XMLSchemaReference runtimeSchemaRef = context.getSchema().runtimeSchemaReference(); String runtimeSchemaContext = ""; for (Iterator stream = context.namedComponentChain(); stream.hasNext(); ) { runtimeSchemaContext = "/" + ((MWNamedSchemaComponent) stream.next()).qName() + runtimeSchemaContext; } runtimeSchemaRef.setSchemaContext(runtimeSchemaContext); if (context instanceof MWComplexTypeDefinition) { runtimeSchemaRef.setType(XMLSchemaReference.COMPLEX_TYPE); } else if (context instanceof MWSimpleTypeDefinition) { runtimeSchemaRef.setType(XMLSchemaReference.SIMPLE_TYPE); } else if (context instanceof MWElementDeclaration) { runtimeSchemaRef.setType(XMLSchemaReference.ELEMENT); } else if (context instanceof MWModelGroupDefinition) { runtimeSchemaRef.setType(XMLSchemaReference.GROUP); } return runtimeSchemaRef; } else { return null; } } protected NamespaceResolver runtimeNamespaceResolver() { if (this.getSchemaContext() != null) { return this.getSchemaContext().getSchema().runtimeNamespaceResolver(); } else { return null; } } public abstract AbstractDirectMapping buildDefaultRuntimeDirectMapping(); public abstract AbstractCompositeDirectCollectionMapping buildDefaultRuntimeDirectCollectionMapping(); public abstract AbstractCompositeObjectMapping buildDefaultRuntimeCompositeObjectMapping(); public abstract AbstractCompositeCollectionMapping buildDefaultRuntimeCompositeCollectionMapping(); public abstract AbstractTransformationMapping buildDefaultRuntimeTransformationMapping(); // **************** TopLink methods *************************************** public static XMLDescriptor buildDescriptor() { XMLDescriptor descriptor = new XMLDescriptor(); descriptor.setJavaClass(MWXmlDescriptor.class); descriptor.getInheritancePolicy().setParentClass(MWMappingDescriptor.class); XMLCompositeObjectMapping schemaContextHandleMapping = new XMLCompositeObjectMapping(); schemaContextHandleMapping.setAttributeName("schemaContextHandle"); schemaContextHandleMapping.setGetMethodName("getSchemaContextHandleForTopLink"); schemaContextHandleMapping.setSetMethodName("setSchemaContextHandleForTopLink"); schemaContextHandleMapping.setReferenceClass(MWNamedSchemaComponentHandle.class); schemaContextHandleMapping.setXPath("schema-context-handle"); descriptor.addMapping(schemaContextHandleMapping); XMLCompositeObjectMapping defaultRootElementHandleMapping = new XMLCompositeObjectMapping(); defaultRootElementHandleMapping.setAttributeName("defaultRootElementHandle"); defaultRootElementHandleMapping.setGetMethodName("getDefaultRootElementHandleForTopLink"); defaultRootElementHandleMapping.setSetMethodName("setDefaultRootElementHandleForTopLink"); defaultRootElementHandleMapping.setReferenceClass(MWNamedSchemaComponentHandle.class); defaultRootElementHandleMapping.setXPath("default-root-element-handle"); descriptor.addMapping(defaultRootElementHandleMapping); return descriptor; } /** * check for null */ private MWNamedSchemaComponentHandle getSchemaContextHandleForTopLink() { return (this.schemaContextHandle.getComponent() == null) ? null : this.schemaContextHandle; } private void setSchemaContextHandleForTopLink(MWNamedSchemaComponentHandle handle) { NodeReferenceScrubber scrubber = this.buildSchemaContextScrubber(); this.schemaContextHandle = ((handle == null) ? new MWNamedSchemaComponentHandle(this, scrubber) : handle.setScrubber(scrubber)); } /** * check for null */ private MWNamedSchemaComponentHandle getDefaultRootElementHandleForTopLink() { return (this.defaultRootElementHandle.getComponent() == null) ? null : this.defaultRootElementHandle; } private void setDefaultRootElementHandleForTopLink(MWNamedSchemaComponentHandle handle) { NodeReferenceScrubber scrubber = this.buildDefaultRootElementScrubber(); this.defaultRootElementHandle = ((handle == null) ? new MWNamedSchemaComponentHandle(this, scrubber) : handle.setScrubber(scrubber)); } public abstract MWXmlPrimaryKeyPolicy primaryKeyPolicy(); }