Mediations and ESB
Having looked at SCA and BPEL we are now ready to examine another core concept of the IBPM Advanced product. SCA allows us to decouple service callers and service providers from the tight coupling that might be needed to invoke them. BPEL allows us to provide process flow control to describe the sequence of execution. There is still another level of function that we may need. That function is generically called "mediations".
Mediations deals with aspects of the physical bridge to the outside world. When we think about Web Services calls, JMS calls, MQ calls or other interactions, we can easily imagine simple invocations of these technologies. Nine times out of ten, these simple interactions are all that are needed but in some circumstances, we need to exercise detailed and low level control and access. Consider for example a JMS message that contains a property in its header that defines when the message was originally sent. This is not usually surfaced through SCA as SCA abstracts away the details of technical interaction. Consider a Web Service provider that, when called, expects a special token in the SOAP header. Again, an SCA Import doesn't normally accommodate such things as the call to SCA hides the identity and nature of the target system from whomever may be trying to call it.
To solve such problems, lower level access to the physical headers of incoming and outgoing requests has been exposed.
Service Message Object (SMO)
The Service Message Object (SMO) is a representation of the data to be transformed and the resulting output of that transformation. The SMO contains more than just application data. It contains headers for MQ, SOAP and others as well as contextual information that can be saved and later made available. It is essential to learn the SMO in order to use the mediations capabilities.
When a message arrives at an SCA module from outside of IBPM, it may have protocol information associated with it such as MQ or JMS headers or SOAP envelope information. In addition if a request is made outbound from a module, we may wish to set the protocol information. This is above and beyond the payload of the message itself.
In order to work with such information, a tree data structure called the Service Message Object is created by the system. When building a mediation flow, it is the SMO we work with. The SMO is a large and complex data structure. Fortunately it is well organized and doesn't require full mastery of all of its fields in order to be useful.
|| |context||||| ||correlation|||| ||transient|||| ||failinfo|||| |||failureString||| |||origin||| |||invocationPath||| ||||inTerminal|| ||||name|| ||||outTerminal|| ||predecessor|||| ||primitiveContext|||| |||EndpointLookupContext||| ||||endpointReference|| ||||registryAnnotations|| ||||classification|| ||||relationship|| |||FanOutContext||| ||||iteration|| ||||occurrence|| |||WTXContext||| ||shared|||| ||dynamicProperty|||| |||propertySets||| ||||group|| ||||properties|| |||||name| |||||value| |||||type| |||isPropagated||| ||userContext|||| |||entries||| ||||name|| ||||value|| ||||type|| |headers||||| ||SMOHeader|||| |||MessageUUID||| |||Version||| |||MessageType||| |||Operation||| |||Action||| |||Target||| |||AlternateTarget||| |||SourceNode||| |||SourceBindingType||| |||Interface||| ||JMSHeader|||| |||JMSDestination||| |||JMSDeliveryMode||| |||JMSMessageID||| |||JMSTimestamp||| |||JMSCorrelationID||| |||JMSReplyTo||| |||JMSRedelivered||| |||JMSType||| |||JMSExpiration||| |||JMSPriority||| ||SOAPHeader|||| |||namespace||| |||name||| |||prefix||| |||value||| ||SOAPFaultInfo|||| |||faultcode||| |||faultstring||| |||faultactor||| |||extendedFaultInfo||| ||properties|||| |||name||| |||value||| |||type||| ||MQHeader|||| |||md||| |||control||| |||header||| ||HTTPHeader|||| |||control||| |||header||| ||EISHeader|||| ||WSAHeader|||| |body||||| |attachments||||| ||contentID|||| ||contentType|||| ||data|||| ||bodyPath||||
A mediation flow component is itself composed of a sequence of one or more primitive actions that are visually composed in WID. In some products such actions are called nodes while in WPS they are called primitives. A mediation flow is characterized by the combination of these primitives and the configuration attributes associated with each of the primitives.
Every mediation flow starts with an Input primitive. This is the start of the transformation.
The callout primitive is usually the end of the transformation. When a callout is reached, the SMO passed into it is sent out the reference terminal of the SCA Mediation Flow node and sent onwards to what ever is wired to that terminal on the assembly diagram.
The properties of the callout primitive are shown below:
Async timeout (seconds) – The amount of time in seconds after a request message is sent before waiting for a response is abandoned. The default value of this is only 5 seconds which is probably too low, especially when performing manual testing. Other values for this include “0” for immediate return and “-1” for no timeout (unlimited duration).
Invocation Style – One of Synchronous, Asynchronous or Default. Default will eventually resolved to either Synchronous or Asynchronous based on some convoluted rules.
Business Object Map primitive
Custom Mediation primitive
The Custom mediation primitive provides the ability for the programmer to code mediation logic in the Java programming language. Within the primitive, the programmer has addressability to the SMO data structure and can see/play with all aspects of the incoming data. The logic can also choose which of the defined output terminals an outgoing SMO will be sent.
In the code for the Custom Mediation there are a number of predefined objects:
BOFactory boFactory = (BOFactory)ServiceManager.INSTANCE.locateService("com/ibm/websphere/bo/BOFactory"); DataObject newBody = boFactory.createByMessage("http://Med1Tests/I1", "operation1ResponseMsg"); DataObject operation1Response = newBody.createDataObject("operation1Response"); DataObject output1 = operation1Response.createDataObject("output1"); output1.setString("x", "xVal"); output1.setString("y", "yVal"); output1.setString("z", "zVal"); smo.setBody(newBody); out.fire(smo);
Data Handler primitive
The purpose of the DataHandler primitive is to transform data from one format to another by executing a DataHandler. This primitive's configuration allows us to name the data handler type to be used. The configuration is made in the Details section in the Properties view within WID. The following screen shot illustrates this screen.
First, the DataHandler configuration is selected. This is where we select the DataHandler to be invoked at runtime. Clicking on the Browse button opens the DataHandler configuration window:
From here we can select one of the existing DataHandler known to the DataHandler registry. Alternatively, we can select a custom DataHandler from the lower part of the screen. This will examine the workspace looking for a Java Class that implements DataHandler. Optionally, this DataHandler class can be added to the binding registry.
Once the DataHandler has been selected, the Source XPath and Target XPath locations can be supplied. These are locations within the SMO where the input data to the DataHandler will be sourced from and where the output data from the DataHandler will be stored. If a custom data handler is being written, this is data that will be sent to the source parameter of the transform method. The data type of the target field will be the class supplied in targetClass.
Database Lookup primitive
This mediation primitive enables the message to be augmented with information from a database. The primitive is configured with the JNDI name of a JDBC data source, the name of a table in that database and the name of the column in that table that should be used as a key. An XPath expression is then given that defines where that key is located in the input message. At runtime, the row matching that key is retrieved. If a matching row is not found then the message is propagated to the ''keyNotFound'' terminal unchanged. The primitive can then configured with the columns in the returned row that should be set in to the message at locations given by XPaths. The augmented message is then passed to the out terminal. If processing fails, for example because a connection to the database cannot be achieved, then the message is passed to the fail terminal.
A common pattern is likely to be to use a database lookup to place information in to the transient context of the message and then wire the output to a filter which will then use the information that has been retrieved to make a routing decision.
Endpoint Lookup primitive
Event Emitter primitive
Fan In primitive
Fan Out primitive
Flow Order primitive
Gateway Endpoint Lookup primitive
The purpose of this primitive is to perform a lookup of a service registry to dynamically retrieve the endpoint of a target service. This primitive is used in the Gateway and Proxy service patterns.
There are three different techniques for resolving an endpoint via lookup. These methods are:
The information returned from the lookup causes changes to be made to the SMO. Specifically, the following changes are made:
HTTP Header Setter primitive
JMS Header Setter primitive
Message Element Setter primitive
Message Filter primitive
Message Logger primitive
Message Validator primitive
MQ Header Setter primitive
In an MQ message, there can be multiple headers that prefix the payload of the data. These include:
in addition there is a mandatory header of which there can be only one called MQMD.
The purpose of this primitive is to create, copy or delete whole headers as well as set values in those headers. We can create multiple instances of MQRFH2, MQCIH and MQIIH but because there is only one MQMD, it doesn't mean anything to try and create a second instance or delete the original instance of that structure.
This primitive can be very useful for creating an MQHeader in an SMO where no MQHeader exists (for example when the flow was started by something other than MQ).
When using this primitive for the first time, the following instructional box may appear:
In the dependencies section of the module that contains the primitive, check the box for MQ Header primitive schemas.
Policy Resolution primitive
When a mediation flow is given control, it executes based on the logic in the mediation in combination with the data supplied with the incoming message. For example, the logic in the mediation may say that a discount applied if the price is over $1000. The price of an actual order may be found in the body of the incoming message. This works just fine but suffers from a maintenance issue. If the decision logic changes periodically, such as the price at which the discount applies or the value of the discount itself, we would have to open up the Mediation in Process Designer, make the change, save the module and redeploy to the server. Hardly an agile environment. Fortunately, the mediation technology provides a potential solution for this through the use of exposed promoted properties. A property of a mediation can be a variable value used in the solution or a variety of other configurable artifacts. If a property is promoted then it can be dynamically changed through the WAS admin console. This is an improvement but still requires detailed WAS admin console access and means that all mediation flow instances have to use the same single value.
The latest solution is to make use of WSRR and the WS-Policy specification. Using this technique, a set of one or more WS-Policy files can be registered with WSRR. At runtime, the Policy Resolution primitive can be used to contact the WSRR server and dynamically select one or more of those policies based on the values of data passed in as part of the incoming message. Because the policy data is stored as part of WSRR, it is much easier to maintain and modify.
Service Invoke primitive
Set Message Type primitive
SLA Check Primitive
SOAP Header Setter Primitive
Type Filter primitive
UDDI Endpoint Lookup Primitive
The purpose of a Mapping transformation is to build a new SMO using an existing SMO as input data. The ID based tooling present a source tree structure representing the input SMO and a destination or target tree structure representing the result. The developer can then perform wiring to map the source fields to the target fields. When a wiring is made, this is called a transform. ID provides a set of pre-defined transforms to achieve the mapping.
The primitive is called an XSLT transformation as the result of using ID to generate the mappings is saved in a proprietary IBM format called a ".map" file. This .map file is then itself transformed automatically into an XSLT file. It is this XSLT file that is executes by IBPM at run-time using an XSLT 1.0 or XSLT 2.0 processing engine.
When defining the XSLT transformation, you have the ability to select how much of the SMO you wish to map to/from. There are four choices:
convert – Transform a simple data type to another simple data type
custom – Invoke direct code to perform the transformation. The code can be supplied as Xpath, XSLT or Java. See also
for each – Iterate over an array executing a transformation for each element in the array. The output must also be an array.
move – Move is the simplest transformation. It copies the value of the source field to the target field.
group – ???
if, else if, else – ???
join, merge – Merge is similar to local map but instead of just providing a single input source, multiple input sources can be supplied
local map – A local map is a stylistic assistance. It allows a mapping from a complex structure to another complex structure to be nested into an easier to manage sub-mapping. Unlike submaps, a local map provides no reuse.
lookup – ???
move – ???
normalize – White space is removed from the string.
submap – A submap invokes a named pre-existing map to perform the transformation. This allows a map to be created once and re-used in multiple transforms.
substring – ???
XSLT and XPath functions
Within an XSLT primitive mapping, there is the ability to invoke a Java function. This Java must be implemented in a Java class available to the project. Within the Java class, any method that is to be called from the XSLT must be defined as static. The parameters to the method will be taken from the input parameters supplied in the WID editor. The return value from the method will be the value stored in the target.
The catalog of Data Maps
Over time it is not uncommon to create large numbers of Data maps as part of an enterprise solution. ID provides a view call the Data Map Catalog that shows all the available maps plus their inputs, outputs and other related information. From this you can quickly find the map you may wish to use or reuse.
The Data Map Catalog can be opened from the menu bar:
or from the Data Maps folder:
|| |ID|Date|Description| |2141767|01/28/10|MediationRuntimeException and CWSXM1025E on Move transformation on array elements in XSL Transformation primitive|
The Service Gateway pattern
Consider the following illustration. It shows a series of service requesters invoking a series of service providers using ESB technology to mediate between them. As is commonly the case, the ESB may be protocol switching or performing data content/format transformation or some other such task. Obviously this works but can we do better?
Now lets us consider this next diagram:
Once again we have a series of service requesters and service providers but now the routing flows through something called a Service Gateway. A Service Gateway is nothing new from an SCA Mediation perspective, instead it is a pattern of usage as opposed to a radically new technology. The Service Gateway can be thought of as an aggregation of function into a single mediation where previously there would otherwise have been multiple mediations.
Looking at the Service Gateway pattern, it isn't immediately obvious what problem it solves or benefits it adds. However, there are many. Some of them include:
By using the Service Gateway pattern, the target provider services all become accessible through a single incoming endpoint. The providers that are exposed through the Service Gateway effectively become a set of target services that become logically grouped together.
Within Integration Developer, there is a wizard that is available to create these patterns. It can be found at
Window > Show View > Patterns Explorer.
The Service Gateway patterns do not need to be created through the wizard; they can just as well be created by hand.
Consider an example where we have three possible back-end service providers. These may relate to customer service levels such as Silver, Gold and Platinum. If we have a calling service, this would appear to need bindings to each of the three back-end services. This is not a great solution. It could easily end up being brittle. Binding the client to three back-end services doesn't give us much flexibility if we need to change a service location. In addition, we would have to replicate three qualities of service for each of the different back-ends. For example, if we wanted to add logging to the logical service, we would have to perform that task three times.
The solution provided by the mediations functions is the introduction of something called a virtual service. Think of a virtual service as being a logical name of a target service which, at runtime, is resolved via a lookup to the actual service that is to be called. By utilizing this technique, we have again separated the caller from the target service. The caller now supplies the name of the virtual service to be invoked and the mediation performs the determination of how to reach the physical service that the virtual service represents. This pattern is caller a Proxy Gateway.
When a caller invokes a mediation that uses this Proxy Gateway pattern, the mediation looks at the request and then performs a calculation to determine the final destination and then routes the request onwards for processing. The mediation thus becomes a proxy (or stand-in) for the real target service.
The core technology behind the Proxy Gateway pattern is the mediation primitive called the Gateway Endpoint Lookup primitive.
Proxy Gateways are managed from within Business Space using the widget called Proxy Gateway. This can be found in the Solution Operations folder.
Let us look at an example. Imagine we have a Gateway Endpoint Lookup that has the following definition:
Now we need to introduce the concept of a Proxy Group. A Proxy Group is a logical set of service providers that are collected together in a named group/set. By grouping them together we have a way to refer to them as a unit. Notice that in our example we have defined a proxy group called "proxyGroup1". Once the module containing the mediation that contains the gateway endpoint lookup is deployed, a new entry will be found in the Business Space Proxy Gateway widget:
Note the name of the proxy group and the name of the proxy gateway. The proxy gateway name is the name of the module. On the right hand side of the entry there is a pencil icon which indicates an editing session. This is where we associate endpoints with the group. Here is an example of some endpoints already added.
Note the primary attributes of an entry. There is the virtual service name, the endpoint and whether or not it is enabled. To add a new virtual service, enter the location of the wsdl in the WSDL location text box and click the Add Service... button.
We are presented with the details of the new virtual service to add. Clicking Save will save the definitions. A Virtual Service is the mapping of a named entry to a concrete or real endpoint. So based on what we have seen, a Proxy Gateway is a module that can have one or more Gateway Endpoint Lookup primitives. Each one of these can define one or more Proxy Groups and a Proxy Group is a collection of one or more Virtual Services.
Obviously this information has to be stored somewhere. IBPM Advanced provides a built-in storage mechanism for hosting this data. It is the Business Space widgets that provide the administration of these logical functions.
For additional details on using the Proxy Gateway pattern, see the Gateway Endpoint Lookup primitive.
SOAP Message Attachments
With Web Services, a request from a caller is sent to a provider. The caller builds an XML document that conforms to the industry standard SOAP specification that encodes the request that is desired to be made. This is then usually transmitted over HTTP to the service provider which unpacks the SOAP request, performs the work requested of it and may send back a response.
There are cases however where the caller wishes to send over what we generically call attachments. These are commonly much larger items that parameter fields and include such things as images, scanned fax documents, zip files, or office documents. Typically these attachments are natively represented as binary data which is not suitable for encoding within the normal SOAP body as parameters. The product has a limitation of no more than 20 MBytes for the total attachment sizes.
The trick to passing these attachments is to encode them using the Multipart Media (MIME).
Here is an example SOAP message with an attachment:
MIME-Version: 1.0 Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml; start="<email@example.com>" Content-Description: This is the optional message description. --MIME_boundary Content-Type: text/xml; charset=UTF-8 Content-Transfer-Encoding: 8bit Content-ID: <firstname.lastname@example.org> <?xml version='1.0' ?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> .. <theSignedForm href="cid:email@example.com"/> .. </SOAP-ENV:Body> </SOAP-ENV:Envelope> --MIME_boundary Content-Type: image/tiff Content-Transfer-Encoding: binary Content-ID: <firstname.lastname@example.org> ...binary TIFF image... --MIME_boundary--
There are a number of styles of SOAP with attachments. The first is called an unreferenced attachment. It is called this because in the SOAP envelope there is simply no reference to the contained attachment. The alternative is known as a referenced attachment. In this case, an element in the SOAP message logically refers to the attachment data.
A suitable WAS trace flag for tracing mediations is: