diff --git a/eip-splitter/README.md b/eip-splitter/README.md
new file mode 100644
index 000000000..b59147504
--- /dev/null
+++ b/eip-splitter/README.md
@@ -0,0 +1,32 @@
+---
+layout: pattern
+title: EIP Splitter
+folder: eip-splitter
+permalink: /patterns/eip-splitter/
+categories: Enterprise integration
+tags:
+ - Java
+ - Difficulty-Intermittent
+ - Enterprise integration
+---
+
+## Intent
+It is very common in integration systems that incoming messages consists of many items bundled together. For example
+an invoice document contains multiple invoice lines describing transaction (quantity, name of provided
+service/sold goods, price etc.). Such bundled messages may not be accepted by other systems. This is where splitter
+pattern comes in handy. It will take the whole document, split it based on given criteria and send individual
+items to the endpoint.
+
+
+
+## Applicability
+Use the Splitter pattern when
+
+* You need to split received data into smaller pieces to process them individually
+* You need to control the size of data batches you are able to process
+
+## Credits
+
+* [Gregor Hohpe, Bobby Woolf - Enterprise Integration Patterns](http://www.enterpriseintegrationpatterns.com/patterns/messaging/Sequencer.html)
+* [Apache Camel - Documentation](http://camel.apache.org/splitter.html)
+
diff --git a/eip-splitter/etc/sequencer.gif b/eip-splitter/etc/sequencer.gif
new file mode 100644
index 000000000..a925fa209
Binary files /dev/null and b/eip-splitter/etc/sequencer.gif differ
diff --git a/eip-splitter/pom.xml b/eip-splitter/pom.xml
new file mode 100644
index 000000000..fb7e4ca9b
--- /dev/null
+++ b/eip-splitter/pom.xml
@@ -0,0 +1,63 @@
+
+
+
+ * Splitter allows you to split messages based on defined criteria. It takes original message, process it and send + * multiple parts to the output channel. It is not defined if it should keep the order of items though. + *
+ * + */ +@SpringBootApplication +public class App { + + /** + * Program entry point. It starts Spring Boot application and using Apache Camel it auto-configures routes. + * + * @param args command line args + */ + public static void main(String[] args) throws Exception { + // Run Spring Boot application and obtain ApplicationContext + ConfigurableApplicationContext context = SpringApplication.run(App.class, args); + + // Get CamelContext from ApplicationContext + CamelContext camelContext = (CamelContext) context.getBean("camelContext"); + + // Add a new routes that will handle endpoints form SplitterRoute class. + camelContext.addRoutes(new RouteBuilder() { + + @Override + public void configure() throws Exception { + from("{{endpoint}}").log("ENDPOINT: ${body}"); + } + + }); + + // Add producer that will send test message to an entry point in WireTapRoute + String[] stringArray = {"Test item #1", "Test item #2", "Test item #3"}; + camelContext.createProducerTemplate().sendBody("{{entry}}", stringArray); + + SpringApplication.exit(context); + } +} diff --git a/eip-splitter/src/main/java/com/iluwatar/eip/splitter/routes/SplitterRoute.java b/eip-splitter/src/main/java/com/iluwatar/eip/splitter/routes/SplitterRoute.java new file mode 100644 index 000000000..064ad1f68 --- /dev/null +++ b/eip-splitter/src/main/java/com/iluwatar/eip/splitter/routes/SplitterRoute.java @@ -0,0 +1,29 @@ +package com.iluwatar.eip.splitter.routes; + +import org.apache.camel.builder.RouteBuilder; +import org.springframework.stereotype.Component; + +/** + * Sample splitter route definition. + * + *+ * It consumes messages out of the direct:entry entry point and forwards them to direct:endpoint. + * Route accepts messages having body of array or collection of objects. Splitter component split message body and + * forwards single objects to the endpoint. + *
+ * + * In this example input/output endpoints names are stored in application.properties file. + */ +@Component +public class SplitterRoute extends RouteBuilder { + + /** + * Configures the route + * @throws Exception in case of exception during configuration + */ + @Override + public void configure() throws Exception { + // Main route + from("{{entry}}").split().body().to("{{endpoint}}"); + } +} diff --git a/eip-splitter/src/main/resources/application.properties b/eip-splitter/src/main/resources/application.properties new file mode 100644 index 000000000..cb879e6e2 --- /dev/null +++ b/eip-splitter/src/main/resources/application.properties @@ -0,0 +1,2 @@ +entry=direct:entry +endpoint=direct:endpoint diff --git a/eip-splitter/src/test/java/com/iluwatar/eip/splitter/AppTest.java b/eip-splitter/src/test/java/com/iluwatar/eip/splitter/AppTest.java new file mode 100644 index 000000000..bff2cf0b1 --- /dev/null +++ b/eip-splitter/src/test/java/com/iluwatar/eip/splitter/AppTest.java @@ -0,0 +1,15 @@ +package com.iluwatar.eip.splitter; + +import org.junit.Test; + +/** + * Test for App class + */ +public class AppTest { + + @Test + public void testMain() throws Exception { + String[] args = {}; + App.main(args); + } +} diff --git a/eip-splitter/src/test/java/com/iluwatar/eip/splitter/routes/SplitterRouteTest.java b/eip-splitter/src/test/java/com/iluwatar/eip/splitter/routes/SplitterRouteTest.java new file mode 100644 index 000000000..78fc37d91 --- /dev/null +++ b/eip-splitter/src/test/java/com/iluwatar/eip/splitter/routes/SplitterRouteTest.java @@ -0,0 +1,53 @@ +package com.iluwatar.eip.splitter.routes; + +import org.apache.camel.EndpointInject; +import org.apache.camel.Message; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import static org.junit.Assert.assertEquals; + +/** + * Test class for SplitterRoute. + *+ * In order for it to work we have to mock endpoints we want to read/write to. To mock those we need to substitute + * original endpoint names to mocks. + *
+ */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = SplitterRouteTest.class) +@ActiveProfiles("test") +@EnableAutoConfiguration +@ComponentScan +public class SplitterRouteTest { + + @EndpointInject(uri = "{{entry}}") + private ProducerTemplate entry; + + @EndpointInject(uri = "{{endpoint}}") + private MockEndpoint endpoint; + + /** + * Test if endpoint receives three separate messages. + * @throws Exception in case of en exception during the test + */ + @Test + @DirtiesContext + public void testSplitter() throws Exception { + + // Three items in one entry message + entry.sendBody(new String[] {"TEST1", "TEST2", "TEST3"}); + + // Endpoint should have three different messages in the end order of the messages is not important + endpoint.expectedMessageCount(3); + endpoint.assertIsSatisfied(); + } +} diff --git a/eip-splitter/src/test/resources/application-test.properties b/eip-splitter/src/test/resources/application-test.properties new file mode 100644 index 000000000..f657ea5a1 --- /dev/null +++ b/eip-splitter/src/test/resources/application-test.properties @@ -0,0 +1,2 @@ +entry=direct:entry +endpoint=mock:endpoint diff --git a/pom.xml b/pom.xml index 774b14019..0c03909de 100644 --- a/pom.xml +++ b/pom.xml @@ -148,6 +148,7 @@