/*
* 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.util.Collections.emptySet;
import static java.util.Optional.of;
import static org.mule.runtime.config.spring.parsers.AbstractMuleBeanDefinitionParser.getConfigFileIdentifier;
import org.mule.runtime.api.app.declaration.ArtifactDeclaration;
import org.mule.runtime.api.exception.MuleRuntimeException;
import org.mule.runtime.config.spring.dsl.model.ApplicationModel;
import org.mule.runtime.config.spring.dsl.model.ComponentBuildingDefinitionRegistry;
import org.mule.runtime.config.spring.dsl.processor.ArtifactConfig;
import org.mule.runtime.config.spring.dsl.processor.ConfigFile;
import org.mule.runtime.config.spring.dsl.processor.ConfigLine;
import org.mule.runtime.config.spring.dsl.processor.xml.XmlApplicationParser;
import org.mule.runtime.config.spring.dsl.spring.BeanDefinitionFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader;
import org.springframework.beans.factory.xml.XmlReaderContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Allows us to hook in our own Hierarchical Parser delegate. this enables the parsing of custom spring bean elements nested
* within each other
*/
public class MuleBeanDefinitionDocumentReader extends DefaultBeanDefinitionDocumentReader {
private final BeanDefinitionFactory beanDefinitionFactory;
private final XmlApplicationParser xmlApplicationParser;
// This same instance is called several time to parse different XML files so a stack is needed to save previous state.
private final Stack<ApplicationModel> applicationModelStack = new Stack<>();
private final ComponentBuildingDefinitionRegistry componentBuildingDefinitionRegistry;
public MuleBeanDefinitionDocumentReader(BeanDefinitionFactory beanDefinitionFactory,
XmlApplicationParser xmlApplicationParser,
ComponentBuildingDefinitionRegistry componentBuildingDefinitionRegistry) {
this.beanDefinitionFactory = beanDefinitionFactory;
this.xmlApplicationParser = xmlApplicationParser;
this.componentBuildingDefinitionRegistry = componentBuildingDefinitionRegistry;
}
@Override
protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root,
BeanDefinitionParserDelegate parentDelegate) {
BeanDefinitionParserDelegate delegate = createBeanDefinitionParserDelegate(readerContext);
delegate.initDefaults(root, parentDelegate);
return delegate;
}
protected MuleHierarchicalBeanDefinitionParserDelegate createBeanDefinitionParserDelegate(XmlReaderContext readerContext) {
return new MuleHierarchicalBeanDefinitionParserDelegate(readerContext, this, applicationModelStack::peek,
beanDefinitionFactory, getElementsValidator());
}
protected ElementValidator[] getElementsValidator() {
return new ElementValidator[0];
}
/**
* Override to reject configuration files with no namespace, e.g. mule legacy configuration file.
*/
@Override
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (!StringUtils.hasLength(root.getNamespaceURI())) {
getReaderContext().error("Unable to locate NamespaceHandler for namespace [null]", root);
} else {
super.parseBeanDefinitions(root, delegate);
}
}
@Override
protected void preProcessXml(Element root) {
try {
List<ConfigLine> configLines = new ArrayList<>();
configLines.add(xmlApplicationParser.parse(root).get());
ArtifactConfig artifactConfig = new ArtifactConfig.Builder()
.addConfigFile(new ConfigFile(getConfigFileIdentifier(getReaderContext().getResource()), configLines)).build();
applicationModelStack.push(new ApplicationModel(artifactConfig, new ArtifactDeclaration(), emptySet(),
of(componentBuildingDefinitionRegistry)));
} catch (Exception e) {
throw new MuleRuntimeException(e);
}
}
@Override
protected void postProcessXml(Element root) {
applicationModelStack.pop();
}
}