From 7dda54bb798f41b68277f61dc76616b289885104 Mon Sep 17 00:00:00 2001 From: David Syer Date: Thu, 29 Jul 2010 11:14:53 +0000 Subject: [PATCH] INT-1298: Combine some message group features and base classes --- ...tractAggregatingMessageGroupProcessor.java | 128 ++++++++++++++ ...essionEvaluatingMessageGroupProcessor.java | 30 +++- ...essionEvaluatingMessageListProcessor.java} | 6 +- .../ExpressionEvaluatingReleaseStrategy.java | 2 +- .../MessageListMethodAdapterHelper.java | 160 ------------------ .../aggregator/MessageListProcessor.java | 2 +- .../MethodInvokingMessageGroupProcessor.java | 6 +- ...> MethodInvokingMessageListProcessor.java} | 6 +- .../MethodInvokingReleaseStrategy.java | 6 +- ...nEvaluatingMessageGroupProcessorTests.java | 47 +++-- .../config/AggregatorParserTests.java | 4 +- .../org.eclipse.wst.common.component | 6 + 12 files changed, 206 insertions(+), 197 deletions(-) rename spring-integration-core/src/main/java/org/springframework/integration/aggregator/{AbstractExpressionEvaluatingMessageListProcessor.java => ExpressionEvaluatingMessageListProcessor.java} (94%) delete mode 100644 spring-integration-core/src/main/java/org/springframework/integration/aggregator/MessageListMethodAdapterHelper.java rename spring-integration-core/src/main/java/org/springframework/integration/aggregator/{MessageListMethodAdapter.java => MethodInvokingMessageListProcessor.java} (95%) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/AbstractAggregatingMessageGroupProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/AbstractAggregatingMessageGroupProcessor.java index 22ed000964..1e1042d218 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/AbstractAggregatingMessageGroupProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/AbstractAggregatingMessageGroupProcessor.java @@ -13,20 +13,29 @@ package org.springframework.integration.aggregator; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.Map; import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.aop.support.AopUtils; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.integration.Message; import org.springframework.integration.MessageHeaders; +import org.springframework.integration.annotation.Header; import org.springframework.integration.core.MessageBuilder; import org.springframework.integration.core.MessageChannel; import org.springframework.integration.core.MessagingTemplate; import org.springframework.integration.store.MessageGroup; import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; /** * Base class for MessageGroupProcessor implementations that aggregate the group of Messages into a single Message. @@ -88,4 +97,123 @@ public abstract class AbstractAggregatingMessageGroupProcessor implements Messag protected abstract Object aggregatePayloads(MessageGroup group); + protected MessageListProcessor getAdapter(Object candidate, Class annotationType) { + Method method = findAggregatorMethod(candidate, annotationType); + if (method == null) { + return null; + } + return new MethodInvokingMessageListProcessor(candidate, method); + } + + private Method findAggregatorMethod(Object candidate, Class annotationType) { + Class targetClass = AopUtils.getTargetClass(candidate); + if (targetClass == null) { + targetClass = candidate.getClass(); + } + Method method = this.findAnnotatedMethod(targetClass, annotationType); + if (method == null) { + method = this.findSinglePublicMethod(targetClass); + } + return method; + } + + private Method findAnnotatedMethod(final Class targetClass, final Class annotationType) { + final AtomicReference annotatedMethod = new AtomicReference(); + ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() { + public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { + Annotation annotation = AnnotationUtils.findAnnotation(method, annotationType); + if (annotation != null) { + Assert.isNull(annotatedMethod.get(), "found more than one method on target class [" + targetClass + + "] with the annotation type [" + annotationType.getName() + "]"); + annotatedMethod.set(method); + } + } + }); + return annotatedMethod.get(); + } + + private Method findSinglePublicMethod(Class targetClass) { + Set methods = new HashSet(); + for (Method method : targetClass.getMethods()) { + if (!method.getDeclaringClass().equals(Object.class)) { + methods.add(method); + } + } + removeListIncompatibleMethodsFrom(methods); + removeVoidMethodsFrom(methods); + removeUnfittingFrom(methods); + if (methods.size() > 1) { + throw new IllegalArgumentException("Class [" + targetClass + "] contains more than one public Method."); + } + return methods.isEmpty() ? null : methods.iterator().next(); + } + + private void removeListIncompatibleMethodsFrom(Set candidates) { + removeMethodsMatchingSelector(candidates, new MethodSelector() { + public boolean select(Method method) { + int found = 0; + for (Class parameterClass : method.getParameterTypes()) { + if (Collection.class.isAssignableFrom(parameterClass)) { + found++; + } + } + return found != 1; + } + }); + } + + private void removeVoidMethodsFrom(Set candidates) { + removeMethodsMatchingSelector(candidates, new MethodSelector() { + public boolean select(Method method) { + return method.getReturnType().getName().equals("void"); + } + }); + } + + private Set removeUnfittingFrom(Set candidates) { + return removeMethodsMatchingSelector(candidates, new MethodSelector() { + public boolean select(Method method) { + Annotation[][] parameterAnnotations = method.getParameterAnnotations(); + Class[] parameterTypes = method.getParameterTypes(); + return (!isFittinglyAnnotated(parameterTypes, parameterAnnotations)); + } + }); + } + + private boolean isFittinglyAnnotated(Class[] parameterTypes, Annotation[][] parameterAnnotations) { + int candidateParametersFound = 0; + for (int i = 0; i < parameterTypes.length; i++) { + Class parameterType = parameterTypes[i]; + if (Collection.class.isAssignableFrom(parameterType)) { + boolean headerAnnotationFound = false; + for (Annotation annotation : parameterAnnotations[i]) { + if (annotation instanceof Header) { + headerAnnotationFound = true; + } + } + if (!headerAnnotationFound) { + candidateParametersFound++; + } + } + } + return candidateParametersFound == 1; + } + + private Set removeMethodsMatchingSelector(Set candidates, MethodSelector selector) { + Set removed = new HashSet(); + Iterator iterator = candidates.iterator(); + while (iterator.hasNext()) { + Method method = iterator.next(); + if (selector.select(method)) { + iterator.remove(); + removed.add(method); + } + } + return removed; + } + + private interface MethodSelector { + boolean select(Method method); + } + } 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 71b950b287..5e0c17e5ad 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,7 +1,8 @@ package org.springframework.integration.aggregator; -import org.springframework.integration.core.MessageBuilder; -import org.springframework.integration.core.MessageChannel; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.core.convert.ConversionService; import org.springframework.integration.core.MessagingTemplate; import org.springframework.integration.store.MessageGroup; @@ -14,20 +15,33 @@ import org.springframework.integration.store.MessageGroup; * @author Dave Syer * */ -public class ExpressionEvaluatingMessageGroupProcessor extends AbstractExpressionEvaluatingMessageListProcessor - implements MessageGroupProcessor { +public class ExpressionEvaluatingMessageGroupProcessor extends AbstractAggregatingMessageGroupProcessor implements BeanFactoryAware { + + private final ExpressionEvaluatingMessageListProcessor processor; + + public void setBeanFactory(BeanFactory beanFactory) { + processor.setBeanFactory(beanFactory); + } + + public void setConversionService(ConversionService conversionService) { + processor.setConversionService(conversionService); + } + + public void setExpectedType(Class expectedType) { + processor.setExpectedType(expectedType); + } public ExpressionEvaluatingMessageGroupProcessor(String expression) { - super(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 dowstream. */ - public void processAndSend(MessageGroup group, MessagingTemplate messagingTemplate, MessageChannel outputChannel) { - Object newPayload = process(group.getUnmarked()); - messagingTemplate.send(outputChannel, MessageBuilder.withPayload(newPayload).build()); + @Override + protected Object aggregatePayloads(MessageGroup group) { + return processor.process(group.getUnmarked()); } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/AbstractExpressionEvaluatingMessageListProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingMessageListProcessor.java similarity index 94% rename from spring-integration-core/src/main/java/org/springframework/integration/aggregator/AbstractExpressionEvaluatingMessageListProcessor.java rename to spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingMessageListProcessor.java index 470b2b7958..1b5dd52536 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/AbstractExpressionEvaluatingMessageListProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingMessageListProcessor.java @@ -44,7 +44,7 @@ import org.springframework.integration.transformer.MessageTransformationExceptio * @author Dave Syer * @since 2.0 */ -public class AbstractExpressionEvaluatingMessageListProcessor implements BeanFactoryAware { +public class ExpressionEvaluatingMessageListProcessor implements BeanFactoryAware, MessageListProcessor { private final ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true)); @@ -57,7 +57,7 @@ public class AbstractExpressionEvaluatingMessageListProcessor implements BeanFac /** * Create an {@link ExpressionEvaluatingMessageProcessor} for the given expression String. */ - public AbstractExpressionEvaluatingMessageListProcessor(String expression) { + public ExpressionEvaluatingMessageListProcessor(String expression) { try { this.expression = parser.parseExpression(expression); this.getEvaluationContext().addPropertyAccessor(new MapAccessor()); @@ -116,7 +116,7 @@ public class AbstractExpressionEvaluatingMessageListProcessor implements BeanFac * Processes the Message by evaluating the expression with that Message as the root object. The expression * evaluation result Object will be returned. */ - protected Object process(Collection> messages) { + public Object process(Collection> messages) { return this.evaluateExpression(this.expression, messages, this.expectedType); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingReleaseStrategy.java b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingReleaseStrategy.java index 1bd11f6bdd..bb2ed6bcc0 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingReleaseStrategy.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingReleaseStrategy.java @@ -23,7 +23,7 @@ import org.springframework.integration.store.MessageGroup; * * @author Dave Syer */ -public class ExpressionEvaluatingReleaseStrategy extends AbstractExpressionEvaluatingMessageListProcessor implements +public class ExpressionEvaluatingReleaseStrategy extends ExpressionEvaluatingMessageListProcessor implements ReleaseStrategy { public ExpressionEvaluatingReleaseStrategy(String expression) { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MessageListMethodAdapterHelper.java b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MessageListMethodAdapterHelper.java deleted file mode 100644 index 6c148073c1..0000000000 --- a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MessageListMethodAdapterHelper.java +++ /dev/null @@ -1,160 +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.aggregator; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; - -import org.springframework.aop.support.AopUtils; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.integration.annotation.Header; -import org.springframework.util.Assert; -import org.springframework.util.ReflectionUtils; - -/** - * Convenience helper that looks for an appropriate method handling a list of messages and returns null if not found. - * - * @author Dave Syer - * - * @since 2.0 - */ -public class MessageListMethodAdapterHelper { - - public MessageListProcessor getAdapter(Object candidate, Class annotationType) { - Method method = findAggregatorMethod(candidate, annotationType); - if (method == null) { - return null; - } - return new MessageListMethodAdapter(candidate, method); - } - - public Method findAggregatorMethod(Object candidate, Class annotationType) { - Class targetClass = AopUtils.getTargetClass(candidate); - if (targetClass == null) { - targetClass = candidate.getClass(); - } - Method method = this.findAnnotatedMethod(targetClass, annotationType); - if (method == null) { - method = this.findSinglePublicMethod(targetClass); - } - return method; - } - - private Method findAnnotatedMethod(final Class targetClass, final Class annotationType) { - final AtomicReference annotatedMethod = new AtomicReference(); - ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() { - public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { - Annotation annotation = AnnotationUtils.findAnnotation(method, annotationType); - if (annotation != null) { - Assert.isNull(annotatedMethod.get(), "found more than one method on target class [" + targetClass - + "] with the annotation type [" + annotationType.getName() + "]"); - annotatedMethod.set(method); - } - } - }); - return annotatedMethod.get(); - } - - private Method findSinglePublicMethod(Class targetClass) { - Set methods = new HashSet(); - for (Method method : targetClass.getMethods()) { - if (!method.getDeclaringClass().equals(Object.class)) { - methods.add(method); - } - } - removeListIncompatibleMethodsFrom(methods); - removeVoidMethodsFrom(methods); - removeUnfittingFrom(methods); - if (methods.size() > 1) { - throw new IllegalArgumentException("Class [" + targetClass + "] contains more than one public Method."); - } - return methods.isEmpty() ? null : methods.iterator().next(); - } - - private void removeListIncompatibleMethodsFrom(Set candidates) { - removeMethodsMatchingSelector(candidates, new MethodSelector() { - public boolean select(Method method) { - int found = 0; - for (Class parameterClass : method.getParameterTypes()) { - if (Collection.class.isAssignableFrom(parameterClass)) { - found++; - } - } - return found != 1; - } - }); - } - - private void removeVoidMethodsFrom(Set candidates) { - removeMethodsMatchingSelector(candidates, new MethodSelector() { - public boolean select(Method method) { - return method.getReturnType().getName().equals("void"); - } - }); - } - - private Set removeUnfittingFrom(Set candidates) { - return removeMethodsMatchingSelector(candidates, new MethodSelector() { - public boolean select(Method method) { - Annotation[][] parameterAnnotations = method.getParameterAnnotations(); - Class[] parameterTypes = method.getParameterTypes(); - return (!isFittinglyAnnotated(parameterTypes, parameterAnnotations)); - } - }); - } - - private boolean isFittinglyAnnotated(Class[] parameterTypes, Annotation[][] parameterAnnotations) { - int candidateParametersFound = 0; - for (int i = 0; i < parameterTypes.length; i++) { - Class parameterType = parameterTypes[i]; - if (Collection.class.isAssignableFrom(parameterType)) { - boolean headerAnnotationFound = false; - for (Annotation annotation : parameterAnnotations[i]) { - if (annotation instanceof Header) { - headerAnnotationFound = true; - } - } - if (!headerAnnotationFound) { - candidateParametersFound++; - } - } - } - return candidateParametersFound == 1; - } - - private Set removeMethodsMatchingSelector(Set candidates, MethodSelector selector) { - Set removed = new HashSet(); - Iterator iterator = candidates.iterator(); - while (iterator.hasNext()) { - Method method = iterator.next(); - if (selector.select(method)) { - iterator.remove(); - removed.add(method); - } - } - return removed; - } - - private interface MethodSelector { - boolean select(Method method); - } - -} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MessageListProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MessageListProcessor.java index e04fb081c8..c686d23aa3 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MessageListProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MessageListProcessor.java @@ -20,7 +20,7 @@ import java.util.Collection; import org.springframework.integration.Message; /** - * @author dsyer + * @author Dave Syer * */ public interface MessageListProcessor { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingMessageGroupProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingMessageGroupProcessor.java index 833aa61f96..55c91d5879 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingMessageGroupProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingMessageGroupProcessor.java @@ -43,7 +43,7 @@ public class MethodInvokingMessageGroupProcessor extends AbstractAggregatingMess * @param target the object to wrap */ public MethodInvokingMessageGroupProcessor(Object target) { - this.adapter = new MessageListMethodAdapterHelper().getAdapter(target, Aggregator.class); + this.adapter = getAdapter(target, Aggregator.class); Assert.notNull(this.adapter, "No aggregator method could be found for object of type: "+target.getClass()); } @@ -55,7 +55,7 @@ public class MethodInvokingMessageGroupProcessor extends AbstractAggregatingMess * @param methodName the name of the method to invoke */ public MethodInvokingMessageGroupProcessor(Object target, String methodName) { - this.adapter = new MessageListMethodAdapter(target, methodName); + this.adapter = new MethodInvokingMessageListProcessor(target, methodName); } /** @@ -65,7 +65,7 @@ public class MethodInvokingMessageGroupProcessor extends AbstractAggregatingMess * @param method the method to invoke */ public MethodInvokingMessageGroupProcessor(Object target, Method method) { - this.adapter = new MessageListMethodAdapter(target, method); + this.adapter = new MethodInvokingMessageListProcessor(target, method); } @Override diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MessageListMethodAdapter.java b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingMessageListProcessor.java similarity index 95% rename from spring-integration-core/src/main/java/org/springframework/integration/aggregator/MessageListMethodAdapter.java rename to spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingMessageListProcessor.java index 9702ab611f..58f006881a 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MessageListMethodAdapter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingMessageListProcessor.java @@ -38,13 +38,13 @@ import org.springframework.util.ReflectionUtils; * @author Iwein Fuld * @author Dave Syer */ -public class MessageListMethodAdapter implements MessageListProcessor { +public class MethodInvokingMessageListProcessor implements MessageListProcessor { private final DefaultMethodInvoker invoker; protected final Method method; - public MessageListMethodAdapter(Object object, String methodName) { + public MethodInvokingMessageListProcessor(Object object, String methodName) { Assert.notNull(object, "'object' must not be null"); Assert.notNull(methodName, "'methodName' must not be null"); this.method = ReflectionUtils.findMethod(object.getClass(), methodName, new Class[]{List.class}); @@ -53,7 +53,7 @@ public class MessageListMethodAdapter implements MessageListProcessor { this.invoker = new DefaultMethodInvoker(object, this.method); } - public MessageListMethodAdapter(Object object, Method method) { + public MethodInvokingMessageListProcessor(Object object, Method method) { Assert.notNull(object, "'object' must not be null"); Assert.notNull(method, "'method' must not be null"); Assert.isTrue(method.getParameterTypes().length == 1 diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingReleaseStrategy.java b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingReleaseStrategy.java index f75fb01db1..2699aa998c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingReleaseStrategy.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingReleaseStrategy.java @@ -32,15 +32,15 @@ import org.springframework.util.Assert; */ public class MethodInvokingReleaseStrategy implements ReleaseStrategy { - private final MessageListMethodAdapter adapter; + private final MethodInvokingMessageListProcessor adapter; public MethodInvokingReleaseStrategy(Object object, Method method) { - adapter = new MessageListMethodAdapter(object, method); + adapter = new MethodInvokingMessageListProcessor(object, method); this.assertMethodReturnsBoolean(); } public MethodInvokingReleaseStrategy(Object object, String methodName) { - adapter = new MessageListMethodAdapter(object, methodName); + adapter = new MethodInvokingMessageListProcessor(object, methodName); this.assertMethodReturnsBoolean(); } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/aggregator/ExpressionEvaluatingMessageGroupProcessorTests.java b/spring-integration-core/src/test/java/org/springframework/integration/aggregator/ExpressionEvaluatingMessageGroupProcessorTests.java index 5a92e859c5..9512e2ac33 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/aggregator/ExpressionEvaluatingMessageGroupProcessorTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/aggregator/ExpressionEvaluatingMessageGroupProcessorTests.java @@ -8,10 +8,12 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import org.hamcrest.CoreMatchers; import org.hamcrest.Description; import org.hamcrest.Factory; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; +import org.hamcrest.collection.IsMapContaining; import org.hamcrest.core.IsEqual; import org.junit.Before; import org.junit.Test; @@ -20,7 +22,7 @@ import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.integration.Message; -import org.springframework.integration.core.GenericMessage; +import org.springframework.integration.core.MessageBuilder; import org.springframework.integration.core.MessageChannel; import org.springframework.integration.core.MessagingTemplate; import org.springframework.integration.store.MessageGroup; @@ -45,11 +47,10 @@ public class ExpressionEvaluatingMessageGroupProcessorTests { List> messages = new ArrayList>(); @Before - @SuppressWarnings("unchecked") public void setup() { messages.clear(); for (int i = 0; i < 5; i++) { - messages.add(new GenericMessage(i + 1)); + messages.add(MessageBuilder.withPayload(i + 1).setHeader("foo", "bar").build()); } } @@ -61,6 +62,14 @@ public class ExpressionEvaluatingMessageGroupProcessorTests { verify(outputChannel).send(messageWithPayload(5)); } + @Test + public void testProcessAndCheckHeaders() throws Exception { + when(group.getUnmarked()).thenReturn(messages); + processor = new ExpressionEvaluatingMessageGroupProcessor("#root"); + processor.processAndSend(group, template, outputChannel); + verify(outputChannel).send(messageWithHeader("foo", "bar")); + } + @Test public void testProcessAndSendWithProjectionExpressionEvaluated() throws Exception { when(group.getUnmarked()).thenReturn(messages); @@ -86,12 +95,16 @@ public class ExpressionEvaluatingMessageGroupProcessorTests { verify(outputChannel).send(messageWithPayload(3 + 4 + 5)); } + private Message messageWithHeader(String key, Object value) { + return Matchers.argThat(MessageMatcher.hasHeader(IsMapContaining.hasEntry(key, value))); + } + private Message messageWithPayload(Matcher matcher) { - return Matchers.argThat(PayloadMatcher.hasPayload(matcher)); + return Matchers.argThat(MessageMatcher.hasPayload(matcher)); } private Message messageWithPayload(int i) { - return Matchers.argThat(PayloadMatcher.hasPayload(IsEqual.equalTo(i))); + return Matchers.argThat(MessageMatcher.hasPayload(IsEqual.equalTo(i))); } /* @@ -105,16 +118,19 @@ public class ExpressionEvaluatingMessageGroupProcessorTests { return result; } - private static class PayloadMatcher extends TypeSafeMatcher> { + private static class MessageMatcher extends TypeSafeMatcher> { - private final Matcher matcher; + private final Matcher payloadMatcher; + + private final Matcher headerMatcher; /** * @param matcher */ - PayloadMatcher(Matcher matcher) { + MessageMatcher(Matcher matcher, Matcher headerMatcher) { super(); - this.matcher = matcher; + this.payloadMatcher = matcher; + this.headerMatcher = headerMatcher; } /** @@ -122,7 +138,7 @@ public class ExpressionEvaluatingMessageGroupProcessorTests { */ @Override public boolean matchesSafely(Message message) { - return matcher.matches(message.getPayload()); + return payloadMatcher.matches(message.getPayload()) && headerMatcher.matches(message.getHeaders()); } /** @@ -130,13 +146,18 @@ public class ExpressionEvaluatingMessageGroupProcessorTests { */ //@Override public void describeTo(Description description) { - description.appendText("a Message with payload: ").appendDescriptionOf(matcher); - + description.appendText("a Message with payload: ").appendDescriptionOf(payloadMatcher); + description.appendText(" and headers: ").appendDescriptionOf(headerMatcher); } @Factory public static Matcher> hasPayload(Matcher payloadMatcher) { - return new PayloadMatcher(payloadMatcher); + return new MessageMatcher(payloadMatcher, CoreMatchers.anything()); + } + + @Factory + public static Matcher> hasHeader(Matcher headerMatcher) { + return new MessageMatcher(CoreMatchers.anything(), headerMatcher); } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/AggregatorParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/AggregatorParserTests.java index 98827e2a15..3820222290 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/AggregatorParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/AggregatorParserTests.java @@ -38,7 +38,7 @@ import org.springframework.integration.MessageHandlingException; import org.springframework.integration.MessageRejectedException; import org.springframework.integration.aggregator.CorrelatingMessageHandler; import org.springframework.integration.aggregator.CorrelationStrategy; -import org.springframework.integration.aggregator.MessageListMethodAdapter; +import org.springframework.integration.aggregator.MethodInvokingMessageListProcessor; import org.springframework.integration.aggregator.ReleaseStrategy; import org.springframework.integration.aggregator.MethodInvokingReleaseStrategy; import org.springframework.integration.core.MessageBuilder; @@ -114,7 +114,7 @@ public class AggregatorParserTests { DirectFieldAccessor accessor = new DirectFieldAccessor(consumer); Method expectedMethod = TestAggregatorBean.class.getMethod("createSingleMessageFromGroup", List.class); assertEquals("The MethodInvokingAggregator is not injected with the appropriate aggregation method", - expectedMethod, ((MessageListMethodAdapter) new DirectFieldAccessor(accessor + expectedMethod, ((MethodInvokingMessageListProcessor) new DirectFieldAccessor(accessor .getPropertyValue("outputProcessor")).getPropertyValue("adapter")).getMethod()); assertEquals("The AggregatorEndpoint is not injected with the appropriate ReleaseStrategy instance", releaseStrategy, accessor.getPropertyValue("releaseStrategy")); diff --git a/spring-integration-samples/loanshark/.settings/org.eclipse.wst.common.component b/spring-integration-samples/loanshark/.settings/org.eclipse.wst.common.component index c3b12182d2..2911432a91 100644 --- a/spring-integration-samples/loanshark/.settings/org.eclipse.wst.common.component +++ b/spring-integration-samples/loanshark/.settings/org.eclipse.wst.common.component @@ -1,6 +1,12 @@ + + uses + + + uses +