Nav
You are viewing an older version of this section. Click here to navigate to the latest version.

Foreach Processing and Choice Routing Example

This Mule ESB example application demonstrates the power of content-based routing in Web service integrations.

Based on the Loan Broker Example included in chapter nine of Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions (Hohpe, Woolf, 2004), this application minimizes a borrower’s work in acquiring the best interest rate for a loan. This example should help you to make informed decisions about using the four above-listed elements in your Mule applications. 

Content-Based Routing

content_routingMule has the ability to intelligently route a message through different processing pathways according to its content. Using a Choice Router (or Choice Flow Control in Studio), Mule uses an expression to evaluate a message’s properties, or part of its payload, then routes it to a specific pathway (i.e. series of message processors). Content-based routing, as this activity is called, dynamically applies routing criteria to a message at runtime.

Foreach Processing

iteration2An iterative processor, Foreach splits collections into elements, then processes them iteratively without losing any of the message payload. After Foreach splits a message collection and processes the individual elements, it returns a reference to the original message thus resulting in "Java in, Java out" processing.

Message Enriching

enriched4Mule uses Message Enrichers to enrich message payloads with data (i.e. add to the payload), rather than changing payload contents. Mule enriches a message’s payload so that other message processors in the application can access the original payload.

Assumptions

This document assumes that you are familiar with Mule ESB and the Mule Studio interface. To increase your familiarity with Studio, consider completing one or more Mule Studio Tutorials.

This document describes the details of the example within the context of Mule Studio, Mule ESB’s graphical user interface (GUI). Where appropriate, the XML configuration follows the Studio interface screenshot in an expandable section.

Example Use Case

This example application exposes a Web service that processes end user requests for interest rate quotes from banks. From a Web browser, an end user submits a request which contains the following:

  • borrower’s name

  • amount of the loan

  • repayment term of the loan

  • borrower’s social security number (SSN)

The application accesses other Web services to process the request, then responds to the end user. The response identifies the bank name and interest rate of the lowest quote.

The Web service uses five elements to maximize its processing efficiency:

  • Choice Flow Controls to route messages based on content

  • Transformers to convert message payloads’ data format

  • Message Enrichers to add to, rather than change, message payloads

  • Foreach to iteratively, and synchronously, process message payloads

  • Dynamic Endpoints to send requests to different banks depending on the message payload

Set Up and Run the Example

As with this example, you can create template applications straight out of the box in Mule Studio or Mule Standalone (Mule ESB without Studio). You can tweak the configurations of these use case-based templates to create your own customized applications in Mule.

Follow the procedure below to create, then run the Loan Broker application in Mule ESB.

  1. Create, then run the example application in Mule Studio.

  2. Open your Web browser.

  3. Type http://localhost:11081/?name=Muley&amount=20000&term=48&ssn=1234 into the address bar of your browser, then press enter to elicit a response from the application (below).

    submitted_m

  4. In your browser’s address bar, replace the amount value with 5000, then press enter to elicit a new response from the application (below).

    submitted2_m

How it Works

This example application consists of several flows and subflows. These flows integrate Web services to process end user requests for interest rate quotes from banks.

The sections below offer flow-by-flow descriptions of the application’s actions as it processes end user requests.

Loan-broker-sync Flow

As the main flow in the application, this flow coordinates data collection among flows to produce an end user response.

mainLoanBrokerFlow


    
             
          
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<flow name="loan-broker-sync" doc:name="loan-broker-sync" doc:description="The main loanbroker flow that:
 
       i) Receives a customer request
 
      ii) Performs a lookup of the customer credit profile using a component binding
 
     iii) Determines the bank that should be used to request quotes
 
     iv) Sends the request to the selected banks and aggregates responses
 
      v) Selects the lowest quote from the list of quotes
 
     vi) Returns the response to the client
 
        ">
 
        <description>
 
            The main loanbroker flow that:
 
            i) Receives a customer request
 
            ii) Performs a lookup of the customer credit profile using a component binding
 
            iii) Determines the bank that should be used to request quotes
 
            iv) Sends the request to the selected banks and aggregates responses
 
            v) Selects the lowest quote from the list of quotes
 
            vi) Returns the response to the client
 
        </description>
 
 
 
 
        <http:inbound-endpoint address="http://0.0.0.0:11081" exchange-pattern="request-response" doc:name="HTTP"/>
 
 
 
 
        <http:body-to-parameter-map-transformer doc:name="Body to Parameter Map"/>
 
 
 
 
        <choice doc:name="Choice">
 
            <when expression="!(payload['name'] == null || payload['ssn'] == null || payload['amount'] == null || payload['term']==null)">
 
                    <expression-component doc:name="create customer request">
 
                        import org.mule.example.loanbroker.message.CustomerQuoteRequest;
 
                        import org.mule.example.loanbroker.model.Customer;
 
 
 
 
                        payload = new CustomerQuoteRequest(new Customer(payload['name'], Integer.parseInt(payload['ssn'])), Integer.parseInt(payload['amount']), Integer.parseInt(payload['term']));
 
                    </expression-component>
 
 
 
 
                    <enricher source="#[payload]" target="#[flowVars['creditProfile']]" doc:name="Enrich with creditProfile">
 
                        <flow-ref name="lookupCustomerCreditProfile" doc:name="lookupCustomerCreditProfile"/>
 
                    </enricher>
 
 
 
 
                    <enricher source="#[payload]" target="#[flowVars['banks']]" doc:name="Enrich with banks">
 
                        <flow-ref name="lookupBanks" doc:name="lookupBanks"/>
 
                    </enricher>
 
 
 
 
                    <set-variable variableName="quotes" value="#[new java.util.LinkedList()]" doc:name="create empty quotes"/>
 
                    <foreach collection="#[flowVars['banks']]" doc:name="Foreach">
 
                        <enricher target="#[quotes.add($)]" doc:name="Message Enricher">
 
                            <flow-ref name="lookupLoanQuote" doc:name="lookupLoanQuote"/>
 
                        </enricher>
 
                    </foreach>
 
 
 
 
                    <flow-ref name="findLowestLoanQuote" doc:name="findLowestLoanQuote"/>
 
 
 
 
                    <object-to-string-transformer doc:name="Object to String"/>
 
            </when>
 
            <otherwise>
 
                <expression-component doc:name="set error message">payload="Error: incomplete request"</expression-component>
 
            </otherwise>
 
        </choice>
 
 
 
 
        <catch-exception-strategy doc:name="Catch Exception Strategy">
 
            <set-payload value="Error processing loan request" doc:name="Set error message"/>
 
        </catch-exception-strategy>
 
    </flow> 

