/*
* 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.parsers.generic;
import org.mule.runtime.config.spring.parsers.assembly.BeanAssembler;
import org.mule.runtime.config.spring.parsers.assembly.BeanAssemblerFactory;
import org.mule.runtime.config.spring.parsers.assembly.DefaultBeanAssembler;
import org.mule.runtime.config.spring.parsers.assembly.DefaultBeanAssemblerFactory;
import org.mule.runtime.config.spring.parsers.assembly.configuration.PropertyConfiguration;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.w3c.dom.Element;
import java.util.List;
/**
* A child definition parser that wraps the child object
*/
public class WrappingChildDefinitionParser extends ChildDefinitionParser {
private final Class wrapperClass;
private final String propertyNameInWrapper;
private final String unwrappedPropertyName;
private final WrappingController wrappingController;
public WrappingChildDefinitionParser(String setterMethod, Class clazz, Class constraint, boolean allowClassAttribute,
Class wrapperClass, String propertyNameInWrapper, String unwrappedPropertyName,
WrappingController wrappingController) {
super(setterMethod, clazz, constraint, allowClassAttribute);
this.wrapperClass = wrapperClass;
this.propertyNameInWrapper = propertyNameInWrapper;
this.unwrappedPropertyName = unwrappedPropertyName;
this.wrappingController = wrappingController;
}
@Override
public String getPropertyName(Element e) {
if (!wrappingController.shouldWrap(e)) {
return unwrappedPropertyName;
} else {
return super.getPropertyName(e);
}
}
@Override
protected void preProcess(Element element) {
super.preProcess(element);
if (wrappingController.shouldWrap(element)) {
setBeanAssemblerFactory(new MessageProcessorWrappingBeanAssemblerFactory(wrapperClass, propertyNameInWrapper));
} else {
setBeanAssemblerFactory(new DefaultBeanAssemblerFactory());
}
}
/**
* Determines whether to wrap the child based on the where it appears in the DOM.
*/
public interface WrappingController {
boolean shouldWrap(Element elm);
}
private static class MessageProcessorWrappingBeanAssemblerFactory implements BeanAssemblerFactory {
private final Class wrapperClass;
private final String propertyNameInWrapper;
public MessageProcessorWrappingBeanAssemblerFactory(Class wrapperClass, String propertyNameInWrapper) {
this.wrapperClass = wrapperClass;
this.propertyNameInWrapper = propertyNameInWrapper;
}
public BeanAssembler newBeanAssembler(PropertyConfiguration beanConfig, BeanDefinitionBuilder bean,
PropertyConfiguration targetConfig, BeanDefinition target) {
return new MessageProcessorWrappingBeanAssembler(beanConfig, bean, targetConfig, target, wrapperClass,
propertyNameInWrapper);
}
}
private static class MessageProcessorWrappingBeanAssembler extends DefaultBeanAssembler {
private final Class wrapperClass;
private final String propertyNameInWrapper;
public MessageProcessorWrappingBeanAssembler(PropertyConfiguration beanConfig, BeanDefinitionBuilder bean,
PropertyConfiguration targetConfig, BeanDefinition target, Class wrapperClass,
String propertyNameInWrapper) {
super(beanConfig, bean, targetConfig, target);
this.wrapperClass = wrapperClass;
this.propertyNameInWrapper = propertyNameInWrapper;
}
public void insertBeanInTarget(String oldName) {
if (target == null) {
// TODO MULE-9638 - This is possible when the parent node is parsed by the new mechanism
return;
}
String newName = bestGuessName(targetConfig, oldName, target.getBeanClassName());
MutablePropertyValues targetProperties = target.getPropertyValues();
PropertyValue pv = targetProperties.getPropertyValue(newName);
Object oldValue = null == pv ? null : pv.getValue();
BeanDefinitionBuilder wrapper = BeanDefinitionBuilder.genericBeanDefinition(wrapperClass);
wrapper.addPropertyValue(propertyNameInWrapper, bean.getBeanDefinition());
if (oldValue == null) {
oldValue = new ManagedList();
pv = new PropertyValue(newName, oldValue);
targetProperties.addPropertyValue(pv);
}
if (targetConfig.isCollection(oldName)) {
List list = retrieveList(oldValue);
list.add(wrapper.getBeanDefinition());
} else {
targetProperties.addPropertyValue(newName, wrapper.getBeanDefinition());
}
}
}
}