/*
* Copyright 2002-2014 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.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.w3c.dom.Element;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.MessagingGatewayRegistrar;
import org.springframework.integration.gateway.GatewayMethodMetadata;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
/**
* Parser for the <gateway/> element.
*
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Gary Russell
* @author Artem Bilan
*/
public class GatewayParser implements BeanDefinitionParser {
private final MessagingGatewayRegistrar registrar = new MessagingGatewayRegistrar();
@Override
@SuppressWarnings("rawtypes")
public BeanDefinition parse(final Element element, ParserContext parserContext) {
boolean isNested = parserContext.isNested();
final Map<String, Object> gatewayAttributes = new HashMap<String, Object>();
gatewayAttributes.put("name", element.getAttribute(AbstractBeanDefinitionParser.ID_ATTRIBUTE));
gatewayAttributes.put("defaultPayloadExpression", element.getAttribute("default-payload-expression"));
gatewayAttributes.put("defaultRequestChannel",
element.getAttribute(isNested ? "request-channel" : "default-request-channel"));
gatewayAttributes.put("defaultReplyChannel",
element.getAttribute(isNested ? "reply-channel" : "default-reply-channel"));
gatewayAttributes.put("errorChannel", element.getAttribute("error-channel"));
String asyncExecutor = element.getAttribute("async-executor");
if (!element.hasAttribute("async-executor") || StringUtils.hasLength(asyncExecutor)) {
gatewayAttributes.put("asyncExecutor", asyncExecutor);
}
else {
gatewayAttributes.put("asyncExecutor", null);
}
gatewayAttributes.put("mapper", element.getAttribute("mapper"));
gatewayAttributes.put("defaultReplyTimeout",
element.getAttribute(isNested ? "reply-timeout" : "default-reply-timeout"));
gatewayAttributes.put("defaultRequestTimeout",
element.getAttribute(isNested ? "request-timeout" : "default-request-timeout"));
List<Element> headerElements = DomUtils.getChildElementsByTagName(element, "default-header");
if (!CollectionUtils.isEmpty(headerElements)) {
List<Map<String, Object>> headers = new ArrayList<Map<String, Object>>(headerElements.size());
for (Element e : headerElements) {
Map<String, Object> header = new HashMap<String, Object>();
header.put("name", e.getAttribute("name"));
header.put("value", e.getAttribute("value"));
header.put("expression", e.getAttribute("expression"));
headers.add(header);
}
gatewayAttributes.put("defaultHeaders", headers.toArray(new Map[headers.size()]));
}
List<Element> methodElements = DomUtils.getChildElementsByTagName(element, "method");
if (!CollectionUtils.isEmpty(methodElements)) {
Map<String, BeanDefinition> methodMetadataMap = new ManagedMap<String, BeanDefinition>();
for (Element methodElement : methodElements) {
String methodName = methodElement.getAttribute("name");
BeanDefinitionBuilder methodMetadataBuilder = BeanDefinitionBuilder.genericBeanDefinition(
GatewayMethodMetadata.class);
methodMetadataBuilder.addPropertyValue("requestChannelName",
methodElement.getAttribute("request-channel"));
methodMetadataBuilder.addPropertyValue("replyChannelName", methodElement.getAttribute("reply-channel"));
methodMetadataBuilder.addPropertyValue("requestTimeout", methodElement.getAttribute("request-timeout"));
methodMetadataBuilder.addPropertyValue("replyTimeout", methodElement.getAttribute("reply-timeout"));
boolean hasMapper = StringUtils.hasText(element.getAttribute("mapper"));
Assert.state(!hasMapper || !StringUtils.hasText(element.getAttribute("payload-expression")),
"'payload-expression' is not allowed when a 'mapper' is provided");
IntegrationNamespaceUtils.setValueIfAttributeDefined(methodMetadataBuilder, methodElement,
"payload-expression");
List<Element> invocationHeaders = DomUtils.getChildElementsByTagName(methodElement, "header");
if (!CollectionUtils.isEmpty(invocationHeaders)) {
Assert.state(!hasMapper, "header elements are not allowed when a 'mapper' is provided");
Map<String, Object> headerExpressions = new ManagedMap<String, Object>();
for (Element headerElement : invocationHeaders) {
BeanDefinition expressionDef = IntegrationNamespaceUtils
.createExpressionDefinitionFromValueOrExpression("value", "expression", parserContext,
headerElement, true);
headerExpressions.put(headerElement.getAttribute("name"), expressionDef);
}
methodMetadataBuilder.addPropertyValue("headerExpressions", headerExpressions);
}
methodMetadataMap.put(methodName, methodMetadataBuilder.getBeanDefinition());
}
gatewayAttributes.put("methods", methodMetadataMap);
}
gatewayAttributes.put("serviceInterface", element.getAttribute("service-interface"));
BeanDefinitionHolder gatewayHolder = this.registrar.parse(gatewayAttributes);
if (isNested) {
return gatewayHolder.getBeanDefinition();
}
else {
BeanDefinitionReaderUtils.registerBeanDefinition(gatewayHolder, parserContext.getRegistry());
return null;
}
}
}