The request-response HTTP Inbound Endpoint in this flow receives an end user request. Because it has a two-way message exchange pattern, this HTTP endpoint is responsible for both receiving and returning messages.

Next, the Body to Parameter Map Transformer converts the data format of the message payload from HTTP body data to a Java map. The Loan Broker application only processes Java message payloads.

Then, Mule employs a content-based router to direct the message for further processing. The Choice Flow Control routes each message to one of two processing pathways according to its payload contents (see image and code below).

  • If the message payload contains a complete request (i.e. the borrower’s name and SSN, and the amount and the term of the loan), the choice flow control passes the message to the create customer request Expression Component.

  • If the message payload is an incomplete request, the choice flow control passes the message to the set error message expression component. This component sets the payload of the message to read Error: incomplete request. Mule processes the message no further. Instead, it responds to the end user with the error message.

choice_first_route2


    
             
          
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<choice doc:name="Choice">
 
            <when expression="!(payload['name'] == null || payload['ssn'] == null || payload['amount'] == null || payload['term']==null)">
 
                    <expression-component doc:name="create customer request">
 
                        import org.mule.example.loanbroker.message.CustomerQuoteRequest;
 
                        import org.mule.example.loanbroker.model.Customer;
 
 
 
 
                        payload = new CustomerQuoteRequest(new Customer(payload['name'], Integer.parseInt(payload['ssn'])), Integer.parseInt(payload['amount']), Integer.parseInt(payload['term']));
 
                    </expression-component>
 
 
 
 
                    <enricher source="#[payload]" target="#[flowVars['creditProfile']]" doc:name="Enrich with creditProfile">
 
                        <flow-ref name="lookupCustomerCreditProfile" doc:name="lookupCustomerCreditProfile"/>
 
                    </enricher>
 
 
 
 
                    <enricher source="#[payload]" target="#[flowVars['banks']]" doc:name="Enrich with banks">
 
                        <flow-ref name="lookupBanks" doc:name="lookupBanks"/>
 
                    </enricher>
 
 
 
 
                    <set-variable variableName="quotes" value="#[new java.util.LinkedList()]" doc:name="create empty quotes"/>
 
                    <foreach collection="#[flowVars['banks']]" doc:name="Foreach">
 
                        <enricher target="#[quotes.add($)]" doc:name="Message Enricher">
 
                            <flow-ref name="lookupLoanQuote" doc:name="lookupLoanQuote"/>
 
                        </enricher>
 
                    </foreach>
 
 
 
 
                    <flow-ref name="findLowestLoanQuote" doc:name="findLowestLoanQuote"/>
 
 
 
 
                    <object-to-string-transformer doc:name="Object to String"/>
 
            </when>
 
            <otherwise>
 
                <expression-component doc:name="set error message">payload="Error: incomplete request"</expression-component>
 
            </otherwise>
 
        </choice> 

The create customer request component uses expressions to extract data from the message payload. It uses the data to create a new Java object with three values:

  1. the Customer, which identifies both the borrower’s name and SSN

  2. one Integer, which identifies the amount of the loan

  3. a second Integer, which identifies the loan repayment term


          
       
1
<expression-component doc:name="create customer request">import org.mule.example.loanbroker.message.CustomerQuoteRequest; import org.mule.example.loanbroker.model.Customer; payload = new CustomerQuoteRequest(new Customer(payload['name'], Integer.parseInt(payload['ssn'])), Integer.parseInt(payload['amount']), Integer.parseInt(payload['term']));</expression-component>

