February 5, 2010

Domain Value Maps in Oracle Service Bus

Imagine you are performing a mapping in Oracle Service Bus where a field in your source message may contain one of a number of different values which gets mapped to one of a number of different values in the target message, e.g. you might need to map airport names to airport codes:

Airport Name Airport Code
London Heathrow LHR
Edinburgh EDI
Southampton SOU
Dublin DUB
London Gatwick LGW
Los Angeles LAX
Tokyo HND
San Francisco SFO
…. ….

This sort of mapping is typically called a domain value map as you are mapping from values in one domain to another.

Oracle Service Bus does not yet have built-in support for domain value maps - this is being integrated from the mediator component in SOA Suite and should be available in the 11gR2 release - so how do you handle this type of mapping in the meantime? Well, there are a number of options:

a) Add this information into your XQuery/XSLT transformation in the form of if/then logic

- Not very elegant

- Only really manageable for a small number of entities

b) Use the fn-bea:execute-sql() function to lookup these values from a database

- Good solution when there are lots of entities and their values change regularly

- However, likely to be more expensive in terms of performance and more complex -  data source configuration, database setup/maintenance etc.

c) Use a domain value map in Oracle Service Bus

Hey? I thought you said Oracle Service Bus didn’t have domain value map support yet? Not quite, I said it doesn’t have built-in support for domain value maps, but that doesn’t mean we can’t make domain value maps work in the meantime.

The way to do this is the following:

Create a domain value map in JDeveloper

- Create a new SOA application

- Right click on the newly created project within this application and select New

- From the SOA Tier category, select Transformation and in the Items list select Domain Value Map

createDVM

- Click OK and then give your domain value map a name, description and enter the first couple of values

createDVM2

- Click OK again, and then add some more domain values to your domain value map using the green plus sign until it looks something like this:

createDVM3

- Save your work.

Import the domain value map into Oracle Service Bus

- Create an XQuery transformation file called AirportNamesToAirportCodesDVM using the contents of the domain value map you created by switching to the Source tab in JDeveloper and copying and pasting the whole dvm tag which includes all the data (you don’t need the XML declaration and generated comment above this) into the contents of the XQuery file in Oracle Service Bus

Import the domain value map schema into Oracle Service Bus

- Create an XML schema file for the domain value map using the domain value map schema which can be found here.

Define your XQuery mapping in Oracle Service Bus

- In Oracle Service Bus create a new XQuery transformation and include both the domain value map and your source message (containing the airport name) as source types:

createDVM4

- Set the target type of the transform to be your output message type

- Then in the XQuery mapper drag and drop a wire from the airport name field in the source messages to the airport code airport code field in the target message

- In the Target Expression tab replace $airportName with

$dvm/ns0:rows/ns0:row[ns0:cell[1]=$airportName]/ns0:cell[2]

and click Apply. This XPath expression basically says: “take the contents of the second column of the row in the domain value map where the first column’s contents equals the name of the airport in my source message”

Your mapping should now look like this:

createDVM5

Test your transform

- Switch to the test tab

- Populate your domain value map with some values (this will be the dvm source variable)

- Switch to the input message source variable and enter the name of the airport (or your full source message if you have done something more complex than this example)  and click the green arrow to test your XQuery:

createDVM6

Using the transform in a proxy service message flow

To use the transform in a proxy service message flow (i.e. within an action such as a Replace) you will need to create the dvm variable by adding an Assign action before the action in which you plan to do the transform.

createDVM7

You will then need to use this variable and the source message as inputs to the transformation in your Replace action.

Why use this approach?

- Domain value maps can be used in multiple transformations

- Domain value maps are one of the most efficient way of mapping relatively small, fairly static sets of data (Note: the first invocation of a transformation including a domain value map will take longer as it has to load the domain value map and cache it – subsequent invocations will be faster).

- Having these mapping defined in one places makes it easy for them to be modified if required

- Using JDeveloper to define your domain value map makes it easier to maintain, and means you can use the same domain value map with other SOA Suite components and future proofs it for when domain value maps are fully supported in Oracle Service Bus

 

XPath by example in Oracle Service Bus

Oracle Service Bus (and the other products in the SOA Suite) is designed to help you solve the majority of common integration scenarios without writing any code. However, as one customer pointed out to me recently:

“You may not have to write any code, but you still need to write XPath which is just as complicated!”

Well, I’m not sure I agree XPath is as complicated as a programming language such as C or Java , but I can see where they are coming from. Learning XPath can seem hard without real world examples, so in the remainder of this post I am going to demonstrate by way of examples, some of the most common XPath expressions I see customers using.

Lets assume the XML below forms the message payload (i.e. the contents of the body variable, $body) in Oracle Service Bus and we are just using a Log action to print out the result.

