SAP Gateway
Browsing All 253 Articles Latest Live
Mark channel Not-Safe-For-Work? cancel confirm NSFW Votes: (0 votes)
Are you the publisher? Claim or contact us about this channel.

SAP CodeJam


In this blog I am collecting information about what you can do in advance when attending a SAP CodeJam about SAP Gateway and provide links about SCN blogs that we will use in such an event.


What to prepare in advance


*Remember this is a "bring your own laptop" event**

You have to bring your own laptop with you. On this you have to have installed SAPGUI to work with the SAP Gateway design time, the SAP Gateway Service Builder. In addition you need a browser to access the SAP Web IDE.

Gateway System

We will provide a SAP Gateway Sandbox system for the time of the event. This will however be dismantled afterwards. So if you want to work in a system that is available after the event we recommend to go for a SCN Trial Editions of SAP NetWeaver Application Server ABAP 7.5. More information how to get your hands on a trial version can be found here: http://www.sap.com/abaptrial



In order to connect to the Gateway System and to develop your own services you have to have SAPGUI installed on your desktop.

If not already installed you can get it here: http://www.sdn.sap.com/irj/sdn/index?rid=/webcontent/uuid/1024acfb-5b30-2e10-f2bd-ccce5d8692b1


Please note:

Though the link above tells you that you will be downloading a "SAP NetWeaver Application Server ABAP 7.03 64-bit Trial" you will get a mail that contains several download links so that you are able to download SAPGUI only without the need to download a complete ABAP AS 7.03 .



In order to generate a SAP UI5 application that can consume the OData service that you are going to build we will use SAP Web IDE.

There is no need to install anything on your laptop since SAP Web IDE runs in the SAP HANA Cloud platform.

The only thing that you have to do is to register for a free HCP developer account using your SCN credentials.

This you can do here: SAP HANA Cloud Cockpit

A file to import the destination of the ABAP demo system we use has been attached to this blog. You only have to replace the IP-Address that we will share with you when you attend the event.

Get the ABAP Development Tools for Eclipse

Install the latest version of the ABAP Development Tools for Eclipse from the update site SAP Development Tools for Eclipse. This tool is needed if you want to create your own CDS view.


How To Guides


OData service development with SAP Gateway - code-based service development - Part I


OData service development with SAP Gateway - code-based service development - Part II


OData service development with SAP Gateway using CDS via Referenced Data Sources

OData service development with SAP Gateway using CDS via Referenced Data Sources - How to implement updates

Closing session of Soft State OData service




I would like to share the idea how you can manage or kill the session of your Soft State OData Service.

For more information regarding Soft State Support for OData Services look here: http://help.sap.com/saphelp_gateway20sp09/helpdata/en/f6/5f8e5318e83d27e10000000a44538d/content.htm

and here:


As discussed, you will probably implement Stateful or Soft State OData in the applications, where you can gain a lot from this. This can be any application, which is continuously working with considerable amount of data. Typical example would be taking an order with many items and complex pricing or very complex and flexible reports, which are working with the data stored in the memory. By default, your session will timeout according to the settings you set up for your service in the transaction SICF.

Now it comes a tricky question, how big should this timeout be? 1 hour or maybe 1 second? You’llsay, depends on the application. Yes, true. But, isn’t it better to make it manageable?

Imagine in your order taking application you have simply forgotten, or maybe it is just not possible, to release the memory after the order is finished. Your memory will be leaking, right? Even closing the browser will not help. You will see more and more pending sessions in SM04 (AL08) transaction, consuming more and more memory of your system.


Below I will describe one way how you can close the Soft State OData session programmatically.

First, what you need to know that it is possible to kill this session right from transaction SM04. Therefore, we will simulate exactly this step.

You can get the session information using CL_SERVER_INFO => GET_SESSION_LIST. After that, you will need to call the function TH_DELETE_USER to kill this session. Let’s to a simple function, where the input parameter would be a path to the OData service.

*"*"Local Interface:
include: tskhincl.
data: server_info  type ref to cl_server_info.
data(lv_path) = iv_path.
translatelv_pathto upper case.
createobject server_info.
data(session_list) = server_info->get_session_list( with_application_info = 1
= sy-mandt ).
loop at session_list assigning field-symbol(<fs_session_info>)
where user_name  = sy-uname
and logon_type= 3
and logon_sub_type= 4
and act_program= 'SAPMHTTP'.
translate<fs_session_info>-application_info to upper case.
call function 'TH_DELETE_USER'
= sy-uname
client          = sy-mandt
= <fs_session_info>-logon_hdl
= <fs_session_info>-logon_id
= 1
others          = 2.
ifsy-subrc<> 0.


Then you need to call this function somehow. In my case, the function TH_DELETE_USER does not work if I call it from the same session, which I am trying to kill. Don’t know why, but it was the case. Therefore, you need to call it from another session, which can be another OData service or simply a web-rfc function.

I used the last option. For more information regarding web-rfc, see here: http://scn.sap.com/community/netweaver-as/blog/2012/08/07/webrfc--simply-calling-an-rfc-from-javascript

So, the function looks very simple.

*"*"Local Interface:
*"       'application/json'
data: path type string.
data: rctype numc5.
read table query_stringwith key name = '_OdataSrv'.
= query_string-value.
= path
= rc.
data: htmldoclike line of html.
concatenate'{"results": [ {"key": "path", "value": "' path '"},'
' {"key": "error", "value": "' rc '"}]}' into htmldoc-line.
inserthtmldocinto table html.


After that, you just need to call it via the URL: http://<server>:<port>//sap/bc/webrfc?_FUNCTION=<FUNC_NAME>&_OdataSrv=<SERVICE_PATH>

At last, you need to create a JavaScript function and attach it to proper event (e.g. window.onbeforeunload / window.addEventListener) or a button. From there you can call the above URL, for instance as AJAX request.

Hope it was useful.

If you find any mistake or a bug, or have a better solution, do not hesitate to comment it cout.

BR, Dima



Uninstallation of SAP Gateway add-ons IW_FNDGC, IW_GIL, IW_SPI, IW_SCS, IW_CNT 200 and IW_CBS 200




SAP Gateway consist out of several add-ons. Some of them are mandatory while others are only optional and some are even legacy. A complete list of SAP Gateway add-ons can be found in the SAP Online Help Installing SAP Gateway Components - SAP Gateway - SAP Library


So far all of the above mentioned add-ons have to be maintained and upgraded in a customer system landscape once you have installed them because it was not possible to uninstall SAP Gateway add-ons in the past. In the "worst case" you could have up to ten SAP Gateway add-ons installed in your SAP Gateway Hub and SAP Business Suite Backend


In order to offer the option to simplify your SAP Gateway landscape and because several of the SAP Gateway add-ons will not be supported by S/4 HANA you have now the option to uninstall the following SAP Gateway add-ons:


  • IW_SCS 200, IW_CNT 200 and IW_CBS 200
  • IW_GIL 100 and IW_SPI 100
  • IW_FNDGC 100


In the following two pictures these uninstallable add-ons have been marked with red.


The add-ons GW_CORE, IW_FND, IW_BEP and IW_HDB are not uninstallable since their content became part of the software component SAP_GWFND which is part of the SAP Basis as of SAP NetWeaver 740.

If we have a look at the add-on / software component structure of SAP Gateway as of SAP NetWeaver 740 it turns out that the total number of add-ons / software components that are mandatory and thus not uninstallable has been reduced to two add-ons while up to six add-ons are now uninstallable.


Please note that IW_PGW is used for SAP Fiori applications such as the MyInbox and that it is planned to include the coding into the software component SAP_GWFND as well.




As mentioned above there are two reasons why you may want to remove an SAP Gateway add-on:


1. Remove add-ons that are not needed


As said, some of the add-ons only contain legacy functionality such as the screen scraping generator (IW_SCS) as well as (outdated) content which is based on the so called generic channel (IW_CNT and IW_CBS). Therefore you can uninstall these add-ons unless you are using services that are based on these legacy components. See SAP Note 2312680 for more details.


The add-on IW_FNDGC is only needed for customers using the above mentioned (outdated) services based on the Generic Channel when they upgrade their SAP Gateway Hub to SAP NetWeaver 740. This is because the add-ons IW_CNT and IW_CBS do depend on components that are shipped with the add-on IW_FNDGC. Therefore you can uninstall this add-on as well once you have uninstalled the add-ons IW_CNT and IW_CBS mentioned above.

