From 9c7ee5ed1d221c8519c9671996687ad15f37ae17 Mon Sep 17 00:00:00 2001 From: adkm Date: Mon, 16 Oct 2017 19:33:15 +0200 Subject: [PATCH 1/4] #173 Added new pattern, tests --- eip-splitter/README.md | 20 ++++++ eip-splitter/pom.xml | 68 +++++++++++++++++++ .../java/com/iluwatar/eip/splitter/App.java | 45 ++++++++++++ .../eip/splitter/routes/SplitterRoute.java | 26 +++++++ .../src/main/resources/application.properties | 2 + .../com/iluwatar/eip/splitter/AppTest.java | 15 ++++ .../splitter/routes/SplitterRouteTest.java | 53 +++++++++++++++ .../resources/application-test.properties | 2 + 8 files changed, 231 insertions(+) create mode 100644 eip-splitter/README.md create mode 100644 eip-splitter/pom.xml create mode 100644 eip-splitter/src/main/java/com/iluwatar/eip/splitter/App.java create mode 100644 eip-splitter/src/main/java/com/iluwatar/eip/splitter/routes/SplitterRoute.java create mode 100644 eip-splitter/src/main/resources/application.properties create mode 100644 eip-splitter/src/test/java/com/iluwatar/eip/splitter/AppTest.java create mode 100644 eip-splitter/src/test/java/com/iluwatar/eip/splitter/routes/SplitterRouteTest.java create mode 100644 eip-splitter/src/test/resources/application-test.properties diff --git a/eip-splitter/README.md b/eip-splitter/README.md new file mode 100644 index 000000000..92ade7cb4 --- /dev/null +++ b/eip-splitter/README.md @@ -0,0 +1,20 @@ +--- +layout: pattern +title: EIP Splitter +folder: eip-splitter +permalink: /patterns/eip-splitter/ +categories: Enterprise integration +tags: + - Java + - Difficulty-Intermittent + - Enterprise integration +--- + +## Intent + + +## Applicability + + +## Credits + diff --git a/eip-splitter/pom.xml b/eip-splitter/pom.xml new file mode 100644 index 000000000..dd9f23e63 --- /dev/null +++ b/eip-splitter/pom.xml @@ -0,0 +1,68 @@ + + + + 4.0.0 + eip-splitter + + com.iluwatar + java-design-patterns + 1.18.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.apache.camel + camel-core + ${camel.version} + + + org.apache.camel + camel-csv + ${camel.version} + + + + org.apache.camel + camel-spring-boot + ${camel.version} + + + + + org.springframework.boot + spring-boot-starter-test + + + + org.apache.camel + camel-test-spring + ${camel.version} + + + + \ No newline at end of file diff --git a/eip-splitter/src/main/java/com/iluwatar/eip/splitter/App.java b/eip-splitter/src/main/java/com/iluwatar/eip/splitter/App.java new file mode 100644 index 000000000..9d7c1fc16 --- /dev/null +++ b/eip-splitter/src/main/java/com/iluwatar/eip/splitter/App.java @@ -0,0 +1,45 @@ +package com.iluwatar.eip.splitter; + +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; + +/** + * + *

+ *

