INT-1477, added Loan Broker section to the samples, changed diagrams to be extracted from GUI tooling available in STS (with slight editing)

This commit is contained in:
Oleg Zhurakousky
2010-09-29 11:53:42 -04:00
parent 2a6620b6e8
commit d3a083ecdb
7 changed files with 243 additions and 5 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -149,13 +149,251 @@ That includes Samples, so if you can't find what you are looking for let us know
</para>
<section id="samples-loan-broker">
<title>Loan Broker</title>
<para>
In this section, we will review a <emphasis>Loan Broker</emphasis> sample application that is included in the
Spring Integration samples. This sample is inspired by one of the samples featured in Gregor
Hohpe's <ulink url="http://www.eaipatterns.com/ramblings.html">Ramblings</ulink>.
</para>
<para>The diagram below represents the entire process</para>
<para>
<mediaobject>
<imageobject role="fo">
<imagedata fileref="src/docbkx/resources/images/loan-broker-eip.png"
format="PNG" align="center"/>
</imageobject>
<imageobject role="html">
<imagedata fileref="images/loan-broker-eip.png" format="PNG" align="center"/>
</imageobject>
</mediaobject>
</para>
<para>Now lets look at this process in more details</para>
<para>
At the core of EIP architecture are the very simple yet powerful concepts of Pipes and Filters and Message. Endpoints (Filters) are
connected with one another via Channels (Pipes). The producing endpoint sends Message to the Channel and the Message is retrieved
by the Consuming endpoint. This 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, thus providing for a very loosely
coupled and flexible collaboration model while also, decoupling Integration concerns from Business concerns. EIP extends this architecture
by further defining:
<itemizedlist>
<listitem>
<para>The types of pipes (Point-to-Point Channel, Publish-Subscribe Channel, Channel Adapter, etc.)</para>
</listitem>
<listitem>
<para>The core filters and patterns around how filters collaborate with pipes
(Message Router, Splitters and Aggregators, various Message Transformation patterns, etc.)</para>
</listitem>
</itemizedlist>
</para>
<para>
The details and variations of this use case are very nicely described in Chapter 9 of the EIP Book, but here is the brief summary;
A Consumer while shopping for the best Loan Quote(s) subscribes to the services of a Loan Broker, which handles details such as:
<itemizedlist>
<listitem>
<para>Consumer pre-screening (e.g., obtain and review the consumer's Credit history)</para>
</listitem>
<listitem>
<para>Determine the most appropriate Banks (e.g., based on consumer's credit history/score)</para>
</listitem>
<listitem>
<para>Send a Loan quote request to each selected Bank</para>
</listitem>
<listitem>
<para>Collect responses from each Bank</para>
</listitem>
<listitem>
<para>Filter responses and determine the best quote(s), based on consumer's requirements.</para>
</listitem>
<listitem>
<para>Pass the Loan quote(s) back to the consumer.</para>
</listitem>
</itemizedlist>
</para>
<para>
Obviously the real process of obtaining a loan quote is a bit more complex, but since our goal here is to demonstrate how
Enterprise Integration Patterns are realized and implemented within SI, the use case has been simplified to concentrate only on
the Integration aspects of the process. It is not an attempt to give you an advice in consumer finances.
</para>
<para>
As you can see, by hiring 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/implement must be flexible so any changes
could be introduced quickly and painlessly.
Speaking of change, the Loan Broker sample does not actually talk to any 'imaginary' Banks or Credit bureaus. Those services are stubbed out.
Our goal here is to assemble, orchestrate and test the integration aspect of the process as a whole. Only then can we start thinking about
wiring such process to the real services. At that time the assembled process and its configuration will not change regardless of the number
of Banks a particular Loan Broker is dealing with, or the type of communication media (or protocols) used (JMS, WS, TCP, etc.)
to communicate with these Banks.
</para>
<para> <emphasis>DESIGN</emphasis> </para>
<para>
As you analyze the 6 requirements above you'll quickly see that they all fall into the category of Integration concerns.
For 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. We then have to filter such information to select the most appropriate list of
Banks, and so on. Enrich, filter, select these are all integration concerns for which EIP defines a solution in the form of patterns.
SI provides an implementation of these patterns.
</para>
<para><emphasis>Messaging Gateway</emphasis>
<mediaobject>
<imageobject role="fo">
<imagedata fileref="src/docbkx/resources/images/gateway.png"
format="PNG" align="center"/>
</imageobject>
<imageobject role="html">
<imagedata fileref="images/gateway.png" format="PNG" align="center"/>
</imageobject>
</mediaobject>
</para>
<para>
The <emphasis>Messaging Gateway</emphasis> pattern provides a simple mechanism to access messaging systems, including our Loan Broker.
In SI you define the <emphasis>Gateway</emphasis> as a Plain Old Java Interface (no need to provide an implementation), configure it via the
XML <emphasis>&lt;gateway&gr;</emphasis> element or via annotation and use it as any other Spring bean. SI will take care of
delegating and mapping method invocations to the Messaging infrastructure by generating a <emphasis>Message</emphasis> (payload is mapped to an
input parameter of the method) and sending it to the designated channel.
<programlisting language="xml"><![CDATA[<gateway id="loanBrokerGateway"
default-request-channel="loanBrokerPreProcessingChannel"
service-interface="org.springframework.integration.samples.loanbroker.LoanBrokerGateway">
<method name="getBestLoanQuote">
<header name="RESPONSE_TYPE" value="BEST"/>
</method>
</gateway>]]></programlisting>
</para>
<para>
Our current <emphasis>Gateway</emphasis> provides two methods that could be invoked. One that will return the best single quote and another one that
will return all quotes. Somehow downstream we need to know what type of reply the caller is looking for. The best way to achieve
this in Messaging architecture is to enrich the content of the message with some meta-data describing your intentions.
<emphasis>Content Enricher</emphasis> is one of the patterns that addresses this and although Spring Integration does provide a
separate configuration element to enrich Message Headers with arbitrary data (we'll see it later), as a convenience, since
<emphasis>Gateway</emphasis> element is responsible to construct the initial <emphasis>Message</emphasis> it provides embedded
capability to enrich the newly created <emphasis>Message</emphasis> with arbitrary <emphasis>Message Headers</emphasis>. In our
example we are adding header RESPONSE_TYPE with value 'BEST'' whenever the getBestQuote() method is invoked. For other method
we are not adding any header. Now we can check downstream for an existence of this header and based on its presence and its value
we can determine what type of reply the caller is looking for.
</para>
<para>
Based on the use case we also know there are some pre-screening steps that needs to be performed such as getting and evaluating the consumer's
credit score, simply because some premiere Banks will only typically accept quote requests from consumers that meet a minimum credit
score requirement. So it would be nice if the <emphasis>Message</emphasis> would be enriched with such information before it is forwarded
to the Banks. It would also be nice if when several processes needs to be completed to provide such meta-information, those
processes could be grouped in a single unit. In our use case we need to determine credit score and based on the credit score and some
rule select a list of <emphasis>Message Channels</emphasis> (Bank Channels) we will sent quote request to.
</para>
<para><emphasis>Composed Message Processor</emphasis> </para>
<para>
The <emphasis>Composed Message Processor</emphasis> pattern describes rules around building endpoints that maintain control over message flow which
consists of multiple message processors. In Sprig Integration <emphasis>Composed Message Processor</emphasis> pattern is implemented via
<emphasis>&lt;chain&gt;</emphasis> element.
<mediaobject>
<imageobject role="fo">
<imagedata fileref="src/docbkx/resources/images/chain.png"
format="PNG" align="center"/>
</imageobject>
<imageobject role="html">
<imagedata fileref="images/chain.png" format="PNG" align="center"/>
</imageobject>
</mediaobject>
</para>
<para>
As you can see from the above configuration we have a chain with inner header-enricher element which will further enrich the
content of the <emphasis>Message</emphasis> with the header CREDIT_SCORE and value that will be determined by the call to a
credit service (simple POJO spring bean identified by 'creditBureau' name) and then it will delegate to the <emphasis>Message Router</emphasis>
</para>
<para><emphasis>Message Router</emphasis>
<mediaobject>
<imageobject role="fo">
<imagedata fileref="src/docbkx/resources/images/bank-router.png"
format="PNG" align="center"/>
</imageobject>
<imageobject role="html">
<imagedata fileref="images/bank-router.png" format="PNG" align="center"/>
</imageobject>
</mediaobject>
</para>
<para>
There are several implementation of <emphasis>Message Routing</emphasis> pattern available in Spring Integration. Here we are using
router that will determine a list of channels based on evaluating an expression (Spring Expression Language) which will look at
the credit score that was determined is the previous step and will select the list of channels from the Map bean with id 'banks'
whose values are 'premier' or 'secondary' based o the value of credit score. Once the list of <emphasis>Channels</emphasis> is selected, the
<emphasis>Message</emphasis> will be routed to those <emphasis>Channels</emphasis>.
</para>
<para>
Now, one last thing the Loan Broker needs to to is to receive the loan quotes form the banks, aggregate them by consumer
(we don't 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 reply back to the consumer.
</para>
<para><emphasis>Message Aggregator</emphasis>
<mediaobject>
<imageobject role="fo">
<imagedata fileref="src/docbkx/resources/images/quotes-aggregator.png"
format="PNG" align="center"/>
</imageobject>
<imageobject role="html">
<imagedata fileref="images/quotes-aggregator.png" format="PNG" align="center"/>
</imageobject>
</mediaobject>
</para>
<para>
An <emphasis>Aggregator</emphasis> pattern describes an endpoint which groups related <emphasis>Messages</emphasis> into a single
<emphasis>Message</emphasis>. Criteria and rules can be provided to determine an aggregation and correlation strategy.
SI provides several implementations of the <emphasis>Aggregator</emphasis> pattern as well as a convenient name-space based configuration.
<programlisting language="xml"><![CDATA[<aggregator id="quotesAggregator"
input-channel="quotesAggregationChannel"
method="aggregateQuotes">
<beans:bean class="org.springframework.integration.samples.loanbroker.LoanQuoteAggregator"/>
</aggregator>]]></programlisting>
</para>
<para>
Our Loan Broker defines a 'quotesAggregator' bean via the <emphasis>&lt;aggregator&gt;</emphasis> element which provides a default
aggregation and correlation strategy. The default correlation strategy correlates messages based on the <code>$corelationId</code> header
(see <emphasis>Correlation Identifier</emphasis> pattern). What's interesting is that we never provided the value for this header.
It was set earlier by the router automatically, when it generated a separate <emphasis>Message</emphasis> for each Bank channel.
</para>
<para>
Once the <emphasis>Messages</emphasis> are correlated they are released to the actual <emphasis>Aggregator</emphasis> implementation.
Although default <emphasis>Aggregator</emphasis> is provided by SI, its strategy (gather the list of payloads from all
<emphasis>Messages</emphasis> and construct a new <emphasis>Message</emphasis> with this List as payload) does not satisfy our
requirement. The reason is that our consumer might require a single best quote or all quotes. To communicate the consumer's
intention, earlier in the process we set the RESPONSE_TYPE header. Now 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 will not work
because we have to determine which loan quote is the best).
</para>
<para>
Obviously selecting the best quote could be based on complex criteria and would influence the complexity of the aggregator implementation and
configuration, but for now we are making it simple. If consumer wants the best quote we will select a quote with the lowest interest
rate. To accomplish that the LoanQuoteAggregator.java will sort all the quotes and return the first one.
The <classname>LoanQuote.java</classname> implements <interfacename>Comparable</interfacename> which compares quotes based on the rate attribute.
Once the response <emphasis>Message</emphasis> is created it is sent to the default-reply-channel of the <emphasis>Messaging Gateway</emphasis>
(thus the consumer) which started the process. Our consumer got the Loan Quote!
</para>
<para>Conclusion</para>
<para>
As you can see a rather complex process was assembled based on POJO (read existing, legacy), light weight, embeddable messaging
framework (Sprig Integration) with a loosely coupled programming model intended to simplify integration of heterogeneous systems
without requiring a heavy-weight ESB-like engine or proprietary development and deployment environment, becouse as a developer you
should not be porting your Swing or console-based application to an ESB-like server or implementing proprietary interfaces just
because you have an integration concern.
</para>
<para>
This and other samples in this section are build on top of Enterprise Integration Patterns that meant to describe "building blocks"
for YOUR solution but not to be solutions in of themselves. Integration concerns exist in all types of applications (server based and not)
and should not require change in design, testing and deployment strategy if such applications need to integrate with one another.
</para>
</section>
<section id="samples-cafe">
<title>The Cafe Sample</title>
<para>
In this section, we will review a sample application that is included in the Spring Integration
distribution. This sample is inspired by one of the samples featured in Gregor Hohpe's
<ulink url="http://www.eaipatterns.com/ramblings.html">Ramblings</ulink>.
In this section, we will review a <emphasis>Cafe</emphasis> sample application that is included in the
Spring Integration samples. This sample is inspired by another sample featured in Gregor
Hohpe's <ulink url="http://www.eaipatterns.com/ramblings.html">Ramblings</ulink>.
</para>
<para>
The domain is that of a Cafe, and the basic flow is depicted in the following diagram:
@@ -163,11 +401,11 @@ That includes Samples, so if you can't find what you are looking for let us know
<para>
<mediaobject>
<imageobject role="fo">
<imagedata fileref="src/docbkx/resources/images/cafe-demo.png"
<imagedata fileref="src/docbkx/resources/images/cafe-eip.png"
format="PNG" align="center"/>
</imageobject>
<imageobject role="html">
<imagedata fileref="images/cafe-demo.png" format="PNG" align="center"/>
<imagedata fileref="images/cafe-eip.png" format="PNG" align="center"/>
</imageobject>
</mediaobject>
</para>