cancel
Showing results for 
Search instead for 
Did you mean: 

HELP for WebDynpro web service model with complex structure

Former Member
0 Kudos

Hello,

I am having trouble calling a Web Service from webdynpro. So far I have been using several simple web services (either internal or external) with just few parameters to be set in the request. All went well until I started to integrate in WebDynpro a more complex one.

The web service I need to call now is an external service that provides interactive customer address correction. Basically it has a structure similar to the following one:

Request_InteractiveSoap_validate (the service itself with execute method)

addInteractiveRequest (structure 0..1)

campaignID (string)

jobToken (string)

addressIn (structure 0..1)

country (string)

locality (string)

postalCode (string)

...

authentication (structure 0..1)

customerID (long)

password (string)

...

parameters (structure 0..1)

capitalization (string)

...

streetWithHNo (string)

Response (structure 0..1)

Result (structure 0..1)

errorMessage (string)

errorCode (long)

resultCount (long)

results (structure 0..N)

elementMatchStatus (string)

resultPercentage (double)

addressOut (structure 0..1)

country (string)

locality (string)

postalCode (string)

...

In WebDynpro I have created a model based on the web service WSDL and bound it to the component controlles as well as to the view controller. At startup I populate request values and then execute the web service on demand with the code that follows.

ComplexType_Authentication auth = new ComplexType_Authentication();

auth.setCustomerID(102822L);

auth.setDepartmentID(0L);

auth.setPassword("********");

ComplexType_Parameters pars = new ComplexType_Parameters();

pars.setCountryOfOrigin("COO_ITA");

pars.setStreetWithHNo(true);

pars.setCountryType("NAME_EN");

pars.setLineSeparator("LST_LF");

pars.setPreferredLanguage("PFL_LANG_EN");

pars.setCapitalization("NO_CHANGE");

pars.setFormattedAddressWithOrganization(false);

pars.setRemoveDiacritics(false);

ComplexType_Address addr = new ComplexType_Address();

addr.setHouseNumber("30");

addr.setStreet("Via Manin");

addr.setCountry("Italy");

addr.setPostalCode("21100");

addr.setLocality("VARESE");

ComplexType_AddInteractiveRequest in = new ComplexType_AddInteractiveRequest();

in.setCampaignID("s45X");

in.setJobToken("token123");

in.setAddress(addr);

in.setParameters(pars);

in.setAuthentication(auth);

Request_InteractiveSoap_validate req = new Request_InteractiveSoap_validate();

req.setAddInteractiveRequest(in);

IPrivateTest.IRequest_InteractiveSoap_validateElement mreq = wdContext.createRequest_InteractiveSoap_validateElement(req);

wdContext.nodeRequest_InteractiveSoap_validate().bind(mreq);

//I also need to bind the followin child nodes or I do not see initial values

//in the GUI elements in the view. ??!!??

wdContext.nodeAddInteractiveRequest().bind(in);

wdContext.nodeAddressIn().bind(addr);

wdContext.nodeAuthentication().bind(auth);

wdContext.nodeParameters().bind(pars);

At some point I call....

//----


// If I use the context bound to the model an uncomplete request is generated

// and the web service returns a complain

//----


IWDMessageManager msg = wdComponentAPI.getMessageManager();

try {

wdContext.currentRequest_InteractiveSoap_validateElement().modelObject().execute();

wdContext.nodeResponse().invalidate();

wdContext.nodeResult().invalidate();

}

catch (Exception e) {

msg.reportWarning(e.getMessage());

}

The response I get is an error. Once executed, the web service receives only the request with a populated addInteractiveRequest (only fields campaignID and jobToken). All other nested structure elements below addInteractiveRequest like addressIn, authentication and parameters are empty despite the values I have set in the model which are also visible in the gui elements of the view controller.

If I call the web service by using the underlying client proxy that is automatically generated by WebDynpro it works well and I get back a populated response.

//----


// If I use the internally generated webservice proxy... it works

//----