+ */ +@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..61ec80631 --- /dev/null +++ b/eip-splitter/src/main/java/com/iluwatar/eip/splitter/routes/SplitterRoute.java @@ -0,0 +1,26 @@ +package com.iluwatar.eip.splitter.routes; + +import org.apache.camel.builder.RouteBuilder; +import org.springframework.stereotype.Component; + +/** + * Sample splitter route definition. + * + *

+ *

+ * + * 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 From 767f41ad905b83f8b2807a199f2cf748f6e618fc Mon Sep 17 00:00:00 2001 From: adkm Date: Tue, 17 Oct 2017 00:12:41 +0200 Subject: [PATCH 2/4] #173 Removed unneeded dependencies --- eip-splitter/pom.xml | 5 ----- .../src/main/java/com/iluwatar/eip/splitter/App.java | 8 ++++++++ .../com/iluwatar/eip/splitter/routes/SplitterRoute.java | 3 +++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/eip-splitter/pom.xml b/eip-splitter/pom.xml index dd9f23e63..fb7e4ca9b 100644 --- a/eip-splitter/pom.xml +++ b/eip-splitter/pom.xml @@ -40,11 +40,6 @@ camel-core ${camel.version} - - org.apache.camel - camel-csv - ${camel.version} - org.apache.camel diff --git a/eip-splitter/src/main/java/com/iluwatar/eip/splitter/App.java b/eip-splitter/src/main/java/com/iluwatar/eip/splitter/App.java index 9d7c1fc16..1f52e9569 100644 --- a/eip-splitter/src/main/java/com/iluwatar/eip/splitter/App.java +++ b/eip-splitter/src/main/java/com/iluwatar/eip/splitter/App.java @@ -7,9 +7,17 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; /** + * 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. * *

+ * 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 { 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 index 61ec80631..064ad1f68 100644 --- 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 @@ -7,6 +7,9 @@ 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. From 0aa84e37f20e42172b80f04396eda431d743e01c Mon Sep 17 00:00:00 2001 From: adkm Date: Tue, 17 Oct 2017 12:42:41 +0200 Subject: [PATCH 3/4] #173 Pattern description --- eip-splitter/README.md | 12 ++++++++++++ eip-splitter/etc/sequencer.gif | Bin 0 -> 2298 bytes 2 files changed, 12 insertions(+) create mode 100644 eip-splitter/etc/sequencer.gif diff --git a/eip-splitter/README.md b/eip-splitter/README.md index 92ade7cb4..b59147504 100644 --- a/eip-splitter/README.md +++ b/eip-splitter/README.md @@ -11,10 +11,22 @@ tags: --- ## 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. +![alt text](./etc/sequencer.gif "Splitter") ## 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 0000000000000000000000000000000000000000..a925fa2098777dadbf4c9e9a2006e9513421b8dc GIT binary patch literal 2298 zcmVM)j$~<` zXsWJk>%Q9|%W!Sqc&_h!@BbtjVK}4#kI1BQ$!t1p2coq2tXi+wtajUpPNxU1cuX#v z&mZp>jBdN%@c2%>CWhtsynfF|(Cc=6f`f#GOn-m`cZQ6Oj*lmZfQyiomY0>1b(EN$ zo}Y4>Yn-5^rl(n=QlzM@uCG3-fv~i-wlK1+x4XQ(9HP3u!o$8otHH#{%Cs{^%g@lZ z$kEi*nA6tT+J)HL-ru3%;^TVV>7`uiUB1OEd82n6^~ zU;udh61wwOa3Dd00}v{lc#a{&hYlrD-1yDkMSvgwHF6wjt=`9m0SJmD$?}=Wlo(+G zT-mbbFp~rWIs{4c3cjB}g9;r=bf`^nKy#kd*;8H7r%jak)f_n&c7g2gjG43R*KIxHkwrxb?a;PC*FN(S zuW zGOk7Ab2;Xw+l?_4x#B4t`uHM{{Sh%(X{05BB#u^2*rSt%eF&w8B!0GuV`D=0*mGNQ z`6P%zsx_o!f53G}oL8nnr*;=am7kg;;uGZ%gJ6Y)pgw68$4dnyny5jFCR%3>P4cPW zn_E>i#-mW=$!MdSI=ZK%E>e2vrKHZ5X91lqDv+X>q5vock%Fq8s7|~JLaWV{S}6qw zs2V_{sIFQ7t|my4XPYzf=Vq*(DSH_ItxXu4hOS!>>q0$>rW)+8){^i=1CFvy@|imVsZtfuyhwh@Nb;r(A1l zfB^!HT{hVPjGeR}MSs0*qicTvhy)Qg9W%w{o(1!`09SqQ$9Zb)8$?LXTj4#t})~t8`-e~O|V&7s|9z)<+SC;s}k{f+GxQ(CfdgGACn>yHK zuzUH-&UQXSvK3=Yb?8&{6Zldg1r4sRhnu`QudO%FxZ04#`?lA^+WR}Nm_ zRxDx~JEX-MI--aC1B@K!__i^wPlI^`1r|ZL#@O7CiK$u2APH#@Lzc0MXVjwu{Ux;s zJ<^SVq@Z#vcrr^0k%*V;S#UPFx!z4}iEiv*Ut|d$S}I3zm&D^LS$Q2U9;Fv1AtNGp z$xGt+@|U{^<{@9WKocyon4WASGMAyuTpG}W(6r7mr&)_?p7K-Kgv~a&2@7uu^P02S zV>q8CO>*7@m*2e1ROU&~dA8G?#Yo{fhsc_G`tzScxhFoUc}H~WA!i89*+923ziGRmD^p>*)oOLs2xuLvUj0xftMXN^ zcr`0rYv9+w{*|nVl~Y}LQCPu}HLQ*;D_|Y_Rmx_{t%(&ZWcRvQlHS#_d==}X8oO7t ziuSTk%`9MrO4rU746~bkY@TBA+0t@0ve&AuYU`l_PEbXtSMvm+bgK-e+IF(XJxyv= zE8FC@HMyJrjcr)giUQ*X_Zpa;?Q&aNDC(wCt=2t_SP>gq@Gh6I<4vk)y<1)82BE7v z!|r*r>s;3|gSn@zZ)5YSUdVE{1iDCTbVEyExtjIA_N51M2dv+_R`#&FMKFNjV%P^u zSF;jMFku&LS+@E$wHH2ah8YN23xl?~8t#ODeB%OJ%?25_FV-<6)a%^X(pShKrf~>-JJ{wv7{5JMac(8cK*iR$x8r^9 zb}5YH@17U9`6Yy)1Z?EPwz$O`%CZQ&+}5Uqx3_W*S)Sb~Ws&V!cvreIp6l}GDYLZC zmRhf;fAbpOuqpb$jJ|GO3QTD>L%7i+MYLV9>}Ej^`La=FG*!18>MGwy(@Ms{l^N{b zPj8shLWb|8VSQrlrn(iY&T)Oq{A%zTw$;3@v9DJh>?Ge>k-LtytLuzpWfxk^PKK^l zk6lD*b6VD_wzjk9L+m5p_RiG)M5NOk?P8PKyw?6ModI0sO4pjj;f}Yw=S}Z=+xy=5 U&bPkz&F_Bu``-ZHY6JiPJ08586aWAK literal 0 HcmV?d00001 From dd828bcd6c1415c27fe198c465de5f7a882b1cc7 Mon Sep 17 00:00:00 2001 From: adkm Date: Tue, 17 Oct 2017 12:46:28 +0200 Subject: [PATCH 4/4] #173 Update pom --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 774b14019..0c03909de 100644 --- a/pom.xml +++ b/pom.xml @@ -148,6 +148,7 @@ throttling partial-response eip-wire-tap + eip-splitter