/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.config.xml;
import java.util.List;
import org.w3c.dom.Element;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.integration.config.ExpressionFactoryBean;
import org.springframework.integration.expression.ValueExpression;
import org.springframework.integration.transformer.ContentEnricher;
import org.springframework.integration.transformer.support.ExpressionEvaluatingHeaderValueMessageProcessor;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
/**
* Parser for the 'enricher' element.
*
* @author Mark Fisher
* @author Artem Bilan
* @author Liujiong
* @author Kris Jacyna
* @author Gary Russell
* @since 2.1
*/
public class EnricherParser extends AbstractConsumerEndpointParser {
@Override
protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
final BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ContentEnricher.class);
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "request-channel");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "error-channel");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "request-timeout");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
List<Element> subElements = DomUtils.getChildElementsByTagName(element, "property");
if (!CollectionUtils.isEmpty(subElements)) {
ManagedMap<String, Object> expressions = new ManagedMap<String, Object>();
ManagedMap<String, Object> nullResultExpressions = new ManagedMap<String, Object>();
for (Element subElement : subElements) {
String name = subElement.getAttribute("name");
String value = subElement.getAttribute("value");
String type = subElement.getAttribute("type");
String expression = subElement.getAttribute("expression");
String nullResultExpression = subElement.getAttribute("null-result-expression");
boolean hasAttributeValue = StringUtils.hasText(value);
boolean hasAttributeExpression = StringUtils.hasText(expression);
boolean hasAttributeNullResultExpression = StringUtils.hasText(nullResultExpression);
if (hasAttributeValue && hasAttributeExpression) {
parserContext.getReaderContext().error("Only one of 'value' or 'expression' is allowed", element);
}
if (!hasAttributeValue && !hasAttributeExpression && !hasAttributeNullResultExpression) {
parserContext.getReaderContext()
.error("One of 'value' or 'expression' or 'null-result-expression' is required", element);
}
BeanDefinition expressionDef = null;
BeanDefinition nullResultExpressionExpressionDef;
if (hasAttributeValue) {
BeanDefinitionBuilder expressionBuilder =
BeanDefinitionBuilder.genericBeanDefinition(ValueExpression.class);
if (StringUtils.hasText(type)) {
expressionBuilder.addConstructorArgValue(new TypedStringValue(value, type));
}
else {
expressionBuilder.addConstructorArgValue(value);
}
expressionDef = expressionBuilder.getBeanDefinition();
}
else if (hasAttributeExpression) {
if (StringUtils.hasText(type)) {
parserContext.getReaderContext().error("The 'type' attribute for '<property>' of '<enricher>' " +
"is not allowed with an 'expression' attribute.", element);
}
expressionDef = BeanDefinitionBuilder
.genericBeanDefinition(ExpressionFactoryBean.class)
.addConstructorArgValue(expression)
.getBeanDefinition();
}
if (expressionDef != null) {
expressions.put(name, expressionDef);
}
if (hasAttributeNullResultExpression) {
nullResultExpressionExpressionDef =
BeanDefinitionBuilder.genericBeanDefinition(ExpressionFactoryBean.class)
.addConstructorArgValue(nullResultExpression).getBeanDefinition();
nullResultExpressions.put(name, nullResultExpressionExpressionDef);
}
}
if (expressions.size() > 0) {
builder.addPropertyValue("propertyExpressions", expressions);
}
if (nullResultExpressions.size() > 0) {
builder.addPropertyValue("nullResultPropertyExpressions", nullResultExpressions);
}
}
subElements = DomUtils.getChildElementsByTagName(element, "header");
if (!CollectionUtils.isEmpty(subElements)) {
ManagedMap<String, Object> expressions = new ManagedMap<String, Object>();
ManagedMap<String, Object> nullResultHeaderExpressions = new ManagedMap<String, Object>();
for (Element subElement : subElements) {
String name = subElement.getAttribute("name");
String nullResultHeaderExpression = subElement.getAttribute("null-result-expression");
String valueElementValue = subElement.getAttribute("value");
String expressionElementValue = subElement.getAttribute("expression");
boolean hasAttributeValue = StringUtils.hasText(valueElementValue);
boolean hasAttributeExpression = StringUtils.hasText(expressionElementValue);
boolean hasAttributeNullResultExpression = StringUtils.hasText(nullResultHeaderExpression);
if (hasAttributeValue && hasAttributeExpression) {
parserContext.getReaderContext().error("Only one of '" + "value" + "' or '"
+ "expression" + "' is allowed", subElement);
}
if (!hasAttributeValue && !hasAttributeExpression && !hasAttributeNullResultExpression) {
parserContext.getReaderContext()
.error("One of 'value' or 'expression' or 'null-result-expression' is required", subElement);
}
BeanDefinition expressionDef = null;
if (hasAttributeValue) {
expressionDef = new RootBeanDefinition(LiteralExpression.class);
expressionDef.getConstructorArgumentValues().addGenericArgumentValue(valueElementValue);
}
else if (hasAttributeExpression) {
expressionDef =
IntegrationNamespaceUtils.createExpressionDefIfAttributeDefined("expression", subElement);
}
if (StringUtils.hasText(subElement.getAttribute("expression"))
&& StringUtils.hasText(subElement.getAttribute("type"))) {
parserContext.getReaderContext()
.warning("The use of a 'type' attribute is deprecated since 4.0 "
+ "when using 'expression'", subElement);
}
if (expressionDef != null) {
BeanDefinitionBuilder valueProcessorBuilder = BeanDefinitionBuilder
.genericBeanDefinition(ExpressionEvaluatingHeaderValueMessageProcessor.class)
.addConstructorArgValue(expressionDef)
.addConstructorArgValue(subElement.getAttribute("type"));
IntegrationNamespaceUtils.setValueIfAttributeDefined(valueProcessorBuilder, subElement, "overwrite");
expressions.put(name, valueProcessorBuilder.getBeanDefinition());
}
if (hasAttributeNullResultExpression) {
BeanDefinition nullResultExpressionDefinition = IntegrationNamespaceUtils
.createExpressionDefIfAttributeDefined("null-result-expression", subElement);
BeanDefinitionBuilder nullResultValueProcessorBuilder = BeanDefinitionBuilder
.genericBeanDefinition(ExpressionEvaluatingHeaderValueMessageProcessor.class)
.addConstructorArgValue(nullResultExpressionDefinition)
.addConstructorArgValue(subElement.getAttribute("type"));
IntegrationNamespaceUtils.setValueIfAttributeDefined(nullResultValueProcessorBuilder, subElement,
"overwrite");
nullResultHeaderExpressions.put(name, nullResultValueProcessorBuilder.getBeanDefinition());
}
}
if (expressions.size() > 0) {
builder.addPropertyValue("headerExpressions", expressions);
}
if (nullResultHeaderExpressions.size() > 0) {
builder.addPropertyValue("nullResultHeaderExpressions", nullResultHeaderExpressions);
}
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "should-clone-payload");
String requestPayloadExpression = element.getAttribute("request-payload-expression");
if (StringUtils.hasText(requestPayloadExpression)) {
BeanDefinitionBuilder expressionBuilder =
BeanDefinitionBuilder.genericBeanDefinition(ExpressionFactoryBean.class)
.addConstructorArgValue(requestPayloadExpression);
builder.addPropertyValue("requestPayloadExpression", expressionBuilder.getBeanDefinition());
}
return builder;
}
@Override
protected boolean replyChannelInChainAllowed(Element element) {
return true;
}
}