/*
* Copyright 2002-2016 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.splitter;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Before;
import org.junit.Test;
import org.springframework.integration.IntegrationMessageHeaderAccessor;
import org.springframework.integration.annotation.Splitter;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.GenericMessage;
/**
* @author Alex Peters
* @author Artem Bilan
* @author Gary Russell
* @since 4.1
*/
public class StreamingSplitterTests {
private Message<?> message;
@Before
public void setUp() {
message = new GenericMessage<String>("foo.bar");
}
@Test
public void splitToIterator_sequenceSizeInLastMessageHeader()
throws Exception {
int messageQuantity = 5;
MethodInvokingSplitter splitter = new MethodInvokingSplitter(new IteratorTestBean(
messageQuantity));
QueueChannel replyChannel = new QueueChannel();
splitter.setOutputChannel(replyChannel);
splitter.handleMessage(message);
List<Message<?>> receivedMessages = replyChannel.clear();
Collections.sort(receivedMessages, (o1, o2) ->
o1.getHeaders().get(IntegrationMessageHeaderAccessor.SEQUENCE_NUMBER, Integer.class)
.compareTo(o2.getHeaders().get(IntegrationMessageHeaderAccessor.SEQUENCE_NUMBER, Integer.class)));
assertThat(receivedMessages.get(4)
.getHeaders()
.get(IntegrationMessageHeaderAccessor.SEQUENCE_NUMBER, Integer.class),
is(messageQuantity));
}
@Test
public void splitToIterator_sourceMessageHeadersIncluded() throws Exception {
String anyHeaderKey = "anyProperty1";
String anyHeaderValue = "anyValue1";
message = MessageBuilder.fromMessage(message)
.setHeader(anyHeaderKey, anyHeaderValue)
.build();
int messageQuantity = 5;
MethodInvokingSplitter splitter = new MethodInvokingSplitter(new IteratorTestBean(
messageQuantity));
QueueChannel replyChannel = new QueueChannel();
splitter.setOutputChannel(replyChannel);
splitter.handleMessage(message);
List<Message<?>> receivedMessages = replyChannel.clear();
assertThat(receivedMessages.size(), is(messageQuantity));
for (Message<?> reveivedMessage : receivedMessages) {
MessageHeaders headers = reveivedMessage.getHeaders();
assertTrue("Unexpected result with: " + headers, headers.containsKey(anyHeaderKey));
assertThat("Unexpected result with: " + headers,
headers.get(anyHeaderKey, String.class),
is(anyHeaderValue));
assertThat("Unexpected result with: " + headers,
headers.get(IntegrationMessageHeaderAccessor.CORRELATION_ID, UUID.class),
is(message.getHeaders().getId()));
}
}
@Test
public void splitToIterator_allMessagesSent() throws Exception {
int messageQuantity = 5;
MethodInvokingSplitter splitter = new MethodInvokingSplitter(new IteratorTestBean(
messageQuantity));
QueueChannel replyChannel = new QueueChannel();
splitter.setOutputChannel(replyChannel);
splitter.handleMessage(message);
assertThat(replyChannel.getQueueSize(), is(messageQuantity));
}
@Test
public void splitToIterable_allMessagesSent() throws Exception {
int messageQuantity = 5;
MethodInvokingSplitter splitter = new MethodInvokingSplitter(new IterableTestBean(
messageQuantity));
QueueChannel replyChannel = new QueueChannel();
splitter.setOutputChannel(replyChannel);
splitter.handleMessage(message);
assertThat(replyChannel.getQueueSize(), is(messageQuantity));
}
@Test
public void splitToIterator_allMessagesContainSequenceNumber()
throws Exception {
final int messageQuantity = 5;
MethodInvokingSplitter splitter = new MethodInvokingSplitter(new IteratorTestBean(
messageQuantity));
DirectChannel replyChannel = new DirectChannel();
splitter.setOutputChannel(replyChannel);
new EventDrivenConsumer(replyChannel, message -> assertThat("Failure with msg: " + message,
message.getHeaders().get(IntegrationMessageHeaderAccessor.SEQUENCE_NUMBER, Integer.class),
is(Integer.valueOf((String) message.getPayload())))).start();
splitter.handleMessage(message);
}
@Test
public void splitWithMassiveReplyMessages_allMessagesSent()
throws Exception {
final int messageQuantity = 100000;
MethodInvokingSplitter splitter = new MethodInvokingSplitter(new IteratorTestBean(
messageQuantity));
DirectChannel replyChannel = new DirectChannel();
splitter.setOutputChannel(replyChannel);
final AtomicInteger receivedMessageCounter = new AtomicInteger(0);
new EventDrivenConsumer(replyChannel, message -> {
assertThat("Failure with msg: " + message, message.getPayload(), is(notNullValue()));
receivedMessageCounter.incrementAndGet();
}).start();
splitter.handleMessage(message);
assertThat(receivedMessageCounter.get(), is(messageQuantity));
}
static class IteratorTestBean {
final int max;
AtomicInteger counter = new AtomicInteger(0);
IteratorTestBean(int max) {
this.max = max;
}
@Splitter
public Iterator<String> annotatedMethod(String input) {
return new Iterator<String>() {
@Override
public boolean hasNext() {
return counter.get() < max;
}
@Override
public String next() {
if (!hasNext()) {
throw new IllegalStateException("Last element reached!");
}
return String.valueOf(counter.incrementAndGet());
}
@Override
public void remove() {
throw new AssertionError("not implemented!");
}
};
}
}
static class IterableTestBean {
final int max;
AtomicInteger counter = new AtomicInteger(0);
IterableTestBean(int max) {
this.max = max;
}
@Splitter
public Iterable<String> annotatedMethod(String input) {
return new Iterable<String>() {
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
@Override
public boolean hasNext() {
return counter.get() < max;
}
@Override
public String next() {
if (!hasNext()) {
throw new IllegalStateException(
"Last element reached!");
}
return String.valueOf(counter.incrementAndGet());
}
@Override
public void remove() {
throw new AssertionError("not implemented!");
}
};
}
};
}
}
}