INT-2312 Add HTTP RequestMapping support

The general idea is to use Spring-MVC as much as possible.

* Introduce `RequestMapping`, `IntegrationRequestMappingHandlerMapping`
* Introduce XSD nested element `<request-mapping>` for HTTP Inbound Endpoints
* Introduce `inboundCommonAttributes` XSD attributeGroup for HTTP Inbound Endpoints
* Introduce `IntegrationNamespaceUtils#createExpressionDefIfAttributeDefined` & `IntegrationNamespaceUtils#createDirectChannel`
* Remove deprecated `name` attribute
* Remove `UriPathHandlerMapping` as superseded by `IntegrationRequestMappingHandlerMapping`
* Add documentation for `<request-mapping>`
  - Add description to Reference Manual about `<request-mapping>`
* Add documentation to section 'What's new'
* Add additional test for `<request-mapping>`

JIRA: https://jira.springsource.org/browse/INT-2312, https://jira.springsource.org/browse/INT-2619

Additional changes:

* INT-2528 Remove deprecations in HTTP module
  - JIRA: https://jira.springsource.org/browse/INT-2528
* Add Jackson 2 support for HTTP-inbound
* Using Jackson 2 HttpMessageConverter if Jackson 2 is available in classpath
* Make `RequestMapping` public
* Introduce `HttpContextUtils` and move `HANDLER_MAPPING_BEAN_NAME` to it
* Revert and deprecate public API
* Improve JavaDocs
* Improve Reference Manual

Thanks also to Biju Kunjummen for his incorporated commit.
This commit is contained in:
Artem Bilan
2012-08-21 18:04:45 +03:00
committed by Gunnar Hillert
parent 28131aab32
commit 6a9cb75668
26 changed files with 1428 additions and 761 deletions

View File

@@ -20,7 +20,6 @@ import java.util.List;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
@@ -40,6 +39,8 @@ import org.springframework.integration.endpoint.AbstractPollingEndpoint;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
@@ -58,11 +59,11 @@ import org.springframework.util.xml.DomUtils;
*/
public abstract class IntegrationNamespaceUtils {
static final String BASE_PACKAGE = "org.springframework.integration";
static final String REF_ATTRIBUTE = "ref";
static final String METHOD_ATTRIBUTE = "method";
static final String ORDER = "order";
static final String EXPRESSION_ATTRIBUTE = "expression";
public static final String BASE_PACKAGE = "org.springframework.integration";
public static final String REF_ATTRIBUTE = "ref";
public static final String METHOD_ATTRIBUTE = "method";
public static final String ORDER = "order";
public static final String EXPRESSION_ATTRIBUTE = "expression";
public static final String HANDLER_ALIAS_SUFFIX = ".handler";
public static final String REQUEST_HANDLER_ADVICE_CHAIN = "request-handler-advice-chain";
public static final String AUTO_STARTUP = "auto-startup";
@@ -303,7 +304,8 @@ public abstract class IntegrationNamespaceUtils {
/**
* Utility method to configure HeaderMapper for Inbound and Outbound channel adapters/gateway
*/
public static void configureHeaderMapper(Element element, BeanDefinitionBuilder rootBuilder, ParserContext parserContext, Class<?> headerMapperClass, String replyHeaderValue){
public static void configureHeaderMapper(Element element, BeanDefinitionBuilder rootBuilder,
ParserContext parserContext, Class<?> headerMapperClass, String replyHeaderValue) {
String defaultMappedReplyHeadersAttributeName = "mapped-reply-headers";
if (!StringUtils.hasText(replyHeaderValue)){
replyHeaderValue = defaultMappedReplyHeadersAttributeName;
@@ -429,11 +431,11 @@ public abstract class IntegrationNamespaceUtils {
return adviceChain;
}
public static RootBeanDefinition createExpressionDefinitionFromValueOrExpression(String valueElementName,
public static BeanDefinition createExpressionDefinitionFromValueOrExpression(String valueElementName,
String expressionElementName, ParserContext parserContext, Element element, boolean oneRequired) {
Assert.hasText(valueElementName, "'valueElementName' must not be empty");
Assert.hasText(expressionElementName, "'expressionElementName' must no be empty");
Assert.hasText(expressionElementName, "'expressionElementName' must not be empty");
String valueElementValue = element.getAttribute(valueElementName);
String expressionElementValue = element.getAttribute(expressionElementName);
@@ -450,19 +452,16 @@ public abstract class IntegrationNamespaceUtils {
parserContext.getReaderContext().error("One of '" + valueElementName + "' or '"
+ expressionElementName + "' is required", element);
}
RootBeanDefinition expressionDef = null;
BeanDefinition expressionDef = null;
if (hasAttributeValue) {
expressionDef = new RootBeanDefinition(LiteralExpression.class);
expressionDef.getConstructorArgumentValues().addGenericArgumentValue(valueElementValue);
}
else if (hasAttributeExpression){
expressionDef = new RootBeanDefinition(ExpressionFactoryBean.class);
expressionDef.getConstructorArgumentValues().addGenericArgumentValue(expressionElementValue);
else {
expressionDef = createExpressionDefIfAttributeDefined(expressionElementName, element);
}
return expressionDef;
}
public static void registerSpelFunctionBean(BeanDefinitionRegistry registry, String functionId, String className,
String methodSignature) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SpelFunctionFactoryBean.class)
@@ -470,4 +469,30 @@ public abstract class IntegrationNamespaceUtils {
.addConstructorArgValue(methodSignature);
registry.registerBeanDefinition(functionId, builder.getBeanDefinition());
}
public static BeanDefinition createExpressionDefIfAttributeDefined(String expressionElementName, Element element) {
Assert.hasText(expressionElementName, "'expressionElementName' must no be empty");
String expressionElementValue = element.getAttribute(expressionElementName);
if (StringUtils.hasText(expressionElementValue)){
BeanDefinitionBuilder expressionDefBuilder = BeanDefinitionBuilder.genericBeanDefinition(ExpressionFactoryBean.class);
expressionDefBuilder.addConstructorArgValue(expressionElementValue);
return expressionDefBuilder.getRawBeanDefinition();
}
return null;
}
public static String createDirectChannel(Element element, ParserContext parserContext) {
String channelId = element.getAttribute(ID_ATTRIBUTE);
if (!StringUtils.hasText(channelId)) {
parserContext.getReaderContext().error("The channel-adapter's 'id' attribute is required when no 'channel' "
+ "reference has been provided, because that 'id' would be used for the created channel.", element);
}
BeanDefinitionBuilder channelBuilder = BeanDefinitionBuilder.genericBeanDefinition(DirectChannel.class);
BeanDefinitionHolder holder = new BeanDefinitionHolder(channelBuilder.getBeanDefinition(), channelId);
BeanDefinitionReaderUtils.registerBeanDefinition(holder, parserContext.getRegistry());
return channelId;
}
}