<?xml version="1.0" encoding="UTF-8"?>
<p:PurchaseOrder id="1234" xmlns:p="
http://www.someshop.com/PurchaseOrder" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.someshop.com/PurchaseOrder PurchaseOrder.xsd ">
  <p:date>2010-04-02</p:date>
  <p:custID>C7123843</p:custID>
  <p:items>
    <p:item id="GF234324">
      <p:description>Denim Jeans</p:description>
      <p:department>Clothing</p:department>
      <p:price>30.99</p:price>
      <p:quantity>2</p:quantity>
    </p:item>
    <p:item id="HD312782">
      <p:description>iPod 80Gb White</p:description>
      <p:department>Electrical</p:department>
      <p:price>99.99</p:price>
      <p:quantity>1</p:quantity>
    </p:item>
    <p:item id="HD998775">
      <p:description>iPod Headphones</p:description>
      <p:department>Electrical</p:department>
      <p:price>19.99</p:price>
      <p:quantity>1</p:quantity>
    </p:item>
    <p:item id="KD123984">
      <p:description>Frying Pan</p:description>
      <p:department>Home</p:department>
      <p:price>9.99</p:price>
      <p:quantity>1</p:quantity>
    </p:item>
  </p:items>
  <p:cardDetails>
    <p:type>Mastercard</p:type>
    <p:cardNumber>1234-5678-1234-5678</p:cardNumber>
  </p:cardDetails>
</p:PurchaseOrder>

Below are the XPath expressions you will need to log the various information from the payload:

a) The purchase order id:

$body/pur:PurchaseOrder/@id

Note: The actual namespace prefix, i.e. pur (the default assigned by Oracle Service Bus in this case), does not have to match the namespace prefix in the original XML document (p), however they both need to point to the namespace URL http://www.someshop.com/PurchaseOrder.

b) The customer id:

$body/pur:PurchaseOrder/pur:custID/text()

Note: In contrast to attributes, XML elements (nodes) can contain a variety of different types of data or even other complex elements, hence the use of the text() function to get the textual data from the element.

c) The card number (assuming you don’t know its path):

$body//pur:cardNumber/text()

Note: The use of // in XPath is not advised (unless absolutely necessary) as it does involve searching through the whole XML tree and so is not  very performant particularly for large payloads.

d) The card number (assuming you don’t know its path or namespace):

$body//*:cardNumber/text()

e) The number of items in the purchase order:

count($body/pur:PurchaseOrder/pur:items/pur:item)

Note: We are using the count function and pointing to the repeating item element in the XML payload.

f) The id of the first item in the order:

$body/pur:PurchaseOrder/pur:items/pur:item[1]/@id

Note: We are using the [1] to select the first item – XPath is unlike most programming languages which index  arrays from 0 rather than 1.

g) The item(s) with id GF234324:

$body/pur:PurchaseOrder/pur:items/pur:item[@id="GF234324"]

Note: This expression will actually return a list of all items whose id attribute is GF234324 – in our example there is only one item with this id.

h) The description of the item with id GF234324:

$body/pur:PurchaseOrder/pur:items/pur:item[@id="GF234324"]/pur:description/text()

Note: This works because there is only one item with this id in the payload.

i) The electrical items in the purchase order:

$body/pur:PurchaseOrder/pur:items/pur:item[pur:department="Electrical"]

j) The second electrical item in the purchase order:

$body/pur:PurchaseOrder/pur:items/pur:item[pur:department="Electrical"][2]

k) The last item in the purchase order:

$body/pur:PurchaseOrder/pur:items/pur:item[last()]

Note: We are using the last() function here to determine the last item in the purchase order.

l) The second item in the purchase order:

$body/pur:PurchaseOrder/pur:items/pur:item[position()=2]

Note: We are using the position() function here to determine the second item in the purchase order.

m) The purchase order date in UK date format (i.e. DD/MM/YYYY)

translate('AB/CD/EFGH','EFGH-CD-AB', xs:string($body/pur:PurchaseOrder/pur:date))

Note: We are using the translate function here to convert the date to UK format. The first argument represents the output format (i.e. UK date format), the second argument represents the incoming format (i.e. XML schema date format) and the third argument represents the thing we are translating (i.e. the purchase order date).

Note: The translate function only works on strings and so we need to convert the purchase order date into a string, hence the use of the xs:string function.

 

If you’d like to get a simple introduction into XPath and related XML technologies I can highly recommend w3Schools who do free tutorials on a variety of XML technologies including one on XPath.

If you’d like to share any other XPath expressions you commonly use, please add them in the comments.

August 14, 2009

Handling the transformation of multiple message types in Oracle Service Bus

Roger wrote a blog post recently about my post entitled “Dynamic transformations in Oracle Service Bus 10gR3“ which got me thinking about the different ways you can handle the transformation of multiple message types in Oracle Service Bus and the things you should consider before selecting one approach over another.

Before I discuss the different solutions and their benefits/disadvantages, let me describe the basic scenario I am talking about:

“I have/want to be able to receive messages in a number of different message formats and transform them into a common format in order to invoke a backend service.”

In terms of handling this in Oracle Service Bus there are a number of possible solutions:

Solution 1 – A separate proxy service for each message type

Solution 2 – A single proxy service containing if/then logic to determine the appropriate transform to apply for each message type

Solution 3 – A single proxy service which selects the appropriate transform to perform by inspecting the message type and determining the correct transform to apply at runtime (as described in Dynamic transformations in Oracle Service Bus 10gR3)

Before we consider why you would choose one over the other, lets make some assumptions:

- We have N different message types

- Each message type needs to be transformed into the same common data format

- We are invoking a single common business service

- We already have a message definition (WSDL, XML Schema or MFL) for the common data format

Now, on to the comparison:

  Solution 1 Solution 2 Solution 3
Number of assets to create/manage 3N
N x Proxy services
N x Transforms
N x Message definitions
2N+1
1 x Proxy service
N x Transforms
N x Message definitions
2N+1
1 x Proxy service
N x Transforms
N x Message definitions
Work required to add N+1th message type +1 Proxy service
+1 Transform
+1 Message definition
Modify existing proxy service
+1 Transform
+1 Message definition
+1 Transform
+1 Message definition
Adding message type dependent logic/error handling/monitoring Easy as each message type has its own proxy service

Possible but makes the proxy service more complex and harder to maintain Possible but only by adding if/then logic which suffers from the same issues as solution 2.
Adding message type independent logic/error handling/monitoring Difficult as it has to be added to each proxy service Easy as this can be added outside of the if/then logic Easy as everything in the proxy service is message type independent
Changing the incoming message transport/protocol Difficult as every proxy service would need to be changed Easy as there is only one proxy service to modify As solution 2.
Message validity Since the proxy service interfaces will be strongly typed all messages should be valid. The proxy service interface has to be weakly typed to accept multiple message types and so there is more likelihood you will have to handle invalid messages. As solution 2.

In conclusion, I recommend choosing:

Solution 1 – If you have lots of message type dependent logic; need to ensure messages are valid and don’t mind the maintenance overhead

Solution 2 – If you have a few message types; don’t mind modifying the proxy service to add a new message type and don’t want the overhead of managing multiple proxy services

Solution 3 – If you have lots of different message types that change regularly and you don’t want to have to make proxy service changes to add a new message type

I’m keen to hear your thoughts/experiences/comments.

July 16, 2009

Send an Email with a binary attachment from Oracle Service Bus – Part 4

When I started writing this sequence of articles on sending email from Oracle Service Bus I only expected to write 2 parts but following a number of requests asking how to send emails with attachments I wrote Part 3. Now, following a number of people having problems sending email with binary attachments, I’m writing Part 4 – hopefully this will be the last one!

In Part 3 I explained one method for sending a binary attachment, but this relied on your proxy service being a messaging service which had an input message type of binary – fine if the only variable in your outbound email is the binary attachment, but limited if you want a number of components (e.g. subject, to address, etc. ) to be variable.

So, lets create a proxy service of messaging type which has an input message type of XML defined by the following XML schema:

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="
http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.oracle.com/Email" xmlns:tns="http://www.oracle.com/Email" elementFormDefault="qualified">

    <element name="Email" type="tns:EmailType"></element>
    <complexType name="EmailType">
        <sequence>
            <element name="to" type="string" minOccurs="0" />
            <element name="subject" type="string" minOccurs="0" />
            <element name="body" type="string" minOccurs="1" />
            <element name="attachment" type="tns:AttachmentType" minOccurs="1" />
        </sequence>
    </complexType>

    <complexType name="AttachmentType">
        <sequence>
            <element name="name" type="string" minOccurs="1" />
            <element name="type" type="string" minOccurs="1" />
            <element name="content" type="base64Binary" minOccurs="1" />
        </sequence>
    </complexType>
</schema>

i.e. we can specify the to, subject and body fields of the email, plus the attachment name, type and content.

Hopefully you won’t be surprised to see the basic structure of the proxy service message flow is very similar to that described in Part 3:

SendEmailWithBinaryAttachmentProxyMessageFlow

Note the key differences are the addition of a Java callout (this decodes the incoming base64Binary content) and the Transport Header and Replace actions swapping places (this is only to ensure we only replace the payload of the message, once we have extracted all the pieces we are interested in).

The Java callout should look something like (note you may need to click on the images below to see the complete image):

java-callout-properties

This is basically invoking a Java method called decode, in the class BinaryConversion, in the package com.oracle, in the Jar file called binary.jar which will decode the incoming attachment content data. This is not built in functionality in Oracle Service Bus and so you will need to create this class file and Jar file yourself and add it in to your Oracle Service Bus project. The decode method should look like:

public static byte[] decode(String base64binary)
            throws IOException
    {
        BASE64Decoder decoder = new BASE64Decoder();
        return decoder.decodeBuffer(base64binary);
    }

The Insert action properties are basically the same as in Part 3, but with some of the hardcoded information replaced with XPath queries retrieving the information from the incoming message payload. Note the Content-Type must be a valid Internet Media type (MIME type), e.g. for a PDF file it should be application/pdf.

insert-properties

The Transport Header action properties simply specify the values of the to and subject fields:

transportHeaderProperties

And finally, the Replace action simply sets the body of the email to be as defined in the input message:

replace-properties

Note: In order to test this proxy service you will need a base64 encoded version of your attachment available. This can be obtained by using one of the many online tools such as the one available here which allows you to select your file and then convert it to base64 (simply copy and paste the text from the top window into the attachment content field in your test input data).

An example test might look something like:

<ema:Email xmlns:ema="http://www.oracle.com/Email">
    <ema:to>joe.bloggs@oracle.com</ema:to>
    <ema:subject>Email from OSB with binary attachment</ema:subject>
    <ema:body>This is the email body</ema:body>
    <ema:attachment>
        <ema:name>HelloWorld.pdf</ema:name>
        <ema:type>application/pdf</ema:type>
        <ema:content>JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0ZpbHRlci9GbGF0ZURl

………(extra characters removed for brevity)……….

          CjE0MzQ5CiUlRU9GCg==</ema:content>
    </ema:attachment>
</ema:Email>

