/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.module.extension.internal.capability.xml.schema.builder;
import static java.lang.String.format;
import static java.math.BigInteger.ONE;
import static java.math.BigInteger.ZERO;
import static org.mule.runtime.extension.api.util.ExtensionMetadataTypeUtils.getId;
import static org.mule.runtime.extension.api.util.ExtensionMetadataTypeUtils.isMap;
import static org.mule.runtime.config.spring.dsl.api.xml.SchemaConstants.MAX_ONE;
import static org.mule.runtime.config.spring.dsl.api.xml.SchemaConstants.UNBOUNDED;
import org.mule.metadata.api.model.ArrayType;
import org.mule.metadata.api.model.MetadataType;
import org.mule.metadata.api.model.ObjectType;
import org.mule.metadata.api.visitor.MetadataTypeVisitor;
import org.mule.runtime.extension.api.dsl.syntax.DslElementSyntax;
import org.mule.runtime.module.extension.internal.capability.xml.schema.model.ComplexType;
import org.mule.runtime.module.extension.internal.capability.xml.schema.model.ExplicitGroup;
import org.mule.runtime.module.extension.internal.capability.xml.schema.model.LocalComplexType;
import org.mule.runtime.module.extension.internal.capability.xml.schema.model.ObjectFactory;
import org.mule.runtime.module.extension.internal.capability.xml.schema.model.TopLevelElement;
import java.util.List;
/**
* Builder delegation class to generate an XSD schema that describes an {@link ArrayType}
*
* @since 4.0.0
*/
class CollectionSchemaDelegate {
private final ObjectFactory objectFactory = new ObjectFactory();
private final SchemaBuilder builder;
CollectionSchemaDelegate(SchemaBuilder builder) {
this.builder = builder;
}
void generateCollectionElement(ArrayType metadataType, DslElementSyntax collectionDsl, String description, boolean required,
List<TopLevelElement> all) {
LocalComplexType collectionComplexType = generateCollectionComplexType(collectionDsl, metadataType);
TopLevelElement collectionElement = builder.createTopLevelElement(collectionDsl.getElementName(),
required ? ONE : ZERO,
MAX_ONE);
collectionElement.setAnnotation(builder.createDocAnnotation(description));
collectionElement.setComplexType(collectionComplexType);
all.add(collectionElement);
}
private LocalComplexType generateCollectionComplexType(DslElementSyntax collectionDsl, final ArrayType metadataType) {
final LocalComplexType collectionComplexType = new LocalComplexType();
final ExplicitGroup sequence = new ExplicitGroup();
final MetadataType genericType = metadataType.getType();
DslElementSyntax itemDsl = collectionDsl.getGeneric(genericType)
.orElseThrow(() -> new IllegalArgumentException(format("Missing item's DSL information for collection [%s]",
collectionDsl.getAttributeName())));
genericType.accept(new MetadataTypeVisitor() {
/**
* For a Collection with an {@link ObjectType} as generic. The generated {@link ComplexType} declares a sequence of either a
* {@code ref} or a {@code choice}.
* <p/>
* It creates an element {@code ref} to the concrete element whose {@code type} is the {@link ComplexType} associated to the
* {@code objectType}
* <p/>
* In the case of having a {@link DslElementSyntax#isWrapped wrapped} {@link ObjectType}, then a {@link ExplicitGroup
* Choice} group that can receive a {@code ref} to any subtype that this wrapped type might have, be it either a top-level
* element for the mule schema, or if it can only be declared as child of this element.
*
* If the collections's value is a map, then a value attribute is created for the value map.
*
* @param objectType the item's type
*/
@Override
public void visitObject(ObjectType objectType) {
if (isMap(objectType)) {
defaultVisit(objectType);
return;
}
DslElementSyntax typeDsl = builder.getDslResolver().resolve(objectType)
.orElseThrow(() -> new IllegalArgumentException(format("The given type [%s] cannot be represented as a collection item",
getId(objectType))));
if (typeDsl.isWrapped()) {
ExplicitGroup choice = builder.createTypeRefChoiceLocalOrGlobal(typeDsl, objectType, ZERO, UNBOUNDED);
sequence.getParticle().add(objectFactory.createChoice(choice));
} else {
TopLevelElement collectionItemElement = builder.createTypeRef(typeDsl, objectType, false);
collectionItemElement.setMaxOccurs(UNBOUNDED);
sequence.getParticle().add(objectFactory.createElement(collectionItemElement));
}
}
/**
* For a Collection with any other type as generic.
* The generated {@link ComplexType} declares a sequence of child elements with an inline declaration of the type
*
* @param metadataType the item's type
*/
@Override
protected void defaultVisit(MetadataType metadataType) {
final LocalComplexType complexType = new LocalComplexType();
complexType.getAttributeOrAttributeGroup().add(builder.createValueAttribute(genericType));
TopLevelElement collectionItemElement =
builder.createTopLevelElement(itemDsl.getElementName(), ZERO, UNBOUNDED);
collectionItemElement.setComplexType(complexType);
sequence.getParticle().add(objectFactory.createElement(collectionItemElement));
}
});
collectionComplexType.setSequence(sequence);
return collectionComplexType;
}
}