HaO 2015-04-27: I am attacking the subject to write a more or less generic TCLWS Web Service client for SAP. This is my "progress report page", which might involve the next days when I progress.
Thanks to Gerald W. Lester for the great package !
This is the book I am using for reference: [L1 ]
SAP has many authentication and transport security options. I tried HTTP Basic Authentication and no transport layer security.
Within this clt thread [L2 ], JMar wrote how to use basic authentication:
#-- http basic authentication set authinfo [ base64::encode $szUsername:$szPassword ] set httpHeader [ list Authorization "Basic $authinfo" ] set szResponseDct [ ::WS::Client::DoCall $szServiceName myMethod $myRequest $httpHeader ]
This worked out of the box.
The WSDL file delivered by SAP parses out of the box.
The URL may be taken from SAP "SOAMANAGER" and must include the bindings. URLs from the Web service wizard (SE80) don't contain the binding.
The main Information is that SAP only supports WSDL 1.1 [L3 ]Wikipedia WSDL .
When the service is called without setting any options in TCLWS, one get the error from SAP:
Fehler bei der Web-Service-Verarbeitung; Weitere Details im Web-Service-Fehlerprotokoll auf Provider-Seite (UTC-Zeitstempel ...; Transaktions-ID ...)
this is German, English would be something like: 'Error in Web service processing; more details in the error protocol of the provider'.
Here is the request sent with standard options:
<?xml version="1.0" encoding="utf-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="urn:sap-com:document:sap:rfc:functions" xmlns:tns1="urn:sap-com:document:sap:rfc:functions" xmlns:w="http://schemas.xmlsoap.org/wsdl/" xmlns:d="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns2="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:tns3="http://schemas.xmlsoap.org/wsdl/http/" xmlns:tns4="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns5="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:tns6="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <SOAP-ENV:Body> <tns1:BAPI_NAME> <tns1:MATERIAL>000000000000636339</tns1:MATERIAL> </tns1:BAPI_NAME> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Here is what is proposed by SAP (SE80 F8 "Test Web Service"):
<n0:BAPI_NAME xmlns:n0="urn:sap-com:document:sap:rfc:functions"> <MATERIAL>000000000000636339</MATERIAL> </n0:BAPI_NAME>
When looking to the protocol, one finds out, that the passed variables were not detected.
I checked the available options and tried the with SAP original doc :
Option | Default | After WSDL parse (if different) | Set to | Complementary info |
---|---|---|---|---|
contentType | text/xml;charset=utf-8 | |||
location | http://saphost.de:8025/sap/bc/srt/rfc/sap/zws_bapi_name/001/service0/binding0 | URL to send http request to | ||
skipHeaderLevel | 0 | 0 | No changes on request document | |
skipLevelOnReply | 0 | 0 | Also look for results when Tag <ENV:header> is not present | |
skipLevelWhenActionPresent | 0 | 0 | Removes xml tag '<tns1:BAPI_NAME>' in upper query. Implies 'skipLevelOnReply'. | |
suppressTargetNS | 0 | 0 | 1 | Do not output namespace prefix "tns1:" in front of call variables. In the upper example query, the xml tag '<tns1:MATERIAL>' is replaced by '<MATERIAL>'. This looks much more like the SAP sample. |
targetNamespace | tns1 urn:sap-com:document:sap:rfc:functions w http://schemas.xmlsoap.org/wsdl/ xs http://www.w3.org/2001/XMLSchema d http://schemas.xmlsoap.org/wsdl/soap/ tns2 http://schemas.xmlsoap.org/wsdl/soap12/ tns3 http://schemas.xmlsoap.org/wsdl/http/ tns4 http://schemas.xmlsoap.org/wsdl/mime/ tns5 http://schemas.xmlsoap.org/ws/2004/09/policy tns6 http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd | The book example has none of those. I will remove them in a future try. | ||
parseInAttr | {} | {} | Hard coded to 1. | |
genOutAttr | {} | {} | Utility option hard coded to 1 | |
valueAttrCompatiblityMode | 1 | 1 | How attributes are represented in input/output dict | |
suppressNS | {} | {} | List of namespace prefixes to suppress. Option "suppressTargetNS" sets "tns1" on this list. | |
useTypeNs | {} | {} | Add type namespace in query xml. No change observed. | |
nsOnChangeOnly | {} | {} | Add type namespace in query xml only if different to tns1. No changes observed. | |
noTargetNs | 0 | 0 | 1 | Does not add attribute "xmlns <Targetnamespace>" to request xml tag "SOAP-ENV:Envelope". In the example query, this is 'xmlns="urn:sap-com:document:sap:rfc:functions"'. This is also the case in the example in the book so I tried this option. |
errorOnRedefine | 0 | 0 | Allow to add a service with the same name as an existing service. | |
allowOperOverloading | 1 | 1 | An operation may exist twice in the WSDL | |
UseNS | {} | WS utility option hard coded to 0. | ||
ValueAttr | {} | WS utility option hard coded to {}. |
Here is what was sent with options "suppressTargetNS" and "noTargetNs" and with worked with SAP:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns1="urn:sap-com:document:sap:rfc:functions" xmlns:w="http://schemas.xmlsoap.org/wsdl/" xmlns:d="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns2="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:tns3="http://schemas.xmlsoap.org/wsdl/http/" xmlns:tns4="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns5="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:tns6="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <SOAP-ENV:Body> <tns1:BAPI_NAME> <MATERIAL> 000000000000636339 </MATERIAL> </tns1:BAPI_NAME> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Here is the response of SAP:
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"> <soap-env:Header /> <soap-env:Body> <n0:BAPI_NAMEResponse xmlns:n0="urn:sap-com:document:sap:rfc:functions"> <MATERIALPLANTDATA> <PUR_GROUP /> <ISSUE_UNIT /> </MATERIALPLANTDATA> <MATERIAL_GENERAL_DATA> <MATL_DESC>Sunshine in Boxes</MATL_DESC> </MATERIAL_GENERAL_DATA> <RETURN> <TYPE>S</TYPE> <CODE /> <MESSAGE /> <LOG_NO /> <LOG_MSG_NO>000000</LOG_MSG_NO> <MESSAGE_V1 /> <MESSAGE_V2 /> <MESSAGE_V3 /> <MESSAGE_V4 /> </RETURN> </n0:BAPI_NAMEResponse> </soap-env:Body> </soap-env:Envelope>
and the returned dict looks as follows:
{ MATERIALPLANTDATA { PUR_GROUP {} ISSUE_UNIT {} } MATERIAL_GENERAL_DATA { MATL_DESC "Sunshine in Boxes" } RETURN { TYPE S CODE {} MESSAGE {} LOG_NO {} LOG_MSG_NO 000000 MESSAGE_V1 {} MESSAGE_V2 {} MESSAGE_V3 {} MESSAGE_V4 {} }
Well dont, TCLWS !