This should send an email to joe.bloggs@oracle.com, with the subject “Email from OSB with binary attachment”, with an email body “This is the email body” and a binary attachment HelloWorld.pdf containing whatever information it contained originally (in my case simply the text HelloWorld!).

Hopefully this helps answer all the questions on sending emails with attachments from Oracle Service Bus – at least for now :)

My thoughts on service naming conventions

Customers frequently ask me “What naming conventions should I use for my services?” The problem is there isn’t really a right or wrong answer. However, let me share a few of my thoughts based on my customer experience which I hope you’ll find useful:

Use camel case for service names

Service names are often used by tooling to generate associated artifacts, e.g. JMS queues or endpoint URIs, or on platforms where spaces or special characters are not permitted so I highly recommend using camel case (e.g. EachWordStartsWithACapitalLetter) to name your services as this removes the need for these characters while retaining the readability.

Don’t reveal implementation details in the service name

This not only has the potential to lead to confusion if you decide to change the implementation of the service, but is also a security risk as it gives the service consumer an insight into how the service may be implemented which they may be able to exploit.

Don’t include protocol information in the service name

This is generally unnecessary as the service advertises itself at a particular endpoint which clearly defines the protocol to be used.

Don’t include the word service in the service name

Would you add the word Class to every Java class you define? I’m guessing not. So why add the word service, its unnecessary.

Don’t include a version in the service name

Including the version number in the name of the service can also be a recipe for disaster. What happens when you decide to change the service? If the change is major and includes modifying the interface, then you will probably be happy to rename the service and inform all your service consumers of the new service endpoint. However, if the change is minor, do you really want to have to inform all your service consumers of this? If not, the same service name may actually refer to multiple versions of the service – very confusing!

Make sure the name of the service is something sensible

Sounds obvious enough, but I’m sure many of us have seen services called ABCService before! Naming a service like this is a bad idea for 2 reasons. Firstly, no-one is going to have any idea what the service does and so they are not going to reuse it (one of the key benefits of SOA). Secondly, if something goes wrong naming your services sensibly can aid problem diagnosis as you may be able to identify the problem area by just the name itself.

I have to admit, I like Thomas Erl’s suggestion of using utility-centric (e.g. Notify), task-centric (GetProfile) and entity-centric (Customer) names – read more about this in the Service Labelling section of his article on Standardizing Service Endpoints.

Remember services can have operations

This is not true for all services, but many types of service, e.g. web services, can include operations which can be used to group together related functions. I’d argue it makes more sense to have a single Customer service with operations such as get, add, remove, update rather than 4 services called GetCustomer, AddCustomer, RemoveCustomer and UpdateCustomer.

Operation names don’t need to include the service context or parameters

I regularly see operation names along the lines of getCustomerByCustomerID. Now if this is an operation on the Customer service taking in an ID parameter and returning a Customer then I’d argue calling the operation get is sufficient.

By no means is this a definitive list nor do I suggest you have to follow these conventions in your organisation, however I feel it’s a good starting point. I’d be interested to hear your thoughts on the ideas above and other naming conventions in use in your organisation.

It’s also worth noting, these naming conventions only apply to the service interface and this alone is unlikely to be sufficient to define your service fully. You should also consider defining one, or more, service contracts (typically human readable documents) which describe:

- What your service does

- Behaviour characteristics

- Any security requirements

- Performance characteristics

- Quality of service

- Usage charge

These documents should then be stored alongside your service interface definition in your enterprise repository.

April 2, 2009

Sending an Email with an attachment from Oracle Service Bus – Part 3

Some time ago I wrote a two-part blog post describing how you could use Oracle Service Bus to send email and thought I’d covered just about everything people wanted to know about email. However, over the last few weeks several people have asked how to send email with attachments from Oracle Service Bus, something I didn’t cover in those blog posts, and so this is effectively Part 3.

If you didn’t read my earlier blog posts on sending email (Part 1 and Part 2), I suggest you read them now, as I will be referring to them in the remainder of this post.

Developing a service to send an email with an attachment from Oracle Service Bus is not much different from what I have described so far. In general, you will have an email business service which is responsible for actually sending the email (Part 1), and a proxy service, which routes to this email business service, responsible for defining the actual content of the email and attachment(s) (Part 2). The basic structure of the proxy service message flow for sending an email with an attachment will look something like:

emailWithAttachment

We have a single Route node containing a Routing action configured to send messages to our email business service. As in Part 2, the Request Action flow of the Routing action contains the same Replace action (to set the body of the email message) and a Transport Header action (to set the subject of the email message). The key difference here is the addition of the Insert action which describes the attachment we are going to send:

insertProperties2

As you can see in the image above, we are setting the first child element of the attachments context variable to be the XML expression in the yellow box. This expression is the key to sending an attachment, so lets look at it in more detail:

<con:attachment xmlns:con=”http://www.bea.com/wli/sb/context”>….</con:attachment>

This is the wrapper element required for any attachment.

<con:Content-Type>text/plain</con:Content-Type>

This element defines the Internet media type (aka MIME type) of the attachment – in this case a simple text file attachment.

<con:Content-Disposition>attachment; filename=”Simple.txt”</con:Content-Disposition>

This element specifies how the attachment should be handled by the recipient – in this case as an attachment (as opposed to being inline) with a filename of Simple.txt.

<con:body>I am the attachment contents</con:body>

This element represents the actual contents of the attachment.