With a new CustomerQuoteRequest object in its payload, the message encounters its first Message Enricher. Throughout this flow, Mule enriches messages with data rather than changing the payload contents. By enriching a message, Mule preserves the payload content so that other elements in the application can access the original data.

The Enrich with creditProfile enricher contains only a Flow Reference Component. This type of component invokes other flows, or subflows, in the application to acquire, then add data to the message. In this case, the lookupCustomerCreditProfile component demands that the LookupCustomerCreditProfile subflow access an external Web service to acquire the borrower’s credit score. Mule enriches the message with the credit score, then passes the message to the next enricher in the flow.

As with its predecessor, the Enrich with Banks enricher uses a flow reference component to invoke a subflow and acquire data. In this case, instead of adding a credit score, Mule uses the result of the LookupBanks subflow to add a list of banks to the message payload.

Mule then uses a Variable Transformer to create an empty list variable. Mule will fill this empty quotes list variable with the quotes it fetches from banks. With an empty list to fill, the message next encounters a Foreach scope. One by one, this iterative processor fetches data to populate each item on the list.

To fetch these data, the flow reference component first invokes the LookupLoanQuote subflow to acquire a quote from a bank. Then, the message enricher adds the quote to the list variable. Foreach continues to invoke, then enrich, until it has acquired a quote from each bank on the list of banks. Foreach then passes the message to the next message processor in the flow.

To illustrate foreach’s behavior with an example, imagine a message payload with the following contents:

  • an empty quotes list variable

  • a banks list variable naming two banks from which Mule must request a quote: MuliNational Bank, and IndustrialGrowth Bank

Foreach processes the message payload as follows:

  1. Foreach consults the banks list variable to learn that it should send its first request to MuliNational.

  2. Foreach invokes the LookupLoanQuote subflow.

  3. The LookupLoanQuote subflow calls the getLoanQuote Web service to obtain an interest rate quote from MultiNational.

  4. The LookupLoanQuote subflow provides the Web service response to the Loan-Broker-Sync flow.

  5. The message enricher inserts the interest rate quote from MultiNational into the quotes list variable.

  6. Foreach consults the banks list variable to learn that it should send its second request to IndustrialGrowth.

  7. Foreach invokes the LookupLoanQuote subflow.

  8. The LookupLoanQuote subflow calls the getLoanQuote Web service to obtain an interest rate quote from IndustrialGrowth.

  9. The LookupLoanQuote subflow provides the Web service response to the Loan-Broker-Sync flow.

  10. The message enricher inserts the interest rate quote from IndustrialGrown into the quotes list variable.

  11. Foreach consults the banks list variable to find no more items on the list. It passes the message — now with a list containing two interest rate quotes — to the next message processor. Refer to the table below for a before-and-after comparison of message contents.

    Message Contents Before
    Iterative Processing
    Message Contents After
    Iterative Processing

    banks list variable:
    • www.multinational.com/loans/quotes
    • www.industrialgrowth.com/loans/quotes

    banks list variable:
    • www.multinational.com/loans/quotes
    • www.industrialgrowth.com/loans/quotes

    quote list variable:

    quote list variable:
    • 6.99
    • 6.84

The penultimate message processor in this flow references yet another subflow in the application. The findLowestLoanQuote subflow determines which quote in the list is the lowest, then logs the result in the message payload.

Finally, the Object to String Transformer converts the message payload’s data format from Java to a string. The HTTP endpoint sends the response to the end user.

Notice that the Loan-broker-sync flow also contains a Catch Exception Strategy. Rather than use Mule’s default exception strategy this flow uses a customized exception strategy to handle errors. If an error occurs in the flow, the exception strategy’s Set Payload Transformer sets an error message on the payload. The application sends this error message, which reads, Error processing loan request, as a response to the end user.

LookupCustomerCreditProfile Subflow

Invoked upon demand by the Loan-broker-sync flow, this subflow acquires and logs the borrower’s credit score on the message payload.

customerCreditProfile


    
             
          
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
&lt;sub-flow name="lookupCustomerCreditProfile" doc:name="lookupCustomerCreditProfile" doc:description="
            Returns the customer credit profile obtained form the Credit Agency
        "&gt;
        &lt;description&gt;
            Returns the customer credit profile obtained form the Credit Agency
        &lt;/description&gt;
 
        &lt;set-payload value="#[payload.customer]" doc:name="customer"/&gt;
 
        &lt;processor-chain doc:name="Processor Chain"&gt;
            &lt;cxf:jaxws-client serviceClass="org.mule.example.loanbroker.creditagency.CreditAgencyService" operation="getCreditProfile" doc:name="getCreditProfile"/&gt;
            &lt;http:outbound-endpoint address="http://localhost:18080/mule/TheCreditAgencyService" doc:name="HTTP"/&gt;
        &lt;/processor-chain&gt;
 
        &lt;logger level="INFO" message="Credit profile: #[payload]" doc:name="creditProfile"/&gt;
    &lt;/sub-flow&gt;

To acquire the credit score, the customer transformer sets the payload to Customer, as defined by the create customer request expression transformer. (Recall that the Customer variable contains the borrower’s name and SSN.) Mule sends a request to the getCreditProfile SOAP Web service. The HTTP endpoint inserts the Web service’s response into the subflow.

