INT-330: switched namespace support for aggregator

This commit is contained in:
Iwein Fuld
2010-03-02 16:25:24 +00:00
parent 7a79b956d6
commit 1a38553402
24 changed files with 482 additions and 355 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* 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.
@@ -16,13 +16,20 @@
package org.springframework.integration.aggregator;
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.context.Lifecycle;
import org.springframework.integration.channel.ChannelResolver;
import org.springframework.integration.channel.MessageChannelTemplate;
import org.springframework.integration.channel.NullChannel;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.core.MessageHeaders;
import org.springframework.integration.handler.AbstractMessageHandler;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.store.MessageStore;
import org.springframework.integration.store.SimpleMessageStore;
import org.springframework.scheduling.TaskScheduler;
@@ -47,18 +54,24 @@ import java.util.concurrent.locks.ReentrantLock;
*
* @author Iwein Fuld
*/
public class CorrelatingMessageHandler extends AbstractMessageHandler implements Lifecycle {
public class CorrelatingMessageHandler extends AbstractMessageHandler implements Lifecycle, BeanFactoryAware {
private static final Log logger = LogFactory.getLog(CorrelatingMessageHandler.class);
// TODO: need to support 'resequencer' as well
public static final String COMPONENT_TYPE_LABEL = "aggregator";
public static final String COMPONENT_TYPE_LABEL = "aggregator";
private static final long DEFAULT_SEND_TIMEOUT = 1000l;
private static final long DEFAULT_REAPER_INTERVAL = 1000l;
private static final long DEFAULT_TIMEOUT = 60000l;
private final MessageStore store;
private final MessageGroupProcessor outputProcessor;
private MessageStore store = new SimpleMessageStore(100);
private final CorrelationStrategy correlationStrategy;
private final CompletionStrategy completionStrategy;
private MessageGroupProcessor outputProcessor;
private volatile CorrelationStrategy correlationStrategy = new HeaderAttributeCorrelationStrategy(MessageHeaders.CORRELATION_ID);
private volatile CompletionStrategy completionStrategy = new SequenceSizeCompletionStrategy();
private MessageChannel outputChannel;
private final MessageChannelTemplate channelTemplate = new MessageChannelTemplate();
private volatile MessageChannel discardChannel = new NullChannel();
private ChannelResolver channelResolver;
@@ -67,8 +80,8 @@ public class CorrelatingMessageHandler extends AbstractMessageHandler implements
private volatile TaskScheduler taskScheduler;
private volatile ScheduledFuture<?> reaperFutureTask;
private volatile long reaperInterval = 1000l;
private volatile long timeout = 60000l;
private volatile long reaperInterval = DEFAULT_REAPER_INTERVAL;
private volatile long timeout = DEFAULT_TIMEOUT;
private volatile boolean sendPartialResultOnTimeout;
private Object lifecycleMonitor = new Object();
@@ -78,13 +91,14 @@ public class CorrelatingMessageHandler extends AbstractMessageHandler implements
CompletionStrategy completionStrategy,
MessageGroupProcessor processor) {
Assert.notNull(store);
Assert.notNull(correlationStrategy);
Assert.notNull(completionStrategy);
Assert.notNull(processor);
Assert.notNull(correlationStrategy);
Assert.notNull(completionStrategy);
this.store = store;
this.outputProcessor = processor;
this.correlationStrategy = correlationStrategy;
this.completionStrategy = completionStrategy;
this.outputProcessor = processor;
this.channelTemplate.setSendTimeout(DEFAULT_SEND_TIMEOUT);
}
public CorrelatingMessageHandler(MessageStore store,
@@ -94,6 +108,23 @@ public class CorrelatingMessageHandler extends AbstractMessageHandler implements
new SequenceSizeCompletionStrategy(), processor);
}
public CorrelatingMessageHandler(
MessageGroupProcessor processor) {
this(new SimpleMessageStore(100),
new HeaderAttributeCorrelationStrategy(MessageHeaders.CORRELATION_ID),
new SequenceSizeCompletionStrategy(), processor);
}
public void setCorrelationStrategy(CorrelationStrategy correlationStrategy) {
Assert.notNull(correlationStrategy);
this.correlationStrategy = correlationStrategy;
}
public void setCompletionStrategy(CompletionStrategy completionStrategy) {
Assert.notNull(completionStrategy);
this.completionStrategy = completionStrategy;
}
public void setTaskScheduler(TaskScheduler taskScheduler) {
this.taskScheduler = taskScheduler;
}
@@ -107,6 +138,7 @@ public class CorrelatingMessageHandler extends AbstractMessageHandler implements
}
public void setOutputChannel(MessageChannel outputChannel) {
Assert.notNull(outputChannel, "'outputChannel' must not be null");
this.outputChannel = outputChannel;
}
@@ -118,13 +150,26 @@ public class CorrelatingMessageHandler extends AbstractMessageHandler implements
this.discardChannel = discardChannel;
}
public void setSendTimeout(long sendTimeout) {
this.channelTemplate.setSendTimeout(sendTimeout);
}
public void setSendPartialResultOnTimeout(boolean sendPartialResultOnTimeout) {
this.sendPartialResultOnTimeout = sendPartialResultOnTimeout;
}
public void setBeanFactory(BeanFactory beanFactory) {
if (this.taskScheduler == null) {
this.taskScheduler = IntegrationContextUtils.getRequiredTaskScheduler(beanFactory);
}
}
@Override
protected void handleMessageInternal(Message<?> message) throws Exception {
Object correlationKey = correlationStrategy.getCorrelationKey(message);
if (logger.isDebugEnabled()) {
logger.debug("Handling message with correllationKey [" + correlationKey + "]: " + message);
}
try {
if (tracker.waitForLockIfNotTracked(correlationKey)) {
MessageGroup group =
@@ -135,8 +180,11 @@ public class CorrelatingMessageHandler extends AbstractMessageHandler implements
group.add(message);
if (group.isComplete()) {
if (logger.isDebugEnabled()) {
logger.debug("Completing group with correllationKey [" + correlationKey + "]");
}
outputProcessor.processAndSend(group,
this.resolveReplyChannel(message, this.outputChannel, this.channelResolver));
channelTemplate, this.resolveReplyChannel(message, this.outputChannel, this.channelResolver));
}
} else {
discardChannel.send(message);
@@ -164,7 +212,12 @@ public class CorrelatingMessageHandler extends AbstractMessageHandler implements
}
private void store(Message<?> message, Object correlationKey) {
store.put(message);
Message toStore = message;
if (!correlationKey.equals(message.getHeaders().getCorrelationId())) {
toStore = MessageBuilder.fromMessage(message)
.setCorrelationId(correlationKey).build();
}
store.put(toStore);
if (!keysInBuffer.contains(correlationKey)) {
keysInBuffer.add(new DelayedKey(correlationKey, timeout));
}
@@ -228,7 +281,7 @@ public class CorrelatingMessageHandler extends AbstractMessageHandler implements
MessageChannel outputChannel = resolveReplyChannel(all.get(0), this.outputChannel, this.channelResolver);
boolean processed = false;
if (group.isComplete()) {
outputProcessor.processAndSend(group, outputChannel);
outputProcessor.processAndSend(group, channelTemplate, outputChannel);
processed = true;
}
if (!processed) {
@@ -236,7 +289,7 @@ public class CorrelatingMessageHandler extends AbstractMessageHandler implements
if (logger.isInfoEnabled()) {
logger.info("Processing partially complete messages for key [" + key + "] to: " + outputChannel);
}
outputProcessor.processAndSend(group, outputChannel);
outputProcessor.processAndSend(group, channelTemplate, outputChannel);
} else {
if (logger.isInfoEnabled()) {
logger.info("Discarding partially complete messages for key [" + key + "] to: " + discardChannel);

View File

@@ -0,0 +1,57 @@
/*
* 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 org.springframework.integration.channel.MessageChannelTemplate;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.util.Assert;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* This implementation of MessageGroupProcessor will take the messages from the MessageGroup and pass them on in a
* single message with a Collection as a payload.
*
* @author Iwein Fuld
* @author Alexander Peters
* @since 2.0.0
*/
public class DefaultAggregatingMessageGroupProcessor implements MessageGroupProcessor {
public void processAndSend(MessageGroup group, MessageChannelTemplate channelTemplate, MessageChannel outputChannel) {
Assert.notNull(group, "Message group must not be null.");
Assert.notNull(outputChannel, "'outputChannel' must not be null.");
List<Message<?>> messages = group.getMessages();
Assert.notEmpty(messages, this.getClass().getSimpleName() + " cannot process empty message groups");
channelTemplate.send(aggregateMessages(messages), outputChannel);
}
private Message<? extends Collection> aggregateMessages(List<Message<?>> messages) {
List payloads = new ArrayList(messages.size());
for (Message<?> message : messages) {
payloads.add(message.getPayload());
}
return MessageBuilder.withPayload(payloads).build();
}
}

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.integration.aggregator;
import org.springframework.integration.channel.MessageChannelTemplate;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.core.MessageHeaders;
@@ -25,6 +26,8 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* This class implements all the strategy interfaces needed for a default resequencer.
*
* @author Iwein Fuld
*/
public class DefaultResequencerStrategies implements CorrelationStrategy, CompletionStrategy, MessageGroupProcessor {
@@ -39,12 +42,12 @@ public class DefaultResequencerStrategies implements CorrelationStrategy, Comple
}
public boolean isComplete(List<? extends Message<?>> messages) {
return releasePartialSequences||
messages.get(0).getHeaders().getSequenceSize()==messages.size();
return releasePartialSequences ||
messages.get(0).getHeaders().getSequenceSize() == messages.size();
}
public void processAndSend(MessageGroup group, MessageChannel outputChannel) {
List<Message<?>> all = group.getMessages();
public void processAndSend(MessageGroup group, MessageChannelTemplate channelTemplate, MessageChannel outputChannel) {
List<Message<?>> all = group.getMessages();
Object correlationKey = group.getCorrelationKey();
if (all.size() > 0) {
List<Message> sorted = new ArrayList(all);
@@ -53,13 +56,13 @@ public class DefaultResequencerStrategies implements CorrelationStrategy, Comple
for (Message message : sorted) {
final int sequenceNumber = message.getHeaders().getSequenceNumber();
if (sequenceNumber <= nextSequence.get()) {
outputChannel.send(message);
channelTemplate.send(message, outputChannel);
nextSequence.compareAndSet(sequenceNumber, sequenceNumber + 1);
group.onProcessingOf(message);
}
}
MessageHeaders headers = sorted.get(0).getHeaders();
if (all.size() == headers.getSequenceSize()){
if (all.size() == headers.getSequenceSize()) {
group.onCompletion();
}
}

View File

@@ -35,8 +35,13 @@ public class MessageGroup {
}
public boolean hasNoMessageSuperseding(Message<?> message) {
Integer messageSequenceNumber = message.getHeaders().getSequenceNumber();
if (messageSequenceNumber == null) {
return true;
}
for (Message<?> member : messages) {
if (member.getHeaders().getSequenceNumber() == message.getHeaders().getSequenceNumber()) {
Integer memberSequenceNumber = member.getHeaders().getSequenceNumber();
if (memberSequenceNumber == messageSequenceNumber) {
return false;
}
}

View File

@@ -1,13 +1,24 @@
package org.springframework.integration.aggregator;
import org.springframework.integration.channel.MessageChannelTemplate;
import org.springframework.integration.core.MessageChannel;
/**
* A processor for <i>correlated</i> groups of messages. When a message group is <i>complete</i> it is passed to the
* processor by e.g. the CorrelatingMessageHandler.
*
* @author Iwein Fuld
* @see org.springframework.integration.aggregator.CorrelatingMessageHandler
*/
public interface MessageGroupProcessor {
/**
* Processed the given group and sends the resulting message(s) to the output channel using the channelTemplate.
* Implementations are free to send as little or as many messages based on the invocation as needed. For example the
* DefaultAggregatingMessageGroupProcessor will send only a single message containing a collection of all messages
* in the group, where the resequencing equivalent strategy will send all messages in the group individually.
*/
void processAndSend(MessageGroup group,
MessageChannel outputChannel
MessageChannelTemplate channelTemplate, MessageChannel outputChannel
);
}

View File

@@ -63,7 +63,7 @@ public class MessageListMethodAdapter {
}
protected Method getMethod() {
public Method getMethod() {
return method;
}

View File

@@ -2,6 +2,7 @@ package org.springframework.integration.aggregator;
import org.springframework.integration.annotation.Aggregator;
import org.springframework.integration.annotation.Header;
import org.springframework.integration.channel.MessageChannelTemplate;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.message.MessageBuilder;
@@ -13,14 +14,14 @@ import java.util.*;
public class MethodInvokingMessageGroupProcessor implements MessageGroupProcessor {
private final Object target;
private final Method method;
private final MessageListMethodAdapter adapter;
public MethodInvokingMessageGroupProcessor(Object target) {
this.target = target;
this.method = selectMethodFrom(target);
this.adapter = new MessageListMethodAdapter(target, selectMethodFrom(target));
}
public MethodInvokingMessageGroupProcessor (Object target, String method){
this.adapter = new MessageListMethodAdapter(target, method);
}
@@ -116,7 +117,7 @@ public class MethodInvokingMessageGroupProcessor implements MessageGroupProcesso
}
public void processAndSend(MessageGroup group,
MessageChannel outputChannel
MessageChannelTemplate channelTemplate, MessageChannel outputChannel
) {
final Collection<Message<?>> messagesUpForProcessing = group.getMessages();
Message reply = MessageBuilder.withPayload(
@@ -124,10 +125,10 @@ public class MethodInvokingMessageGroupProcessor implements MessageGroupProcesso
group.onCompletion();
group.onProcessingOf(messagesUpForProcessing
.toArray(new Message[]{}));
outputChannel.send(reply);
channelTemplate.send(reply, outputChannel);
}
public Set<Method> removeMethodsMatchingSelector(Set<Method> candidates, MethodSelector selector) {
private Set<Method> removeMethodsMatchingSelector(Set<Method> candidates, MethodSelector selector) {
Set<Method> removed = new HashSet<Method>();
Iterator<Method> iterator = candidates.iterator();
while (iterator.hasNext()) {

View File

@@ -1,13 +1,22 @@
package org.springframework.integration.aggregator;
import org.springframework.integration.channel.MessageChannelTemplate;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
/**
* This implementation of MessageGroupProcessor will forward all messages inside the group to the given output channel.
* This is useful if there is no requirement to process the messages, but they should just be blocked as a group until
* their CompletionStrategy lets them pass through.
*
* @author Iwein Fuld
* @since 2.0.0
*/
public class PassThroughMessageGroupProcessor implements MessageGroupProcessor {
public void processAndSend(MessageGroup group, MessageChannel outputChannel) {
public void processAndSend(MessageGroup group, MessageChannelTemplate channelTemplate, MessageChannel outputChannel) {
for (Message<?> message : group.getMessages()) {
outputChannel.send(message);
channelTemplate.send(message, outputChannel);
group.onProcessingOf(message);
}
group.onCompletion();

View File

@@ -25,112 +25,119 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
/**
* Parser for the <em>aggregator</em> element of the integration namespace.
* Registers the annotation-driven post-processors.
*
* Parser for the <em>aggregator</em> element of the integration namespace. Registers the annotation-driven
* post-processors.
*
* @author Marius Bogoevici
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Oleg Zhurakousky
*/
public class AggregatorParser extends AbstractConsumerEndpointParser {
private static final String COMPLETION_STRATEGY_REF_ATTRIBUTE = "completion-strategy";
private static final String COMPLETION_STRATEGY_REF_ATTRIBUTE = "completion-strategy";
private static final String COMPLETION_STRATEGY_METHOD_ATTRIBUTE = "completion-strategy-method";
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_REF_ATTRIBUTE = "correlation-strategy";
private static final String CORRELATION_STRATEGY_METHOD_ATTRIBUTE = "correlation-strategy-method";
private static final String CORRELATION_STRATEGY_METHOD_ATTRIBUTE = "correlation-strategy-method";
private static final String DISCARD_CHANNEL_ATTRIBUTE = "discard-channel";
private static final String OUTPUT_CHANNEL_ATTRIBUTE = "output-channel";
private static final String SEND_TIMEOUT_ATTRIBUTE = "send-timeout";
private static final String DISCARD_CHANNEL_ATTRIBUTE = "discard-channel";
private static final String SEND_PARTIAL_RESULT_ON_TIMEOUT_ATTRIBUTE = "send-partial-result-on-timeout";
private static final String SEND_TIMEOUT_ATTRIBUTE = "send-timeout";
private static final String REAPER_INTERVAL_ATTRIBUTE = "reaper-interval";
private static final String SEND_PARTIAL_RESULT_ON_TIMEOUT_ATTRIBUTE = "send-partial-result-on-timeout";
private static final String TRACKED_CORRELATION_ID_CAPACITY_ATTRIBUTE = "tracked-correlation-id-capacity";
private static final String REAPER_INTERVAL_ATTRIBUTE = "reaper-interval";
private static final String TIMEOUT_ATTRIBUTE = "timeout";
private static final String TRACKED_CORRELATION_ID_CAPACITY_ATTRIBUTE = "tracked-correlation-id-capacity";
private static final String COMPLETION_STRATEGY_PROPERTY = "completionStrategy";
private static final String TIMEOUT_ATTRIBUTE = "timeout";
private static final String CORRELATION_STRATEGY_PROPERTY = "correlationStrategy";
private static final String COMPLETION_STRATEGY_PROPERTY = "completionStrategy";
private static final String CORRELATION_STRATEGY_PROPERTY = "correlationStrategy";
@Override
protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
BeanDefinition innerHandlerDefinition = IntegrationNamespaceUtils.parseInnerHandlerDefinition(element, parserContext);
String ref = element.getAttribute(REF_ATTRIBUTE);
BeanDefinitionBuilder builder;
if (innerHandlerDefinition != null || StringUtils.hasText(ref)){
builder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".aggregator.MethodInvokingAggregator");
} else {
builder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".aggregator.DefaultMessageAggregator");
}
if (innerHandlerDefinition != null){
builder.addConstructorArgValue(innerHandlerDefinition);
} else {
if (StringUtils.hasText(ref)) {
builder.addConstructorArgReference(ref);
}
}
if (StringUtils.hasText(element.getAttribute(METHOD_ATTRIBUTE))) {
String method = element.getAttribute(METHOD_ATTRIBUTE);
builder.getRawBeanDefinition().getConstructorArgumentValues().addGenericArgumentValue(method, "java.lang.String");
}
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element,
DISCARD_CHANNEL_ATTRIBUTE);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element,
SEND_TIMEOUT_ATTRIBUTE);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element,
SEND_PARTIAL_RESULT_ON_TIMEOUT_ATTRIBUTE);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element,
REAPER_INTERVAL_ATTRIBUTE);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element,
TRACKED_CORRELATION_ID_CAPACITY_ATTRIBUTE);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-startup");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, TIMEOUT_ATTRIBUTE);
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;
}
@Override
protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
BeanDefinition innerHandlerDefinition = IntegrationNamespaceUtils.parseInnerHandlerDefinition(element, parserContext);
String ref = element.getAttribute(REF_ATTRIBUTE);
BeanDefinitionBuilder builder;
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);
}
}
}
builder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".aggregator.CorrelatingMessageHandler");
BeanDefinitionBuilder processorBuilder = null;
private String createAdapter(String ref, String method, String unqualifiedClassName,
ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".aggregator." + unqualifiedClassName);
builder.addConstructorArgReference(ref);
builder.getRawBeanDefinition().getConstructorArgumentValues().addGenericArgumentValue(method, "java.lang.String");
return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(),
parserContext.getRegistry());
}
if (innerHandlerDefinition != null || StringUtils.hasText(ref)) {
processorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".aggregator.MethodInvokingMessageGroupProcessor");
builder.addConstructorArgValue(processorBuilder.getBeanDefinition());
} else {
builder.addConstructorArgValue(BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".aggregator.DefaultAggregatingMessageGroupProcessor").getBeanDefinition());
}
if (innerHandlerDefinition != null) {
processorBuilder.addConstructorArgValue(innerHandlerDefinition);
} else {
if (StringUtils.hasText(ref)) {
processorBuilder.addConstructorArgReference(ref);
}
}
if (StringUtils.hasText(element.getAttribute(METHOD_ATTRIBUTE))) {
String method = element.getAttribute(METHOD_ATTRIBUTE);
processorBuilder.getRawBeanDefinition().getConstructorArgumentValues().addGenericArgumentValue(method, "java.lang.String");
}
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element,
DISCARD_CHANNEL_ATTRIBUTE);
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element,
OUTPUT_CHANNEL_ATTRIBUTE);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element,
SEND_TIMEOUT_ATTRIBUTE);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element,
SEND_PARTIAL_RESULT_ON_TIMEOUT_ATTRIBUTE);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element,
REAPER_INTERVAL_ATTRIBUTE);
// IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, TRACKED_CORRELATION_ID_CAPACITY_ATTRIBUTE);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-startup");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, TIMEOUT_ATTRIBUTE);
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 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." + unqualifiedClassName);
builder.addConstructorArgReference(ref);
builder.getRawBeanDefinition().getConstructorArgumentValues().addGenericArgumentValue(method, "java.lang.String");
return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(),
parserContext.getRegistry());
}
}

View File

@@ -16,15 +16,15 @@
package org.springframework.integration.store;
import org.springframework.integration.core.Message;
import org.springframework.util.Assert;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.integration.core.Message;
import org.springframework.util.Assert;
/**
* Map-based implementation of {@link MessageStore} that enforces a maximum capacity.
*
@@ -34,46 +34,47 @@ import org.springframework.util.Assert;
*/
public class SimpleMessageStore implements MessageStore {
private final Map<Object, Message<?>> map;
private final Map<Object, Message<?>> map;
public SimpleMessageStore(int capacity) {
this.map = new ConcurrentHashMap<Object, Message<?>>(capacity);
}
public SimpleMessageStore(int capacity) {
this.map = new ConcurrentHashMap<Object, Message<?>>(capacity);
}
@SuppressWarnings("unchecked")
public <T> Message<T> put(Message<T> message) {
return (Message<T>) this.map.put(message.getHeaders().getId(), message);
}
@SuppressWarnings("unchecked")
public <T> Message<T> put(Message<T> message) {
return (Message<T>) this.map.put(message.getHeaders().getId(), message);
}
public Message<?> get(Object key) {
return (key != null) ? this.map.get(key) : null;
}
public Message<?> get(Object key) {
return (key != null) ? this.map.get(key) : null;
}
public List<Message<?>> list() {
return new ArrayList<Message<?>>(this.map.values());
}
public List<Message<?>> list() {
return new ArrayList<Message<?>>(this.map.values());
}
public Message<?> delete(Object key) {
return (key != null) ? this.map.remove(key) : null;
}
public Message<?> delete(Object key) {
return (key != null) ? this.map.remove(key) : null;
}
public int size() {
return this.map.size();
}
public int size() {
return this.map.size();
}
public List<Message<?>> list(Object correlationKey) {
public List<Message<?>> list(Object correlationKey) {
Assert.notNull(correlationKey, "'correlationKey' must not be null");
List<Message<?>> matched = new ArrayList<Message<?>>();
Collection<Message<?>> values = map.values();
for (Message<?> message : values) {
if(message.getHeaders().getCorrelationId().equals(correlationKey)){
matched.add(message);
}
}
return matched;
}
List<Message<?>> matched = new ArrayList<Message<?>>();
Collection<Message<?>> values = map.values();
for (Message<?> message : values) {
Object correlationId = message.getHeaders().getCorrelationId();
if (correlationId != null && correlationId.equals(correlationKey)) {
matched.add(message);
}
}
return matched;
}
}