This leaves us to the add-ons IW_GIL and IW_SPI. These add-ons were developed to allow customers to generate OData services using SEGW in a process called redefinition based on Service Provider Interface objects or GenIL objects. Customers that have installed these add-ons but are not using any service that has been generated based on these add-ons can benefit from the uninstallation option as well.


2. Transition to S/4 HANA


With the transition to S/4 HANA it was decided to not support all add-ons of SAP Gateway since not all of them are used within S/4 HANA and are thus not needed to build OData in S/4 HANA. As a result it was necessary to make these add-ons uninstallable so that they can be uninstalled before starting a transition of a customer SAP Business Suite System to S/4 HANA.


How to remove an SAP Gateway add-on?


1. Import SAINT update


As described in SAP Note 2011192 - Uninstalling ABAP add-ons as of Version 0053 of the SAP Add-On Installation Tool, not only can you install ABAP add-ons, but you can also uninstall them again in certain circumstances.

As of version 0061 it is now possible to uninstall the above mentioned SAP Gateway add-ons using SAINT.


2. Import Attribute Change Packages


Since the service packs in your system are not yet marked as uninstallable you have to import so called Attribute Change Packages that will change the uninstallable attribute of your service pack accordingly. How to find the ACPs is described in SAP Note 1119856 - Description, tips and tricks for Attribute Change Packages


The names of the ACPs you might be looking for are the following









You can search for them via the new launchpad UI from SAP quite easily if you use the following URL




Search ACP for IW_SPI.png


After you have updated SAINT to at least version 0061 you can upload the ACP into SAINT directly from your front end. As described in the note above you do not have to import them. Instead, they already take effect when you upload them into the system when you use the function "Load From Front End") so that they show up in the tab "Deinstallable components".


The following screen shot shows SAINT after the above mentioned ACP IW_SPI====200 has been uploaded.


After upload of ACP IW_SPI.png


More information


You will find more detailed information about the uninstallation procedure and the technical prerequisites in the following SAP Notes:


SAP Gateway 2.0



SAP NetWeaver 7.40


Using SEGW and ABAP in Eclipse


In one of my last blogs about code based OData service development using the SAP Gateway Service Builder (SEGW) I got the (valid) question from Joachim Rees whether I would commend using SE24 to get the ABAP-Code in the generated classes or whether the developers shouldn't use eclipse for that?


I have to admit that I might have been a little bit old fashioned working mostly with SAPGUI and SEGW/SE24. But ABAP in Eclipse has definitely several advantages when you are developing ABAP code.


However the Service Builder is a SAPGUI transaction and like DDIC structures you have to create your SEGW project using SAPGUI. Fortunately there is a nice integration between ABAP in Eclipse and SAPGUI if you start SAPGUI from within ABAP in Eclipse.


So I thought it would be a good idea to show how to start SEGW from within ABAP in Eclipse.


  • Since there has to be at least one ABAP project in your workspace you first have to open the 'ABAP Project Creation Wizard' in order to create a new ABAP project.


  • You then have to select your system and connect to the same
  • Once you have connected to the system an new folder has been created. Choose the "Open SAPGUI button"

  • You will be prompted on which project the SAPGUI should be launched. Select the newly created project.


  • SAPGUI will be opened in a new tab. Here we can start SEGW
  • You can now follow the steps described in my blog OData service development with SAP Gateway - code-based service development - Part I
  • After you have generated your runtime objects you can edit your classes using ABAP in Eclipse by choosing "Go to ABAP Workbench" when right clicking on the DPC_EXT classe in the Runtime Artifacts folder
  • This will now start ABAP in Eclipse rather than SE24.


Have fun using ABAP in Eclipse

A workaround to have Gateway Tool installed in Eclipse Mars

Step-by-Step procedure for CREATE_DEEP_ENTITY in POST operation


For beginners facing issues in creating deep entity for more than one item table for single header.

I will explain how to create SAP Netweaver gateway OData service which will implement  Create Deep Entity for POST operation.

This is for single header and multiple item table.

For example:Header Details:Order notification

                   Item     Details:Order component

                                         Order operation

                                         Order header

                                         Maintenance plan detail


  • Create an custom RFC


  • Create project in T-code 'SEGW'
  • Create 6 entity types and entity sets


        Entity Type 1 -  notif

        Entity Type 2 -  ord_hdr

        Entity Type 3 -  ord_comp

        Entity Type 4 -  ord_opr

        Entity Type 5 -  mpos

        Entity Type 6 -  return(created to hold multiple messages of type BAPIRET2)



        Entity Set 1 - notifSet

       Entity Set 2 - ord_hdrSet

        Entity Set 3 - ord_compSet

        Entity Set 4 - ord_oprSet

        Entity Set 5 - mposSet

        Entity Set 6 - returnSet




  • Create Association and Navigation

       Association 1  notif_comp   (entity notif to ord_comp with cardinality 1:N)

       Association 2  notif_hdr      (entity notif to ord_hdr     with cardinality 1:1)

       Association 3  notif_mpos   (entity notif to ord_mpos with cardinality 1:1)

       Association 4  notif_opr     (entity notif to ord_opr     with cardinality 1:N)

       Association 5  notif_return  (entity notif to ord_return with cardinality 1:N)


  • Navigation property

       Navigation  1     notif_return_nav

       Navigation  2     notif_mpos_nav

       Navigation  3     notif_comp_nav

       Navigation  4     notif_opr_nav

       Navigation  5     notif_hdr_nav





Now let’s generate runtime artifacts. Click on generate runtime object button. It will display

popup . Keep the default class names as-is and click on enter button.


Once generation is successful, you will get 4 classes. 2 for Data provider and 2 for Model provider.



Once registration done successfully .Goto Gateway Client ( call transaction /IWFND/GW_CLIENT to open SAP NW Gateway client)

Append $metadata to base service URL and press execute button. If everything is fine then you will get HTTP

Response as below. Metadata provides information such as Entity type, key property, properties and Entity Set

name and also check service document append ?$format=xml.





      Select ***_MPC_EXT class

      Go to “Types” tab and add new type which is similar to your deep entity structure


     Type decleration :



    BEGIN OF ts_deep_entity ,

      qmnum               TYPE qmnum,

      code                   TYPE char4,

      fllogid                  TYPE diacl_logid,

      tllogid                  TYPE diacl_logid ,

      sectref                TYPE zsectref,

      func_location       TYPE tplnr,

      erdat                   TYPE char15,

      qmnam               TYPE qmnam,

      faultcode            TYPE  zfaultcode,

      asr_gfor              TYPE  boolean,

      nildef                  TYPE  boolean,

      defcode              TYPE  zdefcode,

      def_pos              TYPE  zdef_pos,

      techlog               TYPE ztechlog,

      dd_ltext              TYPE  char200,

      dd_ltext1            TYPE  char200,

      action_text         TYPE  char200,

      action_text1       TYPE  char200,

      structural           TYPE  boolean,

      comp_replacement    TYPE  boolean,

      material_request       TYPE  boolean,

      source                      TYPE  qmgrp,

      dd_order                    TYPE  aufnr,

      dd_notif                     TYPE  qmnum,

      due_date                  TYPE  char15,

      mech                       TYPE  char10,

      inspection                TYPE  char10,

      license                    TYPE  char10,

      add_auth                 TYPE  zadd_auth,

      cross_ref                 TYPE  char25,

        werks                    TYPE werks_d,

      msg_type                TYPE   char1,

      msg_text                 TYPE   char80,

      order_no                  TYPE   aufnr ,

      notif_comp_nav      TYPE STANDARD TABLE OF ts_ord_comp

                                   WITH DEFAULT KEY,

      notif_opr_nav       TYPE STANDARD TABLE OF ts_ord_opr

                                    WITH DEFAULT KEY,

      notif_hdr_nav       TYPE  ts_ord_hdr,

      notif_mpos_nav      TYPE  ts_mpos,

      notif_return_nav TYPE STANDARD TABLE OF  ts_return

                               WITH DEFAULT KEY,

      END OF ts_deep_entity .



      Redefine the method “DEFINE” in the class.



Include the following code in Define method.


super->define( ).


lo_annotation     TYPE REF TO /iwbep/if_mgw_odata_annotation,

lo_entity_type    TYPE REF TO /iwbep/if_mgw_odata_entity_typ,

lo_complex_type   TYPE REF TO /iwbep/if_mgw_odata_cmplx_type,

lo_property       TYPE REF TO /iwbep/if_mgw_odata_property,

lo_entity_set     TYPE REF TO /iwbep/if_mgw_odata_entity_set.




*   ENTITY - Deep Entity



lo_entity_type = model->get_entity_type( iv_entity_name = 'notif' ).




lo_entity_type->bind_structure( iv_structure_name  =




  • Create a custom method 'CUSTOM_CREATE_DEEP_ENTITY' in class '***CL_LI5_LBK__14_DPC_EXT'' whose parameters is similar to

       parameters of method '/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_DEEP_ENTITY'.The only change we need to make is replace the type of                  'ER_DEEP_ENTITY' to the type which we specified in class '***CL_LI5_LBK__14_MPC_EXT=>TS_DEEP_ENTITY'.




METHOD custom_create_deep_entity.





  CONSTANTS:c_crt        TYPE    char4         VALUE    'CRT'    ,

                      c_crad      TYPE    char4         VALUE    'CRAD'   ,

                      c_u          TYPE    char1         VALUE    'U'      ,

                      c_read      TYPE    char4         VALUE    'READ'   ,

                      c_clrd       TYPE    char4         VALUE    'CLRD'   ,

                      c_clsd      TYPE    char4         VALUE    'CLSD'   ,

                      c_upd       TYPE    char3         VALUE    'UPD'    ,

                      c_a          TYPE    char1         VALUE    'A'      .



  TYPES:BEGIN OF return_msg,

        type    TYPE bapi_mtype,

        message TYPE bapi_msg,

        END   OF return_msg.



  DATA:lt_ret_msg TYPE


       ls_ret_msg TYPE  /tcsmro/cl_li5_lbk__14_mpc_ext=>ts_return.




lr_deep_entity TYPE ***cl_li5_lbk__14_mpc_ext=>ts_deep_entity,

lt_ord_comp   TYPE ***cl_li5_lbk__14_mpc_ext=>tt_ord_comp,

ls_ord_comp  TYPE ***cl_li5_lbk__14_mpc_ext=>ts_ord_comp,

lt_ord_opr      TYPE ***cl_li5_lbk__14_mpc_ext=>tt_ord_opr,

ls_ord_opr     TYPE ***cl_li5_lbk__14_mpc_ext=>ts_ord_opr,

lt_mpos         TYPE ***cl_li5_lbk__14_mpc_ext=>tt_mpos,

ls_mpos        TYPE ***cl_li5_lbk__14_mpc_ext=>ts_mpos,

lt_ord_hdr      TYPE ***cl_li5_lbk__14_mpc_ext=>tt_ord_hdr,

ls_ord_hdr      TYPE ***cl_li5_lbk__14_mpc_ext=>ts_ord_hdr,

e_msg_type   TYPE char1,

e_msg_text    TYPE char40,

lt_return         TYPE  ***cl_li5_lbk__14_mpc_ext=>tt_return,

ls_return         TYPE ***cl_li5_lbk__14_mpc_ext=>ts_return.



  DATA :

  ls_general_data TYPE ***li5_lbk_notification,

*ls_general_data TYPE ***LI5_LBK_NOTIF,

*ls_general_data TYPE ***LI5_LBK_NOTIFICATION,

  lt_ord_comp_data TYPE STANDARD TABLE OF ***li5_lbk_ord_comp,

  ls_ord_comp_data TYPE  ***li5_lbk_ord_comp,

********component to RFC structure

  lt_ord_comp_data1 TYPE STANDARD TABLE OF bapi_alm_order_component_e,

  ls_ord_comp_data1 TYPE  bapi_alm_order_component_e,


  lt_ord_opr_data TYPE STANDARD TABLE OF ***Li5_lbk_ord_opr,

  ls_ord_opr_data TYPE ***/li5_lbk_ord_opr,

********operation to RFC structure



  lt_ord_opr_data1 TYPE STANDARD TABLE OF bapi_alm_order_operation_e,

  ls_ord_opr_data1 TYPE  bapi_alm_order_operation_e,





******order header

  lt_ord_hdr_data TYPE STANDARD TABLE OF ***li5_lbk_ord_hdr,

  ls_ord_hdr_data TYPE ***li5_lbk_ord_hdr,

********order header to RFC structure

  lt_ord_hdr_data1 TYPE STANDARD TABLE OF bapi_alm_order_header_e,

  ls_ord_hdr_data1 TYPE bapi_alm_order_header_e,






  lt_mpos_data TYPE STANDARD TABLE OF ***li5_lbk_mpos,

  ls_mpos_data TYPE ***li5_lbk_mpos,

********MPOS to RFC structure

  lt_mpos_data1 TYPE STANDARD TABLE OF mpos,

  ls_mpos_data1 TYPE  mpos,



  ls_mposf    TYPE ***cl_li5_lbk__14_mpc_ext=>ts_mpos.




  <ls_ord_compf> TYPE    ***cl_li5_lbk__14_mpc_ext=>ts_ord_comp,

  <ls_ord_oprf>     TYPE   ***cl_li5_lbk__14_mpc_ext=>ts_ord_opr,

  <ls_ord_hdrf>      TYPE ***cl_li5_lbk__14_mpc_ext=>ts_ord_hdr.





        lr_message_container  TYPE REF TO /iwbep/if_message_container,

        lv_message                 TYPE bapi_msg     ,

        lv_msgid                     TYPE symsgid      ,

        lv_msgno                    TYPE symsgno      .

*lr_message_container = me->mo_context


*  Transform data into the internal structure




  es_data = lr_deep_entity ).

***********Collect the header fields here

  ls_general_data-qmnum             = lr_deep_entity-qmnum.

  ls_general_data-code              =  lr_deep_entity-code.

  ls_general_data-aufnr             =  lr_deep_entity-order_no.

  ls_general_data-fllogid           = lr_deep_entity-fllogid .

  ls_general_data-func_location     =  lr_deep_entity-func_location.

  ls_general_data-strmn             = lr_deep_entity-erdat.

  ls_general_data-qmnam             = lr_deep_entity-qmnam.

  ls_general_data-/smr/faultcode    = lr_deep_entity-faultcode.

  ls_general_data-/smr/asr_gfor     = lr_deep_entity-asr_gfor.

  ls_general_data-/smr/nildef       = lr_deep_entity-nildef.

  ls_general_data-/smr/defcode      = lr_deep_entity-defcode.

  ls_general_data-/smr/def_pos      = lr_deep_entity-def_pos.

  ls_general_data-/smr/techlog      = lr_deep_entity-techlog.

  ls_general_data-dd_ltext          = lr_deep_entity-dd_ltext.

  ls_general_data-dd_ltext1         = lr_deep_entity-dd_ltext1.

  ls_general_data-action_ltext      = lr_deep_entity-action_text.

  ls_general_data-action_ltext1     = lr_deep_entity-action_text1.

  ls_general_data-/smr/structural   = lr_deep_entity-structural.

  ls_general_data-/smr/comp_replacement =


  ls_general_data-/smr/material_request =


  ls_general_data-qmcod             = lr_deep_entity-source.

  ls_general_data-dd_order          = lr_deep_entity-dd_order.

  ls_general_data-dd_notif          = lr_deep_entity-dd_notif.

  ls_general_data-due_date          = lr_deep_entity-due_date.

  ls_general_data-/smr/mech         = lr_deep_entity-mech.

  ls_general_data-/smr/inspection   = lr_deep_entity-inspection.

  ls_general_data-/smr/license      = lr_deep_entity-license.

  ls_general_data-/smr/add_auth     = lr_deep_entity-add_auth.

  ls_general_data-/smr/sectref      = lr_deep_entity-sectref   .

  ls_general_data-plant             = lr_deep_entity-werks.

  ls_general_data-qmtxt             = lr_deep_entity-dd_ltext.

********Collect  comp fields



  LOOP AT lr_deep_entity-notif_comp_nav ASSIGNING <ls_ord_compf>.



    "WHERE  qmnum = lr_deep_entity-qmnum.

    CLEAR  ls_ord_comp_data.

    ls_ord_comp_data-qmnum          = <ls_ord_compf>-qmnum.

    ls_ord_comp_data-reserv_no      = <ls_ord_compf>-reserv_no.

    ls_ord_comp_data-res_item       = <ls_ord_compf>-res_item.

    ls_ord_comp_data-material       = <ls_ord_compf>-material.

    ls_ord_comp_data-material_desc  = <ls_ord_compf>-material_desc.

    ls_ord_comp_data-req_quan       = <ls_ord_compf>-req_quan.

    ls_ord_comp_data-unit           = <ls_ord_compf>-unit.

    ls_ord_comp_data-order_no       = <ls_ord_compf>-order_no.

    ls_ord_hdr_data1-orderid        = <ls_ord_compf>-order_no.

    APPEND  ls_ord_comp_data TO lt_ord_comp_data.

    ls_ord_comp_data1-reserv_no     = <ls_ord_compf>-reserv_no.

    ls_ord_comp_data1-res_item      = <ls_ord_compf>-res_item.

    IF NOT <ls_ord_compf>-material IS INITIAL.



          input        = <ls_ord_compf>-material


          output       = <ls_ord_compf>-material


          length_error = 1

          OTHERS       = 2.




    IF sy-subrc <> 0.