IWDMessageManager msg = wdComponentAPI.getMessageManager();

try {

addws.proxies.Interactive ws = new InteractiveImpl();

InteractiveSoap port = ws.getLogicalPort();

AddInteractiveRequest add = new AddInteractiveRequest();

Authentication auth = new Authentication();

auth.setCustomerID(102822L);

auth.setPassword("********");

auth.setDepartmentID(0L);

add.setAuthentication(auth);

Parameters pars = new Parameters();

pars.setCountryOfOrigin("COO_ITA");

pars.setStreetWithHNo(true);

pars.setCountryType("NAME_EN");

pars.setLineSeparator("LST_LF");

pars.setPreferredLanguage("PFL_LANG_EN");

pars.setCapitalization("NO_CHANGE");

pars.setFormattedAddressWithOrganization(false);

pars.setRemoveDiacritics(false);

add.setParameters(pars);

Address addr = new Address();

addr.setHouseNumber("30");

addr.setStreet("Via Manin");

addr.setCountry("Italy");

addr.setPostalCode("21100");

addr.setLocality("VARESE");

add.setAddress(addr);

AddInteractiveResponse res = port.validate(add);

System.out.println(res.toString());

Result[] rres = res.getResults();

for (int ii = 0; ii < rres.length; ii++) {

msg.reportSuccess("Corrected Address:" + rres[ii].getAddress().getFormattedAddress());

}

}

catch (Exception e) {

msg.reportWarning("Error: " + e.getMessage());

}

I also tried to build a stand alone client proxy and this works well too.

My problem seems to be related with the model being generated by WebDynpro. It does not pass/hold the values to the underlying proxy for elements deeper than 1 level.

Am I doing something wrong or is it a bug/limitation of WebDynpro webservice connector? The WSDL I am dealing with is at http://validator2.addressdoctor.com/addInteractive/Interactive.asmx?WSDL

My environment is SAP WAS 6.40 SP14 and NetWeaver Developer Studio SP14.

Please help.

Kind Regards, Vitaliano Trecca

Accepted Solutions (1)

Accepted Solutions (1)

Former Member
0 Kudos

Hello Trecca,

Check out the following links.

Balakrishnan

Former Member
0 Kudos

Thanks Balakrishnan,

I will try play around with what others have done in those threads. By the way, does this mean that WebDynpro has a bug in handling nested web service structures? I never had to hack the model this way to get BAPI/RFC models to work.

Regards

Answers (4)

Answers (4)

Former Member
0 Kudos

Iam working on a similar scenario, have implemented the procedure mentioned in your post, request is going to the server but the response is throwing the below error:

<b>Service call exception; nested exception is: com.sap.engine.services.webservices.jaxrpc.exceptions.XmlUnmarshalException: XML Deserialization Error. XML is not valid. Node <IviewWorkOrders> child of <m:GetworkOrderListResponse> not described in Schema.</b>

Your help would be highly appreciated.

Former Member
0 Kudos

Vitaliano,

It seems I get your error: you are not creating object hierarchy properly. I imported this service and created test application -- everything works excellent.

Here is my code. See lines in bold -- this is what you have to do instead of node.bind():


final Request_InteractiveSoap_validate ws = new Request_InteractiveSoap_validate();
	
final ComplexType_AddInteractiveRequest request = new ComplexType_AddInteractiveRequest();
<b>ws.setAddInteractiveRequest( request );</b>
	
final ComplexType_Address address = new ComplexType_Address();
address.setCountry("USA");
address.setStreet( "Somewhere" ); 
<b>request.setAddress( address );</b>
	
final Authentication auth = new Authentication();
auth.setCustomerID( 1000 );
auth.setDepartmentID( 10000 );
auth.setPassword( "secret" );
<b>request.setAuthentication( auth );</b>
	
wdContext.nodeValidateAddress().bind( ws );

Valery Silaev

EPAM Systems

http://www.NetWeaverTeam.com

Former Member
0 Kudos

Valery,

thank you for your test. By the way I have done again exactly and only what you did and I am still facing the original problem:

If I bind the context from the controller to a view and attach gui elements to see what values nodes contain, address and authentication show empty values despite values that are set during initialization in the controller's code. The only values that get visible in the view is what I set in the request... request.setJobToken("sometext")... nothing else below that node.

Furthermore, why do you use ComplexType_Address for address node and Authentication (from the underlying generated proxy) for authentication node instead of ComplexType_Authentication?

What versions of SAP WAS and Developer studio are you using? I am really confused now. Did yuo make any change to default settings in the model and/or context after you imported the WSDL?

I am pretty sure I am missing some important step but can't see what.

Thanks and regards,

Vitaliano

Former Member
0 Kudos

Vitaliano,

My environment is NW IDE SP11 and server is NW04s (quite tricky combo, I know

I try both ComplexType_<Type> and <Type> methods -- results are the same.

Probably, you can try this "purist" way -- when working with model nodes, modify only model itself, and context nodes will reflect changes automatically. The context -> model mapping is asymmetrical: when you update model context is updated as well but reverse is not true.

Valery Silaev

EPAM Systems

http://www.NetWeaverTeam.com

Former Member
0 Kudos

With the code as follows I solved my problem. I also found another thread where this issue is mentioned for a web service acessing an ABAP function:

It seems the bug is there since SP11 and not solved yet. The workaround is to set child structures to parents using the underlying original beans as we can see in the code. It is obviously not the expected way of behaviour and use of web service models but at least a temporary solution.


final Request_InteractiveSoap_validate ws = new Request_InteractiveSoap_validate();

final ComplexType_AddInteractiveRequest request = new ComplexType_AddInteractiveRequest();
request.setJobToken("JobToken");
request.setCampaignID("campaignID");
ws.setAddInteractiveRequest(request);

final ComplexType_Address address = new ComplexType_Address();
address.setCountry("Italy");
address.setLocality("MyCity");
address.setStreet("My Street");
address.setPostalCode("21100");
address.setHouseNumber("30");
//request.setAddress(address);
<b>request.getOriginalBean().setAddress(address.getOriginalBean());</b>    

final ComplexType_Authentication auth = new ComplexType_Authentication();
auth.setCustomerID(123456L);
auth.setDepartmentID(0L);
auth.setPassword("secret");
//request.setAuthentication(auth);
<b>request.getOriginalBean().setAuthentication( auth.getOriginalBean());</b>
    
final ComplexType_Parameters pars = new ComplexType_Parameters();
pars.setCountryOfOrigin("COO_ITA");
pars.setStreetWithHNo(true);
pars.setCountryType("NAME_EN");
pars.setLineSeparator("LST_LF");
pars.setPreferredLanguage("PFL_LANG_EN");
pars.setCapitalization("NO_CHANGE");
pars.setFormattedAddressWithOrganization(false);
pars.setRemoveDiacritics(false);
//request.setParameters(pars);
<b>request.getOriginalBean().setParameters(pars.getOriginalBean());</b>

wdContext.nodeValidateAddress().bind(ws);

and later on....


IWDMessageManager msg = wdComponentAPI.getMessageManager();
try {
  wdContext.currentValidateAddressElement().modelObject().execute();
  wdContext.nodeResponse().invalidate();
  wdContext.nodeResult().invalidate();
}
catch (Exception e) {
  msg.reportWarning(e.getMessage());
}

Now initial values are properly propagated to the view controller up to GUI elements and all elements are passed to the SOAP message when the web service is executed.

Thanks you all for the feedbacks.

Former Member
0 Kudos

Vitaliano,

I guess it is nothing wrong with WD per se, the reason is how you bind context to model.

These lines really questionable:


/*I also need to bind the followin child nodes or I do not see initial values
in the GUI elements in the view. ??!!??*/
wdContext.nodeAddInteractiveRequest().bind(in);
wdContext.nodeAddressIn().bind(addr);
wdContext.nodeAuthentication().bind(auth);
wdContext.nodeParameters().bind(pars);

Normally, if you set <b>supplyingRelationRole</b> for all sub-nodes (except "root" model node and starting from it) then you have to only bind top-level model object.

Please check whether you set supplyingRelationRole correctly, get rid of extra bind() calls and only invalidate Response after execute.

Valery Silaev

EPAM Systems

http://www.NetWeaverTeam.com

Former Member
0 Kudos

Valery,

I realize the code is questionable but if I do not bind child nodes too I don't get actual values on the GUI. I tried in many ways but only this one did the job with this web service model.

At the very beginning I followed SAP code samples as well as deep re-reading of WebDynpro for java book. For many BAPI/RFC models I followed the "standard" way you are mentioning and always worked well.

By the way supplyingRelationRole(s) for all sub-nodes are set properly.

I may be doing something wrong with this web service but can't figure out what. Any additional suggestion is welcome.

Former Member
0 Kudos

Hi Valery,

A am having problems with a webservice with complexTypes as well.

I used the getOriginalBean way to set the input parameters and when I use a input parameter that has results it works fine....

But when I use an input parameter that has no result, the webservice itself (via SoapUi) returns:

<?xml version="1.0"?>

<ProjectInfoResp>

<Status>Success</Status>

<MessageList>

<Message>Project 122 not Found in IFFMAN</Message>

<MessageType>Warning</MessageType>

</MessageList>

</ProjectInfoResp>

In the wsdl file the output is defined as:

- <xsd:complexType name="__getProjInfoOutput">

- <xsd:sequence>

<xsd:element name="ProjectOut" nillable="true" type="tns:__ProjInfoOut" />

</xsd:sequence>

</xsd:complexType>

- <xsd:complexType name="__ProjInfoOut">

- <xsd:sequence>

<xsd:element name="ProjectInfoResp" type="tns:__ProjectInfoResp" />

</xsd:sequence>

</xsd:complexType>

- <xsd:complexType name="__msgDetail">

- <xsd:sequence>

<xsd:element name="Message" type="xsd:string" />

<xsd:element name="MessageType" type="xsd:string" />

</xsd:sequence>

</xsd:complexType>

- <xsd:complexType name="__ProjectInfoResp">

- <xsd:sequence>

<xsd:element name="Status" type="xsd:string" />

<xsd:element name="ProjectID" type="xsd:string" minOccurs="0" />

<xsd:element name="ProjectDescription" type="xsd:string" minOccurs="0" />

<xsd:element name="PrimaryCC" type="xsd:string" minOccurs="0" />

<xsd:element name="EnduseCode" type="xsd:string" minOccurs="0" />

<xsd:element name="Potential_USD" nillable="true" type="xsd:float" minOccurs="0" />

<xsd:element name="MNC" nillable="true" type="xsd:float" minOccurs="0" />

<xsd:element name="CSP" nillable="true" type="xsd:float" minOccurs="0" />

<xsd:element name="SoldTo" type="xsd:string" minOccurs="0" />

<xsd:element name="OppType" type="xsd:string" minOccurs="0" />

<xsd:element name="OppPriority" type="xsd:string" minOccurs="0" />

<xsd:element name="MessageList" type="tns:__msgDetail" minOccurs="0" maxOccurs="unbounded" />

</xsd:sequence>

</xsd:complexType>

But inside my webdynpro it gives me to following message:

XML Deserialization Error. Can not create instance of class [NULL] when deserializing XML type [http://schemas.xmlsoap.org/soap/encoding/][Array].

Any idea what I should do to solve this error?

Thanks,

Annemarie Vaessen-Simonse

Former Member
0 Kudos

Vitaliano,

Did you test your WS with WSNavigator application?

If no, then try http://12.0.0.1:50000/wsnavigator (you may need to change host / port in url to point your WebAS server). If WSNavigator works, then this is a coding bug. Otherwise it is a bug of WS proxy generator and you may open CSN.

Valery Silaev

EPAM Systems

http://www.NetWeaverTeam.com

Former Member
0 Kudos

Valery,

the web service is an external one and works perfectly outside webdynpro. I.e. called by a stand alone or deployable web service proxy client.

I actually followed the "hack" that others had to implement to get WebDynpro work with complex parameter arguments in the web service request (as pointed out by Balakrishnan) and got it working now.

It definitely seems a bug in WebDynpro model object and conext binding for web services so I have opened a CSN note with my project attached.

In the next post I will add the code that made it work.

Kind regards,

Vitaliano

Former Member
0 Kudos

This is the "hacked" execute workaround method that makes it all work. I.e. it forces again the values from the bound context to the underlying web service model.

It would be nice if somebody can explain why we need to do this.

public void ExecuteFromModelObjectHack( )

{

//@@begin ExecuteFromModelObjectHack()

IWDMessageManager msg = wdComponentAPI.getMessageManager();

try {

Parameters pars = wdContext.nodeParameters().currentParametersElement().modelObject().getOriginalBean();

pars.setCapitalization( wdContext.currentParametersElement().getCapitalization());

pars.setCountryOfOrigin(wdContext.currentParametersElement().getCountryOfOrigin());

pars.setCountryType(wdContext.currentParametersElement().getCountryType());

pars.setFormattedAddressWithOrganization(wdContext.currentParametersElement().getFormattedAddressWithOrganization());

pars.setLineSeparator(wdContext.currentParametersElement().getLineSeparator());

pars.setPreferredLanguage(wdContext.currentParametersElement().getPreferredLanguage());

pars.setRemoveDiacritics(wdContext.currentParametersElement().getRemoveDiacritics());

pars.setStreetWithHNo(wdContext.currentParametersElement().getStreetWithHNo());

Authentication auth = wdContext.nodeAuthentication().currentAuthenticationElement().modelObject().getOriginalBean();

auth.setCustomerID(wdContext.currentAuthenticationElement().getCustomerID());

auth.setDepartmentID(wdContext.currentAuthenticationElement().getDepartmentID());

auth.setPassword(wdContext.currentAuthenticationElement().getPassword());

Address addr = wdContext.nodeAddressIn().currentAddressInElement().modelObject().getOriginalBean();

addr.setBuilding(wdContext.currentAddressInElement().getBuilding());

addr.setContact(wdContext.currentAddressInElement().getContact());

addr.setCountry(wdContext.currentAddressInElement().getCountry());

addr.setCountrySpecificLocalityLine(wdContext.currentAddressInElement().getCountrySpecificLocalityLine());

addr.setDeliveryAddressLines(wdContext.currentAddressInElement().getDeliveryAddressLines());

addr.setDepartment(wdContext.currentAddressInElement().getDepartment());

addr.setFormattedAddress(wdContext.currentAddressInElement().getFormattedAddress());

addr.setHouseNumber(wdContext.currentAddressInElement().getHouseNumber());

addr.setLocality(wdContext.currentAddressInElement().getLocality());

addr.setOrganization(wdContext.currentAddressInElement().getOrganization());

addr.setPOBox(wdContext.currentAddressInElement().getPOBox());

addr.setPostalCode(wdContext.currentAddressInElement().getPostalCode());

addr.setProvince(wdContext.currentAddressInElement().getProvince());

addr.setRecordID(wdContext.currentAddressInElement().getRecordID());

addr.setResidue(wdContext.currentAddressInElement().getResidue());

addr.setStreet(wdContext.currentAddressInElement().getStreet());

AddInteractiveRequest req = wdContext.nodeAddInteractiveRequest().currentAddInteractiveRequestElement().modelObject().getOriginalBean();

req.setAddress(addr);

req.setAuthentication(auth);

req.setParameters(pars);

Request_InteractiveSoap_validate validate = wdContext.currentRequest_InteractiveSoap_validateElement().modelObject();

validate.execute();

wdContext.nodeResponse().invalidate();

}

catch (Exception e) {

msg.reportWarning(e.getMessage());

}

//@@end

}