Mule leverages Apache’s CXF framework to build Web services. The Processor Chain that wraps the SOAP Component and HTTP outbound endpoint is a CXF requirement. It ensures that Mule completes all processing activities prior to logging the processing result.

Last in this flow, the Logger Component logs the payload of the Web service’s response on the message payload as the Credit Profile.

LookupBanks Subflow

The application prevents exposing all banks to all loan quote requests. A bank that caters to premiere clients, for example, would be irked to receive a request for a quote for a small loan from a borrower with poor credit. To prevent such irksome calls to banks’ Web services, the Loan Broker application employs the LookupBanks subflow.

lookupBanks


    
             
          
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
&lt;sub-flow name="lookupBanks" doc:name="lookupBanks" doc:description="
            Returns the list of banks to contact and returns it as a flow variable 'banks'
        "&gt;
        &lt;description&gt;
            Returns the list of banks to contact and returns it as a flow variable 'banks'
        &lt;/description&gt;
 
        &lt;choice doc:name="Choice"&gt;
            &lt;when expression="payload.getLoanAmount() &amp;gt;= 20000"&gt;
                &lt;expression-component doc:name="Bank1, Bank2"&gt;payload=[new java.net.URI('http://localhost:10080/mule/TheBank1'), new java.net.URI('http://localhost:20080/mule/TheBank2')]&lt;/expression-component&gt;
            &lt;/when&gt;
            &lt;when expression="payload.getLoanAmount() &amp;gt;= 10000 || payload.getLoanAmount() &amp;lt;= 19999"&gt;
                &lt;expression-component doc:name="Bank3, Bank4"&gt;payload=[new java.net.URI('http://localhost:30080/mule/TheBank3'), new java.net.URI('http://localhost:40080/mule/TheBank4')]&lt;/expression-component&gt;
            &lt;/when&gt;
            &lt;otherwise&gt;
                &lt;expression-component doc:name="Bank5"&gt;payload=[new java.net.URI('http://localhost:50080/mule/TheBank5')]&lt;/expression-component&gt;
            &lt;/otherwise&gt;
        &lt;/choice&gt;
 
        &lt;logger level="INFO" message="Banks to contact: #[payload]" doc:name="banks"/&gt;
    &lt;/sub-flow&gt;

Mule first uses a choice flow control to examine the amount in the payload, then routes the message according to the size of the loan.

  • If the loan is more that $20,000, the flow control routes the message to the first expression component, labeled Bank 1, Bank 2.

  • If the loan is more than $10,000, the flow control routes the message to the second expression component, labeled Bank 3, Bank 4.

  • if otherwise (i.e. if the loan is $10,000 or less), the flow control routes the message to the third expression component, labeled Bank 5

choiceBanks


    
             
          
1
2
3
4
5
6
7
8
9
10
11
&lt;choice doc:name="Choice"&gt;
            &lt;when expression="payload.getLoanAmount() &amp;gt;= 20000"&gt;
                &lt;expression-component doc:name="Bank1, Bank2"&gt;payload=[new java.net.URI('http://localhost:10080/mule/TheBank1'), new java.net.URI('http://localhost:20080/mule/TheBank2')]&lt;/expression-component&gt;
            &lt;/when&gt;
            &lt;when expression="payload.getLoanAmount() &amp;gt;= 10000 || payload.getLoanAmount() &amp;lt;= 19999"&gt;
                &lt;expression-component doc:name="Bank3, Bank4"&gt;payload=[new java.net.URI('http://localhost:30080/mule/TheBank3'), new java.net.URI('http://localhost:40080/mule/TheBank4')]&lt;/expression-component&gt;
            &lt;/when&gt;
            &lt;otherwise&gt;
                &lt;expression-component doc:name="Bank5"&gt;payload=[new java.net.URI('http://localhost:50080/mule/TheBank5')]&lt;/expression-component&gt;
            &lt;/otherwise&gt;
        &lt;/choice&gt;

Note that the choice flow control directs the message to the first expression that evaluates to true. For example, it directs a quote request for a loan of $30,000 only to the Bank 1, Bank 2 component.

Each expression component in this subflow contains the URIs of the banks willing to provide an interest rate quote. For example, messages that pass into the Bank 3, Bank 4 component earn, as a payload addition, the URIs for Banks 3 and 4. The banks Logger component records the list of appropriate banks to which to send a request.

LookupLoanQuote Subflow

This sends a quote request to banks' Web services.

