Skip to Content
Technical Articles

POST complex structure Message via OData adapter in PO

Introduction

In my previous blog poster, the way to post simple message structure message via OData adapter in batch mode has been elaborated.

However in that case, the message type is from a flat structure. In real world, the structure of the message to be post might be multi-layer. Whereas NWDS has a defect for generating xsd from a multi-layer structure OData service. In this blog poster, a way to deal with multi-layer complex structure OData service by using POST $batch mode has been introduced.

 

NWDS Issue

I am not sure SAP is aware of this issue. However it does exist. It looks like, when the message structure becomes complex, the OData adapter in NWDS has difficulty to generate XSD. This is the symptom:

Think about a complex message structure like below

We have implemented an OData service with the above message structure.

When we try to generate information by using OData adapter’s Model Operation as below

there will be popup window indicating edmx file created only. whereas the xsd file has not been created.

 

The XSD file has not been generated. The one listed here was created in the last Blog Post.

 

Solution Implementation

It seems that the fact that the NWDS cannot generate XSD file prevents us from posting a complex structure message to backend by using OData adapter. Whereas there is a walk around via a generic xsd.

Here are the steps.

1. XSD file

Create a request xsd file by using the source code below

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
	<xs:element name="batchParts">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="batchChangeSet" nillable="false" minOccurs="0" maxOccurs="unbounded">
					<xs:complexType>
						<xs:sequence>
							<xs:element name="batchChangeSetPart" nillable="false" minOccurs="1" maxOccurs="1">
								<xs:complexType>
									<xs:sequence>
										<xs:any />
										<xs:element name="method" type="xs:string" nillable="false" minOccurs="1" maxOccurs="1"/>
										<xs:element name="uri" type="xs:string" nillable="true" minOccurs="0" maxOccurs="1"/>
										<xs:element name="headers" nillable="true" minOccurs="0" maxOccurs="unbounded">
											<xs:complexType>
												<xs:sequence>
													<xs:element name="header" nillable="true" minOccurs="0" maxOccurs="unbounded">
														<xs:complexType>
															<xs:sequence>
																<xs:element name="headerName" type="xs:string" nillable="false" minOccurs="1" maxOccurs="unbounded"/>
																<xs:element name="headerValue" type="xs:string" nillable="false" minOccurs="1" maxOccurs="unbounded"/>
															</xs:sequence>
														</xs:complexType>
													</xs:element>
												</xs:sequence>
											</xs:complexType>
										</xs:element>
									</xs:sequence>
								</xs:complexType>
							</xs:element>
						</xs:sequence>
					</xs:complexType>
				</xs:element>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

for synchronous call, please create a generic response xsd file as below

<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" targetNamespace="">
   <wsdl:types>
      <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
         <xsd:element name="batchPartResponse">
            <xsd:complexType>
               <xsd:sequence>
                  <xsd:element name="batchChangeSetResponse" maxOccurs="unbounded">
                     <xsd:complexType>
                        <xsd:sequence>
                           <xsd:element name="batchChangeSetPartResponse" maxOccurs="unbounded">
                              <xsd:complexType>
                                 <xsd:sequence>
                                    <xsd:element name="statusCode" type="xsd:string" />
                                    <xsd:element name="statusInfo" type="xsd:string" minOccurs="0" nillable="true" />
                                    <xsd:element name="contentId" type="xsd:string" minOccurs="0" nillable="true" />
                                    <xsd:element name="headers" minOccurs="0" maxOccurs="unbounded" nillable="true">
                                       <xsd:complexType>
                                          <xsd:sequence>
                                             <xsd:element name="Accept-Language" type="xsd:string" minOccurs="0" maxOccurs="unbounded" nillable="true" />
                                             <xsd:element name="DataServiceVersion" type="xsd:string" minOccurs="0" maxOccurs="unbounded" nillable="true" />
                                             <xsd:element name="Accept" type="xsd:string" minOccurs="0" maxOccurs="unbounded" nillable="true" />
                                             <xsd:element name="location" type="xsd:string" minOccurs="0" maxOccurs="unbounded" nillable="true" />
                                             <xsd:element name="Content-Length" type="xsd:string" minOccurs="0" maxOccurs="unbounded" nillable="true" />
                                             <xsd:element name="cache-control" type="xsd:string" minOccurs="0" maxOccurs="unbounded" nillable="true" />
                                             <xsd:element name="dataserviceversion" type="xsd:string" minOccurs="0" maxOccurs="unbounded" nillable="true" />
                                             <xsd:element name="pragma" type="xsd:string" minOccurs="0" maxOccurs="unbounded" nillable="true" />
                                             <xsd:element name="Content-Type" type="xsd:string" minOccurs="0" maxOccurs="unbounded" nillable="true" />
                                          </xsd:sequence>
                                       </xsd:complexType>
                                    </xsd:element>
                                    <xsd:element name="body" nillable="true">
                                       <xsd:complexType>
                                          <xsd:sequence>
                                             <xsd:any />
                                          </xsd:sequence>
                                       </xsd:complexType>
                                    </xsd:element>
                                 </xsd:sequence>
                              </xsd:complexType>
                           </xsd:element>
                        </xsd:sequence>
                     </xsd:complexType>
                  </xsd:element>
               </xsd:sequence>
            </xsd:complexType>
         </xsd:element>
      </xsd:schema>
   </wsdl:types>
   <wsdl:message name="batchPartResponse">
      <wsdl:part name="batchPartResponse" element="batchPartResponse" />
   </wsdl:message>
</wsdl:definitions>

 

2. Imported Archive

Create Request/Response imported archive by using the xsd files above;

3. Service Interface

Create inbound interface by using the imported archive created. For my showcase, i just create an outbound interface and an inbound interface with the same message structure.

The Operation Mapping uses direct mapping on both request and response direction.

 

4. OData Receiver Configuration

In the Parameters tab page, input the URL of OData service into the address field

 

In the Processing tab page, fill in the Entity Set name into the Operation field and check the flag for batch processing

 

In the Advanced tab page, add parameter ContentTypeEncoding to none.

There are only 6 supported content type in $Batch mode which are fix coded in the system. If you are interested in view them, please setup a break point in method /IWCOR/IF_DS_PROCESSOR~PROCESS of class /IWCOR/CL_DS_PROC_DISPATCHER

mv_header_accept = io_request->get_header_field( if_http_header_fields=>accept ).

The default content type generated by OData adapter is not supported by SAP Gateway service framework. by using this parameter, the message will be acceptable.

 

One more information. The OData adapter only supports XML message. It doesn’t support JSON.

Unit Test

In POSTMAN, input the multi-layer request message as below

in my case, i used a REST sender to receive request message from POSTMAN and a direct mapping forwarding the request into OData Receiver adapter to backend.

This is the response message parsed by OData adapter is like this

If we want to check the raw request data that has been converted by OData adapter from the xml source and the raw response data that OData adapter converted for us into the xml response, please trace it via transaction code /IWFND/TRACES

 

from the trace log view, we can see that OData adapter made 4 times call for one consume and it handled the csrf token by itself.

double click on the first line which is the real request/response process.

This is the raw request message after being converted by OData Adapter from XML

 

This is the raw response message from Gateway Service before it has been converted by OData adapter into XML

 

Conclusion

By using the above generic request/response xsd, all kind of complex message structure can be handled by OData adapter. However the mapping program can only java or xslt. It doesn’t support graphic mapping.

Be the first to leave a comment
You must be Logged on to comment or reply to a post.