/* * 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; import static java.lang.String.format; import static org.mule.runtime.api.i18n.I18nMessageFactory.createStaticMessage; import static org.mule.runtime.config.spring.XmlConfigurationDocumentLoader.noValidationDocumentLoader; import static org.mule.runtime.core.api.config.MuleProperties.OBJECT_CONNECTIVITY_TESTING_SERVICE; import static org.mule.runtime.core.api.config.MuleProperties.OBJECT_METADATA_SERVICE; import static org.mule.runtime.core.api.lifecycle.LifecycleUtils.initialiseIfNeeded; import static org.mule.runtime.core.api.lifecycle.LifecycleUtils.startIfNeeded; import static org.mule.runtime.core.util.ClassUtils.withContextClassLoader; import org.mule.runtime.api.app.declaration.ArtifactDeclaration; import org.mule.runtime.api.component.location.Location; import org.mule.runtime.api.exception.MuleException; import org.mule.runtime.api.exception.MuleRuntimeException; import org.mule.runtime.api.lifecycle.InitialisationException; import org.mule.runtime.api.metadata.MetadataService; import org.mule.runtime.config.spring.dsl.model.ApplicationModel; import org.mule.runtime.config.spring.dsl.model.ComponentModel; import org.mule.runtime.config.spring.dsl.model.MinimalApplicationModelGenerator; import org.mule.runtime.core.api.MuleContext; import org.mule.runtime.core.api.connectivity.ConnectivityTestingService; import org.mule.runtime.core.config.ConfigResource; import org.mule.runtime.core.config.bootstrap.ArtifactType; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.support.BeanDefinitionReader; import org.springframework.beans.factory.support.DefaultListableBeanFactory; /** * Implementation of {@link MuleArtifactContext} that allows to create configuration components lazily. * <p/> * Components will be created upon request to use the from the exposed services. * * @since 4.0 */ public class LazyMuleArtifactContext extends MuleArtifactContext implements LazyComponentInitializer { private static final Logger LOGGER = LoggerFactory.getLogger(LazyMuleArtifactContext.class); private ConnectivityTestingService lazyConnectivityTestingService; private MetadataService metadataService; /** * 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.spring.SpringRegistry * @since 4.0 */ public LazyMuleArtifactContext(MuleContext muleContext, ConfigResource[] artifactConfigResources, ArtifactDeclaration artifactDeclaration, OptionalObjectsController optionalObjectsController, Map<String, String> artifactProperties, ArtifactType artifactType, List<ClassLoader> pluginsClassLoaders) throws BeansException { super(muleContext, artifactConfigResources, artifactDeclaration, optionalObjectsController, artifactProperties, artifactType, pluginsClassLoaders); } @Override protected XmlConfigurationDocumentLoader newXmlConfigurationDocumentLoader() { return noValidationDocumentLoader(); } private void createComponents(DefaultListableBeanFactory beanFactory, ApplicationModel applicationModel, boolean mustBeRoot) { applyLifecycle(super.createApplicationComponents(beanFactory, applicationModel, mustBeRoot)); } private void applyLifecycle(List<String> createdComponentModels) { if (muleContext.isInitialised()) { for (String createdComponentModelName : createdComponentModels) { Object object = muleContext.getRegistry().get(createdComponentModelName); try { initialiseIfNeeded(object, true, muleContext); } catch (InitialisationException e) { throw new RuntimeException(e); } } } if (muleContext.isStarted()) { for (String createdComponentModelName : createdComponentModels) { Object object = muleContext.getRegistry().get(createdComponentModelName); try { startIfNeeded(object); } catch (MuleException e) { throw new RuntimeException(e); } } } } /** * During a lazy intialization of an artifact the components should not be created. */ @Override protected void createInitialApplicationComponents(DefaultListableBeanFactory beanFactory, BeanDefinitionReader beanDefinitionReader) { if (!useNewParsingMechanism) { throw new MuleRuntimeException(createStaticMessage("Could not create mule application since lazy init is enabled but there are component in the configuration " + "that are not parsed with the new mechanism " + getOldParsingMechanismComponentIdentifiers())); } } @Override public void initializeComponent(Location location) { withContextClassLoader(muleContext.getExecutionClassLoader(), () -> { MinimalApplicationModelGenerator minimalApplicationModelGenerator = new MinimalApplicationModelGenerator(this.applicationModel, componentBuildingDefinitionRegistry); // First unregister any already initialized/started component unregisterComponents(minimalApplicationModelGenerator.resolveComponentModelDependencies()); ApplicationModel minimalApplicationModel = minimalApplicationModelGenerator.getMinimalModel(location); createComponents((DefaultListableBeanFactory) this.getBeanFactory(), minimalApplicationModel, false); }); } private void unregisterComponents(List<ComponentModel> componentModels) { if (muleContext.isStarted()) { componentModels.stream().forEach(componentModel -> { final String nameAttribute = componentModel.getNameAttribute(); if (nameAttribute != null) { try { muleContext.getRegistry().unregisterObject(nameAttribute); } catch (Exception e) { logger .warn(format("Exception unregistering an object during lazy initialization of component %s, exception message is %s", nameAttribute, e.getMessage())); if (logger.isDebugEnabled()) { logger.debug(e.getMessage(), e); } } } }); } applicationModel.executeOnEveryMuleComponentTree(componentModel -> componentModel.setEnabled(true)); } @Override public ConnectivityTestingService getConnectivityTestingService() { if (lazyConnectivityTestingService == null) { lazyConnectivityTestingService = new LazyConnectivityTestingService(this, muleContext.getRegistry().get(OBJECT_CONNECTIVITY_TESTING_SERVICE)); } return lazyConnectivityTestingService; } @Override public MetadataService getMetadataService() { if (metadataService == null) { metadataService = new LazyMetadataService(this, muleContext.getRegistry().get(OBJECT_METADATA_SERVICE)); } return metadataService; } }