lookupLoanQuotes


    
             
          
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
&lt;sub-flow name="lookupLoanQuote" doc:name="lookupLoanQuote" doc:description="
            Returns a loanQuote from a given bank's URI
        "&gt;
        &lt;description&gt;
            Returns a loanQuote from a given bank's URI
        &lt;/description&gt;
 
        &lt;set-variable variableName="bankUri" value="#[payload]" doc:name="bankUri"/&gt;
 
        &lt;expression-component doc:name="create LoanBrokerLoanRequest"&gt;
            import org.mule.example.loanbroker.message.LoanBrokerQuoteRequest;
 
            LoanBrokerQuoteRequest bqr = new LoanBrokerQuoteRequest();
            bqr.setCreditProfile(flowVars['creditProfile']);
            payload = bqr;
        &lt;/expression-component&gt;
 
        &lt;processor-chain doc:name="Processor Chain"&gt;
            &lt;cxf:jaxws-client serviceClass="org.mule.example.loanbroker.bank.BankService" operation="getLoanQuote" doc:name="getLoanQuote"/&gt;
            &lt;http:outbound-endpoint address="http://#[flowVars['bankUri'].getHost()]:#[flowVars['bankUri'].getPort()]#[flowVars['bankUri'].getPath()]" doc:name="HTTP"/&gt;
        &lt;/processor-chain&gt;
        &lt;logger message="LoanQuote from #[flowVars['bankUri']]: #[payload]" level="INFO" doc:name="quote"/&gt;
    &lt;/sub-flow&gt;

First, the variable transformer stores the Mule message payload — the bank’s URI — as a variable named bankUri. (Recall that this subflow receives requests one at a time from foreach in the Loan-broker-sync flow. Each request’s payload a the URI of a bank.)

The create LoanBrokerLoanRequest component uses expressions to extract the borrower’s credit profile (logged by the creditProfile logger in the LookupCustomerCreditProfile flow) from the message payload. It uses the data to create a request to send to the getLoanQuote Web service.
Mule uses a SOAP component — configured as a JAXWS-client — to send the request to a bank’s Web service. The HTTP outbound endpoint dynamically determines where to send the request based on the bank’s URI in the message payload. It receives the response from the banks’ Web service and pushes the response payload to the quote logger to record.

FindLowestLoanRequest Subflow

This simple subflow uses an expression component to determine which item, in the list of quotes, offers the lowest interest rate. The Logger records the result.

findLowest


    
             
          
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
&lt;sub-flow name="findLowestLoanQuote" doc:name="findLowestLoanQuote" doc:description="
            Returns the loan quote with the lowest interest rate
        "&gt;
        &lt;description&gt;
            Returns the loan quote with the lowest interest rate
        &lt;/description&gt;
 
        &lt;set-variable variableName="lowestQuote" value = "#[null]" doc:name="Variable"/&gt;
        &lt;expression-component doc:name="Expression"&gt;
            &lt;![CDATA[
            import org.mule.example.loanbroker.model.LoanQuote;
 
            for (Object current : (List) flowVars['quotes'])
            {
                LoanQuote loanQuote = (LoanQuote) current;
                if (flowVars['lowestQuote'] == null)
                {
                    flowVars['lowestQuote'] = loanQuote;
                }
                else if (loanQuote.getInterestRate() &lt; flowVars['lowestQuote'].getInterestRate())
                {
                    flowVars['lowestQuote'] = loanQuote;
                }
            }
 
            payload = flowVars['lowestQuote'];
            ]]&gt;
        &lt;/expression-component&gt;
        &lt;logger level="INFO" message="Lowest loan quote: #[payload]" doc:name="lowestQuote"/&gt;
    &lt;/sub-flow&gt;

The expression in the component compares the getInterestRate of items in the list to each other to determine which one is the lowest (see image below).

expressionComponent


    
             
          
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import org.mule.example.loanbroker.model.LoanQuote;
 
            for (Object current : (List) flowVars['quotes'])
            {
                LoanQuote loanQuote = (LoanQuote) current;
                if (flowVars['lowestQuote'] == null)
                {
                    flowVars['lowestQuote'] = loanQuote;
                }
                else if (loanQuote.getInterestRate() &lt; flowVars['lowestQuote'].getInterestRate())
                {
                    flowVars['lowestQuote'] = loanQuote;
                }
            }
 
            payload = flowVars['lowestQuote'];

Mock Flows

The remaining six flows in the application are “mock flows”. They act as external Web services to which the five legitimate flows and subflows call to request data.

Each flow contains:

  • a request-response HTTP Endpoint and SOAP component to receive the requests

  • a Java Component which produces random data to mimic Web service processing.

You do not need to include these flows your customized application; they exist only to support a functional example.

foreach_processing_and_choice_routing


    
             
          
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
 
&lt;mule xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking" xmlns:spring="http://www.springframework.org/schema/beans" xmlns="http://www.mulesoft.org/schema/mule/core"
 
      xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 
      xmlns:http="http://www.mulesoft.org/schema/mule/http"
 
      xmlns:cxf="http://www.mulesoft.org/schema/mule/cxf"
 
      xsi:schemaLocation="
 
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
 
http://www.mulesoft.org/schema/mule/cxf http://www.mulesoft.org/schema/mule/cxf/current/mule-cxf.xsd
 