But I don’t want the filename and/or contents to be hardcoded?

Then simply replace the static values with XPath expressions which will evaluate to the filename and/or contents of your attachment, for example:

<con:attachment xmlns:con="http://www.bea.com/wli/sb/context">
  <con:Content-Type>text/plain</con:Content-Type>
  <con:Content-Disposition>attachment; filename="{$body/email/attachment/filename/text()}"</con:Content-Disposition>
  <con:body>{$body/email/attachment/contents/text()}</con:body>
</con:attachment>

Note the use of the curly braces to ensure this is evaluated as an XPath expression and not just text.

What if my attachment isn’t text?

If your attachment is a binary attachment, such as a PDF, Microsoft Office Document or image, your Insert action properties will be exactly the same, apart from the XML expression which will be slightly different. For example, lets imagine we want to send an attachment called Simple.pdf, our expression will look something like:

<con:attachment xmlns:con="http://www.bea.com/wli/sb/context">
  <con:Content-Type>application/pdf</con:Content-Type>
  <con:Content-Transfer-Encoding>base64</con:Content-Transfer-Encoding>
  <con:Content-Disposition>attachment; filename="Simple.pdf"</con:Content-Disposition>
  <con:body>{$body/ctx:binary-content}</con:body>
</con:attachment>

Note the differences from our earlier example:

- The Internet media type (the Content-Type element) is now the one for a PDF file: application/pdf (for other types of attachment refer to the list of Internet media types here to see what this value should be set to)

- We have added a Content-Transfer-Encoding element which describes how the attachment is encoded (normally in Oracle Service Bus this will be base64).

- The body element (remember this is of the attachment) refers to the binary content within the body of the original message.

But how would I get binary content in the body of the message in the first place?

The simplest way is to make sure your proxy service is a messaging service, using the file transport, expecting an input message of type binary (e.g. a binary file placed in a folder). Oracle Service Bus would read in this file and create a reference to the binary file contained within the ctx:binary-content element within the body. Alternatively, your proxy service may be reading in email which contains binary attachments already.

You can read more about how binary content is handled in Oracle Service Bus here in the documentation.

How can I send multiple attachments?

Simply add another Insert action to insert another attachment to the attachments variable. Unless you are worried about the order of the attachments (only likely for inline attachments) then the only piece that will be different is the content of the XML expression.

   

So, in summary I have shown how to:

- Build a proxy service to send an email with an attachment from Oracle Service Bus

- Configure the Insert action to:

- Send a text or binary attachment

- Dynamically set the filename and contents of the attachments

- Send an email with multiple attachments

If you have anymore questions about how to use the email capabilities of Oracle Service Bus, then let me know by commenting.

November 17, 2008

Dynamic transformations using Oracle Service Bus 10gR3

One of the new features in Oracle Service Bus 10gR3, and one commonly requested by customers, is the ability to choose the transformation to apply to a message based on runtime information - also known as dynamic transformations.

In the previous version of Oracle Service Bus you could only specify the transformation to be performed on the message at design time which may have resulted in:

- Multiple proxy services performing the same mediation logic, but applying different transformations

- A proxy service message flow containing a for loop with a number of cases each performing a different transformation

These scenarios can easily be handled when the number of transformations is small and/or doesn't change regularly but both scenarios involve modifying or creating a proxy service just to add a new transformation. Dynamic transformations allow you to define a proxy service which can handle new transformations being added at a later date.

Let's look at how we might implement a typical scenario where a proxy service accepts multiple versions of a message and applies an appropriate transformation based on the version of the message (determined by the namespace of the root element) in order to convert the message into a common format.

First create a new Oracle Service Bus project called DynamicTransformation (File>New>Oracle Service Bus Project, enter a name of DynamicTransformation and click Finish)

Then create a new schema file called Customer.xsd (File>New>Other>XML Schema) and define the common format with the target namespace http://www.oracle.com/Customer and the following structure:

customer_common_format

Now define a CustomerApplication business service which accepts messages in this format (File>New>Business Service, enter a name of CustomerApplication and click Finish)

Now in the main editor pane, select the General tab for this service and make sure it is defined as a Messaging Service.

Now move to the Messaging tab, set the Request Type to XML and click the Browse button to select the Customer element from Customer.xsd as the message format definition:

Now move to the Transport tab:

- Select the protocol as JMS

- Click Add to accept the default URL or modify it to point to a valid JMS endpoint

(NB. You will need to ensure the connection factory and queue specified in this JMS endpoint exist. If you accept the default, and are running on the default port of 7001 you should only need to create a JMS queue with a JNDI name of CustomerApplicationRequest on the WebLogic Server instance underpinning your Service Bus instance as the connection factory is created for you).

Now move to the JMS Transport tab:

- Select the Message Type as Text and leave the other values as their defaults.

Now test this business service is working as expected by right clicking on it in the Project Explorer and selecting Run As. When the Select Tasks dialog box appears, just click Finish. This should launch the Test Console.

Enter some sample data (the Test Console should have generated the structure for you) and then click Execute.

business_service_testing_customer_application

This should succeed but without a response (this is a one way service and the message has been placed on the CustomerApplicationRequest queue). Navigate to the CustomerApplicationJMS queue and check it contains your message:

customer_application_request

Next create a new schema file called CustomerV1.xsd and define the CustomerV1 format to be in the http://www.oracle.com/CustomerV1 target namespace and have the following structure:

