INT-266 - adding namespace and annotation support for CorrelationStrategy
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.aggregator;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.integration.core.Message;
|
||||
import org.springframework.integration.handler.MessageMappingMethodInvoker;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link CorrelationStrategy} implementation that works as an adapter to another bean.
|
||||
*
|
||||
* @author: Marius Bogoevici
|
||||
*/
|
||||
public class CorrelationStrategyAdapter implements CorrelationStrategy {
|
||||
|
||||
private final MessageMappingMethodInvoker invoker;
|
||||
|
||||
|
||||
public CorrelationStrategyAdapter(Object object, String methodName) {
|
||||
this.invoker = new MessageMappingMethodInvoker(object, methodName, true);
|
||||
}
|
||||
|
||||
public CorrelationStrategyAdapter(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, "Method must accept exactly one parameter");
|
||||
Assert.isTrue(!Void.TYPE.equals(method.getReturnType()), "Method return type must not be void");
|
||||
this.invoker = new MessageMappingMethodInvoker(object, method);
|
||||
}
|
||||
|
||||
|
||||
public Object getCorrelationKey(Message<?> message) {
|
||||
return invoker.invokeMethod(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates that a given method is capable of determining the correlation key
|
||||
* of a message sent as parameter.
|
||||
*
|
||||
* @author: Marius Bogoevici
|
||||
*/
|
||||
@Retention (RetentionPolicy.RUNTIME)
|
||||
@Target (ElementType.METHOD)
|
||||
@Documented
|
||||
public @interface CorrelationStrategy {
|
||||
}
|
||||
@@ -24,8 +24,10 @@ import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.integration.aggregator.AbstractMessageAggregator;
|
||||
import org.springframework.integration.aggregator.CompletionStrategyAdapter;
|
||||
import org.springframework.integration.aggregator.MethodInvokingAggregator;
|
||||
import org.springframework.integration.aggregator.CorrelationStrategyAdapter;
|
||||
import org.springframework.integration.annotation.Aggregator;
|
||||
import org.springframework.integration.annotation.CompletionStrategy;
|
||||
import org.springframework.integration.annotation.CorrelationStrategy;
|
||||
import org.springframework.integration.core.MessageChannel;
|
||||
import org.springframework.integration.message.MessageHandler;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -48,6 +50,7 @@ public class AggregatorAnnotationPostProcessor extends AbstractMethodAnnotationP
|
||||
protected MessageHandler createHandler(Object bean, Method method, Aggregator annotation) {
|
||||
MethodInvokingAggregator aggregator = new MethodInvokingAggregator(bean, method);
|
||||
this.configureCompletionStrategy(bean, aggregator);
|
||||
this.configureCorrelationStrategy(bean, aggregator);
|
||||
String discardChannelName = annotation.discardChannel();
|
||||
if (StringUtils.hasText(discardChannelName)) {
|
||||
MessageChannel discardChannel = this.channelResolver.resolveChannelName(discardChannelName);
|
||||
@@ -79,4 +82,15 @@ public class AggregatorAnnotationPostProcessor extends AbstractMethodAnnotationP
|
||||
});
|
||||
}
|
||||
|
||||
private void configureCorrelationStrategy(final Object bean, final AbstractMessageAggregator aggregator) {
|
||||
ReflectionUtils.doWithMethods(bean.getClass(), new ReflectionUtils.MethodCallback() {
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
Annotation annotation = AnnotationUtils.getAnnotation(method, CorrelationStrategy.class);
|
||||
if (annotation != null) {
|
||||
aggregator.setCorrelationStrategy(new CorrelationStrategyAdapter(bean, method));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
|
||||
package org.springframework.integration.config.xml;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Parser for the <em>aggregator</em> element of the integration namespace.
|
||||
* Registers the annotation-driven post-processors.
|
||||
@@ -36,6 +36,10 @@ public class AggregatorParser extends AbstractConsumerEndpointParser {
|
||||
|
||||
private static final String COMPLETION_STRATEGY_METHOD_ATTRIBUTE = "completion-strategy-method";
|
||||
|
||||
private static final String CORRELATION_STRATEGY_REF_ATTRIBUTE = "correlation-strategy";
|
||||
|
||||
private static final String CORRELATION_STRATEGY_METHOD_ATTRIBUTE = "correlation-strategy-method";
|
||||
|
||||
private static final String DISCARD_CHANNEL_ATTRIBUTE = "discard-channel";
|
||||
|
||||
private static final String SEND_TIMEOUT_ATTRIBUTE = "send-timeout";
|
||||
@@ -50,6 +54,8 @@ public class AggregatorParser extends AbstractConsumerEndpointParser {
|
||||
|
||||
private static final String COMPLETION_STRATEGY_PROPERTY = "completionStrategy";
|
||||
|
||||
private static final String CORRELATION_STRATEGY_PROPERTY = "correlationStrategy";
|
||||
|
||||
|
||||
@Override
|
||||
protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
|
||||
@@ -71,24 +77,31 @@ public class AggregatorParser extends AbstractConsumerEndpointParser {
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, TRACKED_CORRELATION_ID_CAPACITY_ATTRIBUTE);
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-startup");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, TIMEOUT_ATTRIBUTE);
|
||||
final String completionStrategyRef = element.getAttribute(COMPLETION_STRATEGY_REF_ATTRIBUTE);
|
||||
final String completionStrategyMethod = element.getAttribute(COMPLETION_STRATEGY_METHOD_ATTRIBUTE);
|
||||
if (StringUtils.hasText(completionStrategyRef)) {
|
||||
if (StringUtils.hasText(completionStrategyMethod)) {
|
||||
String adapterBeanName = this.createCompletionStrategyAdapter(
|
||||
completionStrategyRef, completionStrategyMethod, parserContext);
|
||||
builder.addPropertyReference(COMPLETION_STRATEGY_PROPERTY, adapterBeanName);
|
||||
}
|
||||
else {
|
||||
builder.addPropertyReference(COMPLETION_STRATEGY_PROPERTY, completionStrategyRef);
|
||||
}
|
||||
}
|
||||
this.injectPropertyWithBean(COMPLETION_STRATEGY_REF_ATTRIBUTE, COMPLETION_STRATEGY_METHOD_ATTRIBUTE, COMPLETION_STRATEGY_PROPERTY,
|
||||
"CompletionStrategyAdapter", element, builder, parserContext);
|
||||
this.injectPropertyWithBean(CORRELATION_STRATEGY_REF_ATTRIBUTE, CORRELATION_STRATEGY_METHOD_ATTRIBUTE, CORRELATION_STRATEGY_PROPERTY,
|
||||
"CorrelationStrategyAdapter", element, builder, parserContext);
|
||||
return builder;
|
||||
}
|
||||
|
||||
private String createCompletionStrategyAdapter(String ref, String method, ParserContext parserContext) {
|
||||
private void injectPropertyWithBean(String beanRefAttribute, String methodRefAttribute, String beanProperty, String adapterClass,
|
||||
Element element, BeanDefinitionBuilder builder, ParserContext parserContext) {
|
||||
final String beanRef = element.getAttribute(beanRefAttribute);
|
||||
final String beanMethod = element.getAttribute(methodRefAttribute);
|
||||
if (StringUtils.hasText(beanRef)) {
|
||||
if (StringUtils.hasText(beanMethod)) {
|
||||
String adapterBeanName = this.createAdapter(beanRef, beanMethod, adapterClass, parserContext);
|
||||
builder.addPropertyReference(beanProperty, adapterBeanName);
|
||||
}
|
||||
else {
|
||||
builder.addPropertyReference(beanProperty, beanRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String createAdapter(String ref, String method, String unqualifiedClassName, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
IntegrationNamespaceUtils.BASE_PACKAGE + ".aggregator.CompletionStrategyAdapter");
|
||||
IntegrationNamespaceUtils.BASE_PACKAGE + ".aggregator." + unqualifiedClassName);
|
||||
builder.addConstructorArgReference(ref);
|
||||
builder.addConstructorArgValue(method);
|
||||
return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry());
|
||||
|
||||
@@ -823,6 +823,17 @@
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="completion-strategy-method"
|
||||
type="xsd:string" />
|
||||
<xsd:attribute name="correlation-strategy" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="java.lang.Object" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="correlation-strategy-method"
|
||||
type="xsd:string" />
|
||||
<xsd:attribute name="discard-channel" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
|
||||
@@ -26,9 +26,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.integration.core.Message;
|
||||
import org.springframework.integration.message.MessageHandlingException;
|
||||
@@ -40,6 +37,9 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* A base or helper class for any Messaging component that acts as an adapter
|
||||
* by invoking a "plain" (not Message-aware) method on a given target object.
|
||||
@@ -47,6 +47,7 @@ import org.springframework.util.StringUtils;
|
||||
* 'methodName', or an Annotation type must be provided.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Marius Bogoevici
|
||||
*/
|
||||
public class MessageMappingMethodInvoker {
|
||||
|
||||
@@ -78,13 +79,17 @@ public class MessageMappingMethodInvoker {
|
||||
this.methodResolver = this.createResolverForAnnotation(annotationType);
|
||||
}
|
||||
|
||||
public MessageMappingMethodInvoker(Object object, String methodName) {
|
||||
public MessageMappingMethodInvoker(Object object, String methodName) {
|
||||
this(object, methodName, false);
|
||||
}
|
||||
|
||||
public MessageMappingMethodInvoker(Object object, String methodName, boolean requiresReturnValue) {
|
||||
Assert.notNull(object, "object must not be null");
|
||||
Assert.notNull(methodName, "methodName must not be null");
|
||||
this.object = object;
|
||||
this.methodResolver = this.createResolverForMethodName(methodName);
|
||||
this.methodResolver = this.createResolverForMethodName(methodName, requiresReturnValue);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Object invokeMethod(Message<?> message) {
|
||||
Assert.notNull(message, "message must not be null");
|
||||
@@ -164,11 +169,12 @@ public class MessageMappingMethodInvoker {
|
||||
return mapper.fromMessage(message);
|
||||
}
|
||||
|
||||
private HandlerMethodResolver createResolverForMethodName(String methodName) {
|
||||
private HandlerMethodResolver createResolverForMethodName(String methodName, boolean requiresReturnValue) {
|
||||
List<Method> methodsWithName = new ArrayList<Method>();
|
||||
Method[] defaultCandidateMethods = HandlerMethodUtils.getCandidateHandlerMethods(this.object);
|
||||
for (Method method : defaultCandidateMethods) {
|
||||
if (method.getName().equals(methodName)) {
|
||||
if (method.getName().equals(methodName)
|
||||
&& (!requiresReturnValue || !Void.TYPE.equals(method.getReturnType()))) {
|
||||
methodsWithName.add(method);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user