From 8737d46c6e8c737b7a76c787809b37c9c43a41ae Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Tue, 12 Oct 2010 19:11:52 -0400 Subject: [PATCH] INT-1382 added support for 'expression' sub-elements in the core schema --- ...pressionEvaluatingCorrelationStrategy.java | 18 +- ...essionEvaluatingMessageGroupProcessor.java | 28 +- .../AbstractMessageHandlerFactoryBean.java | 17 +- .../integration/config/FilterFactoryBean.java | 3 +- .../integration/config/RouterFactoryBean.java | 3 +- .../config/ServiceActivatorFactoryBean.java | 3 +- .../config/SplitterFactoryBean.java | 21 +- .../config/TransformerFactoryBean.java | 3 +- ...tractDelegatingConsumerEndpointParser.java | 35 +- .../expression/DynamicExpression.java | 12 +- .../filter/ExpressionEvaluatingSelector.java | 13 +- .../ExpressionEvaluatingMessageProcessor.java | 19 +- .../router/ExpressionEvaluatingRouter.java | 3 +- .../ExpressionEvaluatingSplitter.java | 3 +- .../ExpressionEvaluatingTransformer.java | 3 +- .../transformer/HeaderEnricher.java | 13 +- .../config/xml/spring-integration-2.0.xsd | 29 +- ...ionEvaluatingCorrelationStrategyTests.java | 27 +- ...pressionFilterIntegrationTests-context.xml | 26 ++ ...namicExpressionFilterIntegrationTests.java | 63 ++++ .../integration/filter/expressions.properties | 1 + ...essionEvaluatingMessageProcessorTests.java | 44 ++- .../http/DefaultInboundRequestMapper.java | 355 ------------------ .../DefaultInboundRequestMapperTests.java | 127 ------- 24 files changed, 317 insertions(+), 552 deletions(-) create mode 100644 spring-integration-core/src/test/java/org/springframework/integration/filter/DynamicExpressionFilterIntegrationTests-context.xml create mode 100644 spring-integration-core/src/test/java/org/springframework/integration/filter/DynamicExpressionFilterIntegrationTests.java create mode 100644 spring-integration-core/src/test/java/org/springframework/integration/filter/expressions.properties delete mode 100644 spring-integration-http/src/main/java/org/springframework/integration/http/DefaultInboundRequestMapper.java delete mode 100644 spring-integration-http/src/test/java/org/springframework/integration/http/DefaultInboundRequestMapperTests.java diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingCorrelationStrategy.java b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingCorrelationStrategy.java index 3b7f708117..6d312628fc 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingCorrelationStrategy.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingCorrelationStrategy.java @@ -16,8 +16,13 @@ package org.springframework.integration.aggregator; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.SpelParserConfiguration; +import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.Message; import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor; +import org.springframework.util.Assert; /** * {@link CorrelationStrategy} implementation that evaluates an expression. @@ -26,12 +31,23 @@ import org.springframework.integration.handler.ExpressionEvaluatingMessageProces */ public class ExpressionEvaluatingCorrelationStrategy implements CorrelationStrategy { + private static final ExpressionParser expressionParser = new SpelExpressionParser(new SpelParserConfiguration(true, true)); + + private final ExpressionEvaluatingMessageProcessor processor; - public ExpressionEvaluatingCorrelationStrategy(String expression) { + + public ExpressionEvaluatingCorrelationStrategy(String expressionString) { + Assert.hasText(expressionString, "expressionString must not be empty"); + Expression expression = expressionParser.parseExpression(expressionString); this.processor = new ExpressionEvaluatingMessageProcessor(expression, Object.class); } + public ExpressionEvaluatingCorrelationStrategy(Expression expression) { + this.processor = new ExpressionEvaluatingMessageProcessor(expression, Object.class); + } + + public Object getCorrelationKey(Message message) { return processor.processMessage(message); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingMessageGroupProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingMessageGroupProcessor.java index 240f43d196..bbfd121fe6 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingMessageGroupProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingMessageGroupProcessor.java @@ -1,3 +1,19 @@ +/* + * Copyright 2002-2010 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.aggregator; import java.util.Map; @@ -15,12 +31,16 @@ import org.springframework.integration.store.MessageGroup; * * @author Alex Peters * @author Dave Syer - * */ public class ExpressionEvaluatingMessageGroupProcessor extends AbstractAggregatingMessageGroupProcessor implements BeanFactoryAware { - + private final ExpressionEvaluatingMessageListProcessor processor; + + public ExpressionEvaluatingMessageGroupProcessor(String expression) { + processor = new ExpressionEvaluatingMessageListProcessor(expression); + } + public void setBeanFactory(BeanFactory beanFactory) { processor.setBeanFactory(beanFactory); } @@ -33,10 +53,6 @@ public class ExpressionEvaluatingMessageGroupProcessor extends AbstractAggregati processor.setExpectedType(expectedType); } - public ExpressionEvaluatingMessageGroupProcessor(String expression) { - processor = new ExpressionEvaluatingMessageListProcessor(expression); - } - /** * Evaluate the expression provided on the unmarked messages (a collection) in the group, and delegate to the * {@link MessagingTemplate} to send downstream. diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMessageHandlerFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMessageHandlerFactoryBean.java index beeabf137c..d3ebf8132b 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMessageHandlerFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMessageHandlerFactoryBean.java @@ -22,6 +22,10 @@ import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.SpelParserConfiguration; +import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.MessageChannel; import org.springframework.integration.core.MessageHandler; import org.springframework.integration.handler.AbstractMessageHandler; @@ -38,13 +42,16 @@ import org.springframework.util.StringUtils; */ abstract class AbstractMessageHandlerFactoryBean implements FactoryBean, BeanFactoryAware { + private static final ExpressionParser expressionParser = new SpelExpressionParser(new SpelParserConfiguration(true, true)); + + private volatile MessageHandler handler; private volatile Object targetObject; private volatile String targetMethodName; - private volatile String expression; + private volatile Expression expression; private volatile MessageChannel outputChannel; @@ -65,7 +72,11 @@ abstract class AbstractMessageHandlerFactoryBean implements FactoryBean processor = new ExpressionEvaluatingMessageProcessor(expression); processor.setBeanFactory(this.getBeanFactory()); return this.configureHandler(new ServiceActivatingHandler(processor)); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/SplitterFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/config/SplitterFactoryBean.java index dbae530ef5..31dc216dcb 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/SplitterFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/SplitterFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -16,6 +16,7 @@ package org.springframework.integration.config; +import org.springframework.expression.Expression; import org.springframework.integration.core.MessageHandler; import org.springframework.integration.splitter.AbstractMessageSplitter; import org.springframework.integration.splitter.DefaultMessageSplitter; @@ -31,12 +32,22 @@ import org.springframework.util.StringUtils; public class SplitterFactoryBean extends AbstractMessageHandlerFactoryBean { private volatile Long sendTimeout; + private volatile boolean requiresReply; + public void setSendTimeout(Long sendTimeout) { this.sendTimeout = sendTimeout; } + public boolean isRequiresReply() { + return requiresReply; + } + + public void setRequiresReply(boolean requiresReply) { + this.requiresReply = requiresReply; + } + @Override MessageHandler createMethodInvokingHandler(Object targetObject, String targetMethodName) { AbstractMessageSplitter splitter = null; @@ -52,7 +63,7 @@ public class SplitterFactoryBean extends AbstractMessageHandlerFactoryBean { } @Override - MessageHandler createExpressionEvaluatingHandler(String expression) { + MessageHandler createExpressionEvaluatingHandler(Expression expression) { return this.configureSplitter(new ExpressionEvaluatingSplitter(expression)); } @@ -68,11 +79,5 @@ public class SplitterFactoryBean extends AbstractMessageHandlerFactoryBean { splitter.setRequiresReply(requiresReply); return splitter; } - public boolean isRequiresReply() { - return requiresReply; - } - public void setRequiresReply(boolean requiresReply) { - this.requiresReply = requiresReply; - } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/TransformerFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/config/TransformerFactoryBean.java index 02545292be..aa782aef31 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/TransformerFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/TransformerFactoryBean.java @@ -16,6 +16,7 @@ package org.springframework.integration.config; +import org.springframework.expression.Expression; import org.springframework.integration.core.MessageHandler; import org.springframework.integration.transformer.ExpressionEvaluatingTransformer; import org.springframework.integration.transformer.MessageTransformingHandler; @@ -54,7 +55,7 @@ public class TransformerFactoryBean extends AbstractMessageHandlerFactoryBean { } @Override - MessageHandler createExpressionEvaluatingHandler(String expression) { + MessageHandler createExpressionEvaluatingHandler(Expression expression) { Transformer transformer = new ExpressionEvaluatingTransformer(expression); return this.createHandler(transformer); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractDelegatingConsumerEndpointParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractDelegatingConsumerEndpointParser.java index 6a5d79ef62..0e32bc975a 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractDelegatingConsumerEndpointParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractDelegatingConsumerEndpointParser.java @@ -38,6 +38,7 @@ abstract class AbstractDelegatingConsumerEndpointParser extends AbstractConsumer @Override protected final BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) { + Object source = parserContext.extractSource(element); BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(this.getFactoryBeanClassName()); BeanComponentDefinition innerDefinition = IntegrationNamespaceUtils.parseInnerHandlerDefinition(element, parserContext); String ref = element.getAttribute(REF_ATTRIBUTE); @@ -45,23 +46,43 @@ abstract class AbstractDelegatingConsumerEndpointParser extends AbstractConsumer boolean hasRef = StringUtils.hasText(ref); boolean hasExpression = StringUtils.hasText(expression); Element scriptElement = DomUtils.getChildElementByTagName(element, "script"); + Element expressionElement = DomUtils.getChildElementByTagName(element, "expression"); if (innerDefinition != null) { - if (hasRef || hasExpression) { + if (hasRef || hasExpression || expressionElement != null) { parserContext.getReaderContext().error( - "Neither 'ref' nor 'expression' are permitted when an inner bean () is configured.", element); + "Neither 'ref' nor 'expression' are permitted when an inner bean () is configured.", source); return null; } builder.addPropertyValue("targetObject", innerDefinition); } + else if (scriptElement != null) { + if (hasRef || hasExpression || expressionElement != null) { + parserContext.getReaderContext().error( + "Neither 'ref' nor 'expression' are permitted when an inner script element is configured.", source); + return null; + } + BeanDefinition scriptBeanDefinition = parserContext.getDelegate().parseCustomElement(scriptElement, builder.getBeanDefinition()); + builder.addPropertyValue("targetObject", scriptBeanDefinition); + } + else if (expressionElement != null) { + if (hasRef || hasExpression) { + parserContext.getReaderContext().error( + "Neither 'ref' nor 'expression' are permitted when an inner 'expression' element is configured.", source); + return null; + } + BeanDefinitionBuilder dynamicExpressionBuilder = BeanDefinitionBuilder.genericBeanDefinition( + "org.springframework.integration.expression.DynamicExpression"); + String key = expressionElement.getAttribute("key"); + String expressionSourceReference = expressionElement.getAttribute("source"); + dynamicExpressionBuilder.addConstructorArgValue(key); + dynamicExpressionBuilder.addConstructorArgReference(expressionSourceReference); + builder.addPropertyValue("expression", dynamicExpressionBuilder.getBeanDefinition()); + } else if (hasRef) { builder.addPropertyReference("targetObject", ref); } else if (hasExpression) { - builder.addPropertyValue("expression", expression); - } - else if (scriptElement != null) { - BeanDefinition scriptBeanDefinition = parserContext.getDelegate().parseCustomElement(scriptElement, builder.getBeanDefinition()); - builder.addPropertyValue("targetObject", scriptBeanDefinition); + builder.addPropertyValue("expressionString", expression); } else if (!this.hasDefaultOption()) { parserContext.getReaderContext().error("Exactly one of the 'ref' attribute, 'expression' attribute, " + diff --git a/spring-integration-core/src/main/java/org/springframework/integration/expression/DynamicExpression.java b/spring-integration-core/src/main/java/org/springframework/integration/expression/DynamicExpression.java index 2857c6fcc8..2ad9983bcb 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/expression/DynamicExpression.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/expression/DynamicExpression.java @@ -68,15 +68,15 @@ public class DynamicExpression implements Expression { } public Object getValue(EvaluationContext context, Object rootObject) throws EvaluationException { - return this.getValue(context, rootObject); + return this.resolveExpression().getValue(context, rootObject); } public T getValue(EvaluationContext context, Class desiredResultType) throws EvaluationException { - return this.getValue(context, desiredResultType); + return this.resolveExpression().getValue(context, desiredResultType); } public T getValue(EvaluationContext context, Object rootObject, Class desiredResultType) throws EvaluationException { - return this.getValue(context, rootObject, desiredResultType); + return this.resolveExpression().getValue(context, rootObject, desiredResultType); } public Class getValueType() throws EvaluationException { @@ -120,7 +120,7 @@ public class DynamicExpression implements Expression { } public boolean isWritable(Object rootObject) throws EvaluationException { - return this.isWritable(rootObject); + return this.resolveExpression().isWritable(rootObject); } public void setValue(EvaluationContext context, Object value) throws EvaluationException { @@ -141,7 +141,9 @@ public class DynamicExpression implements Expression { private Expression resolveExpression() { Locale locale = LocaleContextHolder.getLocale(); - return this.expressionSource.getExpression(this.key, locale); + Expression expression = this.expressionSource.getExpression(this.key, locale); + Assert.state(expression != null, "Unable to resolve Expression with key '" + this.key + "'"); + return expression; } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java b/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java index 5b13de83b7..e1ab8a6a08 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java @@ -16,6 +16,10 @@ package org.springframework.integration.filter; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.SpelParserConfiguration; +import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.core.MessageSelector; import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor; @@ -28,7 +32,14 @@ import org.springframework.integration.handler.ExpressionEvaluatingMessageProces */ public class ExpressionEvaluatingSelector extends AbstractMessageProcessingSelector { - public ExpressionEvaluatingSelector(String expression) { + private static final ExpressionParser expressionParser = new SpelExpressionParser(new SpelParserConfiguration(true, true)); + + + public ExpressionEvaluatingSelector(String expressionString) { + super(new ExpressionEvaluatingMessageProcessor(expressionParser.parseExpression(expressionString), Boolean.class)); + } + + public ExpressionEvaluatingSelector(Expression expression) { super(new ExpressionEvaluatingMessageProcessor(expression, Boolean.class)); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/ExpressionEvaluatingMessageProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/ExpressionEvaluatingMessageProcessor.java index cf85907536..f40ad5a76d 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/ExpressionEvaluatingMessageProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/ExpressionEvaluatingMessageProcessor.java @@ -18,10 +18,7 @@ package org.springframework.integration.handler; import org.springframework.context.expression.MapAccessor; import org.springframework.expression.Expression; -import org.springframework.expression.ExpressionParser; import org.springframework.expression.ParseException; -import org.springframework.expression.spel.SpelParserConfiguration; -import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.Message; import org.springframework.util.Assert; @@ -34,25 +31,27 @@ import org.springframework.util.Assert; */ public class ExpressionEvaluatingMessageProcessor extends AbstractMessageProcessor { - private final ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true)); - private final Expression expression; private final Class expectedType; - public ExpressionEvaluatingMessageProcessor(String expression) { + /** + * Create an {@link ExpressionEvaluatingMessageProcessor} for the given expression. + */ + public ExpressionEvaluatingMessageProcessor(Expression expression) { this(expression, null); } /** - * Create an {@link ExpressionEvaluatingMessageProcessor} for the given expression String. + * Create an {@link ExpressionEvaluatingMessageProcessor} for the given expression + * and expected type for its evaluation result. */ - public ExpressionEvaluatingMessageProcessor(String expression, Class expectedType) { - Assert.hasLength(expression, "The expression must be non empty"); + public ExpressionEvaluatingMessageProcessor(Expression expression, Class expectedType) { + Assert.notNull(expression, "The expression must not be null"); try { - this.expression = parser.parseExpression(expression); + this.expression = expression; this.getEvaluationContext().addPropertyAccessor(new MapAccessor()); this.expectedType = expectedType; } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/ExpressionEvaluatingRouter.java b/spring-integration-core/src/main/java/org/springframework/integration/router/ExpressionEvaluatingRouter.java index 86827fed6a..ec1810ef5a 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/router/ExpressionEvaluatingRouter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/router/ExpressionEvaluatingRouter.java @@ -16,6 +16,7 @@ package org.springframework.integration.router; +import org.springframework.expression.Expression; import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor; /** @@ -28,7 +29,7 @@ import org.springframework.integration.handler.ExpressionEvaluatingMessageProces */ public class ExpressionEvaluatingRouter extends AbstractMessageProcessingRouter { - public ExpressionEvaluatingRouter(String expression) { + public ExpressionEvaluatingRouter(Expression expression) { super(new ExpressionEvaluatingMessageProcessor(expression)); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/splitter/ExpressionEvaluatingSplitter.java b/spring-integration-core/src/main/java/org/springframework/integration/splitter/ExpressionEvaluatingSplitter.java index 999fe697dd..52baa2be8d 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/splitter/ExpressionEvaluatingSplitter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/splitter/ExpressionEvaluatingSplitter.java @@ -18,6 +18,7 @@ package org.springframework.integration.splitter; import java.util.Collection; +import org.springframework.expression.Expression; import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor; /** @@ -32,7 +33,7 @@ import org.springframework.integration.handler.ExpressionEvaluatingMessageProces public class ExpressionEvaluatingSplitter extends AbstractMessageProcessingSplitter { @SuppressWarnings({"unchecked", "rawtypes"}) - public ExpressionEvaluatingSplitter(String expression) { + public ExpressionEvaluatingSplitter(Expression expression) { super(new ExpressionEvaluatingMessageProcessor(expression, Collection.class)); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/transformer/ExpressionEvaluatingTransformer.java b/spring-integration-core/src/main/java/org/springframework/integration/transformer/ExpressionEvaluatingTransformer.java index 0b2de2a56a..679ced3f28 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/transformer/ExpressionEvaluatingTransformer.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/transformer/ExpressionEvaluatingTransformer.java @@ -16,6 +16,7 @@ package org.springframework.integration.transformer; +import org.springframework.expression.Expression; import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor; /** @@ -28,7 +29,7 @@ import org.springframework.integration.handler.ExpressionEvaluatingMessageProces */ public class ExpressionEvaluatingTransformer extends AbstractMessageProcessingTransformer { - public ExpressionEvaluatingTransformer(String expression) { + public ExpressionEvaluatingTransformer(Expression expression) { super(new ExpressionEvaluatingMessageProcessor(expression)); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/transformer/HeaderEnricher.java b/spring-integration-core/src/main/java/org/springframework/integration/transformer/HeaderEnricher.java index dd67cddd4c..39d65cdae5 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/transformer/HeaderEnricher.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/transformer/HeaderEnricher.java @@ -21,9 +21,12 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.SpelParserConfiguration; +import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.Message; import org.springframework.integration.MessagingException; import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor; @@ -168,15 +171,17 @@ public class HeaderEnricher implements Transformer { static class ExpressionEvaluatingHeaderValueMessageProcessor extends AbstractHeaderValueMessageProcessor implements BeanFactoryAware { + private static final ExpressionParser expressionParser = new SpelExpressionParser(new SpelParserConfiguration(true, true)); + private final ExpressionEvaluatingMessageProcessor targetProcessor; /** - * Create a header value processor for the given expression String and the expected type + * Create a header value processor for the given expression string and the expected type * of the expression evaluation result. The expectedType may be null if unknown. */ public ExpressionEvaluatingHeaderValueMessageProcessor(String expressionString, Class expectedType) { - this.targetProcessor = new ExpressionEvaluatingMessageProcessor(expressionString, expectedType); - //this.targetProcessor.setExpectedType(expectedType); + Expression expression = expressionParser.parseExpression(expressionString); + this.targetProcessor = new ExpressionEvaluatingMessageProcessor(expression, expectedType); } public void setBeanFactory(BeanFactory beanFactory) { diff --git a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd index ce725abcb3..abad1e9ca6 100644 --- a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd +++ b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd @@ -2357,7 +2357,12 @@ Name of the header whose value to use. - + + + + + + @@ -2369,6 +2374,28 @@ Name of the header whose value to use. + + + + + The key for retrieving the expression from an ExpressionSource. + + + + + + + The reference to an ExpressionSource. + + + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/aggregator/ExpressionEvaluatingCorrelationStrategyTests.java b/spring-integration-core/src/test/java/org/springframework/integration/aggregator/ExpressionEvaluatingCorrelationStrategyTests.java index 5cc196f450..51f6b2bc65 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/aggregator/ExpressionEvaluatingCorrelationStrategyTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/aggregator/ExpressionEvaluatingCorrelationStrategyTests.java @@ -1,20 +1,36 @@ +/* + * Copyright 2002-2010 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.aggregator; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import org.junit.Test; - +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.SpelParserConfiguration; +import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.message.GenericMessage; /** * @author Alex Peters - * */ public class ExpressionEvaluatingCorrelationStrategyTests { private ExpressionEvaluatingCorrelationStrategy strategy; + @Test(expected = IllegalArgumentException.class) public void testCreateInstanceWithEmptyExpressionFails() throws Exception { strategy = new ExpressionEvaluatingCorrelationStrategy(""); @@ -22,12 +38,15 @@ public class ExpressionEvaluatingCorrelationStrategyTests { @Test(expected = IllegalArgumentException.class) public void testCreateInstanceWithNullExpressionFails() throws Exception { - strategy = new ExpressionEvaluatingCorrelationStrategy(null); + Expression nullExpression = null; + strategy = new ExpressionEvaluatingCorrelationStrategy(nullExpression); } @Test public void testCorrelationKeyWithMethodInvokingExpression() throws Exception { - strategy = new ExpressionEvaluatingCorrelationStrategy("payload.substring(0,1)"); + ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true)); + Expression expression = parser.parseExpression("payload.substring(0,1)"); + strategy = new ExpressionEvaluatingCorrelationStrategy(expression); Object correlationKey = strategy.getCorrelationKey(new GenericMessage("bla")); assertThat(correlationKey, is(String.class)); assertThat((String) correlationKey, is("b")); diff --git a/spring-integration-core/src/test/java/org/springframework/integration/filter/DynamicExpressionFilterIntegrationTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/filter/DynamicExpressionFilterIntegrationTests-context.xml new file mode 100644 index 0000000000..2f8d2b0614 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/filter/DynamicExpressionFilterIntegrationTests-context.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/filter/DynamicExpressionFilterIntegrationTests.java b/spring-integration-core/src/test/java/org/springframework/integration/filter/DynamicExpressionFilterIntegrationTests.java new file mode 100644 index 0000000000..8934f4c62c --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/filter/DynamicExpressionFilterIntegrationTests.java @@ -0,0 +1,63 @@ +/* + * Copyright 2002-2010 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.filter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.integration.MessageChannel; +import org.springframework.integration.core.PollableChannel; +import org.springframework.integration.message.GenericMessage; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Mark Fisher + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class DynamicExpressionFilterIntegrationTests { + + @Autowired + private MessageChannel input; + + @Autowired + private PollableChannel positives; + + @Autowired + private PollableChannel negatives; + + + @Test + public void simpleExpressionBasedFilter() { + this.input.send(new GenericMessage(1)); + this.input.send(new GenericMessage(0)); + this.input.send(new GenericMessage(99)); + this.input.send(new GenericMessage(-99)); + assertEquals(new Integer(1), positives.receive(0).getPayload()); + assertEquals(new Integer(99), positives.receive(0).getPayload()); + assertEquals(new Integer(0), negatives.receive(0).getPayload()); + assertEquals(new Integer(-99), negatives.receive(0).getPayload()); + assertNull(positives.receive(0)); + assertNull(negatives.receive(0)); + } + +} diff --git a/spring-integration-core/src/test/java/org/springframework/integration/filter/expressions.properties b/spring-integration-core/src/test/java/org/springframework/integration/filter/expressions.properties new file mode 100644 index 0000000000..17b14a2975 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/filter/expressions.properties @@ -0,0 +1 @@ +filter.positive=payload > 0 \ No newline at end of file diff --git a/spring-integration-core/src/test/java/org/springframework/integration/handler/ExpressionEvaluatingMessageProcessorTests.java b/spring-integration-core/src/test/java/org/springframework/integration/handler/ExpressionEvaluatingMessageProcessorTests.java index d63f5e4ddf..38f6d893fc 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/handler/ExpressionEvaluatingMessageProcessorTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/handler/ExpressionEvaluatingMessageProcessorTests.java @@ -32,6 +32,10 @@ import org.springframework.context.support.GenericApplicationContext; import org.springframework.context.support.StaticApplicationContext; import org.springframework.core.io.Resource; import org.springframework.expression.EvaluationException; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.SpelParserConfiguration; +import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.message.GenericMessage; /** @@ -43,6 +47,8 @@ public class ExpressionEvaluatingMessageProcessorTests { private static final Log logger = LogFactory.getLog(ExpressionEvaluatingMessageProcessorTests.class); + private static final ExpressionParser expressionParser = new SpelExpressionParser(new SpelParserConfiguration(true, true)); + @Rule public ExpectedException expected = ExpectedException.none(); @@ -50,7 +56,8 @@ public class ExpressionEvaluatingMessageProcessorTests { @Test public void testProcessMessage() { - ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("payload"); + Expression expression = expressionParser.parseExpression("payload"); + ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); assertEquals("foo", processor.processMessage(new GenericMessage("foo"))); } @@ -62,7 +69,8 @@ public class ExpressionEvaluatingMessageProcessorTests { return number+""; } } - ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("#target.stringify(payload)"); + Expression expression = expressionParser.parseExpression("#target.stringify(payload)"); + ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); processor.getEvaluationContext().setVariable("target", new TestTarget()); assertEquals("2", processor.processMessage(new GenericMessage("2"))); } @@ -74,7 +82,8 @@ public class ExpressionEvaluatingMessageProcessorTests { public void ping(String input) { } } - ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("#target.ping(payload)"); + Expression expression = expressionParser.parseExpression("#target.ping(payload)"); + ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); processor.getEvaluationContext().setVariable("target", new TestTarget()); assertEquals(null, processor.processMessage(new GenericMessage("2"))); } @@ -88,7 +97,8 @@ public class ExpressionEvaluatingMessageProcessorTests { } } - ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("#target.find(payload)"); + Expression expression = expressionParser.parseExpression("#target.find(payload)"); + ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); processor.setBeanFactory(new GenericApplicationContext().getBeanFactory()); processor.getEvaluationContext().setVariable("target", new TestTarget()); String result = (String) processor.processMessage(new GenericMessage("classpath:*.properties")); @@ -97,21 +107,24 @@ public class ExpressionEvaluatingMessageProcessorTests { @Test public void testProcessMessageWithDollarInBrackets() { - ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("headers['$id']"); + Expression expression = expressionParser.parseExpression("headers['$id']"); + ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); GenericMessage message = new GenericMessage("foo"); assertEquals(message.getHeaders().getId(), processor.processMessage(message)); } @Test public void testProcessMessageWithDollarPropertyAccess() { - ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("headers.$id"); + Expression expression = expressionParser.parseExpression("headers.$id"); + ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); GenericMessage message = new GenericMessage("foo"); assertEquals(message.getHeaders().getId(), processor.processMessage(message)); } @Test public void testProcessMessageWithStaticKey() { - ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("headers[headers.ID]"); + Expression expression = expressionParser.parseExpression("headers[headers.ID]"); + ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); GenericMessage message = new GenericMessage("foo"); assertEquals(message.getHeaders().getId(), processor.processMessage(message)); } @@ -122,7 +135,8 @@ public class ExpressionEvaluatingMessageProcessorTests { BeanDefinition beanDefinition = new RootBeanDefinition(String.class); beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("bar"); context.registerBeanDefinition("testString", beanDefinition); - ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("payload.concat(@testString)"); + Expression expression = expressionParser.parseExpression("payload.concat(@testString)"); + ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); processor.setBeanFactory(context); GenericMessage message = new GenericMessage("foo"); assertEquals("foobar", processor.processMessage(message)); @@ -134,7 +148,8 @@ public class ExpressionEvaluatingMessageProcessorTests { BeanDefinition beanDefinition = new RootBeanDefinition(String.class); beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("bar"); context.registerBeanDefinition("testString", beanDefinition); - ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("@testString.concat(payload)"); + Expression expression = expressionParser.parseExpression("@testString.concat(payload)"); + ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); processor.setBeanFactory(context); GenericMessage message = new GenericMessage("foo"); assertEquals("barfoo", processor.processMessage(message)); @@ -154,7 +169,8 @@ public class ExpressionEvaluatingMessageProcessorTests { description.appendText("cause to be EvaluationException but was ").appendValue(cause); } }); - ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("payload.fixMe()"); + Expression expression = expressionParser.parseExpression("payload.fixMe()"); + ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); assertEquals("foo", processor.processMessage(new GenericMessage("foo"))); } @@ -172,7 +188,8 @@ public class ExpressionEvaluatingMessageProcessorTests { description.appendText("cause to be UnsupportedOperationException but was ").appendValue(cause); } }); - ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("payload.throwRuntimeException()"); + Expression expression = expressionParser.parseExpression("payload.throwRuntimeException()"); + ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); assertEquals("foo", processor.processMessage(new GenericMessage(new TestPayload()))); } @@ -190,7 +207,8 @@ public class ExpressionEvaluatingMessageProcessorTests { description.appendText("cause to be CheckedException but was ").appendValue(cause); } }); - ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("payload.throwCheckedException()"); + Expression expression = expressionParser.parseExpression("payload.throwCheckedException()"); + ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); assertEquals("foo", processor.processMessage(new GenericMessage(new TestPayload()))); } @@ -213,5 +231,5 @@ public class ExpressionEvaluatingMessageProcessorTests { super(string); } } - + } diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/DefaultInboundRequestMapper.java b/spring-integration-http/src/main/java/org/springframework/integration/http/DefaultInboundRequestMapper.java deleted file mode 100644 index b014325af0..0000000000 --- a/spring-integration-http/src/main/java/org/springframework/integration/http/DefaultInboundRequestMapper.java +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright 2002-2010 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.http; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.ServletRequest; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.integration.Message; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.util.FileCopyUtils; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.multipart.MultipartException; -import org.springframework.web.multipart.MultipartFile; -import org.springframework.web.multipart.MultipartHttpServletRequest; -import org.springframework.web.multipart.MultipartResolver; - -/** - * Default implementation of {@link InboundRequestMapper} for inbound HttpServletRequests. - * The request will be mapped according to the following rules: - *
    - *
  • For a GET request or a POST request with a Content-Type of - * "application/x-www-form-urlencoded", the parameter Map will be copied as the - * payload. The map will be an instance of {@link MultiValueMap} where the keys are - * Strings and the values are Lists of Strings. Those Lists are populated from the - * String array values of the original request parameter Map as described for the - * {@link ServletRequest#getParameterMap()} method.
  • - *
  • If a MultipartResolver has been provided, and a multipart request is - * detected, the multipart file content will be converted to String for any - * "text" content type, or byte arrays otherwise.
  • - *
  • For other request types, the request body will be used as the payload - * and the type will depend on the Content-Type header value. If it begins with - * "text", a String will be created. If the Content-Type is - * "application/x-java-serialized-object", the request body will be expected to - * contain a Serializable Object, and that will be used as the message payload. - * Otherwise, the payload will be a byte array.
  • - *
- * In all cases, the original request headers will be passed in the - * MessageHeaders. Likewise, the following headers will be added: - *
    - *
  • {@link HttpHeaders#REQUEST_URL}
  • - *
  • {@link HttpHeaders#REQUEST_METHOD}
  • - *
  • {@link HttpHeaders#USER_PRINCIPAL} (if available)
  • - *
- * - * @author Mark Fisher - * @author Oleg Zhurakousky - * @since 1.0.2 - */ -public class DefaultInboundRequestMapper implements InboundRequestMapper { - - private final Log logger = LogFactory.getLog(getClass()); - - private volatile MultipartResolver multipartResolver; - - private volatile String multipartCharset = null; - - private volatile boolean copyUploadedFiles; - - - /** - * Specify the {@link MultipartResolver} to use when checking requests. - * If no resolver is provided, this mapper will not support multipart - * requests. - */ - public void setMultipartResolver(MultipartResolver multipartResolver) { - this.multipartResolver = multipartResolver; - } - - /** - * Specify the charset name to use when converting multipart file content - * into Strings. - */ - public void setMultipartCharset(String multipartCharset) { - this.multipartCharset = multipartCharset; - } - - /** - * Specify whether uploaded multipart files should be copied to a temporary - * file on the server. If this is set to 'true', the payload map will - * contain a File instance as the value for each multipart file entry. - * Otherwise the uploaded file's content will be converted to either a - * String or byte array based on the content-type (String for "text/*" and - * byte array otherwise). The default value is false. - */ - public void setCopyUploadedFiles(boolean copyUploadedFiles) { - this.copyUploadedFiles = copyUploadedFiles; - } - - public Message toMessage(HttpServletRequest request) throws Exception { - try { - request = this.checkMultipart(request); - Object payload = createPayloadFromRequest(request); - MessageBuilder builder = MessageBuilder.withPayload(payload); - this.populateHeaders(request, builder); - return builder.build(); - } - finally { - this.cleanupMultipart(request); - } - } - - /** - * Convert the request into a multipart request to make multiparts available. - * If no multipart resolver is set, simply use the existing request. - * @param request current HTTP request - * @return the processed request (multipart wrapper if necessary) - * @see MultipartResolver#resolveMultipart - */ - private HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException { - if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) { - if (request instanceof MultipartHttpServletRequest) { - logger.debug("Request is already a MultipartHttpServletRequest"); - } - else { - return this.multipartResolver.resolveMultipart(request); - } - } - return request; - } - - /** - * Clean up any resources used by the given multipart request (if any). - * @param request current HTTP request - * @see MultipartResolver#cleanupMultipart - */ - private void cleanupMultipart(HttpServletRequest request) { - if (this.multipartResolver != null && request instanceof MultipartHttpServletRequest) { - this.multipartResolver.cleanupMultipart((MultipartHttpServletRequest) request); - } - } - - private Object createPayloadFromRequest(HttpServletRequest request) throws Exception { - Object payload = null; - String contentType = request.getContentType() != null ? request.getContentType() : ""; - if (request instanceof MultipartHttpServletRequest) { - payload = this.createPayloadFromMultipartRequest((MultipartHttpServletRequest) request); - } - else if (contentType.startsWith("multipart/form-data")) { - throw new IllegalArgumentException("Content-Type of 'multipart/form-data' requires a MultipartResolver." + - " Try configuring a MultipartResolver within the ApplicationContext."); - } - else if (request.getMethod().equals("GET")) { - if (logger.isDebugEnabled()) { - logger.debug("received GET request, using parameter map as payload"); - } - payload = this.createPayloadFromParameterMap(request); - } - else if (contentType.startsWith("application/x-www-form-urlencoded")) { - if (logger.isDebugEnabled()) { - logger.debug("received " + request.getMethod() - + " request with form data, using parameter map as payload"); - } - payload = createPayloadFromParameterMap(request); - } - else if (contentType.startsWith("text")) { - if (logger.isDebugEnabled()) { - logger.debug("received " + request.getMethod() - + " request, creating payload with text content"); - } - payload = createPayloadFromTextContent(request); - } - else if (contentType.startsWith("application/x-java-serialized-object")) { - payload = createPayloadFromSerializedObject(request); - } - else { - payload = createPayloadFromInputStream(request); - } - return payload; - } - - @SuppressWarnings("unchecked") - private Object createPayloadFromMultipartRequest(MultipartHttpServletRequest multipartRequest) { - Map payloadMap = new HashMap(multipartRequest.getParameterMap()); - Map fileMap = multipartRequest.getFileMap(); - for (Map.Entry entry : fileMap.entrySet()) { - MultipartFile multipartFile = entry.getValue(); - if (multipartFile.isEmpty()) { - continue; - } - try { - if (this.copyUploadedFiles) { - File tmpFile = File.createTempFile("si_", null); - multipartFile.transferTo(tmpFile); - payloadMap.put(entry.getKey(), tmpFile); - if (logger.isDebugEnabled()) { - logger.debug("copied uploaded file [" + multipartFile.getOriginalFilename() + - "] to temporary file [" + tmpFile.getAbsolutePath() + "]"); - } - } - else if (multipartFile.getContentType() != null && multipartFile.getContentType().startsWith("text")) { - String multipartFileAsString = this.multipartCharset != null ? - new String(multipartFile.getBytes(), this.multipartCharset) : - new String(multipartFile.getBytes()); - payloadMap.put(entry.getKey(), multipartFileAsString); - } - else { - payloadMap.put(entry.getKey(), multipartFile.getBytes()); - } - } - catch (IOException e) { - throw new IllegalArgumentException("Cannot read contents of multipart file", e); - } - } - return Collections.unmodifiableMap(payloadMap); - } - - @SuppressWarnings("unchecked") - private Object createPayloadFromParameterMap(HttpServletRequest request) { - return new UnmodifiableRequestParameterMap(request.getParameterMap()); - } - - private Object createPayloadFromTextContent(HttpServletRequest request) throws IOException { - String charset = request.getCharacterEncoding() != null ? request.getCharacterEncoding() : "utf-8"; - return new String(FileCopyUtils.copyToByteArray(request.getInputStream()), charset); - } - - private Object createPayloadFromSerializedObject(HttpServletRequest request) { - try { - return new ObjectInputStream(request.getInputStream()).readObject(); - } - catch (Exception e) { - throw new IllegalArgumentException("failed to deserialize Object in request", e); - } - } - - private byte[] createPayloadFromInputStream(HttpServletRequest request) throws Exception { - InputStream stream = request.getInputStream(); - int length = request.getContentLength(); - if (length == -1) { - throw new ResponseStatusCodeException(HttpServletResponse.SC_LENGTH_REQUIRED); - } - if (logger.isDebugEnabled()) { - logger.debug("received " + request.getMethod() + " request, " - + "creating byte array payload with content lenth: " + length); - } - byte[] bytes = new byte[length]; - stream.read(bytes, 0, length); - return bytes; - } - - private void populateHeaders(HttpServletRequest request, MessageBuilder builder) { - Enumeration headerNames = request.getHeaderNames(); - if (headerNames != null) { - while (headerNames.hasMoreElements()) { - String headerName = (String) headerNames.nextElement(); - Enumeration headerEnum = request.getHeaders(headerName); - if (headerEnum != null) { - List headers = new ArrayList(); - while (headerEnum.hasMoreElements()) { - headers.add(headerEnum.nextElement()); - } - if (headers.size() == 1) { - builder.setHeader(headerName, headers.get(0)); - } - else if (headers.size() > 1) { - builder.setHeader(headerName, headers); - } - } - } - } - builder.setHeader(HttpHeaders.REQUEST_URL, request.getRequestURL().toString()); - builder.setHeader(HttpHeaders.REQUEST_METHOD, request.getMethod()); - builder.setHeader(HttpHeaders.USER_PRINCIPAL, request.getUserPrincipal()); - } - - - /** - * Map class that extends {@link LinkedMultiValueMap} and implements Serializable. - * The contents of the map are unmodifiable, so calling any modification operation - * (e.g. put, add, or remove) will result in an UnsupportedOperationException. - */ - @SuppressWarnings("serial") - private static class UnmodifiableRequestParameterMap - extends LinkedMultiValueMap implements Serializable { // TODO: in 3.0.1 LMVM implements Serializable - - UnmodifiableRequestParameterMap(Map parameters) { - for (Map.Entry entry : parameters.entrySet()) { - super.put(entry.getKey(), Arrays.asList(entry.getValue())); - } - } - - @Override - public void add(String key, String value) { - throw new UnsupportedOperationException(); - } - - @Override - public void clear() { - throw new UnsupportedOperationException(); - } - - @Override - public List put(String key, List value) { - throw new UnsupportedOperationException(); - } - - @Override - public void putAll(Map> m) { - throw new UnsupportedOperationException(); - } - - @Override - public List remove(Object key) { - throw new UnsupportedOperationException(); - } - - @Override - public void set(String key, String value) { - throw new UnsupportedOperationException(); - } - - @Override - public void setAll(Map values) { - throw new UnsupportedOperationException(); - } - - @Override - public Map toSingleValueMap() { - return Collections.unmodifiableMap(super.toSingleValueMap()); - } - - } - -} diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/DefaultInboundRequestMapperTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/DefaultInboundRequestMapperTests.java deleted file mode 100644 index a6019f11c9..0000000000 --- a/spring-integration-http/src/test/java/org/springframework/integration/http/DefaultInboundRequestMapperTests.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2002-2009 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.http; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.util.HashMap; -import java.util.Map; - -import org.junit.Test; -import org.springframework.integration.Message; -import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.util.FileCopyUtils; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.multipart.MultipartFile; -import org.springframework.web.multipart.MultipartHttpServletRequest; -import org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest; - -/** - * @author Iwein Fuld - * @author Mark Fisher - */ -@SuppressWarnings("unchecked") -public class DefaultInboundRequestMapperTests { - - private static final String SIMPLE_STRING = "just ascii"; - - private static final String COMPLEX_STRING = "A\u00ea\u00f1\u00fcC"; - - private DefaultInboundRequestMapper mapper = new DefaultInboundRequestMapper(); - - @Test - public void simpleUtf8TextMapping() throws Exception { - MockHttpServletRequest request = new MockHttpServletRequest(); - request.setContentType("text"); - request.setCharacterEncoding("utf-8"); - byte[] bytes = SIMPLE_STRING.getBytes("utf-8"); - request.setContent(bytes); - Message message = (Message) mapper.toMessage(request); - assertThat(message.getPayload(), is(SIMPLE_STRING)); - } - - @Test - public void complexUtf8TextMapping() throws Exception { - MockHttpServletRequest request = new MockHttpServletRequest(); - request.setContentType("text"); - // don't forget to specify the character encoding on the request or you - // will end up with unpredictable results! - request.setCharacterEncoding("utf-8"); - byte[] bytes = COMPLEX_STRING.getBytes("utf-8"); - request.setContent(bytes); - Message message = (Message) mapper.toMessage(request); - assertThat(message.getPayload(), is(COMPLEX_STRING)); - } - - @Test - public void newlineTest() throws Exception { - String content = "foo\nbar\n"; - MockHttpServletRequest request = new MockHttpServletRequest(); - request.setContentType("text"); - byte[] bytes = content.getBytes(); - request.setContent(bytes); - Message message = (Message) mapper.toMessage(request); - assertThat(message.getPayload(), is(content)); - } - - @Test - public void emptyStringTest() throws Exception { - String content = ""; - MockHttpServletRequest request = new MockHttpServletRequest(); - request.setContentType("text"); - byte[] bytes = content.getBytes(); - request.setContent(bytes); - Message message = (Message) mapper.toMessage(request); - assertThat(message.getPayload(), is(content)); - } - - @Test - public void multipartUpload() throws Exception { - MockHttpServletRequest request = new MockHttpServletRequest(); - MultiValueMap files = new LinkedMultiValueMap(); - MultipartFile file = new StubMultipartFile("file", "testFile.txt", "foo"); - files.add("file", file); - Map params = new HashMap(); - MultipartHttpServletRequest multipartRequest = new DefaultMultipartHttpServletRequest(request, files, params); - mapper.setCopyUploadedFiles(true); - Message result = mapper.toMessage(multipartRequest); - File tmpFile = (File) ((Map) result.getPayload()).get("file"); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - FileCopyUtils.copy(new FileInputStream(tmpFile), baos); - assertThat(baos.toString(), is("foo")); - tmpFile.deleteOnExit(); - } - - @Test - public void testProcessMessageWithDollar() throws Exception { - MockHttpServletRequest request = new MockHttpServletRequest(); - request.setContentType("text"); - request.setCharacterEncoding("utf-8"); - byte[] bytes = SIMPLE_STRING.getBytes("utf-8"); - request.setContent(bytes); - Message message = (Message) mapper.toMessage(request); - ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("headers['$http_requestUrl']"); - assertEquals(message.getHeaders().get(HttpHeaders.REQUEST_URL), processor.processMessage(message)); - } - -}