use of org.springframework.integration.store.MessageGroup in project spring-integration by spring-projects.
the class AggregatingMessageGroupProcessorHeaderTests method testNullHeaderValue.
@Test
public void testNullHeaderValue() {
DefaultAggregatingMessageGroupProcessor processor = new DefaultAggregatingMessageGroupProcessor();
DirectFieldAccessor dfa = new DirectFieldAccessor(processor);
dfa.setPropertyValue("messageBuilderFactory", new MutableMessageBuilderFactory());
Map<String, Object> headers1 = new HashMap<String, Object>();
headers1.put("k1", "foo");
headers1.put("k2", null);
Message<?> message1 = MutableMessageBuilder.withPayload("test").setCorrelationId(1).setSequenceNumber(1).setSequenceSize(2).copyHeadersIfAbsent(headers1).build();
Map<String, Object> headers2 = new HashMap<String, Object>();
headers2.put("k1", "bar");
headers2.put("k2", 123);
Message<?> message2 = correlatedMessage(1, 2, 2, headers2);
List<Message<?>> messages = Arrays.<Message<?>>asList(message1, message2);
MessageGroup group = new SimpleMessageGroup(messages, 1);
Object result = processor.processMessageGroup(group);
assertNotNull(result);
assertTrue(result instanceof Message<?>);
Message<?> resultMessage = (Message<?>) result;
assertNull(resultMessage.getHeaders().get("k1"));
assertNull(resultMessage.getHeaders().get("k2"));
headers1 = new HashMap<String, Object>();
headers1.put("k1", "foo");
headers1.put("k2", 123);
message1 = correlatedMessage(1, 2, 1, headers1);
headers2 = new HashMap<String, Object>();
headers2.put("k1", "bar");
headers2.put("k2", null);
message2 = MutableMessageBuilder.withPayload("test").setCorrelationId(1).setSequenceNumber(2).setSequenceSize(2).copyHeadersIfAbsent(headers2).build();
messages = Arrays.<Message<?>>asList(message1, message2);
group = new SimpleMessageGroup(messages, 1);
result = processor.processMessageGroup(group);
resultMessage = (Message<?>) result;
assertNull(resultMessage.getHeaders().get("k1"));
assertNull(resultMessage.getHeaders().get("k2"));
}
use of org.springframework.integration.store.MessageGroup in project spring-integration by spring-projects.
the class DelayHandlerTests method testReschedulePersistedMessagesOnStartup.
// INT-1132
@Test
public void testReschedulePersistedMessagesOnStartup() throws Exception {
MessageGroupStore messageGroupStore = new SimpleMessageStore();
this.delayHandler.setDefaultDelay(2000);
this.delayHandler.setMessageStore(messageGroupStore);
this.startDelayerHandler();
Message<?> message = MessageBuilder.withPayload("test").build();
this.input.send(message);
Thread.sleep(100);
// emulate restart
this.taskScheduler.destroy();
assertEquals(1, messageGroupStore.getMessageGroupCount());
assertEquals(DELAYER_MESSAGE_GROUP_ID, messageGroupStore.iterator().next().getGroupId());
assertEquals(1, messageGroupStore.messageGroupSize(DELAYER_MESSAGE_GROUP_ID));
assertEquals(1, messageGroupStore.getMessageCountForAllMessageGroups());
MessageGroup messageGroup = messageGroupStore.getMessageGroup(DELAYER_MESSAGE_GROUP_ID);
Message<?> messageInStore = messageGroup.getMessages().iterator().next();
Object payload = messageInStore.getPayload();
assertEquals("DelayedMessageWrapper", payload.getClass().getSimpleName());
assertEquals(message.getPayload(), TestUtils.getPropertyValue(payload, "original.payload"));
this.taskScheduler.afterPropertiesSet();
this.delayHandler = new DelayHandler(DELAYER_MESSAGE_GROUP_ID, this.taskScheduler);
this.delayHandler.setOutputChannel(output);
this.delayHandler.setDefaultDelay(200);
this.delayHandler.setMessageStore(messageGroupStore);
this.delayHandler.setBeanFactory(mock(BeanFactory.class));
this.startDelayerHandler();
waitForLatch(10000);
assertSame(message.getPayload(), this.resultHandler.lastMessage.getPayload());
assertNotSame(Thread.currentThread(), this.resultHandler.lastThread);
assertEquals(1, messageGroupStore.getMessageGroupCount());
assertEquals(0, messageGroupStore.messageGroupSize(DELAYER_MESSAGE_GROUP_ID));
}
use of org.springframework.integration.store.MessageGroup in project spring-integration by spring-projects.
the class AbstractCorrelatingMessageHandler method forceComplete.
protected void forceComplete(MessageGroup group) {
Object correlationKey = group.getGroupId();
// UUIDConverter is no-op if already converted
Lock lock = this.lockRegistry.obtain(UUIDConverter.getUUID(correlationKey).toString());
boolean removeGroup = true;
try {
lock.lockInterruptibly();
try {
ScheduledFuture<?> scheduledFuture = this.expireGroupScheduledFutures.remove(UUIDConverter.getUUID(correlationKey));
if (scheduledFuture != null) {
boolean canceled = scheduledFuture.cancel(false);
if (canceled && this.logger.isDebugEnabled()) {
this.logger.debug("Cancel 'forceComplete' scheduling for MessageGroup [ " + group + "].");
}
}
MessageGroup groupNow = group;
/*
* If the group argument is not already complete,
* re-fetch it because it might have changed while we were waiting on
* its lock. If the last modified timestamp changed, defer the completion
* because the selection condition may have changed such that the group
* would no longer be eligible. If the timestamp changed, it's a completely new
* group and should not be reaped on this cycle.
*
* If the group argument is already complete, do not re-fetch.
* Note: not all message stores provide a direct reference to its internal
* group so the initial 'isComplete()` will only return true for those stores if
* the group was already complete at the time of its selection as a candidate.
*
* If the group is marked complete, only consider it
* for reaping if it's empty (and both timestamps are unaltered).
*/
if (!group.isComplete()) {
groupNow = this.messageStore.getMessageGroup(correlationKey);
}
long lastModifiedNow = groupNow.getLastModified();
int groupSize = groupNow.size();
if ((!groupNow.isComplete() || groupSize == 0) && group.getLastModified() == lastModifiedNow && group.getTimestamp() == groupNow.getTimestamp()) {
if (groupSize > 0) {
if (this.releaseStrategy.canRelease(groupNow)) {
completeGroup(correlationKey, groupNow);
} else {
expireGroup(correlationKey, groupNow);
}
if (!this.expireGroupsUponTimeout) {
afterRelease(groupNow, groupNow.getMessages(), true);
removeGroup = false;
}
} else {
/*
* By default empty groups are removed on the same schedule as non-empty
* groups. A longer timeout for empty groups can be enabled by
* setting minimumTimeoutForEmptyGroups.
*/
removeGroup = lastModifiedNow <= (System.currentTimeMillis() - this.minimumTimeoutForEmptyGroups);
if (removeGroup && this.logger.isDebugEnabled()) {
this.logger.debug("Removing empty group: " + correlationKey);
}
}
} else {
removeGroup = false;
if (this.logger.isDebugEnabled()) {
this.logger.debug("Group expiry candidate (" + correlationKey + ") has changed - it may be reconsidered for a future expiration");
}
}
} catch (MessageDeliveryException e) {
removeGroup = false;
if (this.logger.isDebugEnabled()) {
this.logger.debug("Group expiry candidate (" + correlationKey + ") has been affected by MessageDeliveryException - " + "it may be reconsidered for a future expiration one more time");
}
throw e;
} finally {
try {
if (removeGroup) {
this.remove(group);
}
} finally {
lock.unlock();
}
}
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
this.logger.debug("Thread was interrupted while trying to obtain lock");
}
}
use of org.springframework.integration.store.MessageGroup in project spring-integration by spring-projects.
the class AbstractCorrelatingMessageHandler method scheduleGroupToForceComplete.
private void scheduleGroupToForceComplete(Object groupId) {
MessageGroup messageGroup = this.messageStore.getMessageGroup(groupId);
scheduleGroupToForceComplete(messageGroup);
}
use of org.springframework.integration.store.MessageGroup in project spring-integration by spring-projects.
the class AbstractCorrelatingMessageHandler method handleMessageInternal.
@Override
protected void handleMessageInternal(Message<?> message) throws Exception {
Object correlationKey = this.correlationStrategy.getCorrelationKey(message);
Assert.state(correlationKey != null, "Null correlation not allowed. Maybe the CorrelationStrategy is failing?");
if (this.logger.isDebugEnabled()) {
this.logger.debug("Handling message with correlationKey [" + correlationKey + "]: " + message);
}
UUID groupIdUuid = UUIDConverter.getUUID(correlationKey);
Lock lock = this.lockRegistry.obtain(groupIdUuid.toString());
lock.lockInterruptibly();
try {
ScheduledFuture<?> scheduledFuture = this.expireGroupScheduledFutures.remove(groupIdUuid);
if (scheduledFuture != null) {
boolean canceled = scheduledFuture.cancel(true);
if (canceled && this.logger.isDebugEnabled()) {
this.logger.debug("Cancel 'ScheduledFuture' for MessageGroup with Correlation Key [ " + correlationKey + "].");
}
}
MessageGroup messageGroup = this.messageStore.getMessageGroup(correlationKey);
if (this.sequenceAware) {
messageGroup = new SequenceAwareMessageGroup(messageGroup);
}
if (!messageGroup.isComplete() && messageGroup.canAdd(message)) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Adding message to group [ " + messageGroup + "]");
}
messageGroup = this.store(correlationKey, message);
if (this.releaseStrategy.canRelease(messageGroup)) {
Collection<Message<?>> completedMessages = null;
try {
completedMessages = this.completeGroup(message, correlationKey, messageGroup);
} finally {
// Possible clean (implementation dependency) up
// even if there was an exception processing messages
afterRelease(messageGroup, completedMessages);
}
if (!isExpireGroupsUponCompletion() && this.minimumTimeoutForEmptyGroups > 0) {
removeEmptyGroupAfterTimeout(messageGroup, this.minimumTimeoutForEmptyGroups);
}
} else {
scheduleGroupToForceComplete(messageGroup);
}
} else {
discardMessage(message);
}
} finally {
lock.unlock();
}
}
Aggregations