http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd
 
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
 
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd " version="EE-3.4.0"&gt;
 
 
 
 
    &lt;description&gt;
 
        This Synchronous variant of loan broker example is modeled on the Enterprise integration Patterns book sample.
 
        See: http://www.eaipatterns.com/ComposedMessagingExample.html
 
    &lt;/description&gt;
 
 
 
 
    &lt;flow name="loan-broker-sync" doc:name="loan-broker-sync" doc:description="The main loanbroker flow that:
 
       i) Receives a customer request
 
      ii) Performs a lookup of the customer credit profile using a component binding
 
     iii) Determines the bank that should be used to request quotes
 
     iv) Sends the request to the selected banks and aggregates responses
 
      v) Selects the lowest quote from the list of quotes
 
     vi) Returns the response to the client
 
        "&gt;
 
        &lt;description&gt;
 
            The main loanbroker flow that:
 
            i) Receives a customer request
 
            ii) Performs a lookup of the customer credit profile using a component binding
 
            iii) Determines the bank that should be used to request quotes
 
            iv) Sends the request to the selected banks and aggregates responses
 
            v) Selects the lowest quote from the list of quotes
 
            vi) Returns the response to the client
 
        &lt;/description&gt;
 
 
 
 
        &lt;http:inbound-endpoint address="http://0.0.0.0:11081" exchange-pattern="request-response" doc:name="HTTP"/&gt;
 
 
 
 
        &lt;http:body-to-parameter-map-transformer doc:name="Body to Parameter Map"/&gt;
 
 
 
 
        &lt;choice doc:name="Choice"&gt;
 
            &lt;when expression="!(payload['name'] == null || payload['ssn'] == null || payload['amount'] == null || payload['term']==null)"&gt;
 
                    &lt;expression-component doc:name="create customer request"&gt;
 
                        import org.mule.example.loanbroker.message.CustomerQuoteRequest;
 
                        import org.mule.example.loanbroker.model.Customer;
 
 
 
 
                        payload = new CustomerQuoteRequest(new Customer(payload['name'], Integer.parseInt(payload['ssn'])), Integer.parseInt(payload['amount']), Integer.parseInt(payload['term']));
 
                    &lt;/expression-component&gt;
 
 
 
 
                    &lt;enricher source="#[payload]" target="#[flowVars['creditProfile']]" doc:name="Enrich with creditProfile"&gt;
 
                        &lt;flow-ref name="lookupCustomerCreditProfile" doc:name="lookupCustomerCreditProfile"/&gt;
 
                    &lt;/enricher&gt;
 
 
 
 
                    &lt;enricher source="#[payload]" target="#[flowVars['banks']]" doc:name="Enrich with banks"&gt;
 
                        &lt;flow-ref name="lookupBanks" doc:name="lookupBanks"/&gt;
 
                    &lt;/enricher&gt;
 
 
 
 
                    &lt;set-variable variableName="quotes" value="#[new java.util.LinkedList()]" doc:name="create empty quotes"/&gt;
 
                    &lt;foreach collection="#[flowVars['banks']]" doc:name="Foreach"&gt;
 
                        &lt;enricher target="#[quotes.add($)]" doc:name="Message Enricher"&gt;
 
                            &lt;flow-ref name="lookupLoanQuote" doc:name="lookupLoanQuote"/&gt;
 
                        &lt;/enricher&gt;
 
                    &lt;/foreach&gt;
 
 
 
 
                    &lt;flow-ref name="findLowestLoanQuote" doc:name="findLowestLoanQuote"/&gt;
 
 
 
 
                    &lt;object-to-string-transformer doc:name="Object to String"/&gt;
 
            &lt;/when&gt;
 
            &lt;otherwise&gt;
 
                &lt;expression-component doc:name="set error message"&gt;payload="Error: incomplete request"&lt;/expression-component&gt;
 
            &lt;/otherwise&gt;
 
        &lt;/choice&gt;
 
 
 
 
        &lt;catch-exception-strategy doc:name="Catch Exception Strategy"&gt;
 
            &lt;set-payload value="Error processing loan request" doc:name="Set error message"/&gt;
 
        &lt;/catch-exception-strategy&gt;
 
    &lt;/flow&gt;
 
 
 
 
    &lt;sub-flow name="lookupCustomerCreditProfile" doc:name="lookupCustomerCreditProfile" doc:description="Returns the customer credit profile obtained form the Credit Agency
 
        "&gt;
 
        &lt;description&gt;
 
            Returns the customer credit profile obtained form the Credit Agency
 
        &lt;/description&gt;
 
 
 
 
        &lt;set-payload value="#[payload.customer]" doc:name="customer"/&gt;
 
 
 
 
        &lt;processor-chain doc:name="Processor Chain"&gt;
 
            &lt;cxf:jaxws-client serviceClass="org.mule.example.loanbroker.creditagency.CreditAgencyService" operation="getCreditProfile" doc:name="getCreditProfile"/&gt;
 
            &lt;http:outbound-endpoint address="http://localhost:18080/mule/TheCreditAgencyService" doc:name="HTTP"/&gt;
 
        &lt;/processor-chain&gt;
 
 
 
 
        &lt;logger level="INFO" message="Credit profile: #[payload]" doc:name="creditProfile"/&gt;
 
    &lt;/sub-flow&gt;
 
 
 
 
    &lt;sub-flow name="lookupBanks" doc:name="lookupBanks" doc:description="Returns the list of banks to contact and returns it as a flow variable 'banks'
 
        "&gt;
 
        &lt;description&gt;
 
            Returns the list of banks to contact and returns it as a flow variable 'banks'
 
        &lt;/description&gt;
 
 
 
 
        &lt;choice doc:name="Choice"&gt;
 
            &lt;when expression="payload.getLoanAmount() &amp;gt;= 20000"&gt;
 
                &lt;expression-component doc:name="Bank1, Bank2"&gt;payload=[new java.net.URI('http://localhost:10080/mule/TheBank1'), new java.net.URI('http://localhost:20080/mule/TheBank2')]&lt;/expression-component&gt;
 
            &lt;/when&gt;
 
            &lt;when expression="payload.getLoanAmount() &amp;gt;= 10000 || payload.getLoanAmount() &amp;lt;= 19999"&gt;
 
                &lt;expression-component doc:name="Bank3, Bank4"&gt;payload=[new java.net.URI('http://localhost:30080/mule/TheBank3'), new java.net.URI('http://localhost:40080/mule/TheBank4')]&lt;/expression-component&gt;
 
            &lt;/when&gt;
 
            &lt;otherwise&gt;
 
                &lt;expression-component doc:name="Bank5"&gt;payload=[new java.net.URI('http://localhost:50080/mule/TheBank5')]&lt;/expression-component&gt;
 
            &lt;/otherwise&gt;
 
        &lt;/choice&gt;
 
 
 
 
        &lt;logger level="INFO" message="Banks to contact: #[payload]" doc:name="banks"/&gt;
 
    &lt;/sub-flow&gt;
 
 
 
 
    &lt;sub-flow name="lookupLoanQuote" doc:name="lookupLoanQuote" doc:description="Returns a loanQuote from a given bank's URI
 
        "&gt;
 
        &lt;description&gt;
 
            Returns a loanQuote from a given bank's URI
 
        &lt;/description&gt;
 
 
 
 
        &lt;set-variable variableName="bankUri" value="#[payload]" doc:name="bankUri"/&gt;
 
 
 
 
        &lt;expression-component doc:name="create LoanBrokerLoanRequest"&gt;
 
            import org.mule.example.loanbroker.message.LoanBrokerQuoteRequest;
 
 
 
 
            LoanBrokerQuoteRequest bqr = new LoanBrokerQuoteRequest();
 
            bqr.setCreditProfile(flowVars['creditProfile']);
 
            payload = bqr;
 
        &lt;/expression-component&gt;
 
 
 
 
        &lt;processor-chain doc:name="Processor Chain"&gt;
 
            &lt;cxf:jaxws-client serviceClass="org.mule.example.loanbroker.bank.BankService" operation="getLoanQuote" doc:name="getLoanQuote"/&gt;
 
            &lt;http:outbound-endpoint address="http://#[flowVars['bankUri'].getHost()]:#[flowVars['bankUri'].getPort()]#[flowVars['bankUri'].getPath()]" doc:name="HTTP"/&gt;
 
        &lt;/processor-chain&gt;
 
        &lt;logger message="LoanQuote from #[flowVars['bankUri']]: #[payload]" level="INFO" doc:name="quote"/&gt;
 
    &lt;/sub-flow&gt;
 
 
 
 
    &lt;sub-flow name="findLowestLoanQuote" doc:name="findLowestLoanQuote" doc:description="Returns the loan quote with the lowest interest rate
 
        "&gt;
 
        &lt;description&gt;
 
            Returns the loan quote with the lowest interest rate
 
        &lt;/description&gt;
 
 
 
 
        &lt;expression-component doc:name="Expression"&gt;
 
            &lt;![CDATA[
 
            import org.mule.example.loanbroker.model.LoanQuote;
 
 
 
 
            LoanQuote lowestQuote = null;
 
 
 
 
            for (Object current : (List) flowVars['quotes'])
 
            {
 
                LoanQuote loanQuote = (LoanQuote) current;
 
                if (lowestQuote == null)
 
                {
 
                    lowestQuote = loanQuote;
 
                }
 
                else if (loanQuote.getInterestRate() &lt; lowestQuote.getInterestRate())
 
                {
 
                    lowestQuote = loanQuote;
 
                }
 
            }
 
 
 
 
            payload = lowestQuote;
 
            ]]&gt;
 
        &lt;/expression-component&gt;
 
        &lt;logger level="INFO" message="Lowest loan quote: #[payload]" doc:name="lowestQuote"/&gt;
 
    &lt;/sub-flow&gt;
 
 
 
 
    &lt;!--
 
       MOCK SERVICES
 
    --&gt;
 
 
 
 
    &lt;flow name="TheCreditAgencyService" doc:name="TheCreditAgencyService" doc:description="The credit agency service will get the credit profile for a customer
 
        "&gt;
 
        &lt;description&gt;
 
            The credit agency service will get the credit profile for a customer
 
        &lt;/description&gt;
 
 
 
 
        &lt;http:inbound-endpoint address="http://localhost:18080/mule/TheCreditAgencyService" exchange-pattern="request-response" doc:name="HTTP"/&gt;
 
        &lt;cxf:jaxws-service serviceClass="org.mule.example.loanbroker.creditagency.DefaultCreditAgency" doc:name="SOAP"/&gt;
 
        &lt;component doc:name="creditAgency"&gt;
 
            &lt;singleton-object class="org.mule.example.loanbroker.creditagency.DefaultCreditAgency"/&gt;
 
        &lt;/component&gt;
 
    &lt;/flow&gt;
 
 
 
 
    &lt;flow name="Bank1Flow" doc:name="Bank1Flow" doc:description="Mock flow representing Bank 1
 
        "&gt;
 
        &lt;description&gt;
 
            Mock flow representing Bank 1
 
        &lt;/description&gt;
 
 
 
 
        &lt;http:inbound-endpoint address="http://localhost:10080/mule/TheBank1" exchange-pattern="request-response" doc:name="HTTP"/&gt;
 
        &lt;cxf:jaxws-service serviceClass="org.mule.example.loanbroker.bank.Bank" doc:name="SOAP"/&gt;
 
        &lt;component doc:name="Bank 1"&gt;
 
            &lt;singleton-object class="org.mule.example.loanbroker.bank.Bank"&gt;
 
                &lt;property key="bankName" value="Bank #1"/&gt;
 
            &lt;/singleton-object&gt;
 
        &lt;/component&gt;
 
    &lt;/flow&gt;
 
 
 
 
    &lt;flow name="Bank2Flow" doc:name="Bank2Flow" doc:description="Mock flow representing Bank 2
 
        "&gt;
 
        &lt;description&gt;
 
            Mock flow representing Bank 2
 
        &lt;/description&gt;
 
 
 
 
        &lt;http:inbound-endpoint address="http://localhost:20080/mule/TheBank2" exchange-pattern="request-response" doc:name="HTTP"/&gt;
 
        &lt;cxf:jaxws-service serviceClass="org.mule.example.loanbroker.bank.Bank" doc:name="SOAP"/&gt;
 
 
 
 
        &lt;component doc:name="Bank 2"&gt;
 
            &lt;singleton-object class="org.mule.example.loanbroker.bank.Bank"&gt;
 
                &lt;property key="bankName" value="Bank #2"/&gt;
 
            &lt;/singleton-object&gt;
 
        &lt;/component&gt;
 
    &lt;/flow&gt;
 
 
 
 
    &lt;flow name="Bank3Flow" doc:name="Bank3Flow" doc:description="Mock flow representing Bank 3
 
        "&gt;
 
        &lt;description&gt;
 
            Mock flow representing Bank 3
 
        &lt;/description&gt;
 
 
 
 
        &lt;http:inbound-endpoint address="http://localhost:30080/mule/TheBank3" exchange-pattern="request-response" doc:name="HTTP"/&gt;
 
        &lt;cxf:jaxws-service serviceClass="org.mule.example.loanbroker.bank.Bank" doc:name="SOAP"/&gt;
 
        &lt;component doc:name="Bank 3"&gt;
 
            &lt;singleton-object class="org.mule.example.loanbroker.bank.Bank"&gt;
 
                &lt;property key="bankName" value="Bank #3"/&gt;
 
            &lt;/singleton-object&gt;
 
        &lt;/component&gt;
 
    &lt;/flow&gt;
 
 
 
 
    &lt;flow name="Bank4Flow" doc:name="Bank4Flow" doc:description="Mock flow representing Bank 4
 
        "&gt;
 
        &lt;description&gt;
 
            Mock flow representing Bank 4
 
        &lt;/description&gt;
 
 
 
 
        &lt;http:inbound-endpoint address="http://localhost:40080/mule/TheBank4" exchange-pattern="request-response" doc:name="HTTP"/&gt;
 
        &lt;cxf:jaxws-service serviceClass="org.mule.example.loanbroker.bank.Bank" doc:name="SOAP"/&gt;
 
        &lt;component doc:name="Bank 4"&gt;
 
            &lt;singleton-object class="org.mule.example.loanbroker.bank.Bank"&gt;
 
                &lt;property key="bankName" value="Bank #4"/&gt;
 
            &lt;/singleton-object&gt;
 
        &lt;/component&gt;
 
    &lt;/flow&gt;
 
 
 
 
    &lt;flow name="Bank5Flow" doc:name="Bank5Flow" doc:description="Mock flow representing Bank 5
 
        "&gt;
 
        &lt;description&gt;
 
            Mock flow representing Bank 5
 
        &lt;/description&gt;
 
 
 
 
        &lt;http:inbound-endpoint address="http://localhost:50080/mule/TheBank5" exchange-pattern="request-response" doc:name="HTTP"/&gt;
 
        &lt;cxf:jaxws-service serviceClass="org.mule.example.loanbroker.bank.Bank" doc:name="SOAP"/&gt;
 
        &lt;component doc:name="Bank 5"&gt;
 
            &lt;singleton-object class="org.mule.example.loanbroker.bank.Bank"&gt;
 
                &lt;property key="bankName" value="Bank #5"/&gt;
 
            &lt;/singleton-object&gt;
 
        &lt;/component&gt;
 
    &lt;/flow&gt;
 
&lt;/mule&gt; 

See Also