customer_v1 

And one called CustomerV2.xsd defining our CustomerV2 format to be in the http://www.oracle.com/CustomerV2 target namespace and have the following structure:

customer_v2

Next, lets create our transformations: Version1.xq (which converts from CustomerV1 format to the common Customer format):

Version1

And Version2.xq (which converts from Customer V2 format to the common Customer format):

Version2

NB. It is important the target namespaces and transformation filenames are named as described as this is how the correct transformation is selected.

So now we have our transformations and formats defined, the final step is to create our Customer proxy service (File>New>Proxy Service, enter name Customer and click Finish) which will actually perform the dynamic transformation.

In the General tab, select the Service Type to be Messaging Service.

In the Messaging tab, select the Request Type to be XML but don't specify a format (this is because this service can accept both V1 and V2 message formats).

In the Transport tab, select the Protocol to be JMS and accept the default endpoint (the queue and connection factory pointed at by this JMS endpoint will be created for you).

In the Message Flow tab create a message flow like the following which routes to the CustomerApplication business service:

dynamic_transformation_message_fllow

The Assign action extracts the version number (the last digit) from the namespace URI for the Customer element and stores it in the version variable:

assign_properties

NB. The XPath expression here gets the namespace URI of the Customer element (fn:namespace-uri), converts it into a string (fn:string) and then extracts the version number from the end of the string (fn:substring-after).

The Replace action replaces the entire contents of the body with the result of performing the XQuery transformation, the name of which is determined, in this case, by concatenating the static string DynamicTransformation/Version with the value stored in the version variable:

replace_properties 

In order to create the Expression line you need to have clicked in the Expression field and completed the XQuery editor as follows:

xquery_expression_editor

The Bind Variables field defines the variable passed to the transformation. To create this simply enter the name Customer in the Add Custom Variable field and clicked Add. The XPath expression here evaluates to the Customer element within the body, irrespective of namespace.

After completing this, save everything and then launch the Test Console on the Customer proxy service (right click on it and select Run As).

Enter a CustomerV1 format message into the payload field (you can generate a sample one of these by right clicking on CustomerV1.xsd in Workshop and selecting Generate XML).

Then click Execute.

The invocation should succeed without a response - the V1 message should have been transformed to the common Customer format, the CustomerApplication business service invoked and a common Customer format message placed on the CustomerApplicationRequest JMS queue. Check the JMS queue to see this is the case.

Then try the same, but replace the payload with a CustomerV2 format message. This should also succeed without a response - the V2 message having been also transformed to the common Customer format and placed on the CustomerApplicationRequest JMS queue. Again, check the JMS queue to see that this is the case.

That's it. You've just implemented your first dynamic transformation with Oracle Service Bus - congratulations!

NB. A few words of caution when adopting an approach like the one described above. Since your proxy service now has a weakly defined service contract rather than a strongly defined one you will need to describe to your service consumers the message structure(s) your service supports (probably via documentation) and also ensure you have some error handling to deal with unsupported message formats.

Click here for the Oracle Service Bus configuration jar, which includes the Customer proxy service, the CustomerApplication business service, the Customer XML schemas, the transformations and the sample messages.

October 29, 2008

A look at Oracle Service Bus 10g Release 3

Last Friday (24th October) saw the release of Oracle Service Bus 10g Release 3 (download here and read the documentation here) on the Oracle Technical Network (OTN) - the first release of the product formerly known as AquaLogic Service Bus, since the Oracle acquisition of BEA. oracle_service_bus_install_screen

So what's new, apart from the version numbering :)

Oracle branding

The product and documentation have now been re-branded to reflect the new name, Oracle Service Bus. NB. There are a few parts where the product's BEA heritage sneaks through, such as choosing a BEA home directory, etc. but you can expect these to disappear in future releases.

Re-based on Oracle WebLogic Server 10gR3

Oracle Service Bus is still built on WebLogic Server but the version incorporated has moved up to WebLogic Server 10gR3 - the first version of WebLogic Server since the BEA merger. This will be the version on which we aim to standardise all the relevant ex-BEA and Oracle products.

There are a whole raft of new features in this version of WebLogic Server but one which warrants specific mention here is the .NET JMS client which allows .NET applications to natively invoke JMS proxy services hosted on the Oracle Service Bus - something a number of customers had been asking for.

Action metrics

Earlier versions of Oracle Service Bus have allowed you to gather service and pipeline metrics using Oracle Service Bus, i.e. the number of messages, average response time etc. but you can now drill down to the Action level as well. This is incredibly useful for identifying performance hot-spots in your proxy message flow (actions taking a long time to complete) - prime examples are service callouts, Java callouts and transformations. Visit the Monitoring Oracle Service Bus at Runtime section of the documentation for more information.

Message tracing

When you use the Test Console to test proxy and business services hosted on Oracle Service Bus you can see the message being traced through the message flow in the lower section. This is useful for development but not typically something that is used in production. However, operational people may want/need to enable message level tracing temporarily (at a particular level of detail) in order to help diagnose a problem. They can now do this using the new message tracing capabilities exposed in the Oracle Service Bus console. Find out more here.

Visual Debuggingdebug_perspective

