Wednesday, September 20, 2006

Dealing with Complex Input Params in ADF Web Service Data Controls

A comment on a recent post prompts me to clarify how Web Service complex input parameters can be used in an ADF application

If the inputs are simple types or a single complex object (not an array of objects) then when you create the ADF Data Control for the service the data control palette gives you the structure of the parameters, enabling you to drag them on to a page as a parameter form or an action of some kind.

To illustrate consider the following method definition:

public Quote processOrderQuote(String productName, String itenType, String partnum, String quantity, String price)

Published as a web service, the complexTypes as seen in the WSDL file look like this:

The ADF Data Control created from the WSDL file uses OrderQuote elements as the String parameters. It wouldn't be my choice to name my parameters param0 - param4, not best practice, but that's the way this WSDL has been created. Dragging the OrderQuote service call onto a page will give you a choice of data bindings - perhaps you need a parameter form so that the input can be recorded directly, or perhaps just a command button or link where the input parameters will be existing data in your application

What about the more complex situation where the input parameter is an array of objects?

To illustrate consider the following method definition:

public Quote processPOItemsQuote(Item[] items)

Published as a web service, the complexTypes in the WSDL file look like this:

And the Data Control looks like this:

In this case the input parameter - the array of objects - is not dealt with directly by the data control. I'm working with JSF so I need to use a managed bean to populate the input parameter, the principle is the same in other UIs too. In my scenario, I need a parameter form for a user to enter the itemId and quantity of the item they want to get a quote on. To keep my example simple, just one item is going to be quoted on - but an array is still needed to fulfill the service's input requirement.

1. I've created a JSF JSP page (getPOQuote.jsp) with a backing bean ( First I want to add my input paramaters to the bean. I've added 2 new variables to the and using JDeveloper I can automatically generate the accessors:

2. Next I need to create a method to populate the array that my service is expecting as a parameter. I added the getItems method:

3. I add two ADF Faces Core: InputText components onto my page and use the Property Inspector(PI) to give them the labels I want

4. Now I want to bind the value of these input fields to my new backing bean attributes. I select the Quantity field and in the PI Value property type #{ and hit enter. This tells the framework that I want to use the Expression Builder(EB) and I can open the EB by clicking the ellipses button.

5. Now I can browse to my backing_getPOQuote managed bean and double-click the quantity attribute to create the expression #{backing_getPOQuote.quantity}. This ensures that the user input to the quantity field is bound to the quantity attribute of the managed bean. I need to repeat this for the Item Id field and bind that to itemId

6. Finally, back in my page I can drag the POItemsQuote(Object) service from the DC palette onto the page as a ADF Command Button. In the Action Binding Editor I can use the ellipses to the right of the Value column to browse to the items attribute of my managed bean (remember in Step2 I created the getItems method in my managed bean) to pass the input object to the service

7. Back in my page, if I open the Page Definition File I can see that the POItemQuote methodAction is now correctly populated with backing_getPOQuote.items being passed in as param0

And that's it, add a page to show the result of the service, add a navigation case to it and run!

Friday, September 15, 2006

SOA and the Database - Heresy?

It comes up a lot at conferences and seminars: Where should my business logic reside - the database or the middle-tier? In the SOA world you might think that using the database was the wrong choice, but why not leverage your existing DB-level validation from your Business Services?

I recently had some correspondence with Kent Graziano of ODTUG fame on just this topic. He says, "essentially we generate the TAPI and the associated DB triggers on all tables. The developers then write simple insert, update, and delete SQL against the tables to pass the required data elements. The triggers fire the TAPI procedures and fill in the auto generated stuff (sequence ids, date created, user created, etc). And voila you get referential integrity without coding in the middle tier. One of our apps is even generating the journal records automatically for audit trail. In addition all these applications rely on Oracle views or materialized views (from our read-only ODS) as the source for all the drop down lists. Seems that may be an SOA-type approach as well since we have abstracted the data one layer above the actual database tables (and we reuse the same view definitions for multiple applications to insure one-source of truth across the apps)."

I don't see anything wrong with this approach. Of course, from an SOA point of view you must ensure that your services are just that, and not too fine-grained, but that can be dealt with in or above the DB level in whatever technology or framework you choose to develop business services in.

Moving forward, it might be that Kent's application developers will take advantage of the benefits of middle-tier business logic and rules - for instance using the ESB and Rules Engine of Oracle's SOA Suite - but that's another discussion! So, am I an SOA-heretic to use database logic and services in the same sentence?