* Implement suitable error handling here




    ls_ord_comp_data1-material          = <ls_ord_compf>-material.

    ls_ord_comp_data1-matl_desc         = <ls_ord_compf>-material_desc.


                                        = <ls_ord_compf>-req_quan.




                                       = <ls_ord_compf>-unit.

    ls_ord_comp_data1-item_cat         = <ls_ord_compf>-flag.

    ls_ord_hdr_data1-orderid           = <ls_ord_compf>-order_no.



    APPEND  ls_ord_comp_data1 TO lt_ord_comp_data1.






********Collect  oper fields

  LOOP AT lr_deep_entity-notif_opr_nav  ASSIGNING <ls_ord_oprf>.

    CLEAR  ls_ord_opr_data.

    ls_ord_opr_data-qmnum          = <ls_ord_oprf>-qmnum.

    IF NOT <ls_ord_oprf>-skill IS INITIAL.

      ls_ord_opr_data-skill          = <ls_ord_oprf>-skill.




    ls_ord_opr_data-work_cntr       = <ls_ord_oprf>-work_cntr.

    ls_ord_opr_data-work_activity   = <ls_ord_oprf>-work_activity.

    TRANSLATE <ls_ord_oprf>-unit TO UPPER CASE.

    ls_ord_opr_data-unit            = <ls_ord_oprf>-unit.

    ls_ord_opr_data-order_no        = <ls_ord_oprf>-order_no.

    ls_ord_hdr_data1-orderid        = <ls_ord_oprf>-order_no.

    ls_ord_opr_data-activity        = <ls_ord_oprf>-activity.

    ls_ord_opr_data-sub_activity    = <ls_ord_oprf>-sub_activity.

    ls_ord_opr_data-control_key     = <ls_ord_oprf>-control_key.

    APPEND  ls_ord_opr_data TO lt_ord_opr_data.

    ls_ord_opr_data1-work_cntr      = <ls_ord_oprf>-work_cntr.

    ls_ord_opr_data1-work_activity  = <ls_ord_oprf>-work_activity.

    TRANSLATE <ls_ord_oprf>-unit TO UPPER CASE.

    ls_ord_opr_data1-un_work        = <ls_ord_oprf>-unit.

    ls_ord_hdr_data1-orderid        = <ls_ord_oprf>-order_no.

    ls_ord_opr_data1-activity       = <ls_ord_oprf>-activity.

    ls_ord_opr_data1-sub_activity   = <ls_ord_oprf>-sub_activity.

    ls_ord_opr_data1-control_key    = <ls_ord_oprf>-control_key.

    ls_ord_opr_data1-sub_activity   = <ls_ord_oprf>-flag.

    IF <ls_ord_oprf>-flag = space.

      ls_ord_opr_data1-sub_activity = c_u.


    APPEND  ls_ord_opr_data1 TO lt_ord_opr_data1.




********Collect  MPOS fields

*  LOOP AT lr_deep_entity-notif_mpos_nav  ASSIGNING <ls_mposf>

*   WHERE  qmnum = lr_deep_entity-qmnum.

  ls_mposf = lr_deep_entity-notif_mpos_nav .



  ls_mpos_data1-/smr/dd_type    = ls_mposf-def_cat.

  ls_mpos_data1-/smr/mel_ref    = ls_mposf-mel_ref.

  ls_mpos_data1-/smr/mel_part   = ls_mposf-mel_part.

  ls_mpos_data1-/smr/mel_cat    = ls_mposf-mel_cat.

  ls_mpos_data1-/smr/etops_rat  = ls_mposf-etops_rat.

  ls_mpos_data1-/smr/plan_reqs  = ls_mposf-plan_reqs.

  ls_mpos_data1-/smr/plan_reqb  = ls_mposf-plan_reqb.

  ls_mpos_data1-/smr/plan_reqns = ls_mposf-plan_reqns.

  ls_mpos_data1-/smr/plan_dai   = ls_mposf-plan_dai.

  ls_mpos_data1-/smr/plan_reqnm = ls_mposf-plan_reqnm.

  ls_mpos_data1-/smr/plan_reqni = ls_mposf-plan_reqni.

  ls_mpos_data1-/smr/plan_reqti = ls_mposf-plan_reqti.

  ls_mpos_data1-/smr/offset1 = ls_mposf-repair_within.



  CASE ls_mposf-dd_type.

    WHEN 'P'.

      ls_mpos_data1-/smr/add_typep   = 'X'.

    WHEN 'NP'.

      ls_mpos_data1-/smr/add_typen   = 'X'.

    WHEN 'I'.

      ls_mpos_data1-/smr/add_typei   = 'X'.

    WHEN 'SC'.

      ls_mpos_data1-/smr/add_typecs  = 'X'.

    WHEN 'C'.

      ls_mpos_data1-/smr/add_typec   = 'X'.

      WHEN 'O'.

        ls_mpos_data1-/SMR/ADD_TYPEO = 'X'.


**need to check

  ls_mpos_data1-/smr/offset2 = ls_mposf-rapair_interval.

  ls_mpos_data1-/smr/uom1  = ls_mposf-unit.

  ls_mpos_data1-plnnr = ls_mposf-plnnr.

  ls_mpos_data1-plnal =  ls_mposf-plnal.

  IF NOT ls_mpos_data1-plnnr IS INITIAL.

    ls_mpos_data1-plnty = c_a.


    ls_mpos_data1-plnty = ' '.


***need to check

  ls_mpos_data1-warpl  = ls_mposf-warpl.

  ls_mpos_data1-wapos = ls_mposf-wapos.

  APPEND ls_mpos_data1 TO lt_mpos_data1.


**order header



  APPEND ls_ord_hdr_data1 TO lt_ord_hdr_data1.



  DATA lv_func_name TYPE string.

  CASE lr_deep_entity-code.

    WHEN c_clrd.

      lv_func_name = '/TCSMRO/LI5_LBK_CLEAR_DEFECT'.

    WHEN c_crad.

      lv_func_name = '/TCSMRO/LI5_LBK_DEFER_DEFECT'.

    WHEN c_read.

      lv_func_name = '/TCSMRO/LI5_LBK_REASS_DEFECT'.

    WHEN c_crt.

      lv_func_name = '/TCSMRO/LI5_LBK_RAISE_DEFECT'.

    WHEN c_upd.

      lv_func_name = '/TCSMRO/LI5_UPDATE_DEFECT'.




  IF lv_func_name IS NOT INITIAL.

    CALL FUNCTION lv_func_name


        is_notification = ls_general_data

        it_ord_comp     = lt_ord_comp_data1

        it_ord_opr      = lt_ord_opr_data1

        is_aufnr_hdr    = ls_ord_hdr_data1

        is_mpos         = ls_mpos_data1


        e_msg_type      = e_msg_type

        e_msg_text      = e_msg_text


        et_return       = lt_return.

  ELSEIF lr_deep_entity-code = c_clsd.



        is_notification = ls_general_data


        e_msg_type      = e_msg_type

        e_msg_text      = e_msg_text


        et_return       = lt_return.




  er_deep_entity-msg_text = e_msg_text.

  er_deep_entity-msg_type = e_msg_type.



  LOOP AT lt_return INTO ls_return.

    ls_ret_msg-type    = ls_return-type.

    ls_ret_msg-message = ls_return-message.

    APPEND ls_ret_msg TO lt_ret_msg.




  er_deep_entity-notif_return_nav = lt_ret_msg.








<?xml version="1.0" encoding="UTF-8"?>





<atom:content type="application/xml">




































<atom:content type="application/xml">














<atom:content type="application/xml">























<atom:content type="application/xml">
















<atom:content type="application/xml">























Please note that the names you use while creating the deep structure inside your DPC_EXT class of Create_Deep_Entity method should be same as the navigation properties defined in your SEGW Model.


This is how we need to construct our payload.

Then click on execute button and see the result on right side pane.

OData Service Deployment Options for On-Premise, Mobile and Cloud Scenarios - SAP TechEd 2015 Lecture of the Week


Customers of SAP Business Suite can use SAP Gateway to develop OData services to modernize the user experience with SAP Fiori apps. A question raised by customers is where to run the components. Should they use a separate hub for SAP Gateway or is an embedded deployment the better choice where the SAP Gateway server runs on top of the SAP Business Suite application backend? Or should they leverage cloud offering and use OData provisioning with SAP HANA Cloud Platform with SAP Gateway as service?

If you interested in getting answers to these questions you can watch the replay of this SAP TechEd 2015 lecture of the week:

OData Service Deployment Options for On-Premise, Mobile and Cloud Scenarios


To get the latest information about this topic I am inviting you to attend SAP TechEd 2016 and watch the sessionSAP Gateway deployment options in a nutshell


Those that want to get their hands dirty and see how SAP Fiori apps are build end-to-end on top of the SAP Business Suite are invited to our 4h hands-on session4h hands-on - Developing SAP Fiori Apps for Customers of SAP Business Suite

If you are more interested how to build the latest SAP Fiori apps based on SAP S/4HANA you should visit the  4h hands-on - Building an End-to-End SAP Fiori App Based on SAP S/4HANA and ABAP or the 2h lecture - Building an End-to-End SAP Fiori App Based on SAP S/4HANA and ABAP



This can be considered a continuation of the earlier Blog Post i have written Consume Odata Service in ABAP CL_HTTP_CLIENT->CREATE_BY_DESTINATION. In the earlier post it is described how to trigger a GET method of the Odata Service.


This post would not have been possible if not for the wonderful Community that is SCN. Thank You Wouter Venhuizen , Thomas SchmidtandAshwin Dutt Rfor your cotributions. i would Award you more than 10 Points if i could. For pointing me in the right Direction. Without this i would still be stumbling, lost in the Wildlands of SCN.


Calling https web service POST method from ABAP | SCN.


Even though each question and answer I find may not be particular to the issue i am facing, it always help me channel my investigation in the right direction.


I hope this blog Post does the same.



The Requirement:


We had a recent requirement in our team where we were required to modify some Data in the HANA system from ECC.


There was already a HANA service that we being used by the UI to create the same data, So the solution direction was to use the same service to post Data from ECC to HANA.


The Solution:


The approach was to call a HTTP Post method from ECC using the CL_HTTP_CLIENT class.


the process is the same for instantiating a HTTP Client has already been described in my earlier blog.


The Difference between a GET method and the Post Method for Odata is the X-CSRF token handling.


Since the HTTP POST method is a modifying call, an X-CSRF Token has to be passed for security purposes.

More information on this Topic in the below Link

Cross-Site Request Forgery Protection - SAP Gateway Foundation (SAP_GWFND) - SAP Library


In one of the posts i saw related to this topic on SCN(usage of CSRF token in ABAP report for POST request), the Classes being used were unavailable in ECC because in our landscape the ECC and GATEWAY implementations are on two separate systems.


in the Above post once the X-CSRF Token is fetched the REST object and the HTTP Client are refreshed.


They are re instantiated and then the Token is used in a HTTP POST request. this for some reason was not working when i was using the Class Methods available for CL_HTTP_CLIENT.


the Work around implemented, was to use the same object instantiation for both the GET and POST methods.


  1. Instantiate the Client
  2. Fill headers and set the URI for the GET request of the same Entity for which we want to POST.
    1. While filling the headers we have to pass a header Field with name 'X-CSRF-Token' and value 'Fetch'.
  3. Trigger the  HTTP GET request,
    1. The X-CSRF token can be retrieved from the Response attribute of the HTTP Client object.
  4. Fill the headers of the request Attribute once again. but this time we set the X-CSRF token with the value retrieved from step 3, instead of "Fetch".
    1. Set the Request HTTP method to POST
    2. Fill the BODY of the HTTP request with the data that has to be modified
    3. Trigger the HTTP post request


Note: In between step 3 and 4 we should not refresh the HTTP Client Object that was used to fetch the X-CSRF token.


Detailed Code for above Steps:-




Preparatory Step:- Create RFC destination in SM59

(please refer to Step 1 in my earlier post) Consume Odata Service in ABAP CL_HTTP_CLIENT->CREATE_BY_DESTINATION.


Step1:- Instantiate the HTTP Client in ABAP

DATA:  l_query TYPE string,

       l_body TYPE string,

       l_token TYPE string,       

       l_result TYPE string.


DATA: lo_http_client TYPE REF TO if_http_client.


CONSTANTS:  c_rfchana   TYPE rfcdest VALUE 'RFCHANA', " RFC Destination

            c_query     TYPE string VALUE '/ModifyMaterial'. " Entity name



* fetch X-CSRF token


DATA: l_query TYPE string.    " URI Query

DATA: lo_http_client TYPE REF TO if_http_client.


* Create the HTTP CLient


  CALL METHOD cl_http_client=>create_by_destination


      destination              = C_RFCHANA


      client                   = lo_http_client


      argument_not_found       = 1

      destination_not_found     = 2

      destination_no_authority = 3

      plugin_not_active            = 4

      internal_error                   = 5

      OTHERS                          = 6.


  IF NOT sy-subrc IS INITIAL.




STEP 2:- Fill headers and set URI for GET Method


* create the URI for the client.


  l_query = im_query.


  CALL METHOD cl_http_utility=>set_request_uri


      request = lo_http_client->request

      uri     = l_query.



* update the HTTP Method

  CALL METHOD lo_http_client->request->set_method


      method = lo_http_client->request->co_request_method_get.



* set Content type

  CALL METHOD lo_http_client->request->if_http_entity~set_content_type


      content_type =  'application/json'.



* set header field for fetching X-CSRF token

  CALL METHOD lo_http_client->request->set_header_field


      name  = 'X-CSRF-Token'

      value = 'Fetch'.


Step 3:- Trigger the GET Method




        http_communication_failure = 1

        http_invalid_state         = 2 ). "Send the HTTP request





      http_communication_failure = 1

      http_invalid_state         = 2

      http_processing_failed     = 3 ). "receive the response



****GET x-csrf TOKEN from earlier response


CALL METHOD lo_http_client->response->get_header_field


    name  = 'X-CSRF-Token'


    value = l_token.


Step 4:- Fill headers and Body for HTTP POST method

* Set X-CSRF- Token in the new request.


CALL METHOD lo_http_client->request->set_header_field


    name  = 'X-CSRF-Token'

    value = l_token.


* update the HTTP Method

CALL METHOD lo_http_client->request->set_method


    method = lo_http_client->request->co_request_method_post.



****content type

CALL METHOD lo_http_client->request->set_content_type


    content_type = 'application/json'.


* create Body for the HTTP Post request



CALL METHOD lo_http_client->request->set_cdata


    data = l_body.




      http_communication_failure = 1

      http_invalid_state         = 2 ). "Send the HTTP request






    http_communication_failure = 1

    http_invalid_state         = 2

    http_processing_failed     = 3 ). "receive the response


l_result = lo_http_client->response->get_cdata( ).


This Succesfully posts my data to HANA, and i can read the status code in the response header to check the request status.


Do let me know if this was helpful, as usual i am always available in case you need any further clarifications.


Kind regards,



Unlock your data with OData


Unlock your data with OData


Businesses have valuable data and they want to make that data available to other bodies.

However these data is often locked away based on criteria basis and applications, data can be made available to a few of services.

Now for that raises a whole new set of questions...



Should we use SOAP?

Should we follow Rest services?

Or should it be a custom service?


Its important to pick the right way to share this data. Because we have to find how widely available the data is.

The data should be easily accessible to both information workers and developers.

The Odata or Open data protocol is a web protocol for querying and updating data.

Odata makes it simple to interact with data from a variety of applications and programming languages.



Odata is built on http to ensure broad reach and sense data using ATOM or JSON

All of them of which are widely accepted web standards.


Odata also supports a very advanced query language that enables filtering and ordering data based on any criteria,navigating through relations,client side paging and much more.Odata also supports advanced features like asynchronous queries and requesting just the changes since the last query.These features streamline the use of queries over large datasets.

The Protocol also supports publishers to tag and enable data with domain specific vocabularies.o4.PNG

Odata unlocks data and makes it easy to consume by both information workers and developers.



The value that odata puts on standardizations and query building makes it an ideal solution in exposing data.

Odata was created to provide simple,standardized way to interact with data on the web from any platform or device.



Thank you.....

Developing data driven reusable READ functionality. Part 1



If you have been working with SAP Gateway for a while you will begin to notice the pattern of defining Entities, Entitysets, Associations, etc… and then the coding pattern of redefining GET_ENTITY, GET_ENTITYSET, etc… etc...


In this series of blogs I’d like to introduce you to a data driven pattern which I have found quite useful for speeding up the creation of the READ functionalities of CRUD. Leaving more time to focus on the CUD of CRUD...


Part 2: Reusable READ functionality. Part 2




Just to cover off the prerequisites before we jump into the fun stuff. The functionality shown here has been implemented on an ECC6 system running ABAP 7.31 with a centralized Gateway 7.40 system, as below.



ECC Status.png



GW Status.png


We will be making use of the good old SFLIGHT demo model for this one. So make sure you have access to that also. Though any table / views can be used of course and as you will see quite easily.


The Idea

The beginnings of this idea started when defining another model in SEGW, and longing for CDS views, alas still sitting on an ABAP 7.31 system this isn’t going to happen right? It seems CDS is introduced with ABAP 7.40 SP05.


So why can we not use the model we have just defined in SEGW to drive the functionality of querying the entities? Good question I thought. Time to jump in and do some research/debugging.


By the end of this series of blogs we’ll be in a place to add the following to our redefined GET_ENTITY:


get_gw_helper( )->get_entity(     exporting io_tech_request_context = io_tech_request_context     changing  cs_entity = er_entity               cs_response_context = es_response_context ).


And this to our redefined GET_ENTITYSET:


get_gw_helper( )->get_entityset(      exporting io_tech_request_context = io_tech_request_context      changing  ct_entityset = et_entityset                cs_response_context = es_response_context ).


This will be all that’s required apart from defining the model and registering the service to get our basic query operations working in gateway.

The Design

The main component of the design is our helper class, this will handle the processing of the request. In this class we’ll be making use of the gateways model class, /iwbep/cl_mgw_odata_model. Using the model we can gain access to our tables/views, model entities, properties, referral constraints and much more. These will all aid in making a generic helper class.


We will also be making use of our trusted SE11 to define views when required, saving us the need to create inner joins within the code.

In a later blog we’ll add the functionality to extend our entities with properties not existing on our tables or views via the use of an interface class, and some help from SEGW.



Let’s Start

Alright enough talk, let’s start development. We’ll begin by defining the model in SEGW to see how things should be setup for our helper class to work. Then move onto the helper class and how we can interrogate the model we have just created. First we will be setting up a simple entity and its related entity set.

Our model

Open up transaction SEGW and define a new project, ZFLIGHT and save it as a local object:




Next let’s create a new entity for the airline table SCARR by importing the DDIC structure:



We'll call the entity Airline, and create the default entity set:



Select the attributes to include:



And finally the key:



Now let’s save and generate the run time objects:




Note here we have left the ABAP fieldnames as they exist on the table, also if you take a look at the Airline entity it has a reference to the table we used to import the structure SCARR. Using these two bits of information we can being to create a generic class to handle some of our basic query operations.


To reach the service we will have to call our transaction to maintain services, /IWFND/MAINT_SERVICE and add our service to activate it.



Test the service using the gateway client /IWFND/GW_CLIENT and the $metadata operator to see if our newly create service can be reached:




If all is good, then you should receive back the XML from the request.

Let’s continue with our generic class.



Gateway Helper Class

Initially we will be creating a very simple helper. We will extend this over a couple of blogs to be more robust. Be careful at first though as we are implementing no paging at this stage, so be sure not to use any tables with way too many records and no $filter…


Open up SE80 and create a new class ZCL_GATEWAY_HELPER.

We will give this class 2 attributes to start off with.



  1. MR_MODEL, will keep track of the current model we are working on.
  2. MV_DB_TABNAME, will keep track of the database table or view we are working with.


Now lets create our methods.

constructor(), public

The constructor will take a parameter to the runtime, IR_RUNTIME. By using this we can gain access to the model via the façade as below. We will store the reference to the model in our attribute created above as it’ll be required often.


method constructor.   data: lr_facade type ref to /iwbep/cl_mgw_dp_facade.
* grab a reference to our facade to get our model reference   lr_facade ?= ir_runtime->get_dp_facade( ).
* save our model for reference later   mr_model ?= lr_facade->/iwbep/if_mgw_dp_int_facade~get_model( ).


init(), protected

This will be called both from the GET_ENTITY and GET_ENTITYSET methods of this class. Its purpose funnily enough to initialise everything ready for the next GET request. Here we really interrogate the model to get the main database table or view which we are working from and store this in the MV_DB_TABNAME attribute. The method takes one parameter, IV_ENTITY_NAME, being the current entity name being processed, from this we can grab the structure name, being the database table or view we used in SEGW.




METHOD init.   DATA: lv_entity_name TYPE /iwbep/if_mgw_med_odata_types=>ty_e_med_entity_name,         lr_table_entity TYPE REF TO /iwbep/cl_mgw_odata_entity_typ.
* free last table name used   FREE: mv_db_tabname.
* grab table entity   lv_entity_name = iv_entity_name.   lr_table_entity ?= mr_model->get_entity_type( lv_entity_name ).
* grab DDIC reference   mv_db_tabname = lr_table_entity->/iwbep/if_mgw_odata_re_etype~get_structure( ).

get_entity(), public

In this tutorial we’ll be calling this method from our gateway data provider class extension. In our case this will be class, ZCL_ZFLIGHT_DPC_EXT and method GET_ENTITY. It will have 3 parameters as below and will be responsible for requesting and returning the entity.


It first makes a call to out init() method mention above to get ready for the new request, this will essentially set up our mv_db_tabname attribute to be the table to select from. Next we create a data structure of our passed in entity, so we can get the values of the converted keys, followed by a call to the keys passed in. We then use these two bits of information to loop over the keys and build our where condition for the OSQL statement. Finally making the call to the OSQL statement with the predetermined values.




method get_entity.   data: lt_keys type /iwbep/t_mgw_tech_pairs,         lv_db_where type string,         lv_db_and type string value '',         lr_data type ref to data.   field-symbols: <ls_key> like line of lt_keys,                  <ls_data> type any,                  <lv_value> type any.
* initialise   init( io_tech_request_context->get_entity_type_name( ) ).   if mv_db_tabname is not initial.
* create data struct to grab converted keys     create data lr_data like cs_entity.     assign lr_data->* to <ls_data>.     io_tech_request_context->get_converted_keys(       importing         es_key_values = <ls_data> ).     lt_keys = io_tech_request_context->get_keys( ).
* loop over keys to build where condition     loop at lt_keys assigning <ls_key>.       assign component <ls_key>-name of structure <ls_data> to <lv_value>.       if sy-subrc = 0.         lv_db_where = lv_db_where && lv_db_and && `( ` && <ls_key>-name && ` = '` && <lv_value> && `' )`.         lv_db_and = ` and `.       endif.     endloop.     if lv_db_where is not initial.       select single *         from (mv_db_tabname)         into corresponding fields of cs_entity         where (lv_db_where).     endif.   endif.

get_entityset(), public

Again this method will be called from our data provider class, ZCL_ZFLIGHT_DPC_EXT and method GET_ENTITYSET. It will take 3 parameters listed below and be responsible for returning the entity set. Again this function makes a call to the init() method to prepare for our new request. Makes a call to the tech request to get the converted filter, from $filter, and then calls the OSQL with the determined values.




method get_entityset.   data: lv_db_where type string.
* initialise   init(     exporting iv_entity_name = io_tech_request_context->get_entity_type_name( ) ).   if mv_db_tabname is not initial.
* $filter, grab our converted filter     lv_db_where = io_tech_request_context->get_osql_where_clause_convert( ).
* execute our select     select *       from (mv_db_tabname)       into corresponding fields of table ct_entityset       where (lv_db_where).   endif.

That’s it for our first simple iteration of this class. We’ll be doing more work here in future blogs. But for now let’s see how we can implement this into our data provider class extension, and test it out.



Data Provider Extension Class

When we hit the generate button in SEGW one of the things that happened was the generation of our data provider extension class, ZCL_ZFLIGHT_DPC_EXT. This class is the one responsible for filling out all of our entities and sets, or at least the entry point to have those entities filled out via other business classes or functions. To implement our generic helper class from here we will create one attribute in this class, as below a reference to our helper class.



Now that's created lets create a method to return our helper class.


