From 4db77d65c823003cbab77361bb46ae1838a287f6 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Tue, 25 Aug 2009 22:35:01 +0000 Subject: [PATCH] INT-28 Added support for headers based on the evaluation of EL expressions provided on the @Publisher annotation. --- .../integration/aop/ExpressionSource.java | 11 ++++- .../aop/MessagePublishingInterceptor.java | 43 +++++++++++++++---- .../aop/MethodAnnotationExpressionSource.java | 6 ++- .../integration/aop/Publisher.java | 9 +++- .../MessagePublishingInterceptorTests.java | 15 ++++--- ...MethodAnnotationExpressionSourceTests.java | 11 +++-- 6 files changed, 74 insertions(+), 21 deletions(-) diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/aop/ExpressionSource.java b/org.springframework.integration/src/main/java/org/springframework/integration/aop/ExpressionSource.java index 10503ef3de..6923923cc8 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/aop/ExpressionSource.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/aop/ExpressionSource.java @@ -35,9 +35,16 @@ interface ExpressionSource { /** - * Returns the expression string to be evaluated. + * Returns the expression string to be evaluated for creating the Message + * payload. */ - String getExpressionString(Method method); + String getPayloadExpression(Method method); + + /** + * Returns the array of expression strings to be evaluated for any headers + * that should be set on the published Message. + */ + String[] getHeaderExpressions(Method method); /** * Returns the variable names to be associated with the intercepted method diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java b/org.springframework.integration/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java index 674ad5a434..090664f739 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java @@ -26,8 +26,10 @@ import org.aopalliance.intercept.MethodInvocation; import org.springframework.aop.support.AopUtils; import org.springframework.context.expression.MapAccessor; import org.springframework.expression.EvaluationContext; +import org.springframework.expression.EvaluationException; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; +import org.springframework.expression.ParseException; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParserConfiguration; import org.springframework.expression.spel.support.StandardEvaluationContext; @@ -35,9 +37,9 @@ import org.springframework.integration.channel.ChannelResolver; import org.springframework.integration.channel.MessageChannelTemplate; import org.springframework.integration.core.Message; import org.springframework.integration.core.MessageChannel; -import org.springframework.integration.gateway.SimpleMessageMapper; -import org.springframework.integration.message.InboundMessageMapper; +import org.springframework.integration.message.MessageBuilder; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; /** * A {@link MethodInterceptor} that publishes Messages to a channel. The @@ -58,8 +60,6 @@ public class MessagePublishingInterceptor implements MethodInterceptor { SpelExpressionParserConfiguration.CreateObjectIfAttemptToReferenceNull | SpelExpressionParserConfiguration.GrowListsOnIndexBeyondSize); - private final InboundMessageMapper messageMapper = new SimpleMessageMapper(); - private volatile ChannelResolver channelResolver; @@ -109,12 +109,19 @@ public class MessagePublishingInterceptor implements MethodInterceptor { } private void publishMessage(Method method, EvaluationContext context) throws Exception { - String expressionString = this.expressionSource.getExpressionString(method); - if (expressionString != null) { - Expression expression = this.parser.parseExpression(expressionString); + String payloadExpressionString = this.expressionSource.getPayloadExpression(method); + if (payloadExpressionString != null) { + Expression expression = this.parser.parseExpression(payloadExpressionString); Object result = expression.getValue(context); if (result != null) { - Message message = this.messageMapper.toMessage(result); + MessageBuilder builder = (result instanceof Message) + ? MessageBuilder.fromMessage((Message) result) + : MessageBuilder.withPayload(result); + Map headers = this.evaluateHeaders(method, context); + if (headers != null) { + builder.copyHeaders(headers); + } + Message message = builder.build(); String channelName = this.expressionSource.getChannelName(method); MessageChannel channel = null; if (channelName != null) { @@ -131,4 +138,24 @@ public class MessagePublishingInterceptor implements MethodInterceptor { } } + private Map evaluateHeaders(Method method, EvaluationContext context) + throws ParseException, EvaluationException { + + String[] headerExpressionStrings = this.expressionSource.getHeaderExpressions(method); + if (headerExpressionStrings != null) { + Map headers = new HashMap(); + context.setRootObject(headers); + for (String headerExpression : headerExpressionStrings) { + if (StringUtils.hasText(headerExpression)) { + Expression expression = this.parser.parseExpression(headerExpression); + expression.getValue(context); + } + } + if (headers.size() > 0) { + return headers; + } + } + return null; + } + } diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/aop/MethodAnnotationExpressionSource.java b/org.springframework.integration/src/main/java/org/springframework/integration/aop/MethodAnnotationExpressionSource.java index e276855ee1..c9af273c49 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/aop/MethodAnnotationExpressionSource.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/aop/MethodAnnotationExpressionSource.java @@ -58,10 +58,14 @@ public class MethodAnnotationExpressionSource implements ExpressionSource { this.channelAttributeName = channelAttributeName; } - public String getExpressionString(Method method) { + public String getPayloadExpression(Method method) { return this.getAnnotationValue(method, null, String.class); } + public String[] getHeaderExpressions(Method method) { + return this.getAnnotationValue(method, "headers", String[].class); + } + public String[] getArgumentNames(Method method) { ExpressionBinding annotation = AnnotationUtils.findAnnotation(method, ExpressionBinding.class); if (annotation != null) { diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/aop/Publisher.java b/org.springframework.integration/src/main/java/org/springframework/integration/aop/Publisher.java index 9aaa72ea4c..c9399645b2 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/aop/Publisher.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/aop/Publisher.java @@ -34,10 +34,17 @@ import java.lang.annotation.Target; public @interface Publisher { /** - * String representation of a Spel Expression. Required. + * String representation of a Spel Expression to evaluate when creating the + * Message payload. Required. */ String value(); + /** + * String representations of Spel Expressions to evaluate for adding any + * headers to the Message. Optional. + */ + String[] headers() default ""; + /** * Name of the Message Channel to which Messages will be published. */ diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingInterceptorTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingInterceptorTests.java index 89486c527a..685335ec62 100644 --- a/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingInterceptorTests.java +++ b/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingInterceptorTests.java @@ -88,22 +88,25 @@ public class MessagePublishingInterceptorTests { return new String[] { "a1", "a2" }; } - public String getChannelName(Method method) { - return "c"; + public String getReturnValueName(Method method) { + return "r"; } public String getExceptionName(Method method) { return "x"; } - public String getExpressionString(Method method) { + public String getPayloadExpression(Method method) { return "#r"; } - public String getReturnValueName(Method method) { - return "r"; + public String[] getHeaderExpressions(Method method) { + return null; + } + + public String getChannelName(Method method) { + return "c"; } - } } diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/aop/MethodAnnotationExpressionSourceTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/aop/MethodAnnotationExpressionSourceTests.java index 2eb2c1393b..c6eec68339 100644 --- a/org.springframework.integration/src/test/java/org/springframework/integration/aop/MethodAnnotationExpressionSourceTests.java +++ b/org.springframework.integration/src/test/java/org/springframework/integration/aop/MethodAnnotationExpressionSourceTests.java @@ -17,6 +17,7 @@ package org.springframework.integration.aop; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import java.lang.reflect.Method; @@ -33,11 +34,15 @@ public class MethodAnnotationExpressionSourceTests { @Test public void defaultBindings() { Method method = getMethod("methodWithExpressionAnnotationOnly", String.class, int.class); - String expressionString = source.getExpressionString(method); + String expressionString = source.getPayloadExpression(method); assertEquals("testExpression1", expressionString); assertEquals(2, source.getArgumentNames(method).length); assertEquals("arg1", source.getArgumentNames(method)[0]); assertEquals("arg2", source.getArgumentNames(method)[1]); + String[] headerStrings = source.getHeaderExpressions(method); + assertNotNull(headerStrings); + assertEquals(1, headerStrings.length); + assertEquals("", headerStrings[0]); assertEquals(ExpressionSource.DEFAULT_ARGUMENT_MAP_NAME, source.getArgumentMapName(method)); assertEquals(ExpressionSource.DEFAULT_EXCEPTION_NAME, source.getExceptionName(method)); assertEquals(ExpressionSource.DEFAULT_RETURN_VALUE_NAME, source.getReturnValueName(method)); @@ -46,7 +51,7 @@ public class MethodAnnotationExpressionSourceTests { @Test public void annotationBindings() { Method method = getMethod("methodWithExpressionBinding", String.class, int.class); - String expressionString = source.getExpressionString(method); + String expressionString = source.getPayloadExpression(method); assertEquals("testExpression2", expressionString); assertEquals(2, source.getArgumentNames(method).length); assertEquals("s", source.getArgumentNames(method)[0]); @@ -78,7 +83,7 @@ public class MethodAnnotationExpressionSourceTests { public void methodWithExpressionAnnotationOnly(String arg1, int arg2) { } - @Publisher(value="#return", channel="foo") + @Publisher(value="#return", channel="foo", headers="bar=123") public void methodWithChannelAndReturnAsPayload() { }