/* * 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.BeanMetadataElement; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.parsing.BeanComponentDefinition; 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.integration.config.ExpressionFactoryBean; import org.springframework.integration.config.IntegrationConfigUtils; import org.springframework.integration.endpoint.ExpressionEvaluatingMessageSource; import org.springframework.integration.endpoint.MethodInvokingMessageSource; import org.springframework.integration.expression.DynamicExpression; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; /** * Parser for the <inbound-channel-adapter/> element. * * @author Mark Fisher * @author Artem Bilan * @author Gary Russell */ public class DefaultInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser { @Override protected BeanMetadataElement parseSource(Element element, ParserContext parserContext) { Object source = parserContext.extractSource(element); BeanMetadataElement result = null; BeanComponentDefinition innerBeanDef = IntegrationNamespaceUtils.parseInnerHandlerDefinition(element, parserContext); String sourceRef = element.getAttribute(IntegrationNamespaceUtils.REF_ATTRIBUTE); String methodName = element.getAttribute(IntegrationNamespaceUtils.METHOD_ATTRIBUTE); String expressionString = element.getAttribute(IntegrationNamespaceUtils.EXPRESSION_ATTRIBUTE); Element scriptElement = DomUtils.getChildElementByTagName(element, "script"); Element expressionElement = DomUtils.getChildElementByTagName(element, "expression"); boolean hasInnerDef = innerBeanDef != null; boolean hasRef = StringUtils.hasText(sourceRef); boolean hasExpression = StringUtils.hasText(expressionString); boolean hasScriptElement = scriptElement != null; boolean hasExpressionElement = expressionElement != null; boolean hasMethod = StringUtils.hasText(methodName); if (!hasInnerDef && !hasRef && !hasExpression && !hasScriptElement && !hasExpressionElement) { parserContext.getReaderContext().error( "Exactly one of the 'ref', 'expression', inner bean, <script> or <expression> is required.", element); } if (hasInnerDef) { if (hasRef || hasExpression) { parserContext.getReaderContext().error( "Neither 'ref' nor 'expression' are permitted when an inner bean (<bean/>) is configured on element " + IntegrationNamespaceUtils.createElementDescription(element) + ".", source); return null; } if (hasMethod) { result = this.parseMethodInvokingSource(innerBeanDef, methodName, element, parserContext); } else { result = innerBeanDef.getBeanDefinition(); } } else if (hasScriptElement) { if (hasRef || hasMethod || hasExpression) { parserContext.getReaderContext().error( "Neither 'ref' and 'method' nor 'expression' are permitted when an inner script element is configured on element " + IntegrationNamespaceUtils.createElementDescription(element) + ".", source); return null; } BeanDefinition scriptBeanDefinition = parserContext.getDelegate().parseCustomElement(scriptElement); BeanDefinitionBuilder sourceBuilder = BeanDefinitionBuilder.genericBeanDefinition( IntegrationConfigUtils.BASE_PACKAGE + ".scripting.ScriptExecutingMessageSource"); sourceBuilder.addConstructorArgValue(scriptBeanDefinition); this.parseHeaderExpressions(sourceBuilder, element, parserContext); result = sourceBuilder.getBeanDefinition(); } else if (hasExpression || hasExpressionElement) { if (hasRef || hasMethod) { parserContext.getReaderContext().error( "The 'ref' and 'method' attributes can't be used with 'expression' attribute or inner <expression>.", element); return null; } if (hasExpression & hasExpressionElement) { parserContext.getReaderContext().error( "Exactly one of the 'expression' attribute or inner <expression> is required.", element); return null; } result = this.parseExpression(expressionString, expressionElement, element, parserContext); } else if (hasRef) { BeanMetadataElement sourceValue = new RuntimeBeanReference(sourceRef); if (hasMethod) { result = this.parseMethodInvokingSource(sourceValue, methodName, element, parserContext); } else { result = sourceValue; } } return result; } private BeanMetadataElement parseMethodInvokingSource(BeanMetadataElement targetObject, String methodName, Element element, ParserContext parserContext) { BeanDefinitionBuilder sourceBuilder = BeanDefinitionBuilder.genericBeanDefinition(MethodInvokingMessageSource.class); sourceBuilder.addPropertyValue("object", targetObject); sourceBuilder.addPropertyValue("methodName", methodName); this.parseHeaderExpressions(sourceBuilder, element, parserContext); return sourceBuilder.getBeanDefinition(); } private BeanMetadataElement parseExpression(String expressionString, Element expressionElement, Element element, ParserContext parserContext) { BeanDefinitionBuilder sourceBuilder = BeanDefinitionBuilder.genericBeanDefinition(ExpressionEvaluatingMessageSource.class); BeanDefinition expressionDef = null; if (StringUtils.hasText(expressionString)) { expressionDef = new RootBeanDefinition(ExpressionFactoryBean.class); expressionDef.getConstructorArgumentValues().addGenericArgumentValue(expressionString); } else { BeanDefinitionBuilder dynamicExpressionBuilder = BeanDefinitionBuilder.genericBeanDefinition( DynamicExpression.class); String key = expressionElement.getAttribute("key"); String expressionSourceReference = expressionElement.getAttribute("source"); dynamicExpressionBuilder.addConstructorArgValue(key); dynamicExpressionBuilder.addConstructorArgReference(expressionSourceReference); expressionDef = dynamicExpressionBuilder.getBeanDefinition(); } sourceBuilder.addConstructorArgValue(expressionDef); sourceBuilder.addConstructorArgValue(null); this.parseHeaderExpressions(sourceBuilder, element, parserContext); return sourceBuilder.getBeanDefinition(); } private void parseHeaderExpressions(BeanDefinitionBuilder builder, Element element, ParserContext parserContext) { List<Element> headerElements = DomUtils.getChildElementsByTagName(element, "header"); if (!CollectionUtils.isEmpty(headerElements)) { ManagedMap<String, Object> headerExpressions = new ManagedMap<String, Object>(); for (Element headerElement : headerElements) { String headerName = headerElement.getAttribute("name"); BeanDefinition expressionDef = IntegrationNamespaceUtils.createExpressionDefinitionFromValueOrExpression("value", "expression", parserContext, headerElement, true); headerExpressions.put(headerName, expressionDef); } builder.addPropertyValue("headerExpressions", headerExpressions); } } }