If, during development, you have often wanted to know what the values of the context variables are at a specific point in the proxy service message flow, then visual debugging is the feature you've been waiting for.  Simply right click on any action in the message flow, and choose Toggle Breakpoint.  Start the server in Debug mode and then right click on your proxy service and choose Debug As to launch the Test Console. Now when you execute your test, the Debug perspective will be launched showing you where you are in the message flow and the values of the variables at this point. Find out more here.

XOP/MTOM support

Message Transmission Optimisation Mechanism (MTOM) and XML-Binary Optimised Packaging (XOP) help boost the performance of web services transferring binary data by enabling the data to be passed through in a compact format (this article explains the 2 standards in a bit more detail). By simply ticking a check box you can enable your proxy service to receive messages in XOP/MTOM format (find out more here), or enable messages sent from Oracle Service Bus to a business service to be in this format (find out more here).

Dynamic transformations

In earlier versions of Oracle Service Bus when you performed an XQuery transformation you had to specify the name of the transformation file at runtime. This limitation was fine for most use cases however numerous customers want to be able to choose which transformation to perform on a message (typically the payload) based on the value of a field (typically in the header). This new feature allows you to dynamically specify the name of the XQuery transformation to be performed based on a value evaluated at runtime.

Oracle BPEL Process Manager transport

In the past, if you had developed business processes in BPEL Process Manager and were looking to expose them via Oracle Service Bus (a good practice as it promotes loose coupling between the client and the business process itself) then you would have had to expose the business process as a web service or JMS service and then connect to them from Oracle Service bus using the standard SOAP/HTTP transport or JMS transport. This approach is fine but adds an extra, unnecessary, performance overhead. With the new version, there is a new native BPEL Process Manager transport enabling you to connect directly from Oracle Service Bus to BPEL Process Manager through a high performance connection.

Improved REST support

Representational State Transfer (better known as REST) is an architectural style which makes uses a combination of HTTP URLs and HTTP verbs to provide a simple, lightweight, service interface. In Oracle Service Bus we now provide full support for exposing your proxy services as REST services and communicating with REST business services. Within a proxy service message flow you can now get easy access to a number of key pieces of information via the inbound and outbound context variables: the HTTP verb (transport/request/http:http-method); the HTTP query string (transport/request/http:query-string) and the relative URI (transport/request/http:relative-URI). When invoking a business service, you can now specify any one of the standard HTTP verbs: POST, PUT, HEAD, GET, DELETE or even specify your own custom verbs if you so wish. Find out more in the HTTP transport section.

IDE improvements

As well as the Oracle re-branding, one of the new improvements in the IDE is the addition of a Resource Summary which gives you a summary of the resources in your Oracle Service Bus configuration in the same way as the Resources view does through the Oracle Service Bus console. This is a particularly useful view if you have multiple projects deployed on a single Oracle Service Bus instance.

Split-Join Enhancements

In the last version of Oracle Service Bus we introduced the Split-Join capability to allow you to break an incoming message up into a number of parts and perform mediation logic on them in parallel. Within these parallel flows we have now added the ability to perform Java callouts for custom validation, transformation, logging, etc. We have also added the ability to log data at a specified severity to the server log file and the ability to invoke one Split-Join from another Split-Join using a high performance mechanism. Read more here.

Interoperability with Oracle Web Services Manager

Oracle Service Bus allows you to apply security policies to service hosted on the bus, whereas Oracle Web Services Manager allows you to apply security policies to services wherever they are hosted. This release sees support for Oracle Web Services Manager and Oracle Service Bus working in conjunction. The common use cases see Oracle Web Services Manager acting as a gateway for either perimeter security, or identity propagation and acting as a client performing message protection or authentication. These use cases are described in the Securing Oracle Service Bus with Oracle Web Services Manager chapter of the Security topic.

Streaming attachments

In earlier versions we had support for streaming the payload of a message, but now we have added support for streaming attachments to disk. This allows you to process messages with large attachments efficiently. Find out more here.

JCA Adapter Framework

Addition of the JCA adapter framework is an important, but currently invisible to the user, addition to the product. This will allow us to support the same JCA adapters as in BPEL Process Manager. Over the next few months we are looking to certify a few key ones of these against Oracle Service Bus:

- Database
- Oracle AQ
- Oracle E-Business Suite
- Siebel
- JD Edwards
- PeopleSoft
- SAP

And eventually we will move towards supporting the same set as in BPEL Process Manager - incredibly useful additions to the product.

Congratulations to the development team and project management team on getting this completed in less than 4 month since the Oracle-BEA acquisition. Expect to see some more detailed posts on some of these aspects in the coming months.

July 9, 2008

Welcome back......and welcome

To those of you who used to read my Dev2Dev blog whilst I was working for BEA, welcome back and for those of you who are finding this blog for the first time, welcome.

Before I begin posting to this new blog I thought it would be a good idea to introduce myself - at least a bit more than the picture and brief job description you can see to the right :)

My name is Chris Tomkins and I am now a Sales Consultant in the Oracle Fusion Middleware team, focusing on the SOA Suite set of products, in particular Oracle Service Bus (based on the product formally known as AquaLogic Service Bus). Before the Oracle acquisition of BEA I spent 8 months working as a Senior Systems Engineer in Pre-Sales as a technology specialist on the AquaLogic Service Bus product and before that 8 years at IBM working in a number of development and testing roles before spending my last 3 years working on WebSphere ESB in a number of roles culminating in leading the Customer SWAT team.

