Dynamic binding using OSB

One of the key advantages of an Enterprise Service Bus, as well as Service Oriented Architecture in general is the quality of Agility, that is, the ability to easily compose new orchestrations of web service operations. In this recipe, we will consider a scenario in which a standard service contract might be implemented by multiple providers, the selection of which we want to dynamically configure at runtime.

For example, let us suppose that we are running an online bookstore and wish to automate stock order requests to multiple publishers. A stock order includes the name of the publisher, details of the book, and the quantity to order:

<stockOrder>
  <publisher>ACME</publisher>
  <bookOrder>
    <book>
      <isbn>1234567890123</isbn>
      <title>Barry Potter</title>
       …
    </book>
    <quantity>Skylight vampires</quantity>
  </bookOrder>
</stockOrder>

This service could be fulfilled by various publishers and new publishers might be joining our network all the time. Ideally, rather than needing to re-code and publish our routing logic every time a new publisher is added, we would like to be able to keep our Stock Order service running with no outage and simply update the routing rules using a configuration file, such as the following:

<routing>
  <rule>
    <key>ACME</key>
    <serviceName>PublisherApp/PublisherACME</serviceName>
  </rule>
  <rule>
    <key>Packt</key>
    <serviceName>PublisherApp/PublisherPackt</serviceName>
  </rule>
  <rule>
    <key>Skynet</key>
    <serviceName>PublisherApp/PublisherSkynet</serviceName>
  </rule>
</routing>

Each of these serviceNames are OSB proxy services, wrapping a particular publisher's online stock ordering service. The idea is that when we want to add a new publisher, we implement a new proxy service implementing the previous service contract and add a <rule> element to the configuration file referencing it.

This recipe will demonstrate how this dynamic routing can be implemented in OSB.

Getting ready

In order to use this design pattern, you will need to define a standard WSDL to be implemented by each of your routing destinations (publishers in our example).

For our purposes, we have defined the WSDL Publisher_Service_1.0.wsdl, which defines the operation submitBookOrder .

We have provided three basic implementations of this service, as defined in the following table:

Publisher

Proxy service

ACME

PublisherApp/PublisherACME

Packt

PublisherApp/PublisherPackt

Skynet

PublisherApp/PublisherSkynet

These implementations are defined in the PublisherApp OSB project which is included in the sample for the book. You will need to open this sample in OEPE and deploy to your instance of OSB.

How to do it...

  1. In the Eclipse IDE, open the the PublisherApp OSB project which is included in the samples. Define a new OSB proxy service, give it the name PublisherService and select Publisher_Service_1.0.wsdl as the WSDL.
  2. The next step is to compose a simple XQuery source file containing a list of routing destinations similar to the following example:
    xquery version "1.0" encoding "Cp1252";
    (:: pragma  type="xs:anyType" ::)
    
    declare namespace xf = "http://tempuri.org/PublisherApp/dynamic-routing-rules/";
    
    declare function xf:dynamic-routing-rules()
    as element(*) {
      <routing>
        <!-- dynamic-routing-rules.xq -->
        <rule>
          <key>ACME</key>
          <serviceName>PublisherApp/PublisherACME</serviceName>
        </rule>
        <rule>
          <key>Packt</key>
          <serviceName>PublisherApp/PublisherPackt</serviceName>
        </rule>
        <rule>
          <key>Skynet</key>
          <serviceName>PublisherApp/PublisherSkynet</serviceName>
        </rule>
      </routing>
    };
    
    
    xf:dynamic-routing-rules()

    Note that in our example, key is the key field we will use to determine which routing rule to apply while serviceName indicates the exact path (within OSB) of the corresponding destination proxy service.

    Save this file within your OSB project as dynamic-routing-rules.xq.

  3. Open your proxy service and select the Message Flow tab. Drag in a Pipeline Pair followed by a Stage, naming the stage as LookupDestination. Within the new stage, add two Assign actions, as shown in the following screenshot:
    How to do it...
  4. For the first Assign action, set Variable as routingRules and select dynamic-routing-rules.xq as the <Expression>.
    How to do it...
  5. For the second Assign action, set Variable as destination and use the following XML fragment as your expression:
    <ctx:route>
      <ctx:service isProxy="true">{
      $routingRules/rule[key/text()=$body//*:publisher/text()]/serviceName/text()
      }</ctx:service>
    </ctx:route>
  6. Next, drag a Route node to the bottom of the Message Flow and place a Dynamic Routing action within that. Set the <Expression> within the Dynamic Routing action as $destination.
    How to do it...

How it works…

The key feature of OSB used for this design pattern is the Dynamic Routing action. The expression used in this action is expected in a very specific format, as per the following XML fragment:

<ctx:route>
  <ctx:service isProxy="$isProxy">$serviceName</ctx:service>
  <!-- operation is optional -->
  <ctx:operation>$operationName</ctx:operation>
</ctx:route>

Note that isProxy is an xsd:boolean. If set to "true" then serviceName must be the complete path to an OSB proxy service, otherwise serviceName must be the complete path of an OSB business service. The complete path should include the OSB project and any subfolders included in the project structure.

In our example, in the LookupDestination stage, we've used the following XPath to determine the serviceName:

  $routingRules/rule[key/text()=$body//*:publisher/text()]/serviceName/text()

This roughly reads as "return the serviceName corresponding to the rule in routingRules for which the key matches the publisher element in the request". In other words, it's a key-value lookup into our configuration file dynamic-routing-rules.xq.

Now, if we need to add a new publisher service, we only need to ensure that its proxy service is added to dynamic-routing-rules.xq and implements the same WSDL.

There's more…

The generic contract of this service comes at a price. Publisher IDs accepted by the service are not restricted and so it's possible to submit a stock order for a publisher which may not exist in the routing rules.

This is easily remedied by adding a conditional block after the LookupDestination stage to confirm that a valid address was retrieved before attempting to route. The expression to use for the condition is as follows:

  fn:data($destination/*:service) = ""

The conditional block should include appropriate logic, such as a Raise Error action.

Another potential issue with this design pattern is that the destination service may not exist! This could be due to a mistake in the routing rules, or because the destination service has not been deployed for whatever reason.

If this is the case, then OSB will raise the following internal error:

  BEA-382612: Error preparing message for dispatch

To detect this issue at runtime, include the following condition expression in your Error Handler block:

  $fault/ctx:errorCode = "BEA-382612"
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.138.178