Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.mule.runtime.config.internal.LazyMuleArtifactContext 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;
import static java.lang.String.format;
import static java.util.Collections.reverse;
import static java.util.Optional.empty;
import static java.util.Optional.of;
import static java.util.stream.Collectors.toList;
import static org.mule.runtime.api.component.location.Location.builderFromStringRepresentation;
import static org.mule.runtime.api.connectivity.ConnectivityTestingService.CONNECTIVITY_TESTING_SERVICE_KEY;
import static org.mule.runtime.api.metadata.MetadataService.METADATA_SERVICE_KEY;
import static org.mule.runtime.api.util.Preconditions.checkState;
import static org.mule.runtime.api.value.ValueProviderService.VALUE_PROVIDER_SERVICE_KEY;
import static org.mule.runtime.config.internal.LazyConnectivityTestingService.NON_LAZY_CONNECTIVITY_TESTING_SERVICE;
import static org.mule.runtime.config.internal.LazyMetadataService.NON_LAZY_METADATA_SERVICE;
import static org.mule.runtime.config.internal.LazyValueProviderService.NON_LAZY_VALUE_PROVIDER_SERVICE;
import static org.mule.runtime.core.api.util.ClassUtils.withContextClassLoader;
import static org.mule.runtime.core.privileged.registry.LegacyRegistryUtils.unregisterObject;
import org.mule.runtime.api.component.ConfigurationProperties;
import org.mule.runtime.api.component.location.Location;
import org.mule.runtime.api.connectivity.ConnectivityTestingService;
import org.mule.runtime.api.exception.MuleException;
import org.mule.runtime.api.lifecycle.Initialisable;
import org.mule.runtime.api.lifecycle.Startable;
import org.mule.runtime.api.metadata.MetadataService;
import org.mule.runtime.api.util.Reference;
import org.mule.runtime.api.value.ValueProviderService;
import org.mule.runtime.app.declaration.api.ArtifactDeclaration;
import org.mule.runtime.config.internal.dsl.model.ConfigurationDependencyResolver;
import org.mule.runtime.config.internal.dsl.model.MinimalApplicationModelGenerator;
import org.mule.runtime.config.internal.model.ApplicationModel;
import org.mule.runtime.config.internal.model.ComponentModel;
import org.mule.runtime.core.api.MuleContext;
import org.mule.runtime.core.api.config.ConfigResource;
import org.mule.runtime.core.api.config.MuleDeploymentProperties;
import org.mule.runtime.core.api.config.bootstrap.ArtifactType;
import org.mule.runtime.core.internal.connectivity.DefaultConnectivityTestingService;
import org.mule.runtime.core.internal.metadata.MuleMetadataService;
import org.mule.runtime.core.internal.value.MuleValueProviderService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
/**
* Implementation of {@link MuleArtifactContext} that allows to create configuration components lazily.
*
* Components will be created upon request to use the from the exposed services.
*
* @since 4.0
*/
public class LazyMuleArtifactContext extends MuleArtifactContext
implements LazyComponentInitializerAdapter, ComponentModelInitializer {
private static final Logger LOGGER = LoggerFactory.getLogger(LazyMuleArtifactContext.class);
private TrackingPostProcessor trackingPostProcessor = new TrackingPostProcessor();
private Optional parentComponentModelInitializer;
/**
* Parses configuration files creating a spring ApplicationContext which is used as a parent registry using the SpringRegistry
* registry implementation to wraps the spring ApplicationContext
*
* @param muleContext the {@link MuleContext} that own this context
* @param artifactDeclaration the mule configuration defined programmatically
* @param optionalObjectsController the {@link OptionalObjectsController} to use. Cannot be {@code null} @see
* org.mule.runtime.config.internal.SpringRegistry
* @param parentConfigurationProperties
* @param disableXmlValidations {@code true} when loading XML configs it will not apply validations.
* @since 4.0
*/
public LazyMuleArtifactContext(MuleContext muleContext, ConfigResource[] artifactConfigResources,
ArtifactDeclaration artifactDeclaration, OptionalObjectsController optionalObjectsController,
Map artifactProperties, ArtifactType artifactType,
List pluginsClassLoaders,
Optional parentComponentModelInitializer,
Optional parentConfigurationProperties, boolean disableXmlValidations)
throws BeansException {
super(muleContext, artifactConfigResources, artifactDeclaration, optionalObjectsController,
extendArtifactProperties(artifactProperties), artifactType, pluginsClassLoaders, parentConfigurationProperties,
disableXmlValidations);
this.applicationModel.executeOnEveryMuleComponentTree(componentModel -> componentModel.setEnabled(false));
this.parentComponentModelInitializer = parentComponentModelInitializer;
muleContext.getCustomizationService().overrideDefaultServiceImpl(CONNECTIVITY_TESTING_SERVICE_KEY,
new LazyConnectivityTestingService(this, () -> getRegistry()
.lookupByName(NON_LAZY_CONNECTIVITY_TESTING_SERVICE)
.get()));
muleContext.getCustomizationService().registerCustomServiceClass(NON_LAZY_CONNECTIVITY_TESTING_SERVICE,
DefaultConnectivityTestingService.class);
muleContext.getCustomizationService().overrideDefaultServiceImpl(METADATA_SERVICE_KEY,
new LazyMetadataService(this, () -> getRegistry()
.lookupByName(NON_LAZY_METADATA_SERVICE)
.get()));
muleContext.getCustomizationService().registerCustomServiceClass(NON_LAZY_METADATA_SERVICE, MuleMetadataService.class);
muleContext.getCustomizationService().overrideDefaultServiceImpl(VALUE_PROVIDER_SERVICE_KEY,
new LazyValueProviderService(this, () -> getRegistry()
.lookupByName(NON_LAZY_VALUE_PROVIDER_SERVICE)
.get(),
muleContext::getConfigurationComponentLocator));
muleContext.getCustomizationService().registerCustomServiceClass(NON_LAZY_VALUE_PROVIDER_SERVICE,
MuleValueProviderService.class);
muleContext.getCustomizationService().overrideDefaultServiceImpl(LAZY_COMPONENT_INITIALIZER_SERVICE_KEY, this);
}
private static Map extendArtifactProperties(Map artifactProperties) {
Map extendedArtifactProperties = new HashMap<>(artifactProperties);
extendedArtifactProperties.put(MuleDeploymentProperties.MULE_LAZY_INIT_DEPLOYMENT_PROPERTY, "true");
return extendedArtifactProperties;
}
@Override
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.prepareBeanFactory(beanFactory);
trackingPostProcessor = new TrackingPostProcessor();
addBeanPostProcessors(beanFactory, trackingPostProcessor);
}
private void applyLifecycle(List createdComponentModels, boolean applyStartPhase) {
muleContext.withLifecycleLock(() -> {
if (muleContext.isInitialised()) {
for (String createdComponentModelName : createdComponentModels) {
Object object = getRegistry().lookupByName(createdComponentModelName).get();
try {
muleContext.getRegistry().applyLifecycle(object, Initialisable.PHASE_NAME);
} catch (MuleException e) {
throw new RuntimeException(e);
}
}
}
if (applyStartPhase && muleContext.isStarted()) {
for (String createdComponentModelName : createdComponentModels) {
Object object = getRegistry().lookupByName(createdComponentModelName).get();
try {
muleContext.getRegistry().applyLifecycle(object, Initialisable.PHASE_NAME, Startable.PHASE_NAME);
} catch (MuleException e) {
throw new RuntimeException(e);
}
}
}
});
}
@Override
public void initializeComponent(Location location) {
initializeComponent(location, true);
}
@Override
public void initializeComponents(ComponentLocationFilter filter) {
initializeComponents(filter, true);
}
@Override
public void initializeComponent(Location location, boolean applyStartPhase) {
applyLifecycle(createComponents(empty(), of(location), getParentComponentModelInitializerAdapter(applyStartPhase)),
applyStartPhase);
}
@Override
public void initializeComponents(ComponentLocationFilter filter, boolean applyStartPhase) {
applyLifecycle(createComponents(of(o -> {
ComponentModel componentModel = (ComponentModel) o;
if (componentModel.getComponentLocation() != null) {
return filter.accept(componentModel.getComponentLocation());
}
return false;
}), empty(), getParentComponentModelInitializerAdapter(applyStartPhase)), applyStartPhase);
}
@Override
public void initializeComponents(Predicate componentModelPredicate,
boolean applyStartPhase) {
applyLifecycle(createComponents(of(componentModelPredicate), empty(),
getParentComponentModelInitializerAdapter(applyStartPhase)),
applyStartPhase);
}
public Optional getParentComponentModelInitializerAdapter(
boolean applyStartPhase) {
return parentComponentModelInitializer
.map(componentModelInitializer -> (LazyMuleArtifactContext.ComponentModelInitializerAdapter) componentModelPredicate1 -> componentModelInitializer
.initializeComponents(componentModelPredicate1, applyStartPhase));
}
private List createComponents(Optional predicateOptional, Optional locationOptional,
Optional parentComponentModelInitializerAdapter) {
checkState(predicateOptional.isPresent() != locationOptional.isPresent(), "predicate or location has to be passed");
List alreadyCreatedApplicationComponents = new ArrayList<>();
alreadyCreatedApplicationComponents.addAll(trackingPostProcessor.getBeansTracked());
reverse(alreadyCreatedApplicationComponents);
trackingPostProcessor.startTracking();
Reference> createdComponents = new Reference<>();
withContextClassLoader(muleContext.getExecutionClassLoader(), () -> {
applicationModel.executeOnEveryMuleComponentTree(componentModel -> componentModel.setEnabled(false));
ConfigurationDependencyResolver dependencyResolver = new ConfigurationDependencyResolver(this.applicationModel,
componentBuildingDefinitionRegistry);
MinimalApplicationModelGenerator minimalApplicationModelGenerator =
new MinimalApplicationModelGenerator(dependencyResolver);
Reference minimalApplicationModel = new Reference<>();
predicateOptional
.ifPresent(predicate -> minimalApplicationModel.set(minimalApplicationModelGenerator.getMinimalModel(predicate)));
locationOptional
.ifPresent(location -> minimalApplicationModel.set(minimalApplicationModelGenerator.getMinimalModel(location)));
// First unregister any already initialized/started component
unregisterBeans(alreadyCreatedApplicationComponents);
objectProviders.clear();
if (parentComponentModelInitializerAdapter.isPresent()) {
List missingComponentNames = dependencyResolver.getMissingDependencies().stream()
.filter(dependencyNode -> dependencyNode.isTopLevel())
.map(dependencyNode -> dependencyNode.getComponentName())
.collect(toList());
parentComponentModelInitializerAdapter.get().initializeComponents(componentModel -> {
if (componentModel.getNameAttribute() != null) {
return missingComponentNames.contains(componentModel.getNameAttribute());
}
return false;
});
} else {
dependencyResolver.getMissingDependencies().stream().forEach(globalElementName -> {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("Ignoring dependency %s because it does not exists", globalElementName));
}
});
}
List applicationComponents =
createApplicationComponents((DefaultListableBeanFactory) this.getBeanFactory(), minimalApplicationModel.get(), false);
createdComponents.set(applicationComponents);
super.prepareObjectProviders();
// This is required to force the execution of postProcessAfterInitialization() for each created component
applicationComponents.forEach(component -> getRegistry().lookupByName(component).get());
});
trackingPostProcessor.stopTracking();
List createdComponentNames = createdComponents.get();
trackingPostProcessor.intersection(createdComponentNames);
return createdComponentNames;
}
@Override
protected void prepareObjectProviders() {
// Do not prepare object providers at this point. No components are going to be created yet. This will be done when creating
// lazy components
}
private void unregisterBeans(List beanNames) {
if (muleContext.isStarted()) {
beanNames.forEach(beanName -> {
try {
unregisterObject(muleContext, beanName);
} catch (Exception e) {
logger
.warn(format("Exception unregistering an object during lazy initialization of component %s, exception message is %s",
beanName, e.getMessage()));
if (logger.isDebugEnabled()) {
logger.debug(e.getMessage(), e);
}
}
});
}
removeFromComponentLocator(beanNames);
}
private void removeFromComponentLocator(List locations) {
locations.forEach(location -> {
componentLocator.removeComponent(builderFromStringRepresentation(location).build());
});
}
/**
* Adapter for {@link ComponentModelInitializer} that hides the lifecycle phase from component model creation logic.
*/
@FunctionalInterface
private interface ComponentModelInitializerAdapter {
void initializeComponents(Predicate componentModelPredicate);
}
}