All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mule.runtime.config.internal.dsl.model.MinimalApplicationModelGenerator Maven / Gradle / Ivy

/*
 * 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.internal.dsl.model;

import static java.util.stream.Collectors.toSet;
import static org.mule.runtime.config.internal.dsl.model.DependencyNode.Type.TOP_LEVEL;
import org.mule.runtime.api.component.location.Location;
import org.mule.runtime.config.api.LazyComponentInitializer;
import org.mule.runtime.config.internal.model.ApplicationModel;
import org.mule.runtime.config.internal.model.ComponentModel;
import org.mule.runtime.dsl.api.component.config.DefaultComponentLocation;

import com.google.common.collect.ImmutableSet;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;

/**
 * Generates the minimal required component set to create a configuration component (i.e.: file:config, ftp:connection, a flow
 * MP). This set is defined by the component dependencies.
 * 

* Based on the requested component, the {@link ComponentModel} configuration associated is introspected to find it dependencies * based on it's {@link org.mule.runtime.dsl.api.component.ComponentBuildingDefinition}. This process is recursively done for each * of the dependencies in order to find all the required {@link ComponentModel}s that must be created for the requested * {@link ComponentModel} to work properly. * * @since 4.0 */ // TODO MULE-9688 - refactor this class when the ComponentModel becomes immutable public class MinimalApplicationModelGenerator { private ConfigurationDependencyResolver dependencyResolver; /** * Creates a new instance. * * @param dependencyResolver a {@link ConfigurationDependencyResolver} associated with an {@link ApplicationModel} */ public MinimalApplicationModelGenerator(ConfigurationDependencyResolver dependencyResolver) { this.dependencyResolver = dependencyResolver; } /** * Resolves the minimal set of {@link ComponentModel componentModels} for the components that pass the * {@link LazyComponentInitializer.ComponentLocationFilter}. * * @param predicate to select the {@link ComponentModel componentModels} to be enabled. * @return the generated {@link ApplicationModel} with the minimal set of {@link ComponentModel}s required. */ public ApplicationModel getMinimalModel(Predicate predicate) { List required = dependencyResolver.findRequiredComponentModels(predicate); required.stream().forEach(componentModel -> { final DefaultComponentLocation componentLocation = componentModel.getComponentLocation(); if (componentLocation != null) { enableComponentDependencies(componentModel); } }); return dependencyResolver.getApplicationModel(); } /** * Resolves the minimal set of {@link ComponentModel componentModels} for the component. * * @param location {@link Location} for the requested component to be enabled. * @return the generated {@link ApplicationModel} with the minimal set of {@link ComponentModel}s required. * @throws NoSuchComponentModelException if the location doesn't match to a component. */ public ApplicationModel getMinimalModel(Location location) { ComponentModel requestedComponentModel = dependencyResolver.findRequiredComponentModel(location); enableComponentDependencies(requestedComponentModel); return dependencyResolver.getApplicationModel(); } /** * Enables the {@link ComponentModel} and its dependencies in the {@link ApplicationModel}. * * @param requestedComponentModel the requested {@link ComponentModel} to be enabled. */ private void enableComponentDependencies(ComponentModel requestedComponentModel) { final String requestComponentModelName = requestedComponentModel.getNameAttribute(); final Set componentDependencies = dependencyResolver.resolveComponentDependencies(requestedComponentModel); final Set alwaysEnabledComponents = dependencyResolver.resolveAlwaysEnabledComponents(); final ImmutableSet.Builder otherRequiredGlobalComponentsSetBuilder = ImmutableSet.builder().addAll(componentDependencies).addAll(alwaysEnabledComponents); if (requestComponentModelName != null && dependencyResolver.getApplicationModel().findTopLevelNamedComponent(requestComponentModelName).isPresent()) { otherRequiredGlobalComponentsSetBuilder.add(new DependencyNode(requestComponentModelName, TOP_LEVEL)); } Set allRequiredComponentModels = resolveDependencies(otherRequiredGlobalComponentsSetBuilder.build()); enableTopLevelElementDependencies(allRequiredComponentModels); enableInnerElementDependencies(allRequiredComponentModels); ComponentModel parentModel = requestedComponentModel.getParent(); while (parentModel != null && parentModel.getParent() != null) { parentModel.setEnabled(true); parentModel = parentModel.getParent(); } // Finally we set the requested componentModel as enabled as it could have been disabled when traversing dependencies requestedComponentModel.setEnabled(true); requestedComponentModel.executedOnEveryInnerComponent(componentModel -> componentModel.setEnabled(true)); enableParentComponentModels(requestedComponentModel); // Mule root component model has to be enabled too this.dependencyResolver.getApplicationModel().getRootComponentModel().setEnabled(true); } private void enableInnerElementDependencies(Set allRequiredComponentModels) { Set noneTopLevelDendencyNames = allRequiredComponentModels.stream() .filter(dependencyNode -> !dependencyNode.isTopLevel()) .map(dependencyNode -> dependencyNode.getComponentName()) .collect(toSet()); dependencyResolver.getApplicationModel().executeOnEveryComponentTree(componentModel -> { if (!componentModel.isEnabled() && componentModel.getNameAttribute() != null && noneTopLevelDendencyNames.contains(componentModel.getNameAttribute())) { componentModel.setEnabled(true); componentModel.executedOnEveryInnerComponent(component -> component.setEnabled(true)); enableParentComponentModels(componentModel); } }); } private void enableTopLevelElementDependencies(Set allRequiredComponentModels) { Set topLevelDendencyNames = allRequiredComponentModels.stream() .filter(dependencyNode -> dependencyNode.isTopLevel()) .map(dependencyNode -> dependencyNode.getComponentName()) .collect(toSet()); Iterator iterator = dependencyResolver.getApplicationModel().getRootComponentModel().getInnerComponents().iterator(); while (iterator.hasNext()) { ComponentModel componentModel = iterator.next(); if (componentModel.getNameAttribute() != null && topLevelDendencyNames.contains(componentModel.getNameAttribute())) { componentModel.setEnabled(true); componentModel.executedOnEveryInnerComponent(component -> component.setEnabled(true)); } } } private void enableParentComponentModels(ComponentModel requestedComponentModel) { ComponentModel parentModel = requestedComponentModel.getParent(); while (parentModel != null && parentModel.getParent() != null) { parentModel.setEnabled(true); parentModel = parentModel.getParent(); } } /** * Resolve all the dependencies for an initial components set. * * @param initialComponents {@ling Set} of initial components to retrieve their dependencies * @return a new {@ling Set} with all the dependencies needed to run all the initial components */ private Set resolveDependencies(Set initialComponents) { Set difference = initialComponents; Set allRequiredComponentModels = new HashSet<>(initialComponents); // While there are new dependencies resolved, calculate their dependencies // This fixes bugs related to not resolving dependencies of dependencies, such as a config for a config // e.g. tlsContext for http request, or a flow-ref inside a flow that is being referenced in another flow. while (difference.size() > 0) { // Only calculate the dependencies for the difference, to avoid recalculating Set newDependencies = dependencyResolver.findComponentModelsDependencies(difference); newDependencies.removeAll(allRequiredComponentModels); allRequiredComponentModels.addAll(newDependencies); difference = newDependencies; } return allRequiredComponentModels; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy