Skip to Content

Introduction


ABAP Web Services (SOAP runtime) is a very powerful technology and with few tips it becomes also more flexible and robust. Virtual Interfaces introduced in SAP Web AS 6.40 provide great
benefits but if you cannot upgrade now then continue to read this weblog.
There are other weblogs on this topic and I suggest to read the followings:

“BSP – a Developer’s Journal Part XIII: Developing ABAP Web Services” by Thomas Jung

“Real Web Services with REST and ICF” by DJ Adams


Headaches due to XML Schemas?


SAP Web AS 6.20 automatically serialize XML to ABAP and vice versa. It is a great feature but what
about if you need more flexibility?
Attributes are not supported and element names are linked to the ABAP dictionary objects.
So, in projects you will normally have to code structures and tables type starting with ZV* (for sales)
and then you will have XML elements called ZV* (not so nice).
It is also quite difficult to produce XML elements completely in lower case (especially the 1st char).

Take the ABAP+XSLT medicine


Do you know ABAP? Do you know XSLT?
If Yes, you can produce XML messages also according to most complicated schema.
Invoke the XSLT processor in your RFC in order to create also the most complex XML document.
Then, move it to an export parameter of type STRING.

So easy?


You are not so lucky and that’s why you will need to continue reading my weblog…
The HTTP handler of the SOAP processor replace <, > and other special chars.

Test it and tell me what happened to your well formatted data…


Here is How-to solve the issue (you will also win a nice SOAP log)

STEP 1 – a new SOAP runtime Class Handler

– in SE24 create a new class handler extending HTTP_EXT_SOAPHANDLER_RFC or coping it

image

– update method IF_HTTP_EXTENSION~HANDLE_REQUEST

image

with the following code:

METHOD if_http_extension~handle_request .

  • Begin of insert

  DATA: o_conv TYPE              REF TO cl_abap_conv_in_ce,

        l_crequest_len           TYPE   i,

        l_crequest               TYPE   string,

        l_cresponse_len          TYPE   i,

        l_cresponse              TYPE   string.

  DATA: l_uuid                   TYPE   sysuuid_c.

  DATA: l_uuid_string            TYPE   string.

  DATA: l_log_file_path          TYPE   string    VALUE ”.   “<– Insert the path where log has to be written

  DATA: l_log_file_name          TYPE   string.

  DATA: l_log_file_sep_req_begin TYPE   string.

  DATA: l_log_file_sep_req_end   TYPE   string.

  DATA: l_log_file_sep_res_begin TYPE   string.

  DATA: l_log_file_sep_res_end   TYPE   string.

  l_log_file_sep_req_begin  = ‘*** Incoming SOAP – Begin **********************************************’.

  l_log_file_sep_req_end    = ‘*** Incoming SOAP – End   **********************************************’.

  l_log_file_sep_res_begin  = ‘*** Outgoing SOAP – Begin **********************************************’.

  l_log_file_sep_res_end    = ‘*** Outgoing SOAP – End   **********************************************’.

  • Log – Get GUID

  CALL FUNCTION ‘SYSTEM_UUID_C_CREATE’

    IMPORTING

      uuid = l_uuid.

  • Log – Build file name

  l_uuid_string = l_uuid.

  CONCATENATE l_log_file_path

              sy-uname

              ‘_’

              l_uuid_string

              ‘.log’

              INTO l_log_file_name.

  • End of insert

  DATA: soap_proc    TYPE REF TO csoaprequestprocessor.

  DATA: rfc_plugin   TYPE REF TO csoaprequestpluginrfc.

  DATA: if_plugin    TYPE REF TO isoaprequestplugin.

  DATA: request   TYPE xstring.

  DATA: response  TYPE xstring.

  DATA: errstrg   TYPE string.

  DATA: errcode   TYPE string.

  CREATE OBJECT soap_proc.

  CREATE OBJECT rfc_plugin.

  if_plugin = rfc_plugin.

  IF soap_proc IS INITIAL

  OR if_plugin IS INITIAL.

    CONCATENATE csoapconstants=>sc_soap_fault_maj_srvr

                csoapconstants=>sc_soap_fault_min_int

      INTO errcode SEPARATED BY ‘.’.

    CALL METHOD csoaptools=>create_simple_string_fault

      EXPORTING

        faultcode   = errcode

        faultstring = ‘Cannot allocate request handler’

      IMPORTING

        stringfault = errstrg.                              “#EC NOTEXT

    CALL METHOD server->response->set_header_field(

      name = ‘Content-Type’

      value = ‘text/xml’ ).

    CALL METHOD server->response->set_cdata( data = errstrg ).

    EXIT.

  ENDIF.

  request = server->request->get_data( ).

  • Begin of insert

  • Convert into STRING

  o_conv = cl_abap_conv_in_ce=>create( input = request ).

  o_conv->read( IMPORTING data = l_crequest len = l_crequest_len ).

  • Log request

  CALL TRANSFORMATION (‘INDENT’)

    SOURCE XML l_crequest

    RESULT XML l_crequest.

  OPEN DATASET l_log_file_name FOR OUTPUT IN TEXT MODE ENCODING UTF-8.

  TRANSFER l_log_file_sep_req_begin TO l_log_file_name.

  TRANSFER l_crequest               TO l_log_file_name.

  TRANSFER l_log_file_sep_req_end   TO l_log_file_name.

  • End of insert

  CALL METHOD soap_proc->process_request

    EXPORTING

      request            = request

      plugin             = if_plugin

    IMPORTING

      response           = response

    EXCEPTIONS

      processing_failure = 1.

  IF sy-subrc NE 0.

    CALL METHOD server->response->set_status(

      code = ‘500’

      reason = ‘Soap document processing failed’ ).

  ENDIF.

  CALL METHOD server->response->set_header_field(

    name = ‘Content-Type’

    value = ‘text/xml; charset=utf-8’ ).

  • Begin of insert

  • Step 1 – Convert into STRING

  o_conv = cl_abap_conv_in_ce=>create( input = response ).

  o_conv->read( IMPORTING data = l_cresponse len = l_cresponse_len ).

  • Step 2 – Replace special STRINGs

  REPLACE ALL OCCURENCES OF

                      ‘<?xml version=”1.0″ encoding=”iso-8859-1″?>’

                      IN l_cresponse WITH ”.

  • Step 3 – Replace special characters

  REPLACE ALL OCCURENCES OF ‘<‘ IN l_cresponse WITH ‘<‘.

  REPLACE ALL OCCURENCES OF ‘>’ IN l_cresponse WITH ‘>’.

  REPLACE ALL OCCURENCES OF ‘”‘ IN l_cresponse WITH ‘”‘.

  REPLACE ALL OCCURENCES OF ”’ IN l_cresponse WITH ””.

  • Step 4 – Convert back to XSTRING

  DATA: oref      TYPE REF TO cl_abap_conv_out_ce.

  DATA: slen      TYPE i.

  DATA: xlen      TYPE i.

  CALL METHOD cl_abap_conv_out_ce=>create

    EXPORTING

      encoding = ‘UTF-8’

      endian   = ‘ ‘         “– or: ‘L’, ‘B’

    RECEIVING

      conv     = oref.

  slen = strlen( l_cresponse ).

  CALL METHOD oref->write

    EXPORTING

      n    = slen

      data = l_cresponse

    IMPORTING

      len  = xlen.

  response = oref->get_buffer( ).

  • Step 5 – Log

  CALL TRANSFORMATION (‘INDENT’)

    SOURCE XML l_cresponse

    RESULT XML l_cresponse.

  TRANSFER l_log_file_sep_res_begin TO l_log_file_name.

  TRANSFER l_cresponse              TO l_log_file_name.

  TRANSFER l_log_file_sep_res_end   TO l_log_file_name.

  • End of insert

  CALL METHOD server->response->set_data( data = response ).

ENDMETHOD.

image

Now attach the CLASS HANDLER created in STEP 1 to this new service:

image

STEP 3 – the Web Service (RFC)

Create a simple RFC enabled function module that export the parameter RESPONSE of TYPE STRING.

image

<BR/>Enjoy invoking your Web Service and do not forget to have a look to the produced log file

(it is called <USER&gt_;<GUID&gt.log in the directory of your SAP Web AS file system)

<BR/>

image


WSDL Generation

Unfortunately no utility can be made available to produce a WSDL describing a response XML schema that
is not known by the system.

Take a while and learn WSDL language, you need to write it manually (if you have the XML schema it’s easy).


Happy SOAP to you…

Sergio

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply