Skip to main content

skip to main content

developerWorks  >  SOA and Web services | WebSphere  >

Aggregation functionality in IBM WebSphere Enterprise Service Bus V6.1, Part 3: Best practices and patterns for aggregation

developerWorks
Document options
PDF format - Fits A4 and Letter

PDF - Fits A4 and Letter
670KB

Get Adobe® Reader®

Document options requiring JavaScript are not displayed

Discuss

Sample code


Rate this page

Help us improve this content


Level: Intermediate

Callum Jackson (callumj@uk.ibm.com), Software Engineer, IBM
Brian Hulse (brian_hulse@uk.ibm.com), Software Engineer, IBM

24 Apr 2008

Part 1 and Part 2 of this three-part series introduced you to the new aggregation capabilities in IBM® WebSphere® Enterprise Service Bus V6.1. Now learn the best practices to follow when using the new aggregation capabilities. This article, the third and final installment in the series, describes four core patterns that you can apply to different business scenarios to design the majority of aggregation mediation applications.

Introduction

Each of the four patterns covered in this article has been applied to a real-life business scenario with the implementations supplied as project interchange files to help in the discussion (see the Downloads section to access these files). Please note that you should take these as blueprints on which to base your own business scenarios, because they guide you on the key points to consider.

General concepts

WebSphere Enterprise Service Bus V6.1 supports a flexible mechanism to construct aggregation scenarios, allowing the mediation developer to combine primitives in a number of different ways to produce a solution. However, when designing flows that use aggregation, you must pay attention to the:

  • Usage of primitives in the correct pattern.
  • Creation and usage of shared context.
  • Correct usage of transformation support.

Each of these is highlighted in the four basic patterns described in this article, which are:

  1. Aggregation of data from multiple sources: This pattern is useful if the results from multiple service invocations, database lookups, and so on need to be combined into a single message.
  2. Batch processing with message enrichment: This pattern is useful if the message to be processed contains a repeating element, and each element needs to be enhanced by acting on each one separately.
  3. Batch processing requiring embedded aggregation: This pattern is useful if the scenario is the basic batch processing pattern described in the second pattern (above), but the enhancement requires information from multiple sources. In this way, it's a combination of the first and second patterns.
  4. Nested aggregation: This pattern is useful if the scenario is the basic batch processing pattern described in the second pattern, but the repeating elements themselves contain repeating elements.



Back to top


Scenario 1: Aggregation of data from multiple sources

This scenario is based on an insurance quote comparison Web site that involves a Web interface that allows users to specify details of their quote. A business processing engine controls the process and submits a single request to an aggregation mediation, which submits this to multiple insurance firms. The responses are then aggregated into a single response for the business process to manipulate before displaying to the user. This scenario was built step by step in the first article in this series; this section discusses the key design considerations for the scenario. (Download the Scenario 1 files.)

Design the aggregation

The input into the flow is the InsuranceQuote interface, which specifies a Quote business object with the relevant data. The first step in planning the aggregation architecture is to determine if all data required to invoke the subsequent services are available in the inbound message or if message enrichment is required. In this scenario, the Quote object contains all the information for both services. If this wasn't the case, then you'd use a combination of this and the batch processing with message enrichment patterns. In fact, for this particular scenario, the interface for the insurance back-end service takes the same business object as does the mediation interface. This means that the transformation prior to the Service Invoke primitives are trivial; however, in more realistic situations, a more complex transformation is normally required.

The mediation flow includes a Fan Out primitive (operating in once mode) receiving the Quote message as input and branching the logic to each insurance back-end service (InsuranceCompanyA and InsuranceCompanyB). Before each Service Invoke primitive, an XSLT converts the body of the message to the correct format, and immediately after the Service Invoke, a Message Element Setter stores the response within the Shared Context for later retrieval when building the aggregated response. These two branches are then collected by a Fan In primitive (operating in count mode). When the second message arrives at the Fan In primitive, its output terminal fires with this message, whereupon a final XSLT transforms the values within the Shared Context into the aggregated response message. This is illustrated in Figure 1.


Figure 1. Insurance quote flow
Insurance quote flow

In this case, the Shared Context is straightforward, containing the parts of the response messages (from the two back-end insurance services) that need to be stored to generate the aggregated response (see Figure 2).


Figure 2. Shared Context for insurance quote
Shared Context for           insurance quote

The final XSLT then builds the response message that's sent directly back; this scenario doesn't include a response flow, because all outbound requests are completed within the request flow of the mediation flow. This design was chosen because there was no obvious single call out; therefore, it made sense to combine the logic within one flow.

This is a very simple usage pattern for aggregation, but its simplicity belies its power, as you can see later in this document when it's combined into a more complex scenario.



Back to top


Scenario 2: Batch processing with message enrichment

This scenario is based on a store ordering system, where a salesperson can submit a request for a number of orders and have them dispatched. The original message coming into the mediation flow identifies the customer for each order via a customer ID. Thus, the order request message needs to be enriched with each customer's shipping details so the dispatch step has all the information it needs to succeed. This enrichment is done within the request flow by calling out to a customer information system, implemented using a Service Invoke primitive. The dispatch system is implemented here as a callout node. (Download the Scenario 2 files.)

Design the aggregation

The key here is that the ordering and dispatch systems are implemented to be batch systems, where multiple records arrive within the same request message. However, the customer information system is implemented to receive a single record—thus introducing the need for aggregation—processing each of the occurrences of the repeating element in the request message individually and then building a batch message appropriate to the dispatch system.

To explore how this basic scenario is built, you must first examine the business objects used (see Figures 3 and 4).


Figure 3. The basic business objects
The basic business           objects

Figure 4. The batch business objects
The batch business           objects

The sales request is a batched array of SalesOrder objects tagged by a batchID.


Figure 5. Request objects
Request objects

Figure 6. Response objects
Response objects

The dispatch system takes a batch of DispatchOrder objects and returns the associated DispatchStatus objects.

The flow overview

You'll look at each part of the flow, as depicted in Figure 7, including the use of the Fan In and Fan Out primitives along with any mappings needed within the overall flow.


Figure 7. Batch-processing flow
Batch-processing flow

However, before doing that, you must first understand how to design a useful Shared Context for this scenario.

Shared Context

The design of the Shared Context is pivotal to a successful aggregation design, and this flow is no different. The goal is to build an array of DispatchOrder objects so that a message can be created to send to the dispatch system. Each DispatchOrder is created from data in the original SalesOrder and enhanced with further data from the customer information system. After this is done, you need to build up an aggregated picture of all of these individual orders by moving them into an array of DispatchOrder objects. This leads to an obvious pattern for the Shared Context (see Figure 8).


Figure 8. Shared Context for batch processing
Shared Context for batch           processing

The current field is used in each iteration of the Fan Out to create the DispatchOrder for the customer in question. This is then appended to the aggregationStore, which is effectively a running total of the aggregation to date. Note: This is a standard pattern for the design of Shared Context usage in aggregation and isn't again throughout this article.

The flow detail

Now take a look at the flow in detail, starting with the aggregation primitives, Fan Out and Fan In. The Fan Out is set to iterate over the repeating elements in the request message, which in this case are the SalesOrders. Equally, the Fan In is set to complete when all of the repeating elements have been handled (see Figure 9).


Figure 9. Fan In details for batch processing

Following the Fan Out is a Message Element Setter called setBatchID, which is used to copy the batchID from the request message into the Shared Context (see Figure 10).


Figure 10. Message Element Setter to set the batchID
Message Element Setter           to set the batchID

This simply seeds the context ready for the creation of the dispatch message at the end of the flow.

Before the customer information system can be invoked, you have to convert the message body into the correct format; you do this using the XSLT primitive called convertToCustomer. This is a simple transform that copies the customerID for the current iteration into the service invocation message. This is achieved by creating inline maps for the context and headers and a simple move of the customerID from the FanOutContext occurrence field into the customerID field in the body of the output message.


Figure 11. Transformation for customer information system
Transformation for           customer information system

The customer information system is invoked using a Service Invoke primitive called customer and returns a message containing the relevant customer details in the body. These need to be copied into the Shared Context, which is done in the XSLT primitive called storeResult.


Figure 12. Transformation to store response from customer information system
Transformation to           store response from customer information system

Notice that in this particular example, the current iteration's output is built from the customer details returned from the service invocation in addition to information copied from the current iteration's occurrence, namely the itemID and the quantity. Initially, this transform was built by creating inline maps for all matching fields; however, since you're copying specifically into the current object of the Shared Context, you must remember to remove the inline map for this particular object, as shown in Figure 13.


Figure 13. Inline map transformation for Shared Context
Inline map           transformation for Shared Context

Now you have the complete results from the current iteration in the current object of Shared Context, but you have to make a copy of these before you start the next iteration. Consequently, the next primitive in the flow is a Message Element Setter, called aggregateResult, which appends the current object into the aggregationStore in Shared Context.


Figure 14. Append response to aggregationStore
Append response to           aggregationStore

The aggregation flow used for each element is now complete. All you need to do is convert the aggregationStore into the correct message for the dispatch Callout node. This defines what occurs when all of the iterations are complete and the Fan In fires its out terminal. You use the XSLT primitive called convertToDispatch to do this.


Figure 15. Transformation of aggregationStore into request
Transformation of           aggregationStore into request

As you can see, the key to the whole aggregation flow is one of building up the required information in each iteration in a current object followed by appending current into the running total aggregationStore in the Shared Context.



Back to top


Scenario 3: Batch processing requiring embedded aggregation

This scenario involves a combination of the two previously described examples, having an aggregation of data from multiple sources embedded within a batch processing aggregation. The scenario is a simple personnel-based application that requests that the payslips for a number of employees be sent out. The back-end service is represented by a Callout node and requires full employee records, rather than the employee IDs, which arrive at the mediation flow. These employee records are created by the mediation from two sources, namely an HR system and a payroll system. The former stores information concerning the employee's name, address, and leave entitlement, while the latter contains information regarding salary and department. (Download the Scenario 3 files.)

Design the aggregation

The scenario makes use of embedded aggregation, because it maps well to the data expected by the two services to be invoked in the mediation flow. In other words, they both expect a single data record on each invocation, but it also allows the full mediation flow to batch requests; this makes use of repeating elements. This is best described by looking at the data objects used by the mediation flow (see Figure 16).


Figure 16. Request and response business objects
Request and response           business objects

The input to the flow is an array of employee identifiers, while the output is an array of status objects, indicating whether the payslip processing succeeded or not. However, each of the services invoked from within the mediation flow can only handle a single record, as shown in Figure 17.


Figure 17. Business objects for back-end system interaction
Business objects for           back-end system interaction

So the outer aggregation iterates through all of the repeating elements, while the inner aggregation builds a response aggregated from the two service invocations. As with the previous example, when a response has to be created from repeating elements, the specification of the Shared Context is key to a successful flow design. In this case, on completion of successful calls to the two services, you need to combine the HRRecord and PayrollRecord results into a single EmployeeRecord. Moreover, this single response needs to be aggregated into an array of records to satisfy the interface for the Payslip service, invoked via the Callout node. Consequently, the same model for Shared Context as previously described is adopted (see Figure 18).


Figure 18. Business objects for back-end system interaction
Business objects for           back-end system interaction

The current field is used to create a single record for each instance of the repeating element, which is then appended to the aggregationStore, a running total of the overall flow.

After the data has been aggregated and batched, the Payslip service is called, which takes an array of EmployeeRecord objects and returns an array of PayslipStatus objects (see Figure 19).


Figure 19. Payslip service business objects
Payslip service           business objects

Now, considering the middle part of the flow, let's look at Figure 20.


Figure 20. Embedded aggregation flow
Embedded aggregation           flow

This embedded aggregation is similar to one previously described and deals with a single record being sent to two systems via service invocations. This is achieved by the XSLT transforms, convertToHR and convertToPayroll, taking the single repeating element occurrence in the FanOutContext and mapping the relevant field into the message most appropriate for the Service Invoke call. The parts of the flow that bracket this are shown in Figure 21.


Figure 21. Outer aggregation splitting
Outer aggregation           splitting

What you see above fires repeatedly until all of the repeating elements are exhausted. The result is shown in Figure 22.


Figure 22. Outer aggregation Fan In
Outer aggregation           Fan In

This then converts the aggregated results in Shared Context into an appropriate request message for the Callout node.

All of the strategies used in XSLT mapping described in the previous scenarios also apply here.



Back to top


Scenario 4: Nested aggregation

This scenario is based on a supermarket company, where each outlet sends multiple restocking orders to a central company-wide system that batches the requests into a single message. This single message is submitted to the mediation flow where, for each order and for each branch, a separate invocation to the order system should occur. (Download the Scenario 4 files.)

Design the aggregation

The key here is that the ordering system is implemented to accept a single record, whereas the input into the mediation module is a nested batch message. This introduces the need for aggregation, and in this case nested aggregation, because the batch request message is repeated on an outlet basis and then repeated on an order basis. Orders are sent individually, the response from each order being stored for later aggregation into a single response message, which shows the status of all the elements in the batch request.

To explore how this basic scenario is built, you must first examine the business objects used (see Figure 23).


Figure 23. The basic business objects
The basic business           objects

The GroupOrders request is a batched array of Outlets tagged by an ID, which itself is a batched array of Orders. This nested structure allows for a nice fit to the nested aggregation structure, which is explained later in this article.


Figure 24. Request business object structure
Request business           object structure

The GroupOrderResult has a similar nested structure to the request. The GroupOrderResult is a batched array of OutletResults tagged by an ID, which itself is a batched array of OrderResults.

The flow overview

In this section, you'll look at each part of the flow, including the use of each Fan In and Fan Out primitive along with any mappings needed within the overall flow (see Figure 25).


Figure 25. Flow overview
Flow overview

However, before doing that, you must first understand how to design a useful Shared Context for this scenario.

Shared Context

As stated earlier, the design of the Shared Context is essential to a successful aggregation design, and within a nested aggregation it's even more critical. The goal is to store the response from each Order into a structure that can then be converted into a single response message. The nested aggregation structure can be considered analogous to a Russian doll, where the initial request is at a company-wide scope, the first aggregation is at the Outlet scope, and the second aggregation is at the Order scope (see Figure 26).


Figure 26. Aggregation structure
Aggregation structure

Understanding the aggregation structure helps in defining the correct Shared Context, as normally there's a mapping. The logic pattern within the mediation flow is:

  • Aggregate on an Outlet basis.
    • Aggregate on an Order basis.
      • Invoke the Order service.
      • Store the current Order service within the current Outlet response.
    • Repeat for each Order associated with the Outlet.
    • Store the current Outlet in the company-wide aggregation store.
  • Repeat for each Outlet.
  • Convert all results into a response message.

This provides the requirement for the Shared Context to be able to store the overall company-wide, the current Outlet, and the current Order response. Figure 27 illustrates what this looks like.


Figure 27. Shared Context business objects
Shared Context business           objects

The flow detail

Now looking at the flow in detail, it's separated into three sections:

  • Company-wide scope
  • Outlet scope
  • Order scope

Figure 28. Company-wide section of flow

At the company-wide scope (see Figure 28) the request message is passed unmodified into the Outlet aggregation, so there's nothing interesting at this stage. On exiting the Outlet aggregation, the response message needs to be generated from the Shared Context. You can accomplish this by using either an XSLT or a BOMapper primitive. In this case an XSLT primitive has been used to map from the aggregationStore within the Shared Context to the response body, and is illustrated in Figures 29 through 31.


Figure 29. Transformation to response message
Transformation to           response message

Figure 30. Response message: OutletResults submap
Response message:           OutletResults submap

Figure 31. Response message: orderResults submap
Response message:           orderResults submap

The important aspect to highlight at this stage is the simple transformation required. Careful consideration of the Shared Context structure has allowed for a straightforward XSLT without the requirement of any custom XSLT.


Figure 32. Outlet
Outlet

The outlet scope provides the looping capabilities over the array of Outlets provided within the request message. The OutletIterator (Fan Out primitive) is set to iterate over the repeating Outlet elements in the request message. Equally, the Fan In is set to complete when all of the repeating elements have been handled (see Figure 33).


Figure 33. Fan In for outlet aggregation
Fan In for outlet           aggregation

Following the Fan Out is a Message Element Setter called StoreOutletID, which is used to copy the ID from the request message into the Shared Context (see Figure 34).


Figure 34. Store the outlet ID
Store the outlet ID

This simply seeds the context ready for appending the current Order to the outlet during the Order aggregation.

Following the Fan In is a Message Element Setter called StoreOutletResult, which appends all of the results for a single outlet into the aggregationStore by using the append option (see Figure 35). In addition, the current Outlet is removed from the Shared Context so that it's ready for the next iteration.


Figure 35. Append the outlet to the aggregationStore
Append the outlet to           the aggregationStore

The Order scope provides the looping capabilities over the array of Orders for each Outlet within the request message. The OrderIterator (Fan Out primitive) is set to iterate over the repeating Orders (contained within the FanOutContext of the first Fan Out primitive).


Figure 36. Order aggregation
Order aggregation

Equally, the Fan In is set to complete when all of the repeating elements have been handled (see Figure 37).


Figure 37. Fan In for order aggregation
Fan In for order           aggregation

Following the Fan Out is an XSLT called TransformToOrder, which converts the new FanOutContext (containing the current Order element) into the request message for the Order service (see Figure 38).


Figure 38. Transformation to order request format
Transformation to           order request format

The Service Invoke then invokes the Order service and, following this, a Message Element Setter called StoreResult stores the result into the currentOrder element within the Shared Context.


Figure 39. Store the current order into the Shared Context
Store the current           order into the Shared Context

The Order result that has been stored within the Shared Context needs to be stored within the Outlet result Order array. Therefore, another Message Element Setter called AppendStore copies the currentOrder into the Outlet Order result array.


Figure 40. Append the current order to the Shared Context
Append the current           order to the Shared Context

There's no need to remove the currentOrder object from the Shared Context at this aggregation level, as the values are overwritten during the next iteration.

As you can see, the aggregation functionality directly maps to the structure of the inbound data, as does Shared Context. In this case, you have repeating elements within repeating elements, so the aggregation is two-fold and nested.



Back to top


Other things to consider

Having looked at the useful patterns in aggregation, there are now other points to consider when designing a mediation flow using aggregation in WebSphere Enterprise Service Bus V6.1.

  • Timeout property for Fan In: The Fan In primitive has an associated timeout property that requires a little explanation so you can use it successfully. The timeout period starts when the associated Fan Out fires an output terminal for the first time. If a message arrives at the Fan In in terminal after this timeout period, it's considered as being late, and the Fan In fires its incomplete terminal. If a mediation primitive is badly behaved, for example, if a DB Lookup primitive is deadlocked, the execution of the flow is also deadlocked; this situation is not mitigated by the Fan In timeout. Consequently, the timeout function should be considered as a way of trapping late messages rather than a way of terminating the aggregation after a specified period.
  • SMO body considerations: The mediation flow programming model guarantees that, with the explicit exception of the Shared Context, separate flow branches are isolated and have their own SMO. Therefore, the body of a message should not be used to store any data that may be needed outside of the Fan Out/Fan In boundary; it can't be relied on. Any data to be used in this way should be stored within the Shared Context, which is supplied for this purpose.
  • Use of the response flow within aggregation: Even with the enhanced intra-flow service invocation support provided by the Service Invoke primitive, response flows play a key role within a mediation. It's important to design the mediation to be easy to maintain and provide a sensible flow of data across the whole mediation flow. If there's a logical single invocation within the mediation flow, it's sensible to use the callout node within the request flow, and then use the response flow for any additional mediation processing. The usage of response flows is demonstrated in the previously described scenarios.


Back to top


Conclusion

This article introduced you to some common aggregation usage patterns and explored how these patterns can be realised using WebSphere Enterprise Service Bus V6.1. This the final in a series of three articles, and, upon completion, you should understand the basic building blocks that make up aggregation scenarios as well as how you can use these to create realistic business flows.




Back to top


Downloads

DescriptionNameSizeDownload method
Scenario 1 sample filesInsuranceQuoteScenario1.zip28KBHTTP
Scenario 2 sample filesStoreMediationScenario2.zip60KBHTTP
Scenario 3 sample filesEmployeeMediationScenario3.zip72KBHTTP
Scenario 4 sample filesNestedAggregationScenario4.zip37KBHTTP
Information about download methods


Resources

Learn

Get products and technologies
  • Innovate your next development project with IBM trial software, available for download or on DVD.


Discuss


About the authors

Callum Jackson photo

Callum Jackson is a software engineer for WebSphere Enterprise Service Bus based in Hursley, United Kingdom, and has worked in the product area since 2005. Prior to this he worked in ISSW on SOA applications for the telecommunication industry.


Brian Hulse photo

Brian Hulse is a senior software engineer for WebSphere Enterprise Service Bus based in Hursley, United Kingdom. He has worked in software development at Hursley for 20 years, the last five of which have been in the SOA arena.




Rate this page


Please take a moment to complete this form to help us better serve you.



 


 


Not
useful
Extremely
useful
 


Share this....

digg Digg this story del.icio.us del.icio.us Slashdot Slashdot it!



Back to top


IBM, the IBM logo, and WebSphere are registered trademarks of IBM in the United States, other countries or both. Other company, product, or service names may be trademarks or service marks of others.