/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.xml.xsd.typeprovider.schemaindexer; import gw.internal.schema.gw.xsd.w3c.xmlschema.types.complex.AnyType; import gw.internal.xml.xsd.typeprovider.XmlSchemaElementTypeData; import gw.internal.xml.xsd.typeprovider.XmlSchemaFlattenedChild; import gw.internal.xml.xsd.typeprovider.XmlSchemaIndex; import gw.internal.xml.xsd.typeprovider.XmlSchemaPropertyType; import gw.internal.xml.xsd.typeprovider.XmlSchemaResourceTypeLoaderBase; import gw.internal.xml.xsd.typeprovider.XmlSchemaTypeInstanceTypeData; import gw.internal.xml.xsd.typeprovider.schema.XmlSchemaElement; import gw.internal.xml.xsd.typeprovider.schema.XmlSchemaType; import gw.util.GosuClassUtil; import gw.util.Pair; import java.util.List; import java.util.Map; import javax.xml.namespace.QName; public class XmlSchemaElementIndexer extends XmlSchemaIndexer<XmlSchemaElement> { @Override public <T> void index( final XmlSchemaElement xsdElement, String prefix, List<XmlSchemaFlattenedChild> flattenedChildren, boolean topLevel, boolean isPlural, XmlSchemaType currentType, boolean createTypes, final Map<QName, XmlSchemaElementTypeData> usedElementNames, Map<Pair<XmlSchemaPropertyType, QName>, Boolean> pluralityMap, final T context, List<Runnable> todo ) { final QName qname; if ( xsdElement.getQName() != null ) { qname = xsdElement.getQName(); } else { qname = xsdElement.getRefName(); } isPlural |= xsdElement.getMaxOccurs() > 1; flattenedChildren.add( new XmlSchemaFlattenedChild( xsdElement, isPlural ) ); setPlurality( pluralityMap, XmlSchemaPropertyType.ELEMENT, qname, isPlural ); prefix = appendToPrefix( prefix, XmlSchemaIndex.makeCamelCase( xsdElement.getName(), null ) ); @SuppressWarnings( {"unchecked"} ) final XmlSchemaIndex<T> schemaIndex = (XmlSchemaIndex<T>) (currentType == null ? xsdElement.getSchemaIndex() : currentType.getSchemaIndex()); final XmlSchemaElementTypeData[] typeData = { null }; if ( createTypes ) { if ( ! usedElementNames.containsKey( qname ) ) { // create typeData for top-level or anonymous element (but not for element refs) if ( topLevel || xsdElement.getRefName() == null ) { boolean anonymousElement = false; String packageName = schemaIndex.getPackageName(); final XmlSchemaResourceTypeLoaderBase<T> typeLoader = schemaIndex.getTypeLoader(); if ( ! topLevel ) { anonymousElement = true; packageName += typeLoader.getAnonymousNamespacePrefix() + ".elements"; } else { packageName += typeLoader.getElementsNamespacePrefix(); } final String typeName = schemaIndex.makeUniqueTypeName( packageName, prefix ); prefix = GosuClassUtil.getNameNoPackage( typeName ); // in case a suffix was added usedElementNames.put( qname, null ); final boolean fanonymousElement = anonymousElement; if ( topLevel ) { typeData[0] = new XmlSchemaElementTypeData<T>( typeLoader, typeName, null, xsdElement, fanonymousElement, context, schemaIndex, null ); schemaIndex.putTypeDataByName( typeName, typeData[0] ); xsdElement.getSchemaIndex().putTypeDataBySchemaObject( xsdElement, typeData[ 0 ] ); usedElementNames.put( qname, typeData[0] ); } else { todo.add( new Runnable() { @Override public void run() { // if this element duplicates a top level element by name, and it's type instance is assignable to the // top level element's type instance, make it extend that top level element boolean createdNewType = true; XmlSchemaElement topLevelElement = schemaIndex.getXmlSchemaElementByQNameIfValid( qname ); XmlSchemaElementTypeData superTypeData = null; if ( topLevelElement != null ) { XmlSchemaElementTypeData topLevelElementTypeData = (XmlSchemaElementTypeData) XmlSchemaIndex.getGosuTypeDataBySchemaObject( topLevelElement ); XmlSchemaTypeInstanceTypeData topLevelElementTypeInstanceTypeData = topLevelElementTypeData.getXmlTypeInstanceTypeData(); XmlSchemaTypeInstanceTypeData myTypeInstanceTypeData; if ( xsdElement.getSchemaType() != null ) { myTypeInstanceTypeData = (XmlSchemaTypeInstanceTypeData) XmlSchemaIndex.getGosuTypeDataBySchemaObject( xsdElement.getSchemaType() ); } else if ( xsdElement.getSchemaTypeName() != null ) { myTypeInstanceTypeData = (XmlSchemaTypeInstanceTypeData) XmlSchemaIndex.getGosuTypeDataBySchemaObject( xsdElement.getSchemaIndex().getXmlSchemaTypeByQName( xsdElement.getSchemaTypeName() ) ); } else { XmlSchemaIndex<?> schemaSchemaIndex = XmlSchemaResourceTypeLoaderBase.findSchemaForNamespace( xsdElement.getSchemaIndex().getTypeLoader().getModule(), "gw.xsd.w3c.xmlschema" ); XmlSchemaType anyTypeType = schemaSchemaIndex.getXmlSchemaTypeByQName( AnyType.$QNAME ); myTypeInstanceTypeData = (XmlSchemaTypeInstanceTypeData) XmlSchemaIndex.getGosuTypeDataBySchemaObject( anyTypeType ); } if ( myTypeInstanceTypeData.equals( topLevelElementTypeInstanceTypeData ) ) { typeData[0] = topLevelElementTypeData; createdNewType = false; schemaIndex.removeTypeName( typeName ); } else { // assignability check XmlSchemaTypeInstanceTypeData mySuperTypeData = myTypeInstanceTypeData.getSuperTypeData(); while ( mySuperTypeData != null ) { if ( mySuperTypeData.equals( topLevelElementTypeInstanceTypeData ) ) { superTypeData = topLevelElementTypeData; // extend the top level element due to assignability break; } mySuperTypeData = mySuperTypeData.getSuperTypeData(); } } } if ( typeData[0] == null ) { typeData[0] = new XmlSchemaElementTypeData<T>( typeLoader, typeName, null, xsdElement, fanonymousElement, context, schemaIndex, superTypeData ); } if ( createdNewType ) { schemaIndex.putTypeDataByName( typeName, typeData[0] ); } xsdElement.getSchemaIndex().putTypeDataBySchemaObject( xsdElement, typeData[ 0 ] ); usedElementNames.put( qname, typeData[0] ); } } ); } } } todo.add( new Runnable() { @Override public void run() { if ( typeData[0] == null ) { typeData[ 0 ] = usedElementNames.get( qname ); if ( typeData[0] != null ) { xsdElement.getSchemaIndex().putTypeDataBySchemaObject( xsdElement, typeData[ 0 ] ); } } } } ); } if ( xsdElement.getSchemaTypeName() == null && xsdElement.getSchemaType() != null ) { // process anonymous type XmlSchemaIndexer.invokeIndexer( xsdElement.getSchemaType(), prefix, flattenedChildren, topLevel, isPlural, null, createTypes, usedElementNames, pluralityMap, context, todo ); } } }