get_gw_helper(), protected

This method with return a reference with lazy instantiation to our gateway helper class.




method get_gw_helper.
* if our helper has not been created yet, then create...   if mr_gw_helper is not bound.     create object mr_gw_helper       exporting         ir_runtime = me.   endif.
* return instance   rr_gw_helper = mr_gw_helper.


Now we can redefine our AIRLINESET_GET_ENTITY() method and call the following:


method airlineset_get_entity.   get_gw_helper( )->get_entity(     exporting io_tech_request_context = io_tech_request_context     changing  cs_entity = er_entity               cs_response_context = es_response_context ).


We can also redefine our AIRLINESET_GET_ENTITYSET() method and call the following:


method airlineset_get_entityset.   get_gw_helper( )->get_entityset(      exporting io_tech_request_context = io_tech_request_context      changing  ct_entityset = et_entityset                cs_response_context = es_response_context ).


Activate all the changes and let’s give it a test.



Ensure that you have some data in your SFLIGHT tables, if not you can run program SAPBC_DATA_GENERATOR to generate some.


Open up the gateway client, /IWFND/GW_CLIENT and try the following:




/sap/opu/odata/sap/ZFLIGHT_SRV/AirlineSet()?$filter=AirlineCurrency eq 'AUD'&$format=json

/sap/opu/odata/sap/ZFLIGHT_SRV/AirlineSet()?$filter=startswith(AirlineName, 'A')&$format=json


Final words

Well I hope you have enjoyed this introduction. There is still a lot more to cover in the following blogs, as we still have quite a few odata operators to take care of and you will see how these can be implemented as we move on though the series, so stay tuned.


I’m also happy for any feedback along the way so please let me know. I'd also be interested in any other methods of how people have been dealing with their gateway implementations.


I have read many a great blog,document,article and post on SCN, so thank you to everyone for sharing your knowledge, hopefully you will find mine just as useful as I have found yours.

See you soon, in part 2.


Reusable READ functionality. Part 2


Returning to our adventures in SAP Gateway, following on from my previous blog:


Developing data driven reusable READ functionality. Part 1


Let's add some more of those odata operators to our generic handler.


But first... we'll clean up some of those pesky compiler warnings and be good citizens by passing back any exceptions. Add the following missing exception definitions as below:




Now that's done, on to the operators.



Now let’s add support for the $select operator. This will allow us to return only properties we are interested in instead of the whole entity. We will being by defining two new custom types to store some attributes about the entity properties from the model. At the moment we are interested in storing the ABAP fieldname and if the field is defined as a key.


types:    begin of ty_table_field,        abap_name type fieldname,        is_key type abap_bool,      end of ty_table_field .  types:    ty_table_field_tab type hashed table of ty_table_field with unique key abap_name .



Now we have defined the types, let’s use the table type to define a class attribute to store these details.

Add a new Class attribute mt_table_fields as below.




init(), change

Open up the init() method and add the below changes to the code.


Define some new data and a field symbol:

data: lt_table_properties type /iwbep/if_mgw_med_odata_types=>ty_t_mgw_odata_properties,         lr_property type ref to /iwbep/cl_mgw_odata_property,         ls_table_field type ty_table_field.
field-symbols:  <ls_property> like line of lt_table_properties.


Add the mt_table_fields class attribute to the free syntax to ensure we are all good for the next run though get_entity() or get_entityset().


free: mv_db_tabname,        mt_table_fields.

The final code to add to the end of the method deals with retrieving the property details from the model definition we are interested, these being the abap_name and is_key.

* grab some table properties, we are interested in, currently only the
* abap name and if the property is a key   lt_table_properties = lr_table_entity->/iwbep/if_mgw_odata_entity_typ~get_properties( ).   loop at lt_table_properties assigning <ls_property>.     lr_property ?= <ls_property>-property.     ls_table_field-abap_name = lr_property->/iwbep/if_mgw_odata_re_prop~get_abap_name( ).     ls_table_field-is_key = lr_property->/iwbep/if_mgw_odata_re_prop~is_key( ).     insert ls_table_field into table mt_table_fields.   endloop.

process_select() - new method, protected


Define a new protected method process_select(). This will have two parameters one being a table of strings which have been generated from a call to io_tech_request_context->get_select_entity_properties( ) and the other a returned string for our OSQL statement.





NOTE: The reason for passing the string table and not io_tech_request_context is due to this method being called from both get_entity() and get_entityset(), which both have io_tech_request_context defined differently, /IWBEP/IF_MGW_REQ_ENTITY and /IWBEP/IF_MGW_REQ_ENTITYSET respectively. These both seem to resolve back to one private method /IWBEP/CL_MGW_REQUEST-> GET_SELECT_ENTITY_PROPERTIES(), though who knows what might change in the future.


The method is quite simplistic, if the $select operator is used then the table will be filled, we loop around this and build our select string. If the table is not filled, we simply return the select all components, *.


method process_select.     field-symbols: <ls_string> type string.
* if $select has been supplied, then loop over table
* and add list of attributes to our osql select string     if it_select_table is not initial.       loop at it_select_table assigning <ls_string>.         rv_db_select = rv_db_select && <ls_string> && ` `.       endloop.     else.
* else dump all properties of our entity       rv_db_select = `*`.     endif.   endmethod.                    "get_db_select


get_entity(), change


Now we make a change to get_entity() to call this new method, and make use of the returned string in our select.


Create a new variable in our method to store the select string:


data: lv_db_select type string.

Make the call to our new method:


if mv_db_tabname is not initial.
* $select, grab fields to select if any     lv_db_select = process_select( io_tech_request_context->get_select_entity_properties( ) ).


Replace the the select single * with our below line:


select single (lv_db_select)


get_entityset(), change


Perform the same actions as we did for get_entity() above, though this time replace the select * with:


select (lv_db_select)


Now let’s activate and test the $select operator, try the following:






Now it’s time to implement our ordering/sorting operator. Define some new constant attributes in the class to handle the conversion from the URI $orderby operator to the OSQL orderby syntax, as below:




process_orderby(), new method, protected

Define a new method process_orderby(). This method will define two parameters, the first being the io_tech_request_context for the entityset and the second the returned string for the OSQL statement.




NOTE: ordering is only implemented with get_entityset() so we can easily pass the io_tech_request_context, as it will always be of type /IWBEP/IF_MGW_REQ_ENTITYSET. Unlike the definition we made for process_select() above.


In this method we make a call to io_tech_request_context->get_orderby() to return our ordering properties supplied on the URI. We loop over these and add them to our ordering string, converting the $orderby asc & desc keywords to the OSQL equivalent.


The second section of this code checks to see if the $top or $skip operator have been supplied. As per odata V2 standard, if it has we must order our data to return consistent results. So if we have not passed a $orderby with a $top or $skip then let’s default to sorting by the entities key properties, making reference to the mt_table_fields is_key we built in the init() method above.


method process_orderby.     data: lt_orderby type /iwbep/t_mgw_tech_order,           lv_order type string.     field-symbols: <ls_orderby> like line of lt_orderby,                    <ls_table_field> like line of mt_table_fields.     lt_orderby = io_tech_request_context->get_orderby( ).
* build order by osql string from order by uri table     loop at lt_orderby assigning <ls_orderby>.       case <ls_orderby>-order.         when mc_ascending.           lv_order = mc_sql_ascending.         when mc_descending.           lv_order = mc_sql_descending.       endcase.       rv_orderby = rv_orderby && <ls_orderby>-property && ` ` && lv_order && ` `.     endloop.
* if $top or $skip supplied and NO $orderby, then order by keys ascending     if ( rv_orderby is initial ) and        ( ( io_tech_request_context->get_top( ) > 0 ) or          ( io_tech_request_context->get_skip( ) > 0 ) ).
* loop over keys and add to ordering       loop at mt_table_fields assigning <ls_table_field> where is_key = abap_true.         rv_orderby = rv_orderby &&  <ls_table_field>-abap_name && ` ` &&  mc_sql_ascending && ` `.       endloop.     endif.   endmethod.                    "process_orderby



get_entityset(), change

Here we will create a new variable to hold the ordering string returned from our call to process_orderby().


data: lv_db_orderby type string.


Next insert our call to the new method, after the call to process_select(), passing our io_tech_request_context and receiving our ordering string.


* $select, grab fields to select if any     lv_db_select = process_select( io_tech_request_context->get_select_entity_properties( ) ).
* $orderby grab our order     lv_db_orderby = process_orderby( io_tech_request_context ).


