/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.transformation.aspects.sql;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xsd.XSDAttributeDeclaration;
import org.eclipse.xsd.XSDComplexTypeDefinition;
import org.eclipse.xsd.XSDComponent;
import org.eclipse.xsd.XSDElementDeclaration;
import org.eclipse.xsd.XSDFeature;
import org.eclipse.xsd.XSDForm;
import org.eclipse.xsd.XSDInclude;
import org.eclipse.xsd.XSDSchema;
import org.eclipse.xsd.XSDSimpleTypeDefinition;
import org.eclipse.xsd.XSDTypeDefinition;
import org.eclipse.xsd.XSDWhiteSpace;
import org.eclipse.xsd.XSDWhiteSpaceFacet;
import org.eclipse.xsd.util.XSDConstants;
import org.eclipse.xsd.util.XSDResourceImpl;
import org.teiid.core.designer.ModelerCoreException;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.core.designer.util.CoreStringUtil;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.metamodel.aspect.sql.SqlAspect;
import org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect;
import org.teiid.designer.core.types.DatatypeManager;
import org.teiid.designer.metamodels.transformation.MappingClass;
import org.teiid.designer.metamodels.transformation.MappingClassColumn;
import org.teiid.designer.metamodels.transformation.MappingClassSet;
import org.teiid.designer.metamodels.transformation.MappingClassSetContainer;
import org.teiid.designer.metamodels.transformation.RecursionErrorMode;
import org.teiid.designer.metamodels.transformation.StagingTable;
import org.teiid.designer.metamodels.transformation.TransformationContainer;
import org.teiid.designer.metamodels.transformation.TransformationMappingRoot;
import org.teiid.designer.metamodels.transformation.TreeMappingRoot;
import org.teiid.designer.metamodels.xml.ChoiceErrorMode;
import org.teiid.designer.metamodels.xml.ChoiceOption;
import org.teiid.designer.metamodels.xml.SoapEncoding;
import org.teiid.designer.metamodels.xml.ValueType;
import org.teiid.designer.metamodels.xml.XmlAll;
import org.teiid.designer.metamodels.xml.XmlAttribute;
import org.teiid.designer.metamodels.xml.XmlChoice;
import org.teiid.designer.metamodels.xml.XmlComment;
import org.teiid.designer.metamodels.xml.XmlContainerNode;
import org.teiid.designer.metamodels.xml.XmlDocument;
import org.teiid.designer.metamodels.xml.XmlDocumentEntity;
import org.teiid.designer.metamodels.xml.XmlDocumentFactory;
import org.teiid.designer.metamodels.xml.XmlDocumentNode;
import org.teiid.designer.metamodels.xml.XmlDocumentPackage;
import org.teiid.designer.metamodels.xml.XmlElement;
import org.teiid.designer.metamodels.xml.XmlNamespace;
import org.teiid.designer.metamodels.xml.XmlRoot;
import org.teiid.designer.metamodels.xml.XmlSequence;
import org.teiid.designer.metamodels.xml.XmlValueHolder;
import org.teiid.designer.metamodels.xml.namespace.NamespaceContext;
import org.teiid.designer.metamodels.xml.util.XmlDocumentUtil;
import org.teiid.designer.metamodels.xml.util.XmlNamespaceComparator;
import org.teiid.designer.metamodels.xsd.XsdUtil;
import org.teiid.designer.query.IQueryService;
import org.teiid.designer.xml.IMappingAttribute;
import org.teiid.designer.xml.IMappingBaseNode;
import org.teiid.designer.xml.IMappingChoiceNode;
import org.teiid.designer.xml.IMappingCriteriaNode;
import org.teiid.designer.xml.IMappingDocument;
import org.teiid.designer.xml.IMappingDocumentFactory;
import org.teiid.designer.xml.IMappingElement;
import org.teiid.designer.xml.IMappingNode;
import org.teiid.designer.xml.IMappingRecursiveElement;
import org.teiid.designer.xml.PluginConstants;
import org.teiid.designer.xml.aspects.sql.MappingContext;
import org.teiid.designer.xml.aspects.sql.XmlDocumentMappingHelper;
/**
* MappingDocumentFormatter
*
* @since 8.0
*/
public class MappingDocumentFormatter {
static final String XSI_TYPE_ATTRIBUTE_NAME = "type"; //$NON-NLS-1$
/**
* Construct an instance of MappingDocumentFormatter.
*/
public static MappingDocumentFormatter create( final XmlDocument xmlDoc,
final MappingContext mappingContext ) {
final List treeMappingRoots = findTreeMappingRoot(xmlDoc);
// Return nothing if there is no tree mapping root ...
if (treeMappingRoots != null && treeMappingRoots.size() != 0) {
final MappingClassSet mappingClassSet = findMappingClassSet(xmlDoc);
if (mappingClassSet != null) {
final MappingDocumentFormatter formatter = new MappingDocumentFormatter(xmlDoc, treeMappingRoots, mappingClassSet,
mappingContext);
return formatter;
}
}
return null;
}
/**
* @param xmlDoc
* @return
*/
private static MappingClassSet findMappingClassSet( final XmlDocument xmlDoc ) {
// Get the resource that contains this object ..
final Resource resource = xmlDoc.eResource();
if (resource == null) return null;
final Iterator iter = resource.getContents().iterator();
while (iter.hasNext()) {
final Object rootObj = iter.next();
if (rootObj instanceof MappingClassSetContainer) {
final MappingClassSetContainer container = (MappingClassSetContainer)rootObj;
final Iterator mcsetiter = container.getMappingClassSets().iterator();
while (mcsetiter.hasNext()) {
final MappingClassSet mcSet = (MappingClassSet)mcsetiter.next();
final EObject target = mcSet.getTarget();
if (target == xmlDoc) return mcSet;
}
}
}
return null;
}
/**
* @param xmlDoc
* @return
*/
private static List findTreeMappingRoot( final XmlDocument xmlDoc ) {
// Get the resource that contains this object ..
final Resource resource = xmlDoc.eResource();
if (resource == null) return Collections.EMPTY_LIST;
final List treeMappingRoots = new LinkedList();
final Iterator iter = resource.getContents().iterator();
while (iter.hasNext()) {
final Object rootObj = iter.next();
if (rootObj instanceof TransformationContainer) {
final TransformationContainer container = (TransformationContainer)rootObj;
final Iterator transformIter = container.getTransformationMappings().iterator();
while (transformIter.hasNext()) {
final TransformationMappingRoot tmroot = (TransformationMappingRoot)transformIter.next();
if (tmroot instanceof TreeMappingRoot) {
final EObject target = tmroot.getTarget();
if (target == xmlDoc) treeMappingRoots.add(tmroot);
}
}
}
}
return treeMappingRoots;
}
private String getNamespacePrefix( final XmlDocumentNode elementOrAttribute,
final NamespaceContext context,
final MappingContext mappingContext ) {
if (elementOrAttribute == null) return null;
// Get the XSDComponent mapped to this document node ...
final XSDComponent xsdComponent = elementOrAttribute.getXsdComponent();
// Find the default target namespace to pass into the getNamespacePrefix(...) method. The default target
// namespace is the namespace associated with this XSDComponent. If one does not exist, then we need
// to walk up the xml document nodes to find one mapping to a target namespace.
final XSDSchema startingSchema = getTargetNamespaceSchema(xsdComponent, context, mappingContext);
final String defaultTargetNamespace = getTargetNamespace(startingSchema, elementOrAttribute, context, mappingContext);
// Get the namespace prefix to assign to this XmlDocumentNode
final String prefix = getNamespacePrefix(xsdComponent, context, mappingContext, defaultTargetNamespace, true, true);
return prefix;
}
/**
* Utility to get a non-empty namespace prefix regardless of what the actual XmlNamespace has for it's prefix. This method does
* not actually change the XmlNamespace object.
*
* @param ns
* @return
*/
private String getNamespacePrefix( final XmlNamespace ns ) {
String prefix = ns.getPrefix();
if (prefix == null || prefix.trim().length() == 0) prefix = XmlDocumentUtil.createXmlPrefixFromUri(ns.getUri());
return prefix;
}
private String getNamespacePrefix( final XSDComponent xsdComponent,
final NamespaceContext context,
final MappingContext mappingContext,
final String defaultTargetNamespace,
final boolean checkWhetherPrefixIsRequired,
final boolean addIfMissing ) {
if (xsdComponent == null) return null;
final XSDSchema schema = getTargetNamespaceSchema(xsdComponent, context, mappingContext);
if (schema == null) return null;
final String uri = (schema.getTargetNamespace() == null ? defaultTargetNamespace : schema.getTargetNamespace());
XmlNamespace namespace = context.getBestNamespace(uri);
if (namespace == null) {
// There is no namespace in the context ...
// First see if the schema component is one of the built-ins (in XMLSchema-instance)
if (XsdUtil.isBuiltInDatatype(xsdComponent)) {
final String prefix = getSchemaNamespacePrefix(context);
if (!checkWhetherPrefixIsRequired || isPrefixRequired(xsdComponent, schema, uri)) return prefix;
return null;
}
// It's not a built-in, so see if we should add it ...
if (uri != null && addIfMissing) {
final XmlNamespace newNs = XmlDocumentFactory.eINSTANCE.createXmlNamespace();
String prefix = XmlDocumentUtil.createXmlPrefixFromUri(uri);
if (prefix == null) prefix = "nspace"; //$NON-NLS-1$
newNs.setPrefix(prefix);
newNs.setUri(uri);
int counter = 0;
while (!context.addXmlNamespace(newNs)) {
++counter;
newNs.setPrefix(prefix + counter);
}
namespace = newNs;
}
}
if (namespace != null) {
final String actualPrefix = namespace.getPrefix();
if (actualPrefix == null || actualPrefix.trim().length() == 0) // This is the default target namespace declaration, so
// return null (see defect 13428)
return null;
final String prefix = getNamespacePrefix(namespace);
if (!checkWhetherPrefixIsRequired || isPrefixRequired(xsdComponent, schema, uri)) return prefix;
return null;
}
return null;
}
private String getSchemaInstanceNamespacePrefix( final NamespaceContext context ) {
final Iterator iter = context.getAllXmlNamespaces().iterator();
while (iter.hasNext()) {
final XmlNamespace nsDecl = (XmlNamespace)iter.next();
final String uri = nsDecl.getUri();
if (uri != null && uri.startsWith("http://www.w3.org/") && uri.endsWith("/XMLSchema-instance")) return getNamespacePrefix(nsDecl); //$NON-NLS-1$ //$NON-NLS-2$
}
// Add the soap encoding namespace ...
final String defaultPrefix = "xsi"; //$NON-NLS-1$
final XmlNamespace newNsDecl = XmlDocumentFactory.eINSTANCE.createXmlNamespace();
newNsDecl.setPrefix(defaultPrefix);
newNsDecl.setUri("http://www.w3.org/2001/XMLSchema-instance"); //$NON-NLS-1$
context.addXmlNamespace(newNsDecl);
return defaultPrefix;
}
private String getSchemaNamespacePrefix( final NamespaceContext context ) {
final Iterator iter = context.getAllXmlNamespaces().iterator();
while (iter.hasNext()) {
final XmlNamespace nsDecl = (XmlNamespace)iter.next();
final String uri = nsDecl.getUri();
if (uri != null && uri.startsWith("http://www.w3.org/") && uri.endsWith("/XMLSchema")) return getNamespacePrefix(nsDecl); //$NON-NLS-1$ //$NON-NLS-2$
}
// Add the soap encoding namespace ...
final String defaultPrefix = "xsd"; //$NON-NLS-1$
final XmlNamespace newNsDecl = XmlDocumentFactory.eINSTANCE.createXmlNamespace();
newNsDecl.setPrefix(defaultPrefix);
newNsDecl.setUri("http://www.w3.org/2001/XMLSchema"); //$NON-NLS-1$
context.addXmlNamespace(newNsDecl);
return defaultPrefix;
}
/**
* Method to return the complete value for the "soap-enc:arrayType" attribute on the supplied element. This method checks the
* schema component referenced by the element, and sees if that complex type has (eventually) a base type of the SOAP-ENC XSD's
* "ArrayType".
*
* @param element the XML element for which the array type is to be determined; never null
* @param context the namespace context from which namespace prefixes should be determined; never null
* @return the value of the "soap-enc:arrayType" attribute; may be null if there is no type
*/
private String getSoapArrayType( final XmlElement element,
final NamespaceContext context,
final MappingContext mappingContext ) {
XSDComponent xsdComponent = element.getXsdComponent();
while (xsdComponent != null) {
if (xsdComponent instanceof XSDComplexTypeDefinition) {
final XSDComplexTypeDefinition complexTypeDefn = (XSDComplexTypeDefinition)xsdComponent;
if (XSDConstants.isAnyType(complexTypeDefn)) return null;
final String name = complexTypeDefn.getName();
if (Soap.ARRAY_TYPE_NAME.equals(name)) {
// Check the namespace of the complext type to see if it is the
final XSDSchema schema = complexTypeDefn.getSchema();
final String targetNS = schema.getTargetNamespace();
if (Soap.TARGET_NAMESPACE_URI.equals(targetNS)) {
// Find the common base type of all containable children ...
final XSDTypeDefinition schemaCompOfChildren = XsdUtil.getCommonBaseTypeForContained(element.getXsdComponent());
if (schemaCompOfChildren == null) {
final String namespacePrefix = getSchemaNamespacePrefix(context);
return namespacePrefix + ":anyType[]"; //$NON-NLS-1$
}
String namespacePrefix = getNamespacePrefix(schemaCompOfChildren,
context,
mappingContext,
null,
false,
true);
// If the namespace prefix is null
if (namespacePrefix == null) // See if the schema component is one of the built-ins (in XMLSchema-instance)
if (XsdUtil.isBuiltInDatatype(schemaCompOfChildren)) namespacePrefix = getSchemaNamespacePrefix(context);
String result = null;
if (namespacePrefix != null && namespacePrefix.trim().length() != 0) result = namespacePrefix
+ ":" + schemaCompOfChildren.getName() + "[]"; //$NON-NLS-1$ //$NON-NLS-2$
else result = schemaCompOfChildren.getName() + "[]"; //$NON-NLS-1$
return result;
}
} else // This complex type is not the SOAP ArrayType, so go to the base type ...
xsdComponent = complexTypeDefn.getBaseTypeDefinition();
}
if (xsdComponent instanceof XSDSimpleTypeDefinition) // ArrayType is a complex type, so this is definitely not a SOAP
// ArrayType
return null;
if (xsdComponent instanceof XSDElementDeclaration) {
final XSDElementDeclaration elmDeclaration = (XSDElementDeclaration)xsdComponent;
xsdComponent = elmDeclaration.getTypeDefinition();
}
// Prevent the infinite loop if processing a type that this method cannot interpret
if (!(xsdComponent instanceof XSDComplexTypeDefinition) && !(xsdComponent instanceof XSDSimpleTypeDefinition)
&& !(xsdComponent instanceof XSDElementDeclaration)) return null;
}
return null;
}
private String getSoapEncodingNamespacePrefix( final NamespaceContext context ) {
final XmlNamespace namespace = context.getBestNamespace(Soap.TARGET_NAMESPACE_URI);
if (namespace != null) {
final String prefix = getNamespacePrefix(namespace);
return prefix;
}
// Add the soap encoding namespace ...
final String defaultPrefix = Soap.DEFAULT_NAMESPACE_PREFIX;
final XmlNamespace newNsDecl = XmlDocumentFactory.eINSTANCE.createXmlNamespace();
newNsDecl.setPrefix(defaultPrefix);
newNsDecl.setUri(Soap.TARGET_NAMESPACE_URI);
context.addXmlNamespace(newNsDecl);
return defaultPrefix;
}
/**
* Return the target namespace string for the specified XmlDocumentNode. If the XmlDocumentNode has no XSDComponent reference or
* is determined to reference a global schema then null is returned.
*
* @param element
* @param context
* @param mappingContext
* @return
* @since 4.2
*/
private static String getTargetNamespace( final XSDSchema startingSchema,
final XmlDocumentNode element,
final NamespaceContext context,
final MappingContext mappingContext ) {
if (element == null) return null;
// Get the XSDComponent mapped to this document node ...
final XSDComponent xsdComponent = element.getXsdComponent();
// If the xsd component is a reference, follow the references looking for a target namespace
if (xsdComponent instanceof XSDFeature) {
final XSDComponent resolvedComponent = XsdUtil.getResolved((XSDFeature)xsdComponent);
if (resolvedComponent != null && resolvedComponent != xsdComponent) {
final String resolvedTNS = ((XSDFeature)resolvedComponent).getTargetNamespace();
if (!CoreStringUtil.isEmpty(resolvedTNS)) return resolvedTNS;
}
}
// Get the target namespace from the schema associated with this xsd component
final XSDSchema schema = getTargetNamespaceSchema(xsdComponent, context, mappingContext);
final String targetNS = (schema == null ? null : schema.getTargetNamespace());
// If we find a target namespace ...
if (!CoreStringUtil.isEmpty(targetNS)) {
// If the starting schema associated with the initial call to this method has a null
// target namespace then it may be either a chameleon schema or a global schema. If
// it is a chameleon schema then the current schema reference, which has a target namespace,
// must have an include declaration to the starting schema. We will check for that now.
if (startingSchema != null && startingSchema.getTargetNamespace() == null) {
// Check for an XSDInclude to the starting schema
if (hasMatchingIncludeDirective(schema, startingSchema)) // The starting schema is a chameleon schema that has been
// included in
// this schema. Therefore we assume the target namespace of this schema.
return targetNS;
// An XSDInclude to the starting schema was not found so the starting schema must be
// a global schema with no target namespace
return null;
}
// If the starting schema associated with the initial call to this method has a target
// namespace so we return it.
return targetNS;
}
// If the target namespace is not defined for this schema, as in the case of a global
// schema or a chameleon schema, go to the parent element in the document and try again.
final XmlElement owner = getXmlElementContainer(element);
return getTargetNamespace(startingSchema, owner, context, mappingContext);
}
/**
* Return the XSDSchema reference for the specified XSDComponent or null if the XSDComponent is null. If the XSDComponent is an
* eProxy the method will try to resolve the XSDResource. If the component is a reference the method will return the referenced
* schema.
*
* @param xsdComponent
* @param context
* @param mappingContext
* @return
* @since 4.2
*/
private static XSDSchema getTargetNamespaceSchema( XSDComponent xsdComponent,
final NamespaceContext context,
final MappingContext mappingContext ) {
if (xsdComponent == null) return null;
XSDSchema schema = xsdComponent.getSchema();
if (schema == null && xsdComponent.eIsProxy()) {
xsdComponent = (XSDComponent)EcoreUtil.resolve(xsdComponent, mappingContext.getResourceSet());
schema = xsdComponent.getSchema();
if (schema == null) {
final Object componentURi = ModelerCore.getModelEditor().getUri(xsdComponent);
final String msg = PluginConstants.Util.getString("MappingDocumentFormatter.Unable_to_determine_schema_in_the_workspace_for_XsdComponent_{0}_when_deriving_Namespace_Prefix_1", componentURi); //$NON-NLS-1$
PluginConstants.Util.log(IStatus.ERROR, msg);
return null;
}
}
// If the component is a reference, find out if the referenced schema has a target namespace ...
if (xsdComponent instanceof XSDFeature) {
final XSDComponent resolvedComponent = XsdUtil.getResolved((XSDFeature)xsdComponent);
if (resolvedComponent != null && resolvedComponent != xsdComponent) {
final XSDSchema resolvedSchema = resolvedComponent.getSchema();
String resolvedTNS = ((XSDFeature)resolvedComponent).getTargetNamespace();
if (CoreStringUtil.isEmpty(resolvedTNS)) resolvedTNS = resolvedSchema.getTargetNamespace();
if (resolvedTNS != null && resolvedTNS.trim().length() != 0) // The referenced schema DOES have a target namespace,
// so this is the
// namespace that should be represented by the prefix (if there is one)
if (resolvedSchema != null && resolvedSchema.eIsProxy()) {
final URI proxyURI = ((InternalEObject)resolvedSchema).eProxyURI();
if (proxyURI != null) {
final XSDResourceImpl resource = (XSDResourceImpl)mappingContext.getResourceSet().getResource(proxyURI.trimFragment(),
true);
if (resource != null) schema = resource.getSchema();
}
} else schema = resolvedSchema;
}
}
return schema;
}
private static XmlElement getXmlElementContainer( final XmlDocumentNode element ) {
if (element == null) return null;
EObject owner = element.eContainer();
while ((owner != null) && !(owner instanceof XmlElement))
owner = owner.eContainer();
return (owner instanceof XmlElement ? (XmlElement)owner : null);
}
private static boolean hasMatchingIncludeDirective( final XSDSchema schemaWithDirectives,
final XSDSchema schemaToCheck ) {
if (schemaWithDirectives != null && schemaToCheck != null) for (final Object content : schemaWithDirectives.eContents())
if (content instanceof XSDInclude) {
final XSDInclude includeDeclaration = (XSDInclude)content;
final XSDSchema resolvedSchema = includeDeclaration.getResolvedSchema();
final String includeSchemaLocation = resolvedSchema.getSchemaLocation();
if (includeSchemaLocation != null && includeSchemaLocation.equals(schemaToCheck.getSchemaLocation())) return true;
}
return false;
}
/**
* Return whether the XSD component should be prefixed in an XML document.
* <p>
* If the XSD component is an element and:
* <ul>
* <li>is global and the schema has a target namespace, then the element needs to be qualified</li>
* <li>is global and the schema does not have a target namespace, then the element is unqualified</li>
* <li>is a reference, then the result is this method called on the referenced element</li>
* <li>is local, the value of the "form" attribute determines whether the element is qualified or unqualified. If the local
* element has no "form" attribute, the value of the schema's "elementFormDefault" attribute determines whether the element is
* qualified or unqualified</li>
* </ul>
* </p>
* <p>
* If the XSD component is an attribute and:
* <ul>
* <li>is global and the schema has a target namespace, then the attribute needs to be qualified</li>
* <li>is global and the schema does not have a target namespace, then the attribute is unqualified</li>
* <li>is a reference, then the result is this method called on the referenced attribute</li>
* <li>is local, the value of the "form" attribute determines whether the attribute is qualified or unqualified. If the local
* attribute has no "form" attribute, the value of the schema's "attributeFormDefault" attribute determines whether the
* attribute is qualified or unqualified</li>
* </ul>
* </p>
* <p>
* Per the XSD specification, the form is determined completely by the element/attribute declaration and it's parent schema.
* (This means that element/attribute refs nor their schema are used to determine whether an element/attribute should be
* qualified.) Therefore, we always resolve any references.
* </p>
*
* @param component the XML Schema component
* @return true if entity is to be unqualified.
*/
private static boolean isPrefixRequired( final XSDComponent component,
final XSDSchema schema,
final String schemaNamespaceUri ) {
// If the component is global, then it must be qualified ...
final boolean global = XsdUtil.isGlobal(component);
if (global) {
if (schemaNamespaceUri == null || schemaNamespaceUri.trim().length() == 0) // There is no schema namespace, so it is
// unqualified
return false;
// There is a schema namespace, so it must be qualified
return true;
}
// If an element or attribute ...
if (component instanceof XSDFeature) { // supertype of both XSDAttributeDeclaration and XSDElementDeclaration
final XSDFeature feature = (XSDFeature)component;
// See if it is a reference ...
final XSDFeature resolvedFeature = XsdUtil.getResolved(feature);
if (resolvedFeature != null && resolvedFeature != feature) {
// 'component' is a ref, so call this method with the resolved object ...
final XSDSchema schemaForResolved = resolvedFeature.getSchema();
final String uri = schemaForResolved.getTargetNamespace();
// and use the resolved schema!!!
return isPrefixRequired(resolvedFeature, resolvedFeature.getSchema(), uri);
}
// Otherwise, it is local and not a reference, so look at the "form" attribute ...
XSDForm form = null;
// If the form attribute is explicitly set on this declaration ...
if (feature.isSetForm()) // It is set, so get it ...
form = feature.getForm();
else // There is no form attribute, so go to the schema and look for the default
if (component instanceof XSDElementDeclaration) {
if (schema.isSetElementFormDefault()) form = schema.getElementFormDefault();
else form = XSDForm.UNQUALIFIED_LITERAL;
} else if (component instanceof XSDAttributeDeclaration) if (schema.isSetAttributeFormDefault()) form = schema.getAttributeFormDefault();
else form = XSDForm.UNQUALIFIED_LITERAL;
if (form != null) switch (form.getValue()) {
case XSDForm.QUALIFIED:
return true;
case XSDForm.UNQUALIFIED:
return false;
}
}
// By default, return true
return true;
}
private boolean includeSoapDefaultEncoding = false;
private final XmlDocument xmlDoc;
private final MappingContext mappingContext;
private final List treeMappingRoots; // instances of TreeMappingRoot
private final XmlDocumentMappingHelper helper;
private boolean indent;
private boolean newlines;
/**
* Construct an instance of MappingDocumentFormatter.
*/
public MappingDocumentFormatter( final XmlDocument xmlDoc,
final List treeMappingRoots,
final MappingClassSet mappingClassSet,
final MappingContext mappingContext ) {
super();
CoreArgCheck.isNotNull(xmlDoc);
CoreArgCheck.isNotNull(treeMappingRoots);
CoreArgCheck.isNotNull(mappingClassSet);
this.includeSoapDefaultEncoding = false;
this.xmlDoc = xmlDoc;
this.treeMappingRoots = treeMappingRoots;
this.mappingContext = mappingContext;
this.helper = new XmlDocumentMappingHelper(this.treeMappingRoots);
}
private IMappingDocumentFactory getFactory() {
IQueryService queryService = ModelerCore.getTeiidQueryService();
return queryService.getMappingDocumentFactory();
}
private void createAttributeNode( final IMappingElement parent,
final XmlAttribute element,
final ElementInfo elementInfo,
final MappingContext mappingContext ) {
final String name = element.getName();
final String nsPrefix = getNamespacePrefix(element, elementInfo.getNamespaceContext(), mappingContext);
IMappingAttribute attribute = null;
// if the namespace equals to "xmlns" then we are defining a namespace attribute
if (nsPrefix != null && nsPrefix.equalsIgnoreCase(IMappingAttribute.NAMESPACE_DECLARATION_ATTRIBUTE_NAMESPACE)) {
// this is default name space where only "xmlns" is defined. We do not need to global map
// as there may be more(I guess..)
getFactory().addNamespace(parent, "", getFixedValue(element)); //$NON-NLS-1$
} else if (name != null && nsPrefix != null
&& nsPrefix.equalsIgnoreCase(IMappingAttribute.NAMESPACE_DECLARATION_ATTRIBUTE_NAMESPACE)) {
getFactory().addNamespace(parent, name, getFixedValue(element));
} else {
attribute = getFactory().createMappingAttribute(name, nsPrefix);
attribute.setNameInSource(getNameInSource(element));
attribute.setDefaultValue(getDefaultValue(element));
attribute.setValue(getFixedValue(element));
attribute.setExclude(element.isExcludeFromDocument());
attribute.setNormalizeText(getXsiTypeTextNormalization(element, mappingContext));
// attribute.setOptional(isOptional(element));
if (parent != null) parent.addAttribute(attribute);
}
}
private IMappingBaseNode createChoiceNode( IMappingBaseNode parent,
final XmlChoice choice,
final ElementInfo elementInfo ) {
final IMappingCriteriaNode criteria = createCriteriaNode(choice);
if (parent != null && parent instanceof IMappingChoiceNode && criteria != null)
parent.addChildNode(criteria);
final IMappingChoiceNode choiceNode = getFactory().createMappingChoiceNode(choice.getDefaultErrorMode().getValue() == ChoiceErrorMode.THROW);
choiceNode.setExclude(choice.isExcludeFromDocument());
choiceNode.setSource(getSource(choice));
if(parent != null)
parent.addChildNode(choiceNode);
choiceNode.addStagingTable(getStagingTable(choice));
return choiceNode;
}
private IMappingNode createCommentNode( final IMappingElement parent,
final XmlComment comment,
final ElementInfo elementInfo ) {
final String text = comment.getText();
if (text != null && text.trim().length() > 0 && parent != null)
parent.addCommentNode(text);
return null;
}
private IMappingCriteriaNode createCriteriaNode( final ChoiceOption element ) {
String criteria = getCriteria(element);
final boolean isDefault = (element.getDefaultFor() != null);
// if criteira node created with no default criteria, then assign some dummy
// criteria so that we have some valid criteria.
if (criteria == null && !isDefault) criteria = "TRUE = FALSE"; //$NON-NLS-1$
return getFactory().createMappingCriteriaNode(criteria, isDefault);
}
/**
* @param rootMappingNode
* @param rootElement
*/
private IMappingDocument createDocumentNode( final XmlRoot xmlRoot,
final NamespaceContext nsContext,
final ElementInfo rootElementInfo,
final MappingContext mappingContext ) {
// Set the SOAP encoding information ...
this.includeSoapDefaultEncoding = xmlDoc.getSoapEncoding().getValue() == SoapEncoding.DEFAULT;
IMappingDocument doc = getFactory().createMappingDocument(xmlDoc.getEncoding(), xmlDoc.isFormatted());
IMappingElement node = processElementNode(xmlRoot, rootElementInfo, mappingContext);
doc.addChildNode(node);
// Create the rest of the mapping node tree.
// When creating the mapping node tree the server assumes that attributes
// of an element are added before its child elements. The order below must
// not be changed.
IMappingBaseNode rootNode = doc.getRootNode();
processNamespaces(xmlRoot.getDeclaredNamespaces(), rootNode, nsContext, rootElementInfo);
processChildren(xmlRoot.getAttributes(), rootNode, nsContext, rootElementInfo);
processChildren(xmlRoot.getComments(), rootNode, nsContext, rootElementInfo);
processChildren(xmlRoot.getEntities(), rootNode, nsContext, rootElementInfo);
processChildren(xmlRoot.getProcessingInstructions(), rootNode, nsContext, rootElementInfo);
return doc;
}
/**
* @param rootMappingNode
* @param rootElement
*/
private IMappingBaseNode createElementNode( IMappingBaseNode parent,
final XmlElement element,
final ElementInfo elementInfo,
final MappingContext mappingContext ) {
final IMappingCriteriaNode criteria = createCriteriaNode(element);
if (parent != null && parent instanceof IMappingChoiceNode && criteria != null)
parent.addChildNode(criteria);
final IMappingElement node = processElementNode(element, elementInfo, mappingContext);
if (parent != null)
parent.addChildNode(node);
return node;
}
/**
* Create the mapping document given the supplied information ...
*
* @param xmlDoc
* @param treeMappingRoot
* @param mappingClassSet
* @return
*/
public IMappingDocument createMapping() {
// Initialize the helper (which contains the map from XML->MappingClassObject
this.helper.initialize();
final XmlRoot xmlRootElement = this.xmlDoc.getRoot();
// final SchemaIncludeMap schemaIncludeMap = new SchemaIncludeMap(moe);
final NamespaceContext nsContext = new NamespaceContext(xmlRootElement, null);
final ElementInfo elementInfo = new ElementInfo(nsContext, null); // not null! see defect 11240
// Create the root of the mapping node tree ...
IMappingDocument document = createDocumentNode(xmlRootElement, nsContext, elementInfo, this.mappingContext);
return document;
}
/**
* Recursive method to generate Mapping Objects at and beneath the specified node.
*
* @param entity the XmlDocumentEntity in the XML document.
* @param parent parent MappingNode of the MappingNode to be created in this method call; this should never be null
* @param context the namespace context for this entity ...
*/
private void createMapping( final XmlDocumentEntity entity,
final IMappingBaseNode parent,
final NamespaceContext namespaceContext,
final MappingContext mappingContext,
final ElementInfo parentInfo ) {
//
final int classifierId = entity.eClass().getClassifierID();
IMappingBaseNode entityMappingNode = null;
ElementInfo entityInfo = parentInfo;
NamespaceContext entityNamespaceContext = namespaceContext;
switch (classifierId) {
case XmlDocumentPackage.XML_ELEMENT:
final XmlElement element = (XmlElement)entity;
entityNamespaceContext = new NamespaceContext(element, namespaceContext);
entityInfo = new ElementInfo(entityNamespaceContext, parentInfo);
entityMappingNode = createElementNode(parent, element, entityInfo, mappingContext);
processNamespaces(element.getDeclaredNamespaces(), entityMappingNode, entityNamespaceContext, entityInfo);
processChildren(element.getAttributes(), entityMappingNode, entityNamespaceContext, entityInfo);
processChildren(element.getComments(), entityMappingNode, entityNamespaceContext, entityInfo);
processChildren(element.getEntities(), entityMappingNode, entityNamespaceContext, entityInfo);
processChildren(element.getProcessingInstructions(), entityMappingNode, entityNamespaceContext, entityInfo);
break;
case XmlDocumentPackage.XML_ATTRIBUTE:
createAttributeNode((IMappingElement)parent, (XmlAttribute)entity, entityInfo, mappingContext);
break;
case XmlDocumentPackage.XML_NAMESPACE:
createNamespaceAttribute((IMappingElement)parent, (XmlNamespace)entity, entityInfo);
break;
case XmlDocumentPackage.XML_ALL:
case XmlDocumentPackage.XML_SEQUENCE:
final XmlContainerNode container = (XmlContainerNode)entity;
entityMappingNode = createSequenceNode(parent, container, entityInfo);
// Case 5069 - removed lines - replaced with eContents - was resulting in implied ordering of output doc.
// processChildren(container.getContainers(),entityMappingNode,namespaceContext,parentInfo);
// processChildren(container.getElements(),entityMappingNode,namespaceContext,parentInfo);
final List kids = container.eContents();
processChildren(kids, entityMappingNode, namespaceContext, parentInfo);
break;
case XmlDocumentPackage.XML_CHOICE:
final XmlChoice choiceNode = (XmlChoice)entity;
entityMappingNode = createChoiceNode(parent, choiceNode, entityInfo);
final List optionsInOrder = choiceNode.getOrderedChoiceOptions();
processChildren(optionsInOrder, entityMappingNode, namespaceContext, parentInfo);
break;
case XmlDocumentPackage.XML_FRAGMENT:
// entityMappingNode = createMappingNode(parentMappingNode,(ProcessingInstruction)entity,entityInfo);
// processChildren = true;
break;
case XmlDocumentPackage.XML_COMMENT:
createCommentNode((IMappingElement)parent, (XmlComment)entity, entityInfo);
break;
case XmlDocumentPackage.PROCESSING_INSTRUCTION:
// entityMappingNode = createMappingNode(parentMappingNode,(ProcessingInstruction)entity,
// namespaceContext,entityInfo);
break;
}
}
public String createMappingString() throws Exception {
final IMappingDocument mapping = createMapping();
return mapping.getMappingString();
}
/**
* @param rootMappingNode
* @param rootElement
*/
private void createNamespaceAttribute( final IMappingElement parent,
final XmlNamespace ns,
final ElementInfo elementInfo ) {
getFactory().addNamespace(parent, ns.getPrefix(), ns.getUri());
}
/**
* @param rootMappingNode
* @param rootElement
*/
private IMappingBaseNode createSequenceNode( IMappingBaseNode parent,
final XmlContainerNode compositor,
final ElementInfo elementInfo ) {
final IMappingCriteriaNode criteria = createCriteriaNode(compositor);
if (parent != null && parent instanceof IMappingChoiceNode && criteria != null)
parent.addChildNode(criteria);
IMappingBaseNode seqNode = null;
if (compositor instanceof XmlSequence)
seqNode = getFactory().createMappingSequenceNode();
else if (compositor instanceof XmlAll)
seqNode = getFactory().createMappingAllNode();
if(seqNode != null) {
parent.addChildNode(seqNode);
seqNode.setExclude(compositor.isExcludeFromDocument());
seqNode.setSource(getSource(compositor));
seqNode.addStagingTable(getStagingTable(compositor));
}
return seqNode;
}
/**
* @param rootMappingNode
* @param rootElement
*/
private void createSoapArrayTypeAttribute( final IMappingElement parent,
final ElementInfo elementInfo ) {
final String value = elementInfo.getSoapArrayType();
if (value == null) return;
final NamespaceContext context = elementInfo.getNamespaceContext();
final String prefix = getSoapEncodingNamespacePrefix(context);
final IMappingAttribute attribute = getFactory().createMappingAttribute(Soap.ARRAY_TYPE_XML_ATTRIBUTE_NAME, prefix);
attribute.setValue(value);
attribute.setOptional(true);
attribute.setAlwaysInclude(true);
parent.addAttribute(attribute);
}
/**
* @param rootMappingNode
* @param rootElement
*/
private void createXsiTypeAttribute( final IMappingElement parent,
final ElementInfo elementInfo ) {
final String value = elementInfo.getXsiType();
if (value == null) return;
final NamespaceContext context = elementInfo.getNamespaceContext();
final String prefix = getSchemaInstanceNamespacePrefix(context);
final IMappingAttribute attribute = getFactory().createMappingAttribute(XSI_TYPE_ATTRIBUTE_NAME, prefix);
attribute.setValue(value);
attribute.setOptional(true);
attribute.setAlwaysInclude(true);
parent.addAttribute(attribute);
}
String getBuitInType( final XmlElement element ) {
final MappingClassColumn mappingClassColumn = this.helper.getMappingClassColumn(element);
if (mappingClassColumn != null) {
final SqlColumnAspect columnAspect = (SqlColumnAspect)org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.getSqlAspect(mappingClassColumn);
EObject dataType = columnAspect.getDatatype(mappingClassColumn);
final DatatypeManager dtm = ModelerCore.getBuiltInTypesManager();
CoreArgCheck.isNotNull(dtm);
try {
dataType = dtm.getDatatypeForXsdType(dataType);
} catch (final ModelerCoreException err) {
PluginConstants.Util.log(err);
}
if (dataType != null && dtm.isBuiltInDatatype(dataType)) return dtm.getName(dataType);
}
return IMappingNode.DEFAULT_BUILT_IN_TYPE;
}
String getCriteria( final ChoiceOption element ) {
String choiceCriteria = element.getChoiceCriteria();
return choiceCriteria;
}
String getDefaultValue( final XmlValueHolder valueHolder ) {
final String value = valueHolder.getValue();
if (value != null) {
final ValueType valueType = valueHolder.getValueType();
if (valueType.getValue() == ValueType.DEFAULT) return value;
}
return null;
}
String getFixedValue( final XmlValueHolder valueHolder ) {
final String value = valueHolder.getValue();
if (value != null) {
final ValueType valueType = valueHolder.getValueType();
if (valueType.getValue() == ValueType.FIXED) return value;
}
return null;
}
private String getFullName( final EObject object ) {
// find the SqlTableAspect for the mapping class ...
final SqlAspect sqlAspect = (SqlAspect)ModelerCore.getMetamodelRegistry().getMetamodelAspect(object, SqlAspect.class);
if (sqlAspect != null) return sqlAspect.getFullName(object);
return null;
}
int getMaxOccurrences( final XmlElement element ) {
final XSDComponent xsdComponent = element.getXsdComponent();
if (xsdComponent != null) return XsdUtil.getMaxOccurs(xsdComponent);
return IMappingNode.DEFAULT_CARDINALITY_MAXIMUM_BOUND.intValue();
}
int getMinOccurrences( final XmlElement element ) {
final XSDComponent xsdComponent = element.getXsdComponent();
if (xsdComponent != null) return XsdUtil.getMinOccurs(xsdComponent);
return IMappingNode.DEFAULT_CARDINALITY_MINIMUM_BOUND.intValue();
}
String getNameInSource( final XmlDocumentEntity element ) {
final MappingClassColumn mappingClassColumn = this.helper.getMappingClassColumn(element);
if (mappingClassColumn != null) return getFullName(mappingClassColumn);
return null;
}
String getRecursionCriteria( final XmlElement element ) {
String criteria = null;
final MappingClass mappingClass = this.helper.getMappingClass(element);
if (mappingClass != null && mappingClass.isRecursionAllowed() && mappingClass.isRecursive()) {
criteria = mappingClass.getRecursionCriteria();
// Rewrite the recursion criteria in terms of the root mapping class (defect 17576)
if (!CoreStringUtil.isEmpty(criteria)) criteria = CoreStringUtil.replaceAll(criteria,
getFullName(mappingClass),
getRecursionMappingClass(element));
}
return criteria;
}
int getRecursionLimit( final XmlElement element ) {
final MappingClass mappingClass = this.helper.getMappingClass(element);
if (mappingClass != null && mappingClass.isRecursionAllowed() && mappingClass.isRecursive()) return mappingClass.getRecursionLimit();
return IMappingNode.DEFAULT_RECURSION_LIMIT.intValue();
}
String getRecursionMappingClass( final XmlElement element ) {
final MappingClass rootMappingClass = this.helper.getRecusionRootMappingClass(element);
if (rootMappingClass != null) return getFullName(rootMappingClass);
return null;
}
private String getSource( final XmlContainerNode compositor ) {
String source = null;
// Find the MappingClass that is bound to this element ...
final MappingClass mappingClass = this.helper.getMappingClass(compositor);
if (mappingClass != null) {
final String fullName = getFullName(mappingClass);
if (fullName != null) source = fullName;
}
return source;
}
String getSource( final XmlDocumentEntity element ) {
final MappingClass mappingClass = this.helper.getMappingClass(element);
if (mappingClass != null) return getFullName(mappingClass);
return null;
}
private String getStagingTable( final XmlDocumentEntity compositor ) {
String stagingTable = null;
// Find the StagingTables that are bound to this element ...
final StagingTable[] tempGroups = this.helper.getStagingTables(compositor);
if (tempGroups != null && tempGroups.length != 0) for (final StagingTable st : tempGroups) {
final String fullName = getFullName(st);
if (fullName != null) stagingTable = fullName;
}
return stagingTable;
}
/**
* Method to return the complete value for the "xsi:type" attribute on the supplied element.
*
* @param element the XML element for which the type is to be determined; never null
* @param context the namespace context from which namespace prefixes should be determined; never null
* @return the value of the "xsi:type" attribute; may be null if there is no type
*/
private String getXsiType( final XmlElement element,
final NamespaceContext context,
final MappingContext mappingContext ) {
// Get the type ...
final XSDComponent xsdComponent = element.getXsdComponent();
if (xsdComponent == null) return null;
// Find the type name and the namespace URI ...
final XSDTypeDefinition typeDefn = XsdUtil.getType(xsdComponent);
final String typeName = typeDefn.getName();
final String nsPrefix = getNamespacePrefix(typeDefn, context, mappingContext, null, false, true);
// Compute what the xsi:type value would be ...
return (nsPrefix == null ? typeName : nsPrefix + ":" + typeName); //$NON-NLS-1$
}
/**
* Method to return the complete value for the "xsi:type" attribute on the supplied element.
*
* @param element the XML element for which the type is to be determined; never null
* @param mappingContext the mapping context
* @return the mapping node property value for text normalization
*/
private String getXsiTypeTextNormalization( final XmlDocumentNode node,
final MappingContext mappingContext ) {
// Get the type ...
final XSDComponent xsdComponent = node.getXsdComponent();
if (xsdComponent == null) return IMappingNode.DEFAULT_NORMALIZE_TEXT;
// Find the type and its underlying whitespace normalization if available ...
final XSDTypeDefinition typeDefn = XsdUtil.getType(xsdComponent);
if (typeDefn instanceof XSDSimpleTypeDefinition) {
final XSDSimpleTypeDefinition simpleTypeDefn = (XSDSimpleTypeDefinition)typeDefn;
final XSDWhiteSpaceFacet facet = simpleTypeDefn.getEffectiveWhiteSpaceFacet();
if (facet != null) {
final XSDWhiteSpace whiteSpaceEnum = facet.getValue();
if (whiteSpaceEnum != null) switch (whiteSpaceEnum.getValue()) {
case XSDWhiteSpace.PRESERVE:
return IMappingNode.NORMALIZE_TEXT_PRESERVE;
case XSDWhiteSpace.REPLACE:
return IMappingNode.NORMALIZE_TEXT_REPLACE;
case XSDWhiteSpace.COLLAPSE:
return IMappingNode.NORMALIZE_TEXT_COLLAPSE;
}
}
}
return IMappingNode.DEFAULT_NORMALIZE_TEXT;
}
/**
* @return
*/
public boolean isIndent() {
return indent;
}
/**
* @return
*/
public boolean isNewlines() {
return newlines;
}
boolean isNillable( final XmlElement element ) {
final XSDComponent xsdComponent = element.getXsdComponent();
if (xsdComponent != null && xsdComponent instanceof XSDElementDeclaration) {
final XSDElementDeclaration xsdElement = (XSDElementDeclaration)xsdComponent;
return xsdElement.isNillable();
}
return IMappingNode.DEFAULT_IS_NILLABLE.booleanValue();
}
boolean isRecursive( final XmlElement element ) {
final MappingClass mappingClass = this.helper.getMappingClass(element);
if (mappingClass != null && mappingClass.isRecursionAllowed() && mappingClass.isRecursive()) return mappingClass.isRecursive();
return false;
}
private void processChildren( final List children,
final IMappingBaseNode parentMappingNode,
final NamespaceContext namespaceContext,
final ElementInfo parentInfo ) {
final Iterator iter = children.iterator();
while (iter.hasNext()) {
final Object child = iter.next();
if (child instanceof XmlDocumentEntity) createMapping((XmlDocumentEntity)child,
parentMappingNode,
namespaceContext,
mappingContext,
parentInfo);
}
}
/**
* @param element
* @param elementInfo
* @param mappingContext
*
* @return element node
*/
private IMappingElement processElementNode(final XmlElement element,
final ElementInfo elementInfo,
final MappingContext mappingContext ) {
IMappingElement node = null;
final String name = element.getName();
final String nsPrefix = getNamespacePrefix(element, elementInfo.getNamespaceContext(), mappingContext);
// There are effectively three types of elements, recursive, criteria and regular..
if (isRecursive(element)) {
// first check if this is a "recursive" element
IMappingRecursiveElement elem = getFactory().createMappingRecursiveElement(name, nsPrefix, getRecursionMappingClass(element));
elem.setCriteria(getRecursionCriteria(element));
elem.setRecursionLimit(getRecursionLimit(element), throwExceptionOnRecursionLimit(element));
node = elem;
} else // this regular element
node = getFactory().createMappingElement(name, nsPrefix);
// now load all other common properties.
node.setMinOccurrs(getMinOccurrences(element));
node.setMaxOccurrs(getMaxOccurrences(element));
node.setNameInSource(getNameInSource(element));
node.setSource(getSource(element));
node.setDefaultValue(getDefaultValue(element));
node.setValue(getFixedValue(element));
node.setNillable(isNillable(element));
node.setExclude(element.isExcludeFromDocument());
node.setType(getBuitInType(element));
node.setNormalizeText(getXsiTypeTextNormalization(element, mappingContext));
node.addStagingTable(getStagingTable(element));
if (this.includeSoapDefaultEncoding) {
// Determine if this element has a SOAP array type ...
final String soapArrayType = getSoapArrayType(element, elementInfo.getNamespaceContext(), mappingContext);
if (soapArrayType != null) {
elementInfo.setSoapArrayType(soapArrayType);
createSoapArrayTypeAttribute(node, elementInfo);
}
// Determine if this element should have an "xsi:type" attribute ...
// Technically, xsi:type (e.g., ="xsd:string") is only required for SOAP encoding
// only if it is a SUBTYPE of what is specified in the container's SOAP-enc:arrayType value
// (e.g., "xsd:string[]"). If it is the same, then it is superfluous.
// However, at this point we will always write it out (this is acceptable to the customer
// requesting this feature).
if (elementInfo.isXsiTypeRequired()) {
final String xsiTypeValue = getXsiType(element, elementInfo.getNamespaceContext(), mappingContext);
elementInfo.setXsiType(xsiTypeValue);
createXsiTypeAttribute(node, elementInfo);
}
}
return node;
}
private void processNamespaces( final List children,
final IMappingBaseNode parentMappingNode,
final NamespaceContext namespaceContext,
final ElementInfo parentInfo ) {
final List orderedNamespaces = new LinkedList(children);
final XmlNamespaceComparator comparator = new XmlNamespaceComparator();
Collections.sort(orderedNamespaces, comparator);
processChildren(orderedNamespaces, parentMappingNode, namespaceContext, parentInfo);
}
/**
* @param b
*/
public void setIndent( final boolean b ) {
indent = b;
}
/**
* @param b
*/
public void setNewlines( final boolean b ) {
newlines = b;
}
boolean throwExceptionOnRecursionLimit( final XmlElement element ) {
final MappingClass mappingClass = this.helper.getMappingClass(element);
if (mappingClass != null && mappingClass.isRecursionAllowed() && mappingClass.isRecursive()) return (mappingClass.getRecursionLimitErrorMode().getValue() == RecursionErrorMode.THROW);
return IMappingNode.DEFAULT_EXCEPTION_ON_RECURSION_LIMIT.booleanValue();
}
private class ElementInfo {
private String soapArrayType;
private String xsiType;
private final ElementInfo parentInfo;
private final NamespaceContext namespaceContext;
private ElementInfo( final NamespaceContext namespaceContext,
final ElementInfo parentInfo ) {
this.parentInfo = parentInfo;
this.namespaceContext = namespaceContext;
}
public NamespaceContext getNamespaceContext() {
return this.namespaceContext;
}
public String getSoapArrayType() {
return soapArrayType;
}
public XmlElement getXmlElement() {
return this.namespaceContext.getXmlElement();
}
public String getXsiType() {
return this.xsiType;
}
public boolean isXsiTypeRequired() {
if (soapArrayType != null) return true;
return (parentInfo != null && parentInfo.getSoapArrayType() != null);
}
public void setSoapArrayType( final String soapArrayType ) {
this.soapArrayType = soapArrayType;
}
public void setXsiType( final String xsiType ) {
this.xsiType = xsiType;
}
}
static final class Soap {
public static final String ARRAY_TYPE_XML_ATTRIBUTE_NAME = "arrayType"; //$NON-NLS-1$
public static final String ARRAY_TYPE_NAME = "Array"; //$NON-NLS-1$
public static final String TARGET_NAMESPACE_URI = "http://schemas.xmlsoap.org/soap/encoding/"; //$NON-NLS-1$
public static final String DEFAULT_NAMESPACE_PREFIX = "soap-enc"; //$NON-NLS-1$
}
}