/* * 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.config.spring.dsl.declaration; import static com.google.common.base.Preconditions.checkArgument; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; import static org.mule.metadata.api.utils.MetadataTypeUtils.getLocalPart; import static org.mule.runtime.api.app.declaration.fluent.ElementDeclarer.forExtension; import static org.mule.runtime.api.app.declaration.fluent.ElementDeclarer.newFlow; import static org.mule.runtime.api.app.declaration.fluent.ElementDeclarer.newObjectValue; import static org.mule.runtime.api.app.declaration.fluent.ParameterSimpleValue.cdata; import static org.mule.runtime.api.app.declaration.fluent.ParameterSimpleValue.plain; import static org.mule.runtime.api.i18n.I18nMessageFactory.createStaticMessage; import static org.mule.runtime.config.spring.XmlConfigurationDocumentLoader.noValidationDocumentLoader; import static org.mule.runtime.config.spring.dsl.processor.xml.XmlCustomAttributeHandler.IS_CDATA; import static org.mule.runtime.deployment.model.internal.application.MuleApplicationClassLoader.resolveContextArtifactPluginClassLoaders; import static org.mule.runtime.extension.api.ExtensionConstants.DISABLE_CONNECTION_VALIDATION_PARAMETER_NAME; import static org.mule.runtime.extension.api.ExtensionConstants.POOLING_PROFILE_PARAMETER_NAME; import static org.mule.runtime.extension.api.ExtensionConstants.RECONNECTION_STRATEGY_PARAMETER_NAME; import static org.mule.runtime.extension.api.ExtensionConstants.REDELIVERY_POLICY_PARAMETER_NAME; import static org.mule.runtime.extension.api.ExtensionConstants.STREAMING_STRATEGY_PARAMETER_NAME; import static org.mule.runtime.extension.api.ExtensionConstants.TLS_PARAMETER_NAME; import static org.mule.runtime.extension.api.declaration.type.StreamingStrategyTypeBuilder.NON_REPEATABLE_BYTE_STREAM_ALIAS; import static org.mule.runtime.extension.api.declaration.type.StreamingStrategyTypeBuilder.REPEATABLE_FILE_STORE_BYTES_STREAM_ALIAS; import static org.mule.runtime.extension.api.declaration.type.StreamingStrategyTypeBuilder.REPEATABLE_IN_MEMORY_BYTES_STREAM_ALIAS; import static org.mule.runtime.extension.api.util.ExtensionMetadataTypeUtils.isMap; import static org.mule.runtime.extension.api.util.ExtensionModelUtils.isInfrastructure; import static org.mule.runtime.extension.internal.dsl.syntax.DslSyntaxUtils.getId; import static org.mule.runtime.extension.internal.dsl.syntax.DslSyntaxUtils.isExtensible; import static org.mule.runtime.internal.dsl.DslConstants.CONFIG_ATTRIBUTE_NAME; import static org.mule.runtime.internal.dsl.DslConstants.CORE_PREFIX; import static org.mule.runtime.internal.dsl.DslConstants.EE_PREFIX; import static org.mule.runtime.internal.dsl.DslConstants.FLOW_ELEMENT_IDENTIFIER; import static org.mule.runtime.internal.dsl.DslConstants.KEY_ATTRIBUTE_NAME; import static org.mule.runtime.internal.dsl.DslConstants.NAME_ATTRIBUTE_NAME; import static org.mule.runtime.internal.dsl.DslConstants.POOLING_PROFILE_ELEMENT_IDENTIFIER; import static org.mule.runtime.internal.dsl.DslConstants.RECONNECT_ELEMENT_IDENTIFIER; import static org.mule.runtime.internal.dsl.DslConstants.RECONNECT_FOREVER_ELEMENT_IDENTIFIER; import static org.mule.runtime.internal.dsl.DslConstants.REDELIVERY_POLICY_ELEMENT_IDENTIFIER; import static org.mule.runtime.internal.dsl.DslConstants.TLS_CONTEXT_ELEMENT_IDENTIFIER; import static org.mule.runtime.internal.dsl.DslConstants.VALUE_ATTRIBUTE_NAME; 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.api.app.declaration.ArtifactDeclaration; import org.mule.runtime.api.app.declaration.ComponentElementDeclaration; import org.mule.runtime.api.app.declaration.ParameterValue; import org.mule.runtime.api.app.declaration.RouteElementDeclaration; import org.mule.runtime.api.app.declaration.fluent.ArtifactDeclarer; import org.mule.runtime.api.app.declaration.fluent.ComponentElementDeclarer; import org.mule.runtime.api.app.declaration.fluent.ConfigurationElementDeclarer; import org.mule.runtime.api.app.declaration.fluent.ConnectionElementDeclarer; import org.mule.runtime.api.app.declaration.fluent.ElementDeclarer; import org.mule.runtime.api.app.declaration.fluent.FlowElementDeclarer; import org.mule.runtime.api.app.declaration.fluent.ParameterListValue; import org.mule.runtime.api.app.declaration.fluent.ParameterObjectValue; import org.mule.runtime.api.app.declaration.fluent.ParameterSimpleValue; import org.mule.runtime.api.app.declaration.fluent.ParameterizedBuilder; import org.mule.runtime.api.app.declaration.fluent.RouteElementDeclarer; import org.mule.runtime.api.app.declaration.fluent.RouterElementDeclarer; import org.mule.runtime.api.app.declaration.fluent.ScopeElementDeclarer; import org.mule.runtime.api.app.declaration.fluent.TopLevelParameterDeclarer; import org.mule.runtime.api.dsl.DslResolvingContext; import org.mule.runtime.api.exception.MuleRuntimeException; import org.mule.runtime.api.meta.model.ComponentModel; import org.mule.runtime.api.meta.model.ExtensionModel; import org.mule.runtime.api.meta.model.config.ConfigurationModel; import org.mule.runtime.api.meta.model.connection.ConnectionProviderModel; import org.mule.runtime.api.meta.model.operation.HasOperationModels; import org.mule.runtime.api.meta.model.operation.OperationModel; import org.mule.runtime.api.meta.model.operation.RouteModel; import org.mule.runtime.api.meta.model.operation.RouterModel; import org.mule.runtime.api.meta.model.operation.ScopeModel; import org.mule.runtime.api.meta.model.parameter.ParameterGroupModel; import org.mule.runtime.api.meta.model.parameter.ParameterModel; import org.mule.runtime.api.meta.model.parameter.ParameterizedModel; import org.mule.runtime.api.meta.model.source.HasSourceModels; import org.mule.runtime.api.meta.model.source.SourceModel; import org.mule.runtime.api.meta.model.util.ExtensionWalker; import org.mule.runtime.api.util.Reference; import org.mule.runtime.config.spring.dsl.model.XmlArtifactDeclarationLoader; import org.mule.runtime.config.spring.dsl.processor.ConfigLine; import org.mule.runtime.config.spring.dsl.processor.SimpleConfigAttribute; import org.mule.runtime.config.spring.dsl.processor.xml.XmlApplicationParser; import org.mule.runtime.config.spring.dsl.processor.xml.XmlApplicationServiceRegistry; import org.mule.runtime.core.registry.SpiServiceRegistry; import org.mule.runtime.extension.api.dsl.syntax.DslElementSyntax; import org.mule.runtime.extension.api.dsl.syntax.resolver.DslSyntaxResolver; import java.io.InputStream; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; import org.w3c.dom.Document; /** * Default implementation of a {@link XmlArtifactDeclarationLoader} * * @since 4.0 */ public class DefaultXmlArtifactDeclarationLoader implements XmlArtifactDeclarationLoader { public static final String TRANSFORM_IDENTIFIER = "transform"; public static final String TRANSFORMER_SET_VARIABLE = "SetVariables"; public static final String TRANSFORMER_GENERAL = "General"; public static final String SCRIPT = "script"; private final DslResolvingContext context; private final Map<ExtensionModel, DslSyntaxResolver> resolvers; private final Map<String, ExtensionModel> extensionsByNamespace = new HashMap<>(); public DefaultXmlArtifactDeclarationLoader(DslResolvingContext context) { this.context = context; this.resolvers = context.getExtensions().stream() .collect(toMap(e -> e, e -> DslSyntaxResolver.getDefault(e, context))); } /** * {@inheritDoc} */ @Override public ArtifactDeclaration load(InputStream configResource) { return load("app.xml", configResource); } /** * {@inheritDoc} */ @Override public ArtifactDeclaration load(String name, InputStream configResource) { context.getExtensions().forEach(e -> extensionsByNamespace.put(e.getXmlDslModel().getPrefix(), e)); ConfigLine configLine = loadArtifactConfig(name, configResource); return declareArtifact(configLine); } private ConfigLine loadArtifactConfig(String name, InputStream resource) { checkArgument(resource != null, "The given application was not found as resource"); Document document = noValidationDocumentLoader().loadDocument(context.getExtensions(), name, resource); return new XmlApplicationParser(new XmlApplicationServiceRegistry(new SpiServiceRegistry(), context), resolveContextArtifactPluginClassLoaders()).parse(document.getDocumentElement()) .orElseThrow(() -> new MuleRuntimeException(createStaticMessage("Could not load load a Configuration from the given resource"))); } private ArtifactDeclaration declareArtifact(ConfigLine configLine) { ArtifactDeclarer artifactDeclarer = ElementDeclarer.newArtifact(); configLine.getConfigAttributes().values().forEach(a -> artifactDeclarer.withCustomParameter(a.getName(), a.getValue())); configLine.getChildren().forEach(line -> declareElement(line, artifactDeclarer)); return artifactDeclarer.getDeclaration(); } private void declareElement(ConfigLine configLine, ArtifactDeclarer artifactDeclarer) { if (configLine.getIdentifier().equals(FLOW_ELEMENT_IDENTIFIER)) { declareFlow(configLine, artifactDeclarer); } else { declareCustomGlobalElement(configLine, artifactDeclarer); } } private void declareCustomGlobalElement(final ConfigLine configLine, final ArtifactDeclarer artifactDeclarer) { final ExtensionModel ownerExtension = getExtensionModel(configLine); final ElementDeclarer extensionElementsDeclarer = forExtension(ownerExtension.getName()); final DslSyntaxResolver dsl = resolvers.get(ownerExtension); Reference<Boolean> alreadyDeclared = new Reference<>(false); new ExtensionWalker() { @Override protected void onConfiguration(ConfigurationModel model) { final DslElementSyntax elementDsl = dsl.resolve(model); if (elementDsl.getElementName().equals(configLine.getIdentifier())) { ConfigurationElementDeclarer configurationDeclarer = extensionElementsDeclarer.newConfiguration(model.getName()); configurationDeclarer.withRefName(getDeclaredName(configLine)); Map<String, SimpleConfigAttribute> attributes = configLine.getConfigAttributes().values().stream() .filter(a -> !a.getName().equals(NAME_ATTRIBUTE_NAME)) .collect(toMap(SimpleConfigAttribute::getName, a -> a)); List<ConfigLine> configComplexParameters = configLine.getChildren().stream() .filter(config -> declareAsConnectionProvider(ownerExtension, model, configurationDeclarer, config)) .collect(toList()); declareParameterizedComponent(model, elementDsl, configurationDeclarer, attributes, configComplexParameters); artifactDeclarer.withGlobalElement(configurationDeclarer.getDeclaration()); alreadyDeclared.set(true); stop(); } } private boolean declareAsConnectionProvider(ExtensionModel ownerExtension, ConfigurationModel model, ConfigurationElementDeclarer configurationDeclarer, ConfigLine config) { Optional<ConnectionProviderModel> connectionProvider = model.getConnectionProviders().stream() .filter(cp -> dsl.resolve(cp).getElementName().equals(config.getIdentifier())) .findFirst(); if (!connectionProvider.isPresent()) { connectionProvider = ownerExtension.getConnectionProviders().stream() .filter(cp -> dsl.resolve(cp).getElementName().equals(config.getIdentifier())) .findFirst(); } if (!connectionProvider.isPresent()) { return true; } ConnectionProviderModel providerModel = connectionProvider.get(); ConnectionElementDeclarer connectionDeclarer = extensionElementsDeclarer.newConnection(providerModel.getName()); declareParameterizedComponent(providerModel, dsl.resolve(providerModel), connectionDeclarer, config.getConfigAttributes(), config.getChildren()); configurationDeclarer.withConnection(connectionDeclarer.getDeclaration()); return false; } }.walk(ownerExtension); if (!alreadyDeclared.get()) { ownerExtension.getTypes().stream() .filter(type -> dsl.resolve(type).map(typeDsl -> typeDsl.getElementName().equals(configLine.getIdentifier())) .orElse(false)) .findFirst() .ifPresent(type -> { TopLevelParameterDeclarer topLevelParameter = extensionElementsDeclarer .newGlobalParameter(configLine.getIdentifier()) .withRefName(getDeclaredName(configLine)); type.accept(getParameterDeclarerVisitor(configLine, dsl.resolve(type).get(), value -> topLevelParameter.withValue((ParameterObjectValue) value))); artifactDeclarer.withGlobalElement(topLevelParameter.getDeclaration()); }); } } private String getDeclaredName(ConfigLine configLine) { return configLine.getConfigAttributes().get(NAME_ATTRIBUTE_NAME).getValue(); } private void declareFlow(ConfigLine configLine, ArtifactDeclarer artifactDeclarer) { final FlowElementDeclarer flow = newFlow().withRefName(getDeclaredName(configLine)); copyExplicitAttributes(configLine.getConfigAttributes(), flow); configLine.getChildren().forEach(line -> { final ExtensionModel ownerExtension = getExtensionModel(line); final ElementDeclarer extensionElementsDeclarer = forExtension(ownerExtension.getName()); final DslSyntaxResolver dsl = resolvers.get(ownerExtension); getComponentDeclaringWalker(flow::withComponent, line, extensionElementsDeclarer, dsl).walk(ownerExtension); }); artifactDeclarer.withGlobalElement(flow.getDeclaration()); } private ExtensionModel getExtensionModel(ConfigLine line) { String namespace = getNamespace(line); ExtensionModel extensionModel = extensionsByNamespace.get(namespace); // TODO EE-5398: Create EE ExtensionModel if (extensionModel == null && EE_PREFIX.equals(namespace)) { extensionModel = extensionsByNamespace.get(CORE_PREFIX); } if (extensionModel == null) { throw new MuleRuntimeException(createStaticMessage("Missing Extension model in the context for namespace [" + namespace + "]")); } return extensionModel; } private ExtensionWalker getComponentDeclaringWalker(final Consumer<ComponentElementDeclaration> declarationConsumer, final ConfigLine line, final ElementDeclarer extensionElementsDeclarer, final DslSyntaxResolver dsl) { return new ExtensionWalker() { @Override protected void onOperation(HasOperationModels owner, OperationModel model) { if (!model.getName().equals(TRANSFORM_IDENTIFIER)) { final DslElementSyntax elementDsl = dsl.resolve(model); if (elementDsl.getElementName().equals(line.getIdentifier())) { ComponentElementDeclarer declarer = extensionElementsDeclarer.newOperation(model.getName()); if (line.getConfigAttributes().get(CONFIG_ATTRIBUTE_NAME) != null) { declarer.withConfig(line.getConfigAttributes().get(CONFIG_ATTRIBUTE_NAME).getValue()); } declareParameterizedComponent(model, elementDsl, declarer, line.getConfigAttributes(), line.getChildren()); declarationConsumer.accept((ComponentElementDeclaration) declarer.getDeclaration()); stop(); } } else { declareTransform(model, e -> e.newOperation(model.getName())); } } @Override protected void onSource(HasSourceModels owner, SourceModel model) { final DslElementSyntax elementDsl = dsl.resolve(model); if (elementDsl.getElementName().equals(line.getIdentifier())) { ComponentElementDeclarer declarer = extensionElementsDeclarer.newSource(model.getName()); if (line.getConfigAttributes().get(CONFIG_ATTRIBUTE_NAME) != null) { declarer.withConfig(line.getConfigAttributes().get(CONFIG_ATTRIBUTE_NAME).getValue()); } declareParameterizedComponent(model, elementDsl, declarer, line.getConfigAttributes(), line.getChildren()); model.getSuccessCallback() .ifPresent(cb -> declareParameterizedComponent(cb, elementDsl, declarer, line.getConfigAttributes(), line.getChildren())); model.getErrorCallback() .ifPresent(cb -> declareParameterizedComponent(cb, elementDsl, declarer, line.getConfigAttributes(), line.getChildren())); declarationConsumer.accept((ComponentElementDeclaration) declarer.getDeclaration()); stop(); } } @Override protected void onScope(HasOperationModels owner, ScopeModel model) { final DslElementSyntax elementDsl = dsl.resolve(model); if (elementDsl.getElementName().equals(line.getIdentifier())) { ScopeElementDeclarer scope = extensionElementsDeclarer.newScope(model.getName()); if (line.getConfigAttributes().get(CONFIG_ATTRIBUTE_NAME) != null) { scope.withConfig(line.getConfigAttributes().get(CONFIG_ATTRIBUTE_NAME).getValue()); } declareParameterizedComponent(model, elementDsl, scope, line.getConfigAttributes(), line.getChildren()); line.getChildren().forEach(child -> { ExtensionModel extensionModel = getExtensionModel(child); getComponentDeclaringWalker(scope::withComponent, child, forExtension(extensionModel.getName()), dsl) .walk(extensionModel); }); declarationConsumer.accept(scope.getDeclaration()); stop(); } } @Override protected void onRouter(HasOperationModels owner, RouterModel model) { final DslElementSyntax elementDsl = dsl.resolve(model); if (elementDsl.getElementName().equals(line.getIdentifier())) { RouterElementDeclarer router = extensionElementsDeclarer.newRouter(model.getName()); if (line.getConfigAttributes().get(CONFIG_ATTRIBUTE_NAME) != null) { router.withConfig(line.getConfigAttributes().get(CONFIG_ATTRIBUTE_NAME).getValue()); } declareParameterizedComponent(model, elementDsl, router, line.getConfigAttributes(), line.getChildren()); model.getRouteModels() .forEach(routeModel -> declareRoute(routeModel, elementDsl, line, extensionElementsDeclarer, dsl) .ifPresent(router::withRoute)); declarationConsumer.accept(router.getDeclaration()); stop(); } } private ComponentElementDeclarer declareComponent(ComponentModel model, Function<ElementDeclarer, ComponentElementDeclarer> declarerProvider) { final DslElementSyntax elementDsl = dsl.resolve(model); if (elementDsl.getElementName().equals(line.getIdentifier())) { ComponentElementDeclarer declarer = declarerProvider.apply(extensionElementsDeclarer); if (line.getConfigAttributes().get(CONFIG_ATTRIBUTE_NAME) != null) { declarer.withConfig(line.getConfigAttributes().get(CONFIG_ATTRIBUTE_NAME).getValue()); } declareParameterizedComponent(model, elementDsl, declarer, line.getConfigAttributes(), line.getChildren()); stop(); return declarer; } return null; } private void declareTransform(ComponentModel model, Function<ElementDeclarer, ComponentElementDeclarer> declarerProvider) { final DslElementSyntax elementDsl = dsl.resolve(model); if (elementDsl.getElementName().equals(line.getIdentifier())) { ComponentElementDeclarer declarer = declarerProvider.apply(extensionElementsDeclarer); copyExplicitAttributes(line.getConfigAttributes(), declarer); // handle set-payload and set-attributes model.getParameterGroupModels().stream() .filter(g -> !g.getName().equals(TRANSFORMER_GENERAL)) .filter(ParameterGroupModel::isShowInDsl) .forEach(group -> elementDsl.getChild(group.getName()) .ifPresent(groupDsl -> line.getChildren().stream() .filter(c -> c.getIdentifier().equals(groupDsl.getElementName())) .findFirst() .ifPresent(groupConfig -> { declarer.withParameter(group.getName(), getTransformParameterBuilder(groupConfig).build()); }))); // handle set-variable model.getAllParameterModels().stream().filter(g -> g.getName().equals(TRANSFORMER_SET_VARIABLE)).findFirst() .ifPresent(group -> { ParameterObjectValue.Builder generalGroup = ElementDeclarer.newObjectValue(); ParameterListValue.Builder setVariablesListBuilder = ElementDeclarer.newListValue(); elementDsl.getChild(TRANSFORMER_GENERAL).get().getChild(TRANSFORMER_SET_VARIABLE) .ifPresent(groupDsl -> line.getChildren().stream() .filter(c -> groupDsl.getElementName().contains(c.getIdentifier())) .forEach(groupConfig -> { setVariablesListBuilder.withValue(getTransformParameterBuilder(groupConfig).build()); })); declarer .withParameter(TRANSFORMER_GENERAL, generalGroup.withParameter(TRANSFORMER_SET_VARIABLE, setVariablesListBuilder.build()).build()); }); declarationConsumer.accept((ComponentElementDeclaration) declarer.getDeclaration()); stop(); } } }; } private ParameterObjectValue.Builder getTransformParameterBuilder(ConfigLine groupConfig) { ParameterObjectValue.Builder objectBuilder = ElementDeclarer.newObjectValue(); copyExplicitAttributes(groupConfig.getConfigAttributes(), objectBuilder); // add DW script text content to script parameter if (groupConfig.getTextContent() != null) { ParameterValue value; if (isCData(groupConfig)) { value = plain(groupConfig.getTextContent()); } else { value = cdata(groupConfig.getTextContent()); } objectBuilder.withParameter(SCRIPT, value); } return objectBuilder; } private boolean isCData(ConfigLine config) { return config.getCustomAttributes().get(IS_CDATA) != null; } private Optional<RouteElementDeclaration> declareRoute(RouteModel model, DslElementSyntax elementDsl, ConfigLine line, ElementDeclarer elementsDeclarer, DslSyntaxResolver dsl) { Reference<RouteElementDeclaration> declaration = new Reference<>(); elementDsl.getChild(model.getName()) .ifPresent(routeDsl -> line.getChildren().stream() .filter(child -> child.getIdentifier().equals(routeDsl.getElementName())) .findFirst() .ifPresent(routeConfig -> { RouteElementDeclarer route = elementsDeclarer.newRoute(model.getName()); declareParameterizedComponent(model, routeDsl, route, routeConfig.getConfigAttributes(), routeConfig.getChildren()); routeConfig.getChildren() .forEach(child -> { ExtensionModel extensionModel = getExtensionModel(child); getComponentDeclaringWalker(route::withComponent, child, forExtension(extensionModel.getName()), dsl) .walk(extensionModel); }); declaration.set(route.getDeclaration()); })); return Optional.ofNullable(declaration.get()); } private void declareParameterizedComponent(ParameterizedModel model, DslElementSyntax elementDsl, ParameterizedBuilder<String, ParameterValue, ?> declarer, Map<String, SimpleConfigAttribute> configAttributes, List<ConfigLine> children) { copyExplicitAttributes(configAttributes, declarer); declareChildParameters(model, elementDsl, children, declarer); } private void declareChildParameters(ParameterizedModel model, DslElementSyntax modelDsl, List<ConfigLine> children, ParameterizedBuilder<String, ParameterValue, ?> declarer) { List<ParameterModel> inlineGroupedParameters = model.getParameterGroupModels().stream() .filter(ParameterGroupModel::isShowInDsl) .peek(group -> modelDsl.getChild(group.getName()) .ifPresent(groupDsl -> children.stream() .filter(c -> c.getIdentifier().equals(groupDsl.getElementName())) .findFirst() .ifPresent(groupConfig -> declareInlineGroup(group, groupDsl, groupConfig, declarer)))) .flatMap(g -> g.getParameterModels().stream()) .collect(toList()); model.getAllParameterModels().stream() .filter(param -> !inlineGroupedParameters.contains(param)) .forEach(param -> modelDsl.getChild(param.getName()) .ifPresent(paramDsl -> { if (isInfrastructure(param)) { handleInfrastructure(param, children, declarer); } else { children.stream() .filter(c -> c.getIdentifier().equals(paramDsl.getElementName())) .findFirst() .ifPresent(paramConfig -> param.getType() .accept(getParameterDeclarerVisitor(paramConfig, paramDsl, value -> declarer.withParameter(param.getName(), value)))); } })); } private void declareInlineGroup(ParameterGroupModel model, DslElementSyntax dsl, ConfigLine config, ParameterizedBuilder<String, ParameterValue, ?> groupContainer) { ParameterObjectValue.Builder builder = ElementDeclarer.newObjectValue(); copyExplicitAttributes(config.getConfigAttributes(), builder); declareComplexParameterValue(model, dsl, config.getChildren(), builder); groupContainer.withParameter(model.getName(), builder.build()); } private void declareComplexParameterValue(ParameterGroupModel group, DslElementSyntax groupDsl, final List<ConfigLine> groupChilds, ParameterObjectValue.Builder groupBuilder) { groupChilds.forEach(child -> group.getParameterModels().stream() .filter(param -> groupDsl.getChild(param.getName()) .map(dsl -> dsl.getElementName().equals(child.getIdentifier())).orElse(false)) .findFirst() .ifPresent(param -> param.getType() .accept(getParameterDeclarerVisitor(child, groupDsl.getChild(param.getName()).get(), value -> groupBuilder.withParameter(param.getName(), value))))); } private MetadataTypeVisitor getParameterDeclarerVisitor(final ConfigLine config, final DslElementSyntax paramDsl, final Consumer<ParameterValue> valueConsumer) { return new MetadataTypeVisitor() { @Override protected void defaultVisit(MetadataType metadataType) { if (config.getTextContent() != null) { valueConsumer.accept(isCData(config) ? cdata(config.getTextContent()) : plain(config.getTextContent())); } } @Override public void visitArrayType(ArrayType arrayType) { ParameterListValue.Builder listBuilder = ElementDeclarer.newListValue(); config.getChildren() .forEach(item -> arrayType.getType().accept( getParameterDeclarerVisitor(item, paramDsl.getGeneric(arrayType.getType()) .get(), listBuilder::withValue))); valueConsumer.accept(listBuilder.build()); } @Override public void visitObject(ObjectType objectType) { if (config.getConfigAttributes().isEmpty() && config.getChildren().isEmpty()) { defaultVisit(objectType); return; } ParameterObjectValue.Builder objectValue = ElementDeclarer.newObjectValue(); if (isMap(objectType)) { createMapValue(objectValue, config); } else { if (paramDsl.isWrapped()) { if (config.getChildren().size() == 1) { createWrappedObject(objectType, objectValue, config); } } else { createObjectValueFromType(objectType, objectValue, config, paramDsl); } } valueConsumer.accept(objectValue.build()); } }; } private void createMapValue(ParameterObjectValue.Builder objectValue, ConfigLine config) { config.getChildren().stream() .map(ConfigLine::getConfigAttributes) .forEach(entry -> { SimpleConfigAttribute entryKey = entry.get(KEY_ATTRIBUTE_NAME); SimpleConfigAttribute entryValue = entry.get(VALUE_ATTRIBUTE_NAME); if (entryKey != null && entryValue != null) { objectValue.withParameter(entryKey.getValue(), entryValue.getValue()); } }); } private void createWrappedObject(ObjectType objectType, ParameterObjectValue.Builder objectValue, ConfigLine config) { ConfigLine wrappedConfig = config.getChildren().get(0); DslSyntaxResolver wrappedElementResolver = resolvers.get(extensionsByNamespace.get(wrappedConfig.getNamespace())); Set<ObjectType> subTypes = context.getTypeCatalog().getSubTypes(objectType); if (!subTypes.isEmpty()) { subTypes.stream() .filter(subType -> wrappedElementResolver.resolve(subType) .map(dsl -> dsl.getElementName().equals(wrappedConfig.getIdentifier())) .orElse(false)) .findFirst() .ifPresent(subType -> createObjectValueFromType(subType, objectValue, wrappedConfig, wrappedElementResolver.resolve(subType).get())); // TODO MULE-12002: Revisit DslSyntaxUtils as part of the API } else if (isExtensible(objectType)) { createObjectValueFromType(objectType, objectValue, wrappedConfig, wrappedElementResolver.resolve(objectType).get()); } } private void createObjectValueFromType(ObjectType objectType, ParameterObjectValue.Builder objectValue, ConfigLine config, DslElementSyntax paramDsl) { // TODO MULE-12002: Revisit DslSyntaxUtils as part of the API objectValue.ofType(getId(objectType)); copyExplicitAttributes(config.getConfigAttributes(), objectValue); config.getChildren().forEach(fieldConfig -> objectType.getFields().stream() .filter(fieldType -> paramDsl.getContainedElement(getLocalPart(fieldType)) .map(fieldDsl -> fieldDsl.getElementName().equals(fieldConfig.getIdentifier())).orElse(false)) .findFirst() .ifPresent(fieldType -> fieldType.getValue().accept( getParameterDeclarerVisitor(fieldConfig, paramDsl .getContainedElement(getLocalPart(fieldType)) .get(), fieldValue -> objectValue .withParameter(getLocalPart(fieldType), fieldValue))))); } private void handleInfrastructure(final ParameterModel paramModel, final List<ConfigLine> declaredConfigs, final ParameterizedBuilder<String, ParameterValue, ?> declarer) { switch (paramModel.getName()) { case RECONNECTION_STRATEGY_PARAMETER_NAME: findAnyMatchingChildById(declaredConfigs, RECONNECT_ELEMENT_IDENTIFIER, RECONNECT_FOREVER_ELEMENT_IDENTIFIER) .ifPresent(config -> { ParameterObjectValue.Builder reconnection = newObjectValue().ofType(config.getIdentifier()); copyExplicitAttributes(config.getConfigAttributes(), reconnection); declarer.withParameter(RECONNECTION_STRATEGY_PARAMETER_NAME, reconnection.build()); }); return; case REDELIVERY_POLICY_PARAMETER_NAME: findAnyMatchingChildById(declaredConfigs, REDELIVERY_POLICY_ELEMENT_IDENTIFIER) .ifPresent(config -> { ParameterObjectValue.Builder redelivery = newObjectValue(); copyExplicitAttributes(config.getConfigAttributes(), redelivery); declarer.withParameter(REDELIVERY_POLICY_PARAMETER_NAME, redelivery.build()); }); return; case POOLING_PROFILE_PARAMETER_NAME: findAnyMatchingChildById(declaredConfigs, POOLING_PROFILE_ELEMENT_IDENTIFIER) .ifPresent(config -> { ParameterObjectValue.Builder poolingProfile = newObjectValue(); cloneAsDeclaration(config, poolingProfile); declarer.withParameter(POOLING_PROFILE_PARAMETER_NAME, poolingProfile.build()); }); return; case STREAMING_STRATEGY_PARAMETER_NAME: // TODO MULE-12001: switch to EE namespace findAnyMatchingChildById(declaredConfigs, REPEATABLE_FILE_STORE_BYTES_STREAM_ALIAS, REPEATABLE_IN_MEMORY_BYTES_STREAM_ALIAS, NON_REPEATABLE_BYTE_STREAM_ALIAS) .ifPresent(config -> { ParameterObjectValue.Builder streaming = newObjectValue() .ofType(config.getIdentifier()); cloneAsDeclaration(config, streaming); declarer.withParameter(STREAMING_STRATEGY_PARAMETER_NAME, streaming.build()); }); return; case TLS_PARAMETER_NAME: findAnyMatchingChildById(declaredConfigs, TLS_CONTEXT_ELEMENT_IDENTIFIER) .ifPresent(config -> { ParameterObjectValue.Builder tls = newObjectValue(); cloneAsDeclaration(config, tls); declarer.withParameter(TLS_PARAMETER_NAME, tls.build()); }); return; case DISABLE_CONNECTION_VALIDATION_PARAMETER_NAME: // Nothing to do here, this has to be propagated as an attribute return; } } private Optional<ConfigLine> findAnyMatchingChildById(List<ConfigLine> configs, String... validIds) { List<String> ids = Arrays.asList(validIds); return configs.stream().filter(c -> ids.contains(c.getIdentifier())).findFirst(); } private void cloneAsDeclaration(ConfigLine config, ParameterObjectValue.Builder poolingProfile) { copyExplicitAttributes(config.getConfigAttributes(), poolingProfile); copyChildren(config, poolingProfile); } private String getNamespace(ConfigLine configLine) { return configLine.getNamespace() == null ? CORE_PREFIX : configLine.getNamespace(); } private void copyExplicitAttributes(Map<String, SimpleConfigAttribute> attributes, ParameterizedBuilder<String, ParameterValue, ?> builder) { attributes.values().stream() .filter(a -> !a.getName().equals(NAME_ATTRIBUTE_NAME) && !a.getName().equals(CONFIG_ATTRIBUTE_NAME)) .filter(a -> !a.isValueFromSchema()) .forEach(a -> builder.withParameter(a.getName(), ParameterSimpleValue.of(a.getValue()))); } private void copyChildren(ConfigLine config, ParameterizedBuilder<String, ParameterValue, ?> builder) { config.getChildren().forEach(child -> { ParameterObjectValue.Builder childBuilder = newObjectValue(); cloneAsDeclaration(child, childBuilder); builder.withParameter(child.getIdentifier(), childBuilder.build()); }); } }