Lastly let’s add the orderby variable to the OSQL statement after the where condition.


where (lv_db_where)         order by (lv_db_orderby).


Now active and test.


     /sap/opu/odata/sap/ZFLIGHT_SRV/AirlineSet()?$orderby=AirlineId desc&$format=json




$top and $skip

Now we have added our ordering we can add our paging, as mentioned to return consistent results with $top and $skip we need to add some ordering.


We’ll start by adding some new attributes to our class, the first being mc_max_top. This is fall back in case no $top has been specified then we will default to mc_max_top. This can be overridden in the call to get_entityset() as we will find out shortly. The second will be the actual maximum value we’ll be limiting to, either mc_max_top or the value passed into get_entityset().





init(), change

We’ll add a new parameter to the init() method iv_max_top to set our attribute above, just to be consistent and do all our initialization in the one spot.




Add the MV_MAX_TOP to the free statement to ensure we clear it out each time through, and add a line to set mv_max_top as below.


* free last table name used   free: mv_db_tabname,         mt_table_fields,         mv_max_top.
* set max top for this entityset.   mv_max_top = iv_max_top.


process_paging(), new method, protected

Create a new method process_paging(). We’ll add an importing parameter io_tech_request_context and two exporting parameters ev_skip and ev_top, to be used in our OSQL statement.




First we simply grab what is being passed on the URI for $top and $skip. In the next section we make sure we have a $top greater than zero and haven’t gone over the maximum allowed. A check for $count is also added here as we do not want to limit the $top any further if someone is simply counting the number of records in a set. So leave $top as is in this case.


Funnily enough $count and $top can be used together, I find this strange if anyone knows why I’d love to know… eg try:





In the last section, if we are processing a $skip, then just add this value to our $top value so we return enough records during the select to cover the complete query.


method process_paging.
* get our $top and $skip     ev_top = io_tech_request_context->get_top( ).     ev_skip = io_tech_request_context->get_skip( ).
* force top to max allowed if not passed in, and not using $count     if ( io_tech_request_context->has_count( ) = abap_false ) and        ( ( ev_top <= 0 ) or ( ev_top > mv_max_top ) ).       ev_top = mv_max_top.     endif.
* check $skip, and add to max rows if required     if ev_skip > 0.       ev_top = ev_top + ev_skip.     endif.   endmethod.                    "process_paging


get_entityset(), change

Let’s add a new attribute to the get_entityset() method to allow us to pass the maximum number of records to return, iv_max_top. This allows as to define different maximums for different entities within our services.




Create two new variables to return the top and skip values from the call to process_paging().


data: lv_top type i,         lv_skip type i.

Next we will make a call to our new method above process_paging(), passing our io_tech_request_context, top and skip.


* $orderby grab our order     lv_db_orderby = process_orderby( io_tech_request_context ).
* $top, $skip, process our paging     process_paging(       exporting io_tech_request_context = io_tech_request_context       importing ev_top = lv_top                 ev_skip = lv_skip ).
* $filter, grab our converted filter     lv_db_where = io_tech_request_context->get_osql_where_clause_convert( ).

Finally on our select statement let’s add the syntax UP TO lv_top ROWS to limit our select to the maximum rows determined, and lastly we will add the code to handle the $skip if supplied, deleting the required number of rows from the front of the results table.


* execute our select       select (lv_db_select) up to lv_top rows         from (mv_db_tabname)         into corresponding fields of table ct_entityset         where (lv_db_where)         order by (lv_db_orderby).       if lv_skip > 0.         delete ct_entityset from 1 to lv_skip.       endif.


Activate all changes and let's test with the following examples:







$inlinecount and $count

Lastly lets add support for our counting operators.


get_entityset(), change

First we will place a check to see if we are processing this URI with the $count operator. If so then let’s call the OSQL with the COUNT(*) syntax and remove our $orderby and $select processing logic as it’s not needed. We will leave the paging, as we saw in the previous example above, a $top can be used with $count? We can also still supply a $filter with $count so let’s leave that process and keep it attached to the WHERE condition.


We finally return the results of the count back into our response context in attribute count.


In the second lot of changes we handle the $inlinecount operator, here we simply count the number or rows in our results set and update the inlinecount attribute of our response context.


So the complete method now looks as follows:


METHOD get_entityset.   DATA: lv_db_where TYPE string,         lv_db_select TYPE string,         lv_db_orderby TYPE string,         lv_top TYPE i,         lv_skip TYPE i.
* initialise   init(     EXPORTING iv_entity_name = io_tech_request_context->get_entity_type_name( )               iv_max_top = iv_max_top ).   IF mv_db_tabname IS NOT INITIAL.
* $top, $skip, process our paging     process_paging(       EXPORTING io_tech_request_context = io_tech_request_context       IMPORTING ev_top = lv_top                 ev_skip = lv_skip ).
* $filter, grab our converted filter     lv_db_where = io_tech_request_context->get_osql_where_clause_convert( ).
* check for $count if present just count the records
* no need to order results, or select fields!     IF io_tech_request_context->has_count( ) = abap_true.
* execute our select       SELECT COUNT(*) UP TO lv_top ROWS         INTO cs_response_context-count         FROM (mv_db_tabname)         WHERE (lv_db_where).     ELSE.
* $select, grab fields to select if any       lv_db_select = process_select( io_tech_request_context->get_select_entity_properties( ) ).
* $orderby grab our order       lv_db_orderby = process_orderby( io_tech_request_context ).
* execute our select       SELECT (lv_db_select) UP TO lv_top ROWS         FROM (mv_db_tabname)         INTO CORRESPONDING FIELDS OF TABLE ct_entityset         WHERE (lv_db_where)         ORDER BY (lv_db_orderby).       IF lv_skip > 0.         DELETE ct_entityset FROM 1 TO lv_skip.       ENDIF.
* $inlinecount, check for inline count and update       IF io_tech_request_context->has_inlinecount( ) = abap_true.         cs_response_context-inlinecount = lines( ct_entityset ).       ENDIF.     ENDIF.   ENDIF.


Let’s activate the changes and try it out:








Entityset max records

We mentioned the new parameter iv_max_top above in the get_entityset() method. Now we can make use of this new parameter in the get_entityset() method from the data provider class. This will allow as to specify maximums per entityset across our service. As below:




get_gw_helper( )->get_entityset(      exporting io_tech_request_context = io_tech_request_context                iv_max_top = 15      changing  ct_entityset = et_entityset                cs_response_context = es_response_context ).



In Closing

We have reach the end of another blog, thank you for following along. I hope it has all made sense so far and has been helpful.

Stay tuned for another blog or two to follow as we continue this adventure along the gateway...



Keep coding, sharing and staying happy.

Set and Get custom HTTP Header


This blog is to illustrate following solution which might be helpful in certain scenario:


     1. Set Custom HTTP Header in sapui5

     2. Get Custom HTTP Header in Gateway


So Let's start !



1. How to set custom HTTP Header in sapui5

This is simple and can be achieved by setHeaders method of either sap.ui.model.odata.v2.ODataModel or sap.ui.model.odata.ODataModel.


Code snippet:

UI5 Code.JPG



Able to see customer header sets in F12:

     F12 in Chrome.JPG




2. How to get custom HTTP Header in GW

Also simple by calling get_dp_facade of interface /iwbep/if_mgw_conv_srv_runtime.


Code snippet:

     GW Code Snipet.JPG


Able to see in GW code runtime:

     Header in GW.JPG


Now we able to set HTTP custom header in UI5 and get in GW.

This is sometimes helpful when you want to pass additional data from UI to GW but found nowhere to place them.

e.g. When implement get_entity/get_stream method, few places we can put parameters. Then maybe header is a place to consider.



Hope it helps !

Dynamic entity structure in the Odata service


Most of the time you will need a flexible Odata entity structure. For example, for adding customer fields or providing only fields which would be displayed in customer scenario.


I found this example from Aron for Media Links: http://scn.sap.com/docs/DOC-44864

But if you need it not for Stream media, but for old good abap tables, please have a look at some additional steps below:


1. You have to perform all steps as described by Aron (except redefining Model and Data provider class methods).

In our example, we will create model with two fields (CARRID and PLANETYPE) from SFLIGHT table:


2. Redefine method Define of model provider class as shown below:


3. Redefine method GET_ENTITYSET of Data provider class as shown below:



Now execute your service adding /Flights and you will see flights data:



With this, you could already build flexible Odata structure. Enjoy!

Browsing All 253 Articles Latest Live