In terms of this blog I plan to post how to solve common customer problems using the products in the SOA Suite, and some answers to commonly asked customer questions. My aim is to do this in such a way that someone with little experience of the products can make sense of them (I don't expect any of my readers to be product experts!). If you have a problem or question then don't hesitate to post it here and I'll try to do my best to answer it. Also, if you don't understand something in one of my posts, then just add a comment explaining your issue and I'll try to explain things more clearly - I really appreciate reader feedback.

If you are keen to know what the future product strategy and roadmap is following the Oracle and BEA merger, and didn't watch it live on 1st July, then I strongly advise you to take watch Thomas Kurian's webcast. The view from the blogosphere and from customers I've spoken to so far seems to be very positive and all of us in Oracle and really excited about the future.

Enjoy reading!

June 6, 2008

Load balancing in Oracle Service Bus v3.0 (Part 2)

Note: This post was first published before Oracle merged with BEA when the Oracle Service Bus product was known as AquaLogic Service Bus, hence the occasional reference to BEA and AquaLogic Service Bus.

In the last post I demonstrated how to configure a business service in Oracle Service Bus to support load balancing across multiple service endpoints. What we didn't consider was what would happen if one of these endpoints was unavailable for some reason - perhaps due to a network or hardware failure, or just down for maintenance. If we leave things as they are then if a service request gets directed to a service endpoint which is currently offline, then this service request will fail. This is almost certainly not what we want to happen - we would prefer this service request to be redirected to an online service endpoint (if one is available) rather than the offline one. Luckily, Oracle Service Bus comes to the rescue with its new endpoint failover feature. This enables us to automatically mark an endpoint as offline, either temporarily or permanently, and hence ensure service requests are only sent to available online endpoints.

To apply this logic to our business service we need to make a couple of changes to our configuration.

The first step is to enable a retry on our business service so that if the endpoint we attempt to invoke is offline we try to invoke an alternative endpoint. To configure this we need to do the following:

- Open up the business service definition for LoadBalancedService

- Switch to the Transport tab

- Set the Retry Count field to 1

retryCount

This is an improvement over our original configuration. Now, if a service request gets directed to an offline endpoint, service bus will recognise this as an error and try to send the service request to an alternate endpoint. However, if this alternate endpoint is also offline then the service request will fail at this stage, even though there could possibly be an online endpoint available. To handle this case as well, we need to enable the offline endpoint URI capability in Oracle Service Bus.

To do this:

- Right click on the server you have defined in the Servers view of Workspace Studio and choose Launch ALSB Administration Console

- Click on the Resource Browser tab in the left hand navigation

- Select the Business Services link

- Click on your LoadBalancedService business service

- Choose the Operational Settings tab

- Click Create in Change Center to start a new session so you can make a change

- Select the checkbox to enable Offline Endpoint URIs and set a retry interval of 10 seconds

enableOfflineEndpointURIs

- Click Update

- Click Activate in Change Center, enter a description of the change you have made and click Submit to apply your changes

That's all there is to it.

What we have done is configured our business service so that if a service request is sent to an endpoint which happens to be offline, service bus marks this endpoint offline and attempts to send the service request to an alternate endpoint (in accordance with the retry count).  Subsequent service requests will not be sent to the offline endpoint until the offline endpoint URI retry interval has elapsed, at which stage service bus will attempt to start sending service requests to the endpoint. If the endpoint is still offline the cycle will repeat, if it is online the service request will be sent to it.

Note: If you wish to mark an endpoint permanently offline, set the offline endpoint URI retry interval to be 0 hours, 0 mins and 0 seconds. In order to mark this endpoint online again, you will need to do this manually through the service bus console.

Note: If you are using the offline endpoint URI setting, you may well want to consider configuring an alert rule to notify you that an endpoint has gone offline so that you can address this. You can do this by following the instructions here.

To test this works, we need to perform the following tests:

- Using the Test Console, invoke the service twice - this should exercise both endpoints. To check this, simply go to the Operations section of the administration console, click on Service Health, then click on LoadBalancedService (if you do not see this in the list, you need to go back and enable monitoring on your business service) and finally on Endpoint URIs. You should see something like the following (provided you have waited for the monitoring aggregation interval):

endpointURIsTest1

- Now make the first endpoint unavailable (how you do this depends on the service you are calling and where it is hosted - for my example, I will just undeploy the application to simulate the endpoint being unavailable).

- Now, using the Test Console, invoke the service again - this request should be routed to the first endpoint as we are using the round-robin load balancing algorithm but since this endpoint is offline, we should see the service request redirected to the other endpoint. To prove this is the case, take a look at the Endpoint URIs monitoring screen again, which should now look something like:

endpointURIsTest2

- From this we can clearly see that service bus attempted to send the request to the EchoService endpoint and it failed (hence an Error Count of 1) because the endpoint was offline. We can also see that EchoService2 received this request as it is still online.

- Now re-enable the EchoService endpoint and invoke the business service again using the Test Console. If we look at the Endpoint URIs monitoring screen again, we should see that this service request has been directed to the now online again EchoService endpoint.

endpointURIsTest3

We now have a business service which load balances across a set of endpoints and handles the majority of communication related issues we may have with these endpoints. The great thing about this is that this business service can now be used across the rest of the service bus, in any proxy service, in exactly the same way as any other business service.