(window.webpackJsonp=window.webpackJsonp||[]).push([[142],{566:function(e,t,n){"use strict";n.r(t);var a=n(56),r=Object(a.a)({},(function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[n("h1",{attrs:{id:"spring-integration-samples"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#spring-integration-samples"}},[e._v("#")]),e._v(" Spring Integration Samples")]),e._v(" "),n("h2",{attrs:{id:"spring-integration-samples-2"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#spring-integration-samples-2"}},[e._v("#")]),e._v(" Spring Integration Samples")]),e._v(" "),n("p",[e._v("As of Spring Integration 2.0, the Spring Integration distribution no longer includes the samples.\nInstead, we have switched to a much simpler collaborative model that should promote better community participation and, ideally, more contributions.\nSamples now have a dedicated GitHub repository.\nSample development also has its own lifecycle, which is not dependent on the lifecycle of the framework releases, although the repository is still tagged with each major release for compatibility reasons.")]),e._v(" "),n("p",[e._v("The great benefit to the community is that we can now add more samples and make them available to you right away without waiting for the next release.\nHaving its own GitHub repository that is not tied to the actual framework is also a great benefit.\nYou now have a dedicated place to suggest samples as well as report issues with existing samples.\nYou can also submit a sample to us as a Pull Request.\nIf we believe your sample adds value, we would be more then glad to add it to the 'samples' repository, properly crediting you as the author.")]),e._v(" "),n("h3",{attrs:{id:"where-to-get-samples"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#where-to-get-samples"}},[e._v("#")]),e._v(" Where to Get Samples")]),e._v(" "),n("p",[e._v("The Spring Integration Samples project is hosted on "),n("a",{attrs:{href:"https://github.com/spring-projects/spring-integration-samples/",target:"_blank",rel:"noopener noreferrer"}},[e._v("GitHub"),n("OutboundLink")],1),e._v(".\nIn order to check out or clone the samples, you must have a Git client installed on your system.\nThere are several GUI-based products available for many platforms (such as "),n("a",{attrs:{href:"https://eclipse.org/egit/",target:"_blank",rel:"noopener noreferrer"}},[e._v("EGit"),n("OutboundLink")],1),e._v(" for the Eclipse IDE).\nA simple Google search can help you find them.\nYou can also use the command line interface for "),n("a",{attrs:{href:"https://git-scm.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Git"),n("OutboundLink")],1),e._v(".")]),e._v(" "),n("table",[n("thead",[n("tr",[n("th"),e._v(" "),n("th",[e._v("If you need more information on how to install or use Git, visit: "),n("a",{attrs:{href:"https://git-scm.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("https://git-scm.com/"),n("OutboundLink")],1),e._v(".")])])]),e._v(" "),n("tbody")]),e._v(" "),n("p",[e._v("To clone (check out) the Spring Integration samples repository by using the Git command line tool, issue the following command:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("$ git clone https://github.com/spring-projects/spring-integration-samples.git\n")])])]),n("p",[e._v("The preceding command clones the entire samples repository into a directory named "),n("code",[e._v("spring-integration-samples")]),e._v(" within the working directory where you issued that "),n("code",[e._v("git")]),e._v(" command.\nSince the samples repository is a live repository, you might want to perform periodic pulls (updates) to get new samples and updates to the existing samples.\nTo do so, issue the following "),n("code",[e._v("git pull")]),e._v(" command:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("$ git pull\n")])])]),n("h3",{attrs:{id:"submitting-samples-or-sample-requests"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#submitting-samples-or-sample-requests"}},[e._v("#")]),e._v(" Submitting Samples or Sample Requests")]),e._v(" "),n("p",[e._v("You can submit both new samples and requests for samples.\nWe greatly appreciate any effort toward improving the samples, including the sharing of good ideas.")]),e._v(" "),n("h4",{attrs:{id:"how-can-i-contribute-my-own-samples"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#how-can-i-contribute-my-own-samples"}},[e._v("#")]),e._v(" How Can I Contribute My Own Samples?")]),e._v(" "),n("p",[e._v("Github is for social coding: if you want to submit your own code examples to the Spring Integration Samples project, we encourage contributions through "),n("a",{attrs:{href:"https://help.github.com/en/articles/creating-a-pull-request/",target:"_blank",rel:"noopener noreferrer"}},[e._v("pull requests"),n("OutboundLink")],1),e._v(" from "),n("a",{attrs:{href:"https://help.github.com/en/articles/fork-a-repo",target:"_blank",rel:"noopener noreferrer"}},[e._v("forks"),n("OutboundLink")],1),e._v(" of this repository.\nIf you want to contribute code this way, please reference, if possible, a "),n("a",{attrs:{href:"https://github.com/spring-projects/spring-integration-samples/issues",target:"_blank",rel:"noopener noreferrer"}},[e._v("GutHub issue"),n("OutboundLink")],1),e._v(" that provides some details regarding your sample.")]),e._v(" "),n("table",[n("thead",[n("tr",[n("th"),e._v(" "),n("th",[e._v("Sign the contributor license agreement"),n("br"),n("br"),e._v("Very important: Before we can accept your Spring Integration sample, we need you to sign the SpringSource contributor license agreement (CLA)."),n("br"),e._v("Signing the contributor’s agreement does not grant anyone commit rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do."),n("br"),e._v("In order to read and sign the CLA, go to:"),n("br"),n("br"),n("a",{attrs:{href:"https://support.springsource.com/spring_committer_signup",target:"_blank",rel:"noopener noreferrer"}},[e._v("https://support.springsource.com/spring_committer_signup"),n("OutboundLink")],1),n("br"),n("br"),e._v("From the "),n("strong",[e._v("Project")]),e._v(" drop down, select "),n("strong",[e._v("Spring Integration")]),e._v("."),n("br"),e._v("The Project Lead is Artem Bilan.")])])]),e._v(" "),n("tbody")]),e._v(" "),n("h4",{attrs:{id:"code-contribution-process"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#code-contribution-process"}},[e._v("#")]),e._v(" Code Contribution Process")]),e._v(" "),n("p",[e._v("For the actual code contribution process, read the Contributor Guidelines for Spring Integration.\nThey apply for the samples project as well.\nYou can find them at "),n("a",{attrs:{href:"https://github.com/spring-projects/spring-integration/blob/main/CONTRIBUTING.md",target:"_blank",rel:"noopener noreferrer"}},[e._v("https://github.com/spring-projects/spring-integration/blob/main/CONTRIBUTING.md"),n("OutboundLink")],1)]),e._v(" "),n("p",[e._v("This process ensures that every commit gets peer-reviewed.\nAs a matter of fact, the core committers follow the exact same rules.\nWe gratefully look forward to your Spring Integration samples!")]),e._v(" "),n("h4",{attrs:{id:"sample-requests"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#sample-requests"}},[e._v("#")]),e._v(" Sample Requests")]),e._v(" "),n("p",[e._v("As "),n("a",{attrs:{href:"#samples-how-can-i-contribute"}},[e._v("mentioned earlier")]),e._v(", the Spring Integration Samples project uses GitHub issue as bug tracking system.\nTo submit new sample requests, visit "),n("a",{attrs:{href:"https://github.com/spring-projects/spring-integration-samples/issues",target:"_blank",rel:"noopener noreferrer"}},[e._v("https://github.com/spring-projects/spring-integration-samples/issues"),n("OutboundLink")],1),e._v(".")]),e._v(" "),n("h3",{attrs:{id:"samples-structure"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#samples-structure"}},[e._v("#")]),e._v(" Samples Structure")]),e._v(" "),n("p",[e._v("Starting with Spring Integration 2.0, the structure of the samples has changed.\nWith plans for more samples, we realized that not all samples have the same goals.\nThey all share the common goal of showing you how to apply and work with the Spring Integration framework.\nHowever, they differ in that some samples concentrate on a technical use case, while others focus on a business use case.\nAlso, some samples are about showcasing various techniques that could be applied to address certain scenarios (both technical and business).\nThe new categorization of samples lets us better organize them based on the problem each sample addresses while giving you a simpler way of finding the right sample for your needs.")]),e._v(" "),n("p",[e._v("Currently there are four categories.\nWithin the samples repository, each category has its own directory, which is named after the category name:")]),e._v(" "),n("p",[e._v("Basic ("),n("code",[e._v("samples/basic")]),e._v(")")]),e._v(" "),n("p",[e._v("This is a good place to get started.\nThe samples here are technically motivated and demonstrate the bare minimum with regard to configuration and code.\nThese should help you to get started quickly by introducing you to the basic concepts, API, and configuration of Spring Integration as well as Enterprise Integration Patterns (EIP).\nFor example, if you are looking for an answer on how to implement and wire a service activator to a message channel, how to use a messaging gateway as a facade to your message exchange, or how to get started with MAIL, TCP/UDP or other modules, this is the right place to find a good sample.\nThe bottom line is "),n("code",[e._v("samples/basic")]),e._v(" is a good place to get started.")]),e._v(" "),n("p",[e._v("Intermediate ("),n("code",[e._v("samples/intermediate")]),e._v(")")]),e._v(" "),n("p",[e._v("This category targets developers who are already familiar with the Spring Integration framework (beyond getting started) but need some more guidance while resolving the more advanced technical problems they might encounter after switching to a messaging architecture.\nFor example, if you are looking for an answer on how to handle errors in various message exchange scenarios or how to properly configure the aggregator for a situation where some messages do not ever arrive for aggregation, or any other issue that goes beyond a basic implementation and configuration of a particular component and exposes “what else” types of problems, this is the right place to find these type of samples.")]),e._v(" "),n("p",[e._v("Advanced ("),n("code",[e._v("samples/advanced")]),e._v(")")]),e._v(" "),n("p",[e._v("This category targets developers who are very familiar with the Spring Integration framework but are looking to extend it to address a specific custom need by using Spring Integration’s public API.\nFor example, if you are looking for samples showing you how to implement a custom channel or consumer (event-based or polling-based) or you are trying to figure out the most appropriate way to implement a custom bean parser on top of the Spring Integration bean parser hierarchy (perhaps when implementing your own namespace and schema for a custom component), this is the right place to look.\nHere you can also find samples that will help you with adapter development.\nSpring Integration comes with an extensive library of adapters to let you connect remote systems with the Spring Integration messaging framework.\nHowever, you might need to integrate with a system for which the core framework does not provide an adapter.\nIf so, you might decide to implement your own (please consider contributing it).\nThis category would include samples showing you how.")]),e._v(" "),n("p",[e._v("Applications ("),n("code",[e._v("samples/applications")]),e._v(")")]),e._v(" "),n("p",[e._v("This category targets developers and architects who have a good understanding of message-driven architecture and EIP and an above-average understanding of Spring and Spring Integration who are looking for samples that address a particular business problem.\nIn other words, the emphasis of the samples in this category is business use cases and how they can be solved with a message-driven architecture and Spring Integration in particular.\nFor example, if you want to see how a loan broker or travel agent process could be implemented and automated with Spring Integration, this is the right place to find these types of samples.")]),e._v(" "),n("table",[n("thead",[n("tr",[n("th"),e._v(" "),n("th",[e._v("Spring Integration is a community-driven framework."),n("br"),e._v("Therefore community participation is IMPORTANT."),n("br"),e._v("That includes samples."),n("br"),e._v("If you cannot find what you are looking for, let us know!")])])]),e._v(" "),n("tbody")]),e._v(" "),n("h3",{attrs:{id:"samples"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#samples"}},[e._v("#")]),e._v(" Samples")]),e._v(" "),n("p",[e._v("Currently, Spring Integration comes with quite a few samples and you can only expect more.\nTo help you better navigate through them, each sample comes with its own "),n("code",[e._v("readme.txt")]),e._v(" file which covers several details about the sample (for example, what EIP patterns it addresses, what problem it is trying to solve, how to run the sample, and other details).\nHowever, certain samples require a more detailed and sometimes graphical explanation.\nIn this section, you can find details on samples that we believe require special attention.")]),e._v(" "),n("h4",{attrs:{id:"loan-broker"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#loan-broker"}},[e._v("#")]),e._v(" Loan Broker")]),e._v(" "),n("p",[e._v("This section covers the loan broker sample application that is included in the Spring Integration samples.\nThis sample is inspired by one of the samples featured in Gregor Hohpe and Bobby Woolf’s book, "),n("a",{attrs:{href:"https://www.enterpriseintegrationpatterns.com/",target:"_blank",rel:"noopener noreferrer"}},[n("em",[e._v("Enterprise Integration Patterns")]),n("OutboundLink")],1),e._v(".")]),e._v(" "),n("p",[e._v("The following diagram shows the entire process:")]),e._v(" "),n("p",[n("img",{attrs:{src:"https://docs.spring.io/spring-integration/docs/current/reference/html/images/loan-broker-eip.png",alt:"loan broker eip"}})]),e._v(" "),n("p",[e._v("Figure 1. Loan Broker Sample")]),e._v(" "),n("p",[e._v("At the core of an EIP architecture are the very simple yet powerful concepts of pipes, filters, and, of course: messages.\nEndpoints (filters) are connected with one another via channels (pipes).\nProducing endpoints send messages to the channel, and the consuming endpoint retrieves the messages.\nThis architecture is meant to define various mechanisms that describe how information is exchanged between the endpoints, without any awareness of what those endpoints are or what information they are exchanging.\nThus, it provides for a very loosely coupled and flexible collaboration model while also decoupling integration concerns from business concerns.\nEIP extends this architecture by further defining:")]),e._v(" "),n("ul",[n("li",[n("p",[e._v("The types of pipes (point-to-point channel, publish-subscribe channel, channel adapter, and others)")])]),e._v(" "),n("li",[n("p",[e._v("The core filters and patterns around how filters collaborate with pipes (Message router, splitters and aggregators, various message transformation patterns, and others)")])])]),e._v(" "),n("p",[e._v("Chapter 9 of the EIP book nicely describes the details and variations of this use case, but here is the brief summary: While shopping for the best loan quote, a consumer subscribes to the services of a loan broker, which handles such details as:")]),e._v(" "),n("ul",[n("li",[n("p",[e._v("Consumer pre-screening (for example, obtaining and reviewing the consumer’s Credit history)")])]),e._v(" "),n("li",[n("p",[e._v("Determining the most appropriate banks (for example, based on the consumer’s credit history or score)")])]),e._v(" "),n("li",[n("p",[e._v("Sending a loan quote request to each selected bank")])]),e._v(" "),n("li",[n("p",[e._v("Collecting responses from each bank")])]),e._v(" "),n("li",[n("p",[e._v("Filtering responses and determining the best quotes, based on consumer’s requirements.")])]),e._v(" "),n("li",[n("p",[e._v("Pass the Loan quotes back to the consumer.")])])]),e._v(" "),n("p",[e._v("The real process of obtaining a loan quote is generally a bit more complex.\nHowever, since our goal is to demonstrate how Enterprise Integration Patterns are realized and implemented within Spring Integration, the use case has been simplified to concentrate only on the integration aspects of the process.\nIt is not an attempt to give you advice in consumer finances.")]),e._v(" "),n("p",[e._v("By engaging a loan broker, the consumer is isolated from the details of the loan broker’s operations, and each loan broker’s operations may defer from one another to maintain competitive advantage, so whatever we assemble and implement must be flexible so that any changes could be introduced quickly and painlessly.")]),e._v(" "),n("table",[n("thead",[n("tr",[n("th"),e._v(" "),n("th",[e._v("The loan broker sample does not actually talk to any 'imaginary' Banks or Credit bureaus."),n("br"),e._v("Those services are stubbed out.")])])]),e._v(" "),n("tbody")]),e._v(" "),n("p",[e._v("Our goal here is to assemble, orchestrate, and test the integration aspects of the process as a whole.\nOnly then can we start thinking about wiring such processes to the real services.\nAt that time, the assembled process and its configuration do not change regardless of the number of banks with which a particular loan broker deals or the type of communication media (or protocols) used (JMS, WS, TCP, and so on) to communicate with these banks.")]),e._v(" "),n("h5",{attrs:{id:"design"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#design"}},[e._v("#")]),e._v(" Design")]),e._v(" "),n("p",[e._v("As you analyze the "),n("a",{attrs:{href:"#samples-loan-broker-requirements"}},[e._v("six requirements")]),e._v(" listed earlier, you can see that they are all integration concerns.\nFor example, in the consumer pre-screening step, we need to gather additional information about the consumer and the consumer’s desires and enrich the loan request with additional meta-information.\nWe then have to filter such information to select the most appropriate list of banks and so on.\nEnrich, filter, and select are all integration concerns for which EIP defines a solution in the form of patterns.\nSpring Integration provides an implementation of these patterns.")]),e._v(" "),n("p",[e._v("The following image shows a representation of a messaging gateway:")]),e._v(" "),n("p",[n("img",{attrs:{src:"https://docs.spring.io/spring-integration/docs/current/reference/html/images/gateway.jpg",alt:"gateway"}})]),e._v(" "),n("p",[e._v("Figure 2. Messaging Gateway")]),e._v(" "),n("p",[e._v("The messaging gateway pattern provides a simple mechanism to access messaging systems, including our loan broker.\nIn Spring Integration, you can define the gateway as a plain old java interface (you need not provide an implementation), configure it with the XML "),n("code",[e._v("")]),e._v(" element or with an annotation in Java, and use it as you would any other Spring bean.\nSpring Integration takes care of delegating and mapping method invocations to the messaging infrastructure by generating a message (the payload is mapped to an input parameter of the method) and sending it to the designated channel.\nThe following example shows how to define such a gateway with XML:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v('\n \n \n \n\n')])])]),n("p",[e._v("Our current gateway provides two methods that could be invoked.\nOne that returns the best single quote and another one that returns all quotes.\nSomehow, downstream, we need to know what type of reply the caller needs.\nThe best way to achieve this in messaging architecture is to enrich the content of the message with some metadata that describes your intentions.\nContent Enricher is one of the patterns that addresses this.\nSpring Integration does, as a convenience, provide a separate configuration element to enrich message headers with arbitrary data (described later)\nHowever, since the "),n("code",[e._v("gateway")]),e._v(" element is responsible for constructing the initial message, it includes ability to enrich the newly created message with arbitrary message headers.\nIn our example, we add a "),n("code",[e._v("RESPONSE_TYPE")]),e._v(" header with a value of "),n("code",[e._v("BEST")]),e._v(" whenever the "),n("code",[e._v("getBestQuote()")]),e._v(" method is invoked.\nFor other methods, we do not add any header.\nNow we can check downstream for the existence of this header.\nBased on its presence and its value, we can determine what type of reply the caller wants.")]),e._v(" "),n("p",[e._v("Based on the use case, we also know tat some pre-screening steps need to be performed, such as getting and evaluating the consumer’s credit score, because some premiere banks only accept quote requests from consumers that meet a minimum credit score requirement.\nSo it would be nice if the message would be enriched with such information before it is forwarded to the banks.\nIt would also be nice if, when several processes need to be completed to provide such meta-information, those processes could be grouped in a single unit.\nIn our use case, we need to determine the credit score and, based on the credit score and some rule, select a list of message channels (bank channels) to which to send quote request.")]),e._v(" "),n("h5",{attrs:{id:"composed-message-processor"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#composed-message-processor"}},[e._v("#")]),e._v(" Composed Message Processor")]),e._v(" "),n("p",[e._v("The composed message processor pattern describes rules around building endpoints that maintain control over message flow, which consists of multiple message processors.\nIn Spring Integration, the composed message processor pattern is implemented by the "),n("code",[e._v("")]),e._v(" element.")]),e._v(" "),n("p",[e._v("The following image shows the chain pattern:")]),e._v(" "),n("p",[n("img",{attrs:{src:"https://docs.spring.io/spring-integration/docs/current/reference/html/images/chain.png",alt:"chain"}})]),e._v(" "),n("p",[e._v("Figure 3. Chain")]),e._v(" "),n("p",[e._v("The preceding image shows that we have a chain with an inner header-enricher element that further enriches the content of the message with the "),n("code",[e._v("CREDIT_SCORE")]),e._v(" header and the value (which is determined by the call to a credit service — a simple POJO spring bean identified by 'creditBureau' name).\nThen it delegates to the message router.")]),e._v(" "),n("p",[e._v("The following image shows the message router pattern:")]),e._v(" "),n("p",[n("img",{attrs:{src:"https://docs.spring.io/spring-integration/docs/current/reference/html/images/bank-router.jpg",alt:"bank router"}})]),e._v(" "),n("p",[e._v("Figure 4. Message Router")]),e._v(" "),n("p",[e._v("Spring Integration offers several implementations of the message routing pattern.\nIn this case, we use a router that determines a list of channels based on evaluating an expression (in Spring Expression Language) that looks at the credit score (determined in the previous step) and selects the list of channels from the "),n("code",[e._v("Map")]),e._v(" bean with an "),n("code",[e._v("id")]),e._v(" of "),n("code",[e._v("banks")]),e._v(" whose values are "),n("code",[e._v("premier")]),e._v(" or "),n("code",[e._v("secondary")]),e._v(", based on the value of credit score.\nOnce the list of channels is selected, the message is routed to those channels.")]),e._v(" "),n("p",[e._v("Now, one last thing the loan broker needs to receive the loan quotes form the banks, aggregate them by consumer (we do not want to show quotes from one consumer to another), assemble the response based on the consumer’s selection criteria (single best quote or all quotes) and send the reply to the consumer.")]),e._v(" "),n("p",[e._v("The following image shows the message aggregator pattern:")]),e._v(" "),n("p",[n("img",{attrs:{src:"https://docs.spring.io/spring-integration/docs/current/reference/html/images/quotes-aggregator.jpg",alt:"quotes aggregator"}})]),e._v(" "),n("p",[e._v("Figure 5. Message Aggregator")]),e._v(" "),n("p",[e._v("An aggregator pattern describes an endpoint that groups related messages into a single message.\nCriteria and rules can be provided to determine an aggregation and correlation strategy.\nSpring Integration provides several implementations of the aggregator pattern as well as a convenient namespace-based configuration.")]),e._v(" "),n("p",[e._v("The following example shows how to define an aggregator:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v('\n \n\n')])])]),n("p",[e._v("Our Loan Broker defines a 'quotesAggregator' bean with the "),n("code",[e._v("")]),e._v(" element, which provides a default aggregation and correlation strategy.\nThe default correlation strategy correlates messages based on the "),n("code",[e._v("correlationId")]),e._v(" header (see "),n("a",{attrs:{href:"https://www.enterpriseintegrationpatterns.com/patterns/messaging/CorrelationIdentifier.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("the correlation identifier pattern in the EIP book"),n("OutboundLink")],1),e._v(").\nNote that we never provided the value for this header.\nIt was automatically set earlier by the router, when it generated a separate message for each bank channel.")]),e._v(" "),n("p",[e._v("Once the messages are correlated, they are released to the actual aggregator implementation.\nAlthough Spring Integration provides a default aggregator, its strategy (gather the list of payloads from all messages and construct a new message with this list as its payload) does not satisfy our requirement.\nHaving all the results in the message is a problem, because our consumer might require a single best quote or all quotes.\nTo communicate the consumer’s intention, earlier in the process we set the "),n("code",[e._v("RESPONSE_TYPE")]),e._v(" header.\nNow we have to evaluate this header and return either all the quotes (the default aggregation strategy would work) or the best quote (the default aggregation strategy does not work because we have to determine which loan quote is the best).")]),e._v(" "),n("p",[e._v("In a more realistic application, selecting the best quote might be based on complex criteria that might influence the complexity of the aggregator implementation and configuration.\nFor now, though, we are making it simple.\nIf the consumer wants the best quote, we select a quote with the lowest interest rate.\nTo accomplish that, the "),n("code",[e._v("LoanQuoteAggregator")]),e._v(" class sorts all the quotes by interest rate and returns the first one.\nThe "),n("code",[e._v("LoanQuote")]),e._v(" class implements "),n("code",[e._v("Comparable")]),e._v(" to compare quotes based on the rate attribute.\nOnce the response message is created, it is sent to the default reply channel of the messaging gateway (and, thus, to the consumer) that started the process.\nOur consumer got the loan quote!")]),e._v(" "),n("p",[e._v("In conclusion, a rather complex process was assembled based on POJO (that is existing or legacy) logic and a light-weight, embeddable messaging framework (Spring Integration) with a loosely coupled programming model intended to simplify integration of heterogeneous systems without requiring a heavy-weight ESB-like engine or a proprietary development and deployment environment.\nAs a developer, you should not need to port your Swing or console-based application to an ESB-like server or implement proprietary interfaces just because you have an integration concern.")]),e._v(" "),n("p",[e._v("This sample and the other samples in this section are built on top of Enterprise Integration Patterns.\nYou can consider them to be “building blocks” for your solution.\nThey are not intended to be complete solutions.\nIntegration concerns exist in all types of application (whether server-based or not).\nOur goal is to make is so that integrating applications does not require changes in design, testing, and deployment strategy.")]),e._v(" "),n("h4",{attrs:{id:"the-cafe-sample"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#the-cafe-sample"}},[e._v("#")]),e._v(" The Cafe Sample")]),e._v(" "),n("p",[e._v("This section covers the cafe sample application that is included in the Spring Integration samples.\nThis sample is inspired by another sample featured in Gregor Hohpe’s "),n("a",{attrs:{href:"https://www.enterpriseintegrationpatterns.com/ramblings.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("Ramblings"),n("OutboundLink")],1),e._v(".")]),e._v(" "),n("p",[e._v("The domain is that of a cafe, and the following diagram depicts the basic flow:")]),e._v(" "),n("p",[n("img",{attrs:{src:"https://docs.spring.io/spring-integration/docs/current/reference/html/images/cafe-eip.png",alt:"cafe eip"}})]),e._v(" "),n("p",[e._v("Figure 6. Cafe Sample")]),e._v(" "),n("p",[e._v("The "),n("code",[e._v("Order")]),e._v(" object may contain multiple "),n("code",[e._v("OrderItems")]),e._v(".\nOnce the order is placed, a splitter breaks the composite order message into a single message for each drink.\nEach of these is then processed by a router that determines whether the drink is hot or cold (by checking the "),n("code",[e._v("OrderItem")]),e._v(" object’s 'isIced' property).\nThe "),n("code",[e._v("Barista")]),e._v(" prepares each drink, but hot and cold drink preparation are handled by two distinct methods: 'prepareHotDrink' and 'prepareColdDrink'.\nThe prepared drinks are then sent to the "),n("code",[e._v("Waiter")]),e._v(" where they are aggregated into a "),n("code",[e._v("Delivery")]),e._v(" object.")]),e._v(" "),n("p",[e._v("The following listing shows the XML configuration:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v('\n\n\n \n\n \n \n\n \n \n\n \n \n\n \n \n\n \n \n\n \n\n \n\n \n\n \n \n\n \n\n\n')])])]),n("p",[e._v("Each message endpoint connects to input channels, output channels, or both.\nEach endpoint manages its own lifecycle (by default, endpoints start automatically upon initialization, to prevent that, add the "),n("code",[e._v("auto-startup")]),e._v(" attribute with a value of "),n("code",[e._v("false")]),e._v(").\nMost importantly, notice that the objects are simple POJOs with strongly typed method arguments.\nThe following example shows the Splitter:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("public class OrderSplitter {\n public List split(Order order) {\n return order.getItems();\n }\n}\n")])])]),n("p",[e._v("In the case of the router, the return value does not have to be a "),n("code",[e._v("MessageChannel")]),e._v(" instance (although it can be).\nIn this example, a "),n("code",[e._v("String")]),e._v(" value that holds the channel name is returned instead, as the following listing shows.")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v('public class DrinkRouter {\n public String resolveOrderItemChannel(OrderItem orderItem) {\n return (orderItem.isIced()) ? "coldDrinks" : "hotDrinks";\n }\n}\n')])])]),n("p",[e._v("Now, turning back to the XML, you can see that there are two "),n("code",[e._v("")]),e._v(" elements.\nEach of these is delegating to the same "),n("code",[e._v("Barista")]),e._v(" instance but with different methods ("),n("code",[e._v("prepareHotDrink")]),e._v(" or "),n("code",[e._v("prepareColdDrink")]),e._v("), each corresponding to one of the two channels where order items have been routed.\nThe following listing shows the Barista class (which contains the "),n("code",[e._v("prepareHotDrink")]),e._v(" and "),n("code",[e._v("prepareColdDrink")]),e._v(" methods)")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v('public class Barista {\n\n private long hotDrinkDelay = 5000;\n private long coldDrinkDelay = 1000;\n\n private AtomicInteger hotDrinkCounter = new AtomicInteger();\n private AtomicInteger coldDrinkCounter = new AtomicInteger();\n\n public void setHotDrinkDelay(long hotDrinkDelay) {\n this.hotDrinkDelay = hotDrinkDelay;\n }\n\n public void setColdDrinkDelay(long coldDrinkDelay) {\n this.coldDrinkDelay = coldDrinkDelay;\n }\n\n public Drink prepareHotDrink(OrderItem orderItem) {\n try {\n Thread.sleep(this.hotDrinkDelay);\n System.out.println(Thread.currentThread().getName()\n + " prepared hot drink #" + hotDrinkCounter.incrementAndGet()\n + " for order #" + orderItem.getOrder().getNumber()\n + ": " + orderItem);\n return new Drink(orderItem.getOrder().getNumber(), orderItem.getDrinkType(),\n orderItem.isIced(), orderItem.getShots());\n }\n catch (InterruptedException e) {\n Thread.currentThread().interrupt();\n return null;\n }\n }\n\n public Drink prepareColdDrink(OrderItem orderItem) {\n try {\n Thread.sleep(this.coldDrinkDelay);\n System.out.println(Thread.currentThread().getName()\n + " prepared cold drink #" + coldDrinkCounter.incrementAndGet()\n + " for order #" + orderItem.getOrder().getNumber() + ": "\n + orderItem);\n return new Drink(orderItem.getOrder().getNumber(), orderItem.getDrinkType(),\n orderItem.isIced(), orderItem.getShots());\n }\n catch (InterruptedException e) {\n Thread.currentThread().interrupt();\n return null;\n }\n }\n}\n')])])]),n("p",[e._v("As you can see from the preceding code excerpt, the "),n("code",[e._v("Barista")]),e._v(" methods have different delays (the hot drinks take five times as long to prepare).\nThis simulates work being completed at different rates.\nWhen the "),n("code",[e._v("CafeDemo")]),e._v(" 'main' method runs, it loops 100 times and sends a single hot drink and a single cold drink each time.\nIt actually sends the messages by invoking the 'placeOrder' method on the "),n("code",[e._v("Cafe")]),e._v(" interface.\nIn the earlier XML configuration, you can see that the "),n("code",[e._v("")]),e._v(" element is specified.\nThis triggers the creation of a proxy that implements the given service interface and connects it to a channel.\nThe channel name is provided on the "),n("code",[e._v("@Gateway")]),e._v(" annotation of the "),n("code",[e._v("Cafe")]),e._v(" interface, as the following interface definition shows:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v('public interface Cafe {\n\n @Gateway(requestChannel="orders")\n void placeOrder(Order order);\n\n}\n')])])]),n("p",[e._v("Finally, have a look at the "),n("code",[e._v("main()")]),e._v(" method of the "),n("code",[e._v("CafeDemo")]),e._v(" itself:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v('public static void main(String[] args) {\n AbstractApplicationContext context = null;\n if (args.length > 0) {\n context = new FileSystemXmlApplicationContext(args);\n }\n else {\n context = new ClassPathXmlApplicationContext("cafeDemo.xml", CafeDemo.class);\n }\n Cafe cafe = context.getBean("cafe", Cafe.class);\n for (int i = 1; i <= 100; i++) {\n Order order = new Order(i);\n order.addItem(DrinkType.LATTE, 2, false);\n order.addItem(DrinkType.MOCHA, 3, true);\n cafe.placeOrder(order);\n }\n}\n')])])]),n("table",[n("thead",[n("tr",[n("th"),e._v(" "),n("th",[e._v("To run this sample as well as eight others, refer to the "),n("code",[e._v("README.txt")]),e._v(" within the "),n("code",[e._v("samples")]),e._v(" directory of the main distribution (as described at "),n("a",{attrs:{href:"#samples"}},[e._v("the beginning of this chapter")]),e._v(").")])])]),e._v(" "),n("tbody")]),e._v(" "),n("p",[e._v("When you run "),n("code",[e._v("cafeDemo")]),e._v(", you can see that the cold drinks are initially prepared more quickly than the hot drinks.\nBecause there is an aggregator, the cold drinks are effectively limited by the rate of the hot drink preparation.\nThis is to be expected, based on their respective delays of 1000 and 5000 milliseconds.\nHowever, by configuring a poller with a concurrent task executor, you can dramatically change the results.\nFor example, you could use a thread pool executor with five workers for the hot drink barista while keeping the cold drink barista as it is.\nThe following listing configures such an arrangement:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v('\n\n \n \n \n\n \n')])])]),n("p",[e._v("Also, notice that the worker thread name is displayed with each invocation.\nYou can see that the hot drinks are prepared by the task-executor threads.\nIf you provide a much shorter poller interval (such as 100 milliseconds), you can see that it occasionally throttles the input by forcing the task scheduler (the caller) to invoke the operation.")]),e._v(" "),n("table",[n("thead",[n("tr",[n("th"),e._v(" "),n("th",[e._v("In addition to experimenting with the poller’s concurrency settings, you can also add the 'transactional' child element and then refer to any "),n("code",[e._v("PlatformTransactionManager")]),e._v(" instance within the context.")])])]),e._v(" "),n("tbody")]),e._v(" "),n("h4",{attrs:{id:"the-xml-messaging-sample"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#the-xml-messaging-sample"}},[e._v("#")]),e._v(" The XML Messaging Sample")]),e._v(" "),n("p",[e._v("The XML messaging sample in "),n("code",[e._v("basic/xml")]),e._v(" shows how to use some of the provided components that deal with XML payloads.\nThe sample uses the idea of processing an order for books represented as XML.")]),e._v(" "),n("table",[n("thead",[n("tr",[n("th"),e._v(" "),n("th",[e._v("This sample shows that the namespace prefix can be whatever you want."),n("br"),e._v("While we usually use, "),n("code",[e._v("int-xml")]),e._v(" for integration XML components, the sample uses "),n("code",[e._v("si-xml")]),e._v("."),n("br"),e._v("("),n("code",[e._v("int")]),e._v(" is short for “Integration”, and "),n("code",[e._v("si")]),e._v(" is short for “Spring Integration”.)")])])]),e._v(" "),n("tbody")]),e._v(" "),n("p",[e._v("First, the order is split into a number of messages, each one representing a single order item from the XPath splitter component.\nThe following listing shows the configuration of the splitter:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v('\n \n \n')])])]),n("p",[e._v("A service activator then passes the message into a stock checker POJO.\nThe order item document is enriched with information from the stock checker about the order item stock level.\nThis enriched order item message is then used to route the message.\nIn the case where the order item is in stock, the message is routed to the warehouse.\nThe following listing configures the "),n("code",[e._v("xpath-router")]),e._v(" that routes the messages:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v('\n \n \n \n\n')])])]),n("p",[e._v("When the order item is not in stock, the message is transformed with XSLT into a format suitable for sending to the supplier.\nThe following listing configures the XSLT transformer:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v('\n')])])])])}),[],!1,null,null,null);t.default=r.exports}}]);