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 (GetPOQuote.java). First I want to add my input paramaters to the bean. I've added 2 new variables to the GetPOQuote.java 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!

20 comments:

Jan Vervecken said...

hi Susan

Suppose the Web Service used in this example has been made available to you by a WSDL, where does the Item class come from that you use in your GetPOQuote.java class?

thanks
Jan Vervecken

Susan said...

Hi Jan

Any complex types described in a WSDL will have a corresponding JavaBean class generated when you use the Web Service Proxy Generator

In this case if I use the Proxy Generator to create the web service proxy from the WSDL file the Item class is generated from the complexType named Item in the WSDL. This is part of the J2EE web service Proxy Generation in JDeveloper
rgds
Susan

Anonymous said...

Thank a lot!

you save my life !

Maitrayee said...

Hi Susan,

I have a requirement of calling a BPEL process which takes as parameter a complex type xml. The xsd structure is something like this:

OrchestrationCustomers (Complex Element)
|-> CustomerNumber (Simple Element)
|-> CustomerName (Simple Element)
|-> OrderHeader (Complex Element)
|->HeaderId (Simple Element)
|->CustomerNumber(Simple Element)
|->OrderLine(Complex Element)
|->Line Id(Simple Element)
|->Product(Simple Element)
|->Quantity((Simple Element)

Moreover, the OrchestrationCustomers and Order Header have a 1:n relationship. The Order Header and OrderLine also have a 1:n relationship.

When I try to add this BPEL Service as a web service to a JSF page, only CustomerNumber(Integer), CustomerName(String) and OrderHeader([Ljava.lang.Object) are among the parameters shown in the Data Control Palette. So, to provide the required arguments, I've created an Object of type OrderHeader with the same structure as in the xsd (including an object of Class OrderLine). Then I've created an array of OrderHeader type with a single member and assigned the array to the parameter(OrderHeader).

When I use this, and run the application in the Debug mode I can see that the entire payload gets created correctly. However when the BPEL process gets invoked, I can see that input received is only: OrchestrationCustomers (Complex Element)
|-> CustomerNumber (Simple Element)
|-> CustomerName (Simple Element)

Hence, while trying to assign some value to some of the Order-child elements, the process errors out.

Could you please throw some light on this issue? Where am I going wrong?

Thanks in advance for your time and effort,
Maitrayee.

satya said...

Hi Susan,

I have to create a webservice proxy for a given wsdl. My WSDL has complextypes, and when i create my proxy i have no problem
but when i call the remote method i get this:

unexpected element type: expected={http://www.siebel.com/xml/Service%20Request%20Detail%20CWx%20CERN}ServiceRequest, actual={http://schemas.xmlsoap.org/soap/encoding/}Array

This is my code:
Query_By_Id queryById = new Query_By_Id();
queryById.setService_Record_ID("1-Y9HGJL");
Query_By_IdResponse resp = myPort.query_By_Id(queryById);
System.out.println("Response = " + resp.toString());

Can you please help me resolve this?
I am trying to solve this for almost a week.

Any help on this is greatly appreciated.

Plz find my WSDL definition for this method alone below:

(the comment section didnt allow tags, so replaced them with --)
Thank you,
Satya

--xsd:element name="Query_By_Id"--
--xsd:complexType--
--xsd:sequence--
--xsd:element name="Service_Record_ID" nillable="true" type="xsd:string"/--
--/xsd:sequence--
--/xsd:complexType--
--/xsd:element--
--xsd:element name="Query_By_IdResponse"--
--xsd:complexType--
--xsd:sequence--
--xsd:element name="Service_Record_Detail" type="bons1:ListOfServiceRequestDetailCwxCernTopElmt"/--
--/xsd:sequence--
--/xsd:complexType--

--xsd:complexType name="ListOfServiceRequestDetailCwxCernTopElmt"--
--xsd:sequence--
--xsd:element maxOccurs="1" minOccurs="1" name="ListOfServiceRequestDetailCwxCern" type="xsdLocal0:ListOfServiceRequestDetailCwxCern"/--
--/xsd:sequence--
--/xsd:complexType--
--xsd:schema xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xsdLocal0="http://www.siebel.com/xml/Service%20Request%20Detail%20CWx%20CERN" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://www.siebel.com/xml/Service%20Request%20Detail%20CWx%20CERN" xmlns:xsd="http://www.w3.org/2001/XMLSchema"--
--xsd:element name="ListOfServiceRequestDetailCwxCern" type="xsdLocal0:ListOfServiceRequestDetailCwxCern"/--
--xsd:complexType name="ListOfServiceRequestDetailCwxCern"--
--xsd:sequence--
--xsd:element maxOccurs="unbounded" minOccurs="0" name="ServiceRequest" type="xsdLocal0:ServiceRequest"/--
--/xsd:sequence--
--/xsd:complexType--
--xsd:complexType name="ServiceRequest"--
--xsd:sequence--
--xsd:element maxOccurs="1" minOccurs="0" name="Created" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="1" name="Abstract" type="xsdLocal0:string100"/--
--xsd:element maxOccurs="1" minOccurs="1" name="Account" type="xsdLocal0:string100"/--
--xsd:element maxOccurs="1" minOccurs="0" name="Area" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="0" name="CHIAResolutionCERN" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="0" name="CatalogIdCERN" type="xsd:string"/--
--xsd:element maxOccurs="1" minOccurs="0" name="CatalogLevel1CERN" type="xsdLocal0:string100"/--
--xsd:element maxOccurs="1" minOccurs="0" name="CatalogLevel2CERN" type="xsdLocal0:string100"/--
--xsd:element maxOccurs="1" minOccurs="0" name="CatalogLevel3CERN" type="xsdLocal0:string100"/--
--xsd:element maxOccurs="1" minOccurs="0" name="CatalogLevel4CERN" type="xsdLocal0:string100"/--
--xsd:element maxOccurs="1" minOccurs="0" name="ClientBaseImpactCERN" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="0" name="CommitTime" type="xsd:string"/--
--xsd:element maxOccurs="1" minOccurs="1" name="ContactLastName" type="xsdLocal0:string50"/--
--xsd:element maxOccurs="1" minOccurs="0" name="ContactLoginCERN" type="xsdLocal0:string50"/--
--xsd:element maxOccurs="1" minOccurs="0" name="CorporateResolutionCERN" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="0" name="CriticalEffectCERN" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="0" name="Description" type="xsdLocal0:string2000"/--
--xsd:element maxOccurs="1" minOccurs="0" name="EntitlementName" type="xsdLocal0:string50"/--
--xsd:element maxOccurs="1" minOccurs="0" name="FreeTextField1CERN" type="xsdLocal0:string100"/--
--xsd:element maxOccurs="1" minOccurs="0" name="IntegrationIdCERN" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="0" name="MnemonicCERN" type="xsdLocal0:string10"/--
--xsd:element maxOccurs="1" minOccurs="0" name="Owner" type="xsdLocal0:string50"/--
--xsd:element maxOccurs="1" minOccurs="0" name="PECAResolutionCERN" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="0" name="Priority" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="1" name="RowStatus" type="xsd:string"/--
--xsd:element maxOccurs="1" minOccurs="0" name="SRNumber" type="xsdLocal0:string64"/--
--xsd:element maxOccurs="1" minOccurs="1" name="SRType" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="0" name="Type" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="0" name="Severity" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="0" name="SolutionCERN" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="0" name="SolutionFamilyCERN" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="1" name="Source" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="1" name="Status" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="1" name="Sub-Status" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="0" name="TeamCERN" type="xsdLocal0:string50"/--
--xsd:element maxOccurs="1" minOccurs="0" name="ServiceRequestType" type="xsdLocal0:string30"/--
--xsd:element maxOccurs="1" minOccurs="0" name="ListOfAction" type="xsdLocal0:ListOfAction"/--
--/xsd:sequence--
>--xsd:attribute name="operation" type="xsd:string"/--
--xsd:attribute name="searchspec" type="xsd:string"/--
--/xsd:complexType--

Susan said...

Satya

Apologies, this fell off my radar. Have you used the OTN JDeveloper forum to get help on this problem? I hope you have resolved it before now!
rgds

Pallavi said...

Hi Susan,

I'm developing a JAX-WS server and client. During my development cycle, I am able to use the web service proxy generation mechanism to get code that can be used on the client side. The generated code is peppered with references to http://localhost:7101/.../...Port?wsdl. Eventually though customers will deploy my service and I need a parameterized client where I can pass in the WSDL URL. What's the easiest way to do this with maximum reuse of generated client code? The client code has warnings not to edit the file.

-Thanks

Susan said...

Here is a more up to date example of using web services in ADF

http://www.oracle.com/technology/products/jdev/howtos/1013/wsadf/adfcomplexwstypes.html

Dark Side said...

Hi Susan, i have a question, do you have any idea, about how can i know if the complex type returned from de web service is popuated or if it is empty before populating the adf table?

I´m trying to get it in order to print an html segment.

Thanks!!!

VB said...

Hi Susan,

I am new to web service. But i need to implement it in my project. The requirement is

In my JSPX page...I have a text field which need to validate the data with outside service provider or with different server (DB). When i enter value it needs to trigger the web service call to validate the enter data through on change or through command button. After validation, i need to throw the msg in my JSPX page. Please help me to develop this service..I am going through all the reference..but if i get step by step or cue cards..it will be very much usefull.

I need to say thanks to all members in forum to answer my querys, because of that i am able to develop the application and now its in production..but still i learned less percentage only..in ADF

Thanks & Regards
VB

Susan said...

VB,

Have you asked this question on the JDeveloper forum? http://forums.oracle.com/forums/forum.jspa?forumID=83

I have to confess that I don't work day to day in web services any more and don't have a quick answer to your request. The folks on the forum are much better helped to work on this type of question

rgds

Susan

Susan said...

VB,

Have you asked this question on the JDeveloper forum? http://forums.oracle.com/forums/forum.jspa?forumID=83

I have to confess that I don't work day to day in web services any more and don't have a quick answer to your request. The folks on the forum are much better helped to work on this type of question

rgds

Susan

James said...

Hi Susan,

I cannot for the life of me make this work. I've followed your examples precisely, I am working in jdev 11g, and attempting to use the PAPI web service.

I keep seeing a fuego.papi.webservice.OperationException error.

Is there some magical trick to making PAPI behave with ADF?

Thanks

- James

Susan said...

James,
This is a very old post and JDeveloper and ADF have come a long way since then! Now you don't have to go to these lengths to work with complex params - ADF should help you all the way. I haven't tested with the PAPI service, but take a look at this blog entry by my colleague Shay - it is a much more uptodate post about complex params
http://blogs.oracle.com/shay/2009/09/web_services_with_complex_data.html

James said...

Hi Susan,

Thanks so much for your quick response!

I've read through Shay's post and the referenced PDF but I'm not sure I'm finding the appropriate info just yet.

In PAPI-WS, one specific call I'm trying to make seems simple enough, an array of objects each containing 3 strings, this is the structure that SOAP UI creates (that works just fine):

pap:instancesAbort>
instanceActivityPairs>
instanceActivityPairs>
activityId> /activityId>
activityName> /activityName>
instanceId> /instanceId>
/instanceActivityPairs>
/instanceActivityPairs>
/pap:instancesAbort>

However in jdev no matter what I've tried the call always appears to look like this: (in the Log):

/env:Header>
env:Body>
ns1:instancesAbort>
instanceActivityPairs/> /ns1:instancesAbort>
/env:Body>

I'm quite confused as I've bound the single parameter (instanceActivityPairs) to a variable of the appropriate jdev-created type of InstanceActivityPairSetBean and init'd all the data throughout.

Any thoughts or other information you could point me towards?

Thank you for your help!!!

- James

Anonymous said...

hello
im a beginner in Jdeveloper
and i need help pleaz
i have 2 input texts fields in which i have to specifie the number of columns and rows
i want to create a button with an action is to create a table with a dimension of the 2 fields
pleaz can one help me
i want a help step by step pleaz an thanks

Susan said...

I cannot answer that from here. I suggest you post your questions on the JDeveloper forum: http://forums.oracle.com/forums/forum.jspa?forumID=83

Anonymous said...

Hi,

Instead of accessing and displaying data from Web Service Data Control on a page, I want to access the Data Control programatically directly in a java class.
Do you know how to get handle of the WS Data Control, methods and return values in a java class?

Anonymous said...

Hi,

Instead of accessing and displaying data from Web Service Data Control on a page,
I want to access the Data Control programatically directly in a java class.
Do you know how to get handle of the WS Data Control, methods and return values in a java class?

Susan said...

check this:

https://forums.oracle.com/forums/thread.jspa?threadID=2347529&tstart=0

You need to access the binding, not the data control.

If you have any further questions on this I suggest you use the forum as I don't work in that area anymore and the forum will provide a better chance of answers
susan