package org.ebayopensource.turmeric.tools.codegen.fastserformat.protobuf.tag; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Stack; import javax.xml.namespace.QName; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.Attribute; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.Attribute.AttributeUse; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.AttributeGroup; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.AttributeGroupType; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.Choice; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.ComplexContent; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.ComplexType; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.ElementType; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.Extension; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.Group; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.GroupType; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.Restriction; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.RestrictionEnumeration; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.SchemaAll; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.SchemaType; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.Sequence; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.Sequence.SequenceEntry; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.SequenceElement; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.SimpleContent; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.SimpleContentExtension; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.SimpleType; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.SimpleTypeList; import org.ebayopensource.turmeric.tools.codegen.external.wsdl.parser.schema.SimpleTypeRestriction; //TODO this class has become extremely bloated and complex. Its responsibility needs to be split /** * Resolves the elements / attributes under a Schema type by flattening them * recursively. */ public class SchemaTypeResolver { private static List<ProtoMessageTag> S_EMPTY_LIST = Collections.emptyList(); private QName currentType = null; private ElementType currentElementType = null; private Map<QName, SchemaType> elementMap = null; private Map<QName, SchemaType> groupMap = null; private Map<QName, SchemaType> attributeMap = null; private Map<QName, SchemaType> attributeGroupMap = null; private Map<QName, SchemaType> schemaMap = null; private final Stack<Integer> choiceStack = new Stack<Integer>(); private int currentAllOccurs = -1; private int refMinOccurs = Integer.MIN_VALUE; private int refMaxOccurs = Integer.MAX_VALUE; private int nestedLevel = 0; public SchemaTypeResolver(QnameMapBuilder mapBuilder) { elementMap = mapBuilder.getElementMap(); groupMap = mapBuilder.getGroupMap(); schemaMap = mapBuilder.getSchemaMap(); attributeMap = mapBuilder.getAttributeMap(); attributeGroupMap = mapBuilder.getAttributeGroupMap(); } /** * For a given schema type, get all the proto messages for that type and its parent. * Types are one of the following - Complex types / Simple types / Elements with an anon type * * @param schemaType * @return - A list of proto fields that need to be assigned for this type. */ public List<ProtoMessageTag> getElements(SchemaType schemaType) { try { List<ProtoMessageTag> result = new ArrayList<ProtoMessageTag>(); SchemaType next = schemaType; currentType = schemaType.getTypeName(); List<ProtoMessageTag> handleSchemaType = handleSchemaType(next); result.addAll(handleSchemaType); return result; } catch (Exception e) { throw new RuntimeException( "There was an internal error while processing the WSDL for types. Tag assignment has failed", e); } } private List<ProtoMessageTag> handleSchemaType(SchemaType next) { nestedLevel++; List<ProtoMessageTag> result = new ArrayList<ProtoMessageTag>(); if (next == null) { nestedLevel--; return S_EMPTY_LIST; } else if (next.isComplex()) { ComplexType complexType = (ComplexType) next; List<ProtoMessageTag> handleComplexType = handleComplexType(complexType); result.addAll(handleComplexType); } else if (next.isSimple()) { SimpleType simpleType = (SimpleType) next; List<ProtoMessageTag> handleSimpleType = handleSimpleType(simpleType); result.addAll(handleSimpleType); } else if (next instanceof GroupType) { GroupType groupType = (GroupType) next; List<ProtoMessageTag> handleGroup = handleGroup(groupType); result.addAll(handleGroup); } else if (next instanceof AttributeGroupType) { AttributeGroupType attributeGroupType = (AttributeGroupType) next; List<ProtoMessageTag> handleAttributeGroup = handleAttributeGroup(attributeGroupType); result.addAll(handleAttributeGroup); } else if (next instanceof Attribute) { Attribute attribute = (Attribute) next; List<Attribute> attributes = new ArrayList<Attribute>(); attributes.add(attribute); List<ProtoMessageTag> handleAttributes = handleAttributes(attributes); result.addAll(handleAttributes); } else if (next.isElement()) { ElementType elementType = (ElementType) next; List<ProtoMessageTag> handleElement = handleElement(elementType); result.addAll(handleElement); } nestedLevel--; return result; } private List<ProtoMessageTag> handleAttributeGroup(AttributeGroupType attributeGroupType) { if (attributeGroupType == null) { return S_EMPTY_LIST; } List<ProtoMessageTag> result = new ArrayList<ProtoMessageTag>(); List<AttributeGroup> attributeGroups = attributeGroupType.getAttributeGroups(); for (AttributeGroup group : attributeGroups) { QName groupRef = group.getGroupRef(); SchemaType schemaType = groupMap.get(groupRef); List<ProtoMessageTag> handleSchemaType = handleSchemaType(schemaType); result.addAll(handleSchemaType); } List<Attribute> attributes = attributeGroupType.getAttributes(); List<ProtoMessageTag> handleAttributes = handleAttributes(attributes); result.addAll(handleAttributes); return result; } private List<ProtoMessageTag> handleAttributes(List<Attribute> attributes) { List<ProtoMessageTag> result = new ArrayList<ProtoMessageTag>(); for (Attribute attribute : attributes) { QName attributeRef = attribute.getAttributeRef(); if (attributeRef != null) { SchemaType schemaType = attributeMap.get(attributeRef); AttributeUse use = attribute.getUse(); if (use == AttributeUse.REQUIRED) { refMinOccurs = 1; } else if (use == AttributeUse.OPTIONAL) { refMinOccurs = 0; } else if (use == AttributeUse.PROHIBHITED) { return result; } List<ProtoMessageTag> handleSchemaType = handleSchemaType(schemaType); result.addAll(handleSchemaType); } else { String nameToUse = attribute.getValueType().getLocalPart(); String attributeName = attribute.getAttributeName(); String currentTypeName = currentType.toString(); AttributeUse use = attribute.getUse(); if (use == AttributeUse.PROHIBHITED) { continue; } if (refMinOccurs >= 1) { use = AttributeUse.REQUIRED; refMinOccurs = Integer.MIN_VALUE; } ProtoMessageTag messageTag = new ProtoMessageTag(currentTypeName, "@" + attributeName, nameToUse); QName valueType = attribute.getValueType(); if (valueType.getLocalPart().equals("NMTOKENS")) { messageTag.setRequired(true); } if (use == AttributeUse.REQUIRED) { messageTag.setRequired(true); } SchemaType schemaType = schemaMap.get(valueType); if(schemaType instanceof SimpleType) { SimpleType simpleType = (SimpleType)schemaType; boolean simpleTypeList = isSimpleTypeList(simpleType); if(simpleTypeList) { messageTag.setRepeating(true); } } result.add(messageTag); } } return result; } private List<ProtoMessageTag> handleGroup(GroupType groupType) { List<ProtoMessageTag> result = new ArrayList<ProtoMessageTag>(); Choice choice = groupType.getChoice(); Sequence sequence = groupType.getSequence(); SchemaAll all = groupType.getAll(); List<ProtoMessageTag> handleChoice = handleChoice(choice); List<ProtoMessageTag> handleSequence = handleSequence(sequence); List<ProtoMessageTag> handleAll = handleAll(all); result.addAll(handleChoice); result.addAll(handleSequence); result.addAll(handleAll); return result; } private List<ProtoMessageTag> handleElement(ElementType elementType) { currentElementType = elementType; QName ref = elementType.getRef(); QName typeNameToUse = elementType.getElementType(); if (ref != null) { SchemaType schemaType = elementMap.get(ref); typeNameToUse = schemaType.getTypeName(); } List<ProtoMessageTag> result = new ArrayList<ProtoMessageTag>(); ComplexType complexType = elementType.getComplexType(); SimpleType simpleType = elementType.getSimpleType(); List<ProtoMessageTag> handleComplexType = handleComplexType(complexType); List<ProtoMessageTag> handleSimpleType = handleSimpleType(simpleType); result.addAll(handleSimpleType); result.addAll(handleComplexType); if (typeNameToUse == null) { typeNameToUse = currentElementType.getTypeName(); if (typeNameToUse == null) { typeNameToUse = currentType; } } String nameToUse = typeNameToUse.getLocalPart(); QName typeName = elementType.getTypeName(); String currentTypeQName = currentType.toString(); if (typeName == null) { typeName = typeNameToUse; } String localPart = typeName.getLocalPart(); ProtoMessageTag messageTag = null; boolean isTopLevel = (nestedLevel==1); if (isTopLevel) { return result; } messageTag = new ProtoMessageTag(currentTypeQName, localPart, nameToUse); int minOccurs = elementType.getMinOccurs(); int maxOccurs = elementType.getMaxOccurs(); minOccurs = refMinOccurs == Integer.MIN_VALUE ? minOccurs : refMinOccurs; maxOccurs = refMaxOccurs == Integer.MAX_VALUE ? maxOccurs : refMaxOccurs; ProtoMessageModifier messageModifier = ProtoMessageModifier.fromBounds(minOccurs, maxOccurs); if (!choiceStack.empty()) { switch (messageModifier) { case REPEATED: { messageTag.setRepeating(true); break; } } } else { switch (messageModifier) { case REPEATED: { messageTag.setRepeating(true); break; } case REQUIRED: { messageTag.setRequired(true); break; } } } String localPart2 = typeNameToUse.getLocalPart(); if (localPart2.equals("NMTOKENS")) { messageTag.setRepeating(true); } if (isSimpleTypeList(simpleType)) { messageTag.setRepeating(true); } SchemaType schemaType = schemaMap.get(typeNameToUse); if (schemaType instanceof SimpleType) { SimpleType type = (SimpleType) schemaType; if (isSimpleTypeList(type)) { messageTag.setRepeating(true); } } if (currentAllOccurs == 0) { messageTag.setRepeating(false); messageTag.setRequired(false); } if (!(messageModifier == ProtoMessageModifier.DO_NOT_ASSIGN)) { result.add(messageTag); } return result; } private List<ProtoMessageTag> handleSimpleType(SimpleType simpleType) { if (simpleType == null) { return S_EMPTY_LIST; } List<ProtoMessageTag> list = new ArrayList<ProtoMessageTag>(); // TODO duplicated logic QName typeName = simpleType.getTypeName(); if (typeName == null) { typeName = currentType; } SimpleTypeList list2 = simpleType.getList(); if (list2 != null) { return S_EMPTY_LIST; } SimpleTypeRestriction restriction = simpleType.getRestriction(); List<ProtoMessageTag> handleSimpleRestriction = handleSimpleRestriction(restriction); list.addAll(handleSimpleRestriction); return list; } private List<ProtoMessageTag> handleComplexType(ComplexType complexType) { if (complexType == null) { return S_EMPTY_LIST; } List<ProtoMessageTag> result = new ArrayList<ProtoMessageTag>(); Sequence sequence = complexType.getSequence(); Choice choice = complexType.getChoice(); List<AttributeGroup> attributeGroup = complexType.getAttributeGroup(); List<Attribute> attributes = complexType.getAttributes(); Group group2 = complexType.getGroup(); SchemaAll complexAll = complexType.getAll(); List<ProtoMessageTag> complexHandleAll = handleAll(complexAll); result.addAll(complexHandleAll); List<ProtoMessageTag> handleGroup = handleGroup(group2); result.addAll(handleGroup); for (AttributeGroup attGroup : attributeGroup) { QName attGroupRef = attGroup.getGroupRef(); SchemaType schemaType = attributeGroupMap.get(attGroupRef); List<ProtoMessageTag> handleSchemaType = handleSchemaType(schemaType); result.addAll(handleSchemaType); } List<ProtoMessageTag> handleSequence = handleSequence(sequence); List<ProtoMessageTag> handleChoice = handleChoice(choice); List<ProtoMessageTag> handleAttributes = handleAttributes(attributes); result.addAll(handleAttributes); result.addAll(handleSequence); result.addAll(handleChoice); ComplexContent complexContent = complexType.getComplexContent(); if (complexContent != null) { Extension extension = complexContent.getExtension(); if (extension != null) { List<ProtoMessageTag> handleExtension = handleExtension(extension); result.addAll(handleExtension); } Restriction restriction = complexContent.getRestriction(); if (restriction != null) { QName base = restriction.getBase(); SchemaType schemaType = schemaMap.get(base); List<ProtoMessageTag> handleSchemaType = handleSchemaType(schemaType); result.addAll(handleSchemaType); SchemaAll all = restriction.getAll(); List<ProtoMessageTag> handleAll = handleAll(all); result.addAll(handleAll); } } SimpleContent simpleContent = complexType.getSimpleContent(); if (simpleContent != null) { SimpleContentExtension extension = simpleContent.getExtension(); SimpleTypeRestriction restriction = simpleContent.getRestriction(); // TODO: Duplicate code here ? if (extension != null) { QName base = extension.getBase(); // Skip handling simple type enumerations. They are not part of // the message SchemaType schemaType2 = schemaMap.get(base); boolean skipHandling = false; if (schemaType2 instanceof SimpleType) { SimpleType testType = (SimpleType) schemaType2; SimpleTypeRestriction restriction2 = testType.getRestriction(); if (restriction2 != null) { List<RestrictionEnumeration> enumerations = restriction2.getEnumerations(); if (enumerations != null) { skipHandling = true; } } } if (!skipHandling) { List<ProtoMessageTag> handleSchemaType2 = handleSchemaType(schemaType2); result.addAll(handleSchemaType2); } String parent = getParent(base); if (parent != null) { ProtoMessageTag valueTag = getValueTag(currentType.toString(), parent); if (!result.contains(valueTag)) { result.add(valueTag); } } List<AttributeGroup> attributeGroups = extension.getAttributeGroups(); for (AttributeGroup group : attributeGroups) { QName groupRef = group.getGroupRef(); SchemaType schemaType = attributeGroupMap.get(groupRef); List<ProtoMessageTag> handleSchemaType = handleSchemaType(schemaType); result.addAll(handleSchemaType); } List<Attribute> attributes2 = extension.getAttributes(); List<ProtoMessageTag> handleSimpleAttributes = handleAttributes(attributes2); result.addAll(handleSimpleAttributes); } if (restriction != null) { List<ProtoMessageTag> handleSimpleRestriction = handleSimpleRestriction(restriction); result.addAll(handleSimpleRestriction); } } return result; } private List<ProtoMessageTag> handleExtension(Extension extension) { List<ProtoMessageTag> result = new ArrayList<ProtoMessageTag>(); QName base = extension.getBase(); SchemaType schemaType2 = schemaMap.get(base); List<ProtoMessageTag> handleSchemaType2 = handleSchemaType(schemaType2); result.addAll(handleSchemaType2); Sequence extensionSequence = extension.getSequence(); Group extensionGroup = extension.getGroup(); Choice choice = extension.getChoice(); List<AttributeGroup> attributeGroups = extension.getAttributeGroup(); List<Attribute> attributeList = extension.getAttributeList(); SchemaAll all = extension.getAll(); for (AttributeGroup attributeGroup : attributeGroups) { QName groupRef = attributeGroup.getGroupRef(); SchemaType schemaType = attributeGroupMap.get(groupRef); List<ProtoMessageTag> handleSchemaType = handleSchemaType(schemaType); result.addAll(handleSchemaType); } List<ProtoMessageTag> handleAttributes = handleAttributes(attributeList); List<ProtoMessageTag> handleSequence = handleSequence(extensionSequence); List<ProtoMessageTag> handleChoice = handleChoice(choice); List<ProtoMessageTag> handleGroup = handleGroup(extensionGroup); List<ProtoMessageTag> handleAll = handleAll(all); result.addAll(handleAttributes); result.addAll(handleChoice); result.addAll(handleSequence); result.addAll(handleGroup); result.addAll(handleAll); return result; } private List<ProtoMessageTag> handleSequence(Sequence sequence) { List<ProtoMessageTag> result = new ArrayList<ProtoMessageTag>(); if (sequence != null) { List<SequenceEntry> entries = sequence.getEntries(); for (SequenceEntry entry : entries) { if (entry.isElement()) { SequenceElement element = entry.getElement(); List<ProtoMessageTag> handleSchemaType = handleSchemaType(element); result.addAll(handleSchemaType); } else if (entry.isChoice()) { Choice choice = entry.getChoice(); List<ProtoMessageTag> handleChoice = handleChoice(choice); result.addAll(handleChoice); } else if (entry.isGroup()) { Group group = entry.getGroup(); List<ProtoMessageTag> handleGroup = handleGroup(group); result.addAll(handleGroup); } else if (entry.isSequence()) { Sequence internalSequence = entry.getSequence(); List<ProtoMessageTag> handleSequence = handleSequence(internalSequence); result.addAll(handleSequence); } } } return result; } private List<ProtoMessageTag> handleChoice(Choice choice) { if (choice == null) { return S_EMPTY_LIST; } choiceStack.push(1); List<ProtoMessageTag> result = new ArrayList<ProtoMessageTag>(); List<SequenceElement> elements = choice.getElements(); for (SequenceElement element : elements) { List<ProtoMessageTag> handleSchemaType = handleSchemaType(element); result.addAll(handleSchemaType); } List<Group> groups = choice.getGroups(); List<Sequence> sequences = choice.getSequences(); List<Choice> choices = choice.getChoices(); for (Group group : groups) { List<ProtoMessageTag> handleGroup = handleGroup(group); result.addAll(handleGroup); } for (Sequence sequence : sequences) { List<ProtoMessageTag> handleSequence = handleSequence(sequence); result.addAll(handleSequence); } for (Choice internalChoice : choices) { List<ProtoMessageTag> handleChoice = handleChoice(internalChoice); result.addAll(handleChoice); } choiceStack.pop(); return result; } private List<ProtoMessageTag> handleGroup(Group group) { if (group == null) { return S_EMPTY_LIST; } QName groupRef = group.getGroupRef(); SchemaType schemaType = groupMap.get(groupRef); List<ProtoMessageTag> result = handleSchemaType(schemaType); return result; } private List<ProtoMessageTag> handleSimpleRestriction(SimpleTypeRestriction restriction) { if (restriction == null) { return S_EMPTY_LIST; } List<ProtoMessageTag> result = new ArrayList<ProtoMessageTag>(); QName base = restriction.getBase(); String localPart = base.getLocalPart(); SchemaType schemaType = schemaMap.get(base); List<ProtoMessageTag> handleSchemaType = handleSchemaType(schemaType); result.addAll(handleSchemaType); List<RestrictionEnumeration> enumerations = restriction.getEnumerations(); boolean isRestriction = enumerations.size() > 0; for (RestrictionEnumeration restrictionEnumeration : enumerations) { String enumValue = restrictionEnumeration.getEnumValue(); ProtoMessageTag messageTag = new ProtoMessageTag(currentType.toString(), enumValue, localPart); result.add(messageTag); } if (!isRestriction) { String parent = getParent(base); if (parent != null) { ProtoMessageTag valueTag = getValueTag(currentType.toString(), parent); if (!result.contains(valueTag)) { result.add(valueTag); } } // TODO duplicate code } return result; } private ProtoMessageTag getValueTag(String typeName, String elementType) { ProtoMessageTag messageTag = new ProtoMessageTag(typeName, "value", elementType); messageTag.setSystemType(true); return messageTag; } private String getParent(QName type) { String result = type.getLocalPart(); SchemaType schemaType = schemaMap.get(type); while (schemaType != null) { if (schemaType instanceof SimpleType) { SimpleType simpleType = (SimpleType) schemaType; SimpleTypeRestriction restriction = simpleType.getRestriction(); if (restriction != null) { // Enum restrictions should not allow further drill downs List<RestrictionEnumeration> enumerations = restriction.getEnumerations(); if (enumerations != null && enumerations.size() > 0) { return simpleType.getTypeName().getLocalPart(); } QName base = restriction.getBase(); result = base.getLocalPart(); schemaType = schemaMap.get(base); } else { result = schemaType.getTypeName().getLocalPart(); schemaType = null; } } else { schemaType = null; result = null; } } return result; } private List<ProtoMessageTag> handleAll(SchemaAll all) { if (all == null) { return S_EMPTY_LIST; } int minOccurs = all.getMinOccurs(); currentAllOccurs = minOccurs; List<ProtoMessageTag> result = new ArrayList<ProtoMessageTag>(); List<SequenceElement> elements = all.getElements(); for (SequenceElement element : elements) { List<ProtoMessageTag> handleSchemaType = handleSchemaType(element); result.addAll(handleSchemaType); } currentAllOccurs = -1; return result; } private boolean isSimpleTypeList(SimpleType simpleType) { if (simpleType != null) { SimpleTypeList list = simpleType.getList(); if (list != null) { return true; } } return false; } }