Are you the publisher? Claim or contact us about this channel


Embed this content in your HTML

Search

Report adult content:

click to rate:

Account: (login)

More Channels


Channel Catalog


Channel Description:

SAP NetWeaver Gateway (formerly called "Project Gateway") is a technology that provides a simple way to connect devices, environments and platforms to SAP software based on market standards. The framework enables development of innovative people centric solutions bringing the power of SAP business software into new experiences such as social and collaboration environments, mobile and tablet devices and rich internet applications. It offers connectivity to SAP applications using any programming language or model without the need for SAP knowledge by leveraging REST services and OData/ATOM protocols '
    0 0

    Updates

    • 02.06.2016 Added link to blog that describes how to implement updates
    • 09.06.2016 Added section how to create the CDS view used for generating an OData service via Referenced Data Sources

     

    Introduction

     

    In a previous blog OData service development with SAP Gateway - code-based service development - Part I I described how to implement as basic OData Service using code based implementation.

     

    Since the recommended development approach as of SAP NetWeaver 750 is to use CDS views I would like to show how a service having the same capabilities as the service in the blog mentioned above can be generated based on CDS views.

     

    It will turn out that from a development perspective in the ABAP stack this is much less effort if appropriate CDS views are in place and if your backend system is based on SAP NetWeaver 750.

     

    If however no appropriate CDS view is in place instead of having the effort of developing an OData service via code based implementation you would have the effort to develop the appropriate DDL source code.

     

    Prerequisites

     

    As a prerequisite we are using a consumption view ZSEPM_C_SALESORDER_TPL since it is not good practice to access core CDS views directly.

     

    This consumption view is then also not annotated as an analytical view as the underlying core CDS view SEPM_I_SALESORDER_E.

     

    How to create this consumption view ZSEPM_C_SALESORDER_TPL is shown in the following.


    If you are using a system for a SAP CodeJam you can skip this step or create your own CDS view by replacing <TPL> with your group number.



    Creating the consumption view

     

    Please note:

    The creation of a consumption view is only necessary if you want to follow this how-to-guide on your own system or if you want to use your own CDS view.

    For a SAP CodeJam or other SAP event we will use a system where this view has already been created.

     

     

     

    • Start the ABAP Development Tools

     

    From the menu choose New --> ABAP Project

    01 Create new ABAP project in ADT.png

    • Select the system (here A4H) from the list of system connections and choose Next

      02 Select A4H from the list of system connections.png


    • In the "Connection Settings" screen press Next
      System Connection Details.png

    • Enter your credentials
      04 logon to system.png

    • Right click on your system connection and select New --> Other ...

    06 new other.png

    • Select DDL source and press Next

      07 DDL source.png
    • Enter the following details for the new DDL source and press Finish

      Package: $TMP
      Name: ZSEPM_C_SALESORDER_XXTPL
      Description: SalesOrders - EPM Demo Data

        07 DDL source 2.png
    •   Cut and paste the source code and press the Activate button. This will create the CDS view that we will use in this how to guide

      08_Create_DDL_source.png

     

    @AbapCatalog.sqlViewName: 'ZSEPM_ISOE_TPL'

    @AbapCatalog.compiler.compareFilter: true

    @AccessControl.authorizationCheck: #CHECK

    @EndUserText.label: 'SalesOrders - EPM Demo Data'

    define view Zsepm_C_Salesorder_Tpl as select from SEPM_I_SalesOrder_E {

                                                                          @ObjectModel.text.association: '_Text'

                                                                      key SEPM_I_SalesOrder_E.SalesOrder,

                                                                          @ObjectModel.readOnly: true

                                                                          SEPM_I_SalesOrder_E.CreationDateTime,

                                                                          @ObjectModel.readOnly: true

                                                                          SEPM_I_SalesOrder_E.LastChangedDateTime,

                                                                          @ObjectModel.readOnly: true

                                                                          SEPM_I_SalesOrder_E.IsCreatedByBusinessPartner,

                                                                          @ObjectModel.readOnly: true

                                                                          SEPM_I_SalesOrder_E.IsLastChangedByBusinessPartner,

                                                                          @ObjectModel.readOnly: true

                                                                          SEPM_I_SalesOrder_E.Customer,

                                                                          @ObjectModel.readOnly: true

                                                                          SEPM_I_SalesOrder_E.TransactionCurrency,

                                                                          @ObjectModel.readOnly: true

                                                                          SEPM_I_SalesOrder_E.GrossAmountInTransacCurrency,

                                                                          @ObjectModel.readOnly: true

                                                                          SEPM_I_SalesOrder_E.NetAmountInTransactionCurrency,

                                                                          @ObjectModel.readOnly: true

                                                                          SEPM_I_SalesOrder_E.TaxAmountInTransactionCurrency,

                                                                          @ObjectModel.readOnly: true

                                                                          SEPM_I_SalesOrder_E.SalesOrderLifeCycleStatus,

                                                                          @ObjectModel.readOnly: true

                                                                          SEPM_I_SalesOrder_E.SalesOrderBillingStatus,

                                                                          @ObjectModel.readOnly: true

                                                                          SEPM_I_SalesOrder_E.SalesOrderDeliveryStatus,

                                                                          @ObjectModel.readOnly: true

                                                                          SEPM_I_SalesOrder_E.SalesOrderOverallStatus,

                                                                          @ObjectModel.readOnly: true

                                                                          SEPM_I_SalesOrder_E.Opportunity,

                                                                          /* Associations */

                                                                          SEPM_I_SalesOrder_E._BillingStatus,

                                                                          SEPM_I_SalesOrder_E._Customer,

                                                                          SEPM_I_SalesOrder_E._DeliveryStatus,

                                                                          SEPM_I_SalesOrder_E._Item,

                                                                          SEPM_I_SalesOrder_E._LifeCycleStatus,

                                                                          SEPM_I_SalesOrder_E._OverallStatus,

                                                                          SEPM_I_SalesOrder_E._Text,

                                                                          SEPM_I_SalesOrder_E._TransactionCurrency

     

    }

     

     

     

    Generating an OData service via Referenced Data Source

     

    • We first have to start with creating a new Service Builder project calledZE2E100_<XX>_2 since the project in the previous blog mentioned above was calledZE2E100_<XX>

      Note:
      Replace <xx> with your group number
    • Right click on the folder Data Model.

      Choose Reference -->
      Modeled Data Source Reference from the context menu

    image082.png

    • The Reference Data Source Wizard opens.


      On the first screen choose:
      CDS Core Data Services for the field Modeled Data Source Type.
      ZSEPM_C_SALESORDER_TPL for the field Modeled Data Source Name

    rds01.jpg

    • In the second window of the wizard select the following associations’

      _CUSTOMER and _ITEM.

      Please note that the cds views SEPM_I_BUSINESSPATNER_E and SEPM_I_SALESORDERITEM_E are automatically selected as well.


      Press Finish

    rds02.jpg

     

     

    • Press the Generate Runtime Objects button


    • In the Model and Service Definition screen leave the default values unchanged and press Continue.

    image086.png

    • In the Create Object Directory Entry dialogue press Local Object or enter $TMP.


    • Expand the folder Service Maintenance right click on the entry GW_HUB and choose Register.

    image088.png

    • In the Add Service dialogue enter $TMP for the package assignment or press Local Object.

    image089.png

    • Expand the folder Service Maintenance right click on the entry GW_HUB and choose SAP Gateway Client.

      Press <Execute>

    image090.png

    • Check the Service Document

      It shall contain three entity sets:
      1. Zsepm_C_Salesorder_Tpl
      2. SEPM_I_SalesOrderItem_E
      3. SEPM_I_BusinessPartner_E

    rds04.jpg

    • Check the metadata document by selecting <Add URI option> and select $metadata

     

    Check the Metadata Document
    Please note that the entity type SEPM_I_SalesOrder_EType contains:

      • Two navigation properties to_Customer and to_Item
      • A property SalesOrder_Text that has been generated by the SADL framework based on the annotation @ObjectModel.text.association: '_Text'.

        Please note this property is annotated as sap:updatable=”false”;

     

    rds06.jpg

    • Now we can test the service and we will see that it supports various query options, $expand and selecting single entities out of the box.

      To do so execute the following URI’s in the SAP Gateway Client (transaction /n/IWFND/GW_CLIENT):
      • /sap/opu/odata/SAP/ZE2E100_XX_2_SRV/Zsepm_C_Salesorder_Tpl?$filter=GrossAmountInTransacCurrency ge 100000&$select=SalesOrder,GrossAmountInTransacCurrency,TransactionCurrency&$format=json

     

      • $skip and $top together with $inlinecount work out of the box as well

        /sap/opu/odata/SAP/ZE2E100_XX_2_SRV/Zsepm_C_Salesorder_Tpl?$filter=GrossAmountInTransacCurrency ge 100000&$select=SalesOrder,GrossAmountInTransacCurrency,TransactionCurrency&$top=2&$skip=1&$inlinecount=allpages&$format=json


    Please note that via &$inlinecount=allpages we retrieve the number of entries that would be returned without using $skip and $top

    rds07.jpg

      • Read a single entity from the list of the sales order

        /sap/opu/odata/SAP/ZE2E100_XX_2_SRV/Zsepm_C_Salesorder_Tpl('5000000<XX>')?$format=json

        Please note that the weird looking key stems from the fact that the CDS view is annotated as an analytical view.

      • Read the list of items of a single sales order via the navigation property to_Item

        /sap/opu/odata/SAP/ZE2E100_XX_2_SRV/Zsepm_C_Salesorder_Tpl('5000000<XX>')/to_Item?$format=json

     

     

     

    How to implement updates in a service that has been generated using referenced data sources will be described in the following blog

     

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

     

     


    0 0

    Introduction

     

    The OData service that has been generated in the first part of this blog is read only.

     

    In the second part of the blog OData service development with SAP Gateway using CDS via Referenced Data Sources I would like to show how we can make the description of the sales order updatable.

     

    This will show

     

    1. how simple updates can be implemented and in particular
    2. how this can be done for Texts that are accessed by the SADL framework via a join and the annotation @ObjectModel.text.association: '_Text'.

     

    Implementation

     

    • Open the Service Builder project ZE2E100_<XX>_2 again that has been built based on the blog mentioned above.
    • Expand the folder Runtime artifacts and right-click on ZZCL_ZE2E100_XX_2_DPC_EXT and choose the entry Go To ABAP Workbench.

    image098.png

    • Switch to edit mode, scroll down to the method ZSEPM_C_SALESORD_UPDATE_ENTITY and make sure to select it and click on the Redefine Method button.

    rds_cud_01.jpg

    • Copy and Paste the coding into the Update method


      method zsepm_c_salesord_update_entity.

     

         data: lt_keys               type /iwbep/t_mgw_tech_pairs,

               ls_key                type /iwbep/s_mgw_tech_pair,

               ls_so_id              type bapi_epm_so_id,

               ls_headerdata_update  type bapi_epm_so_header,

               ls_headerdatax        type bapi_epm_so_headerx,

               ls_headerdata_key     type zcl_ze2e100_xx_2_mpc=>ts_zsepm_c_salesorder_tpltype,

               ls_headerdata_payload type zcl_ze2e100_xx_2_mpc=>ts_zsepm_c_salesorder_tpltype,

               lt_return             type table of bapiret2,

               ls_return             type          bapiret2,

               err_msg               type          string,

               ls_message            type          scx_t100key.

     

         call method io_tech_request_context->get_converted_keys

           importing

             es_key_values = ls_headerdata_key.

     

         io_data_provider->read_entry_data( importing es_data ls_headerdata_payload ).

     

         ls_so_id-so_id = ls_headerdata_key-salesorder.

     

         " Product header data (non-key) fields that can be updated

         " via the BAPI are marked with an 'X'

     

         ls_headerdatax-so_id = ls_headerdata_key-salesorder.

         ls_headerdatax-note = 'X'.

     

         " move content of the fields that should be

         " updated from payload to the corresponding

         " field of the BAPI

     

         move ls_headerdata_key-salesorder to ls_headerdata_update-so_id.

         move ls_headerdata_payload-t_salesorder  to ls_headerdata_update-note.

     

         call function 'BAPI_EPM_SO_CHANGE'

           exporting

             so_id         = ls_so_id         " EPM: SO Id

             soheaderdata  = ls_headerdata_update " EPM: so header data of BOR object

             soheaderdatax = ls_headerdatax

           tables

             return        = lt_return.     " Return Parameter

     

         if lt_return is not initial.

     

           loop at lt_return into ls_return.

     

             err_msg = ls_return-message .

     

           endloop.

     

           ls_message-msgid = 'SY'.

           ls_message-msgno = '002'.

           ls_message-attr1 = err_msg.

     

           raise exception type /iwbep/cx_mgw_busi_exception

             exporting

               textid = ls_message.

     

         endif.

     

     

       endmethod.

     


    Info: The replaced coding above retrieves the content of the properties of the incoming request.

    Since different DDIC structures are used by the entity type and the BAPI that is used to update the sales order the incoming fields are moved to the data structure used by the BAPI.


    • To make the SAP Web IDE CUD Master Detail Template aware that the property SalesOrder_Text is now updatatable we have to annotate the property using the annoation sap:updatable=true.

      In this special case this cannot be done in the CDS view. So we have to use the option to add additional metadata by implementing the DEFINE method in the model provider extension class.
    • Expand the folder Runtime artifacts and right-click on ZZCL_ZE2E100_XX_2_DPC_EXT and choose the entry Go To ABAP Workbench.
    • Copy and paste the following coding into the DEFINE method.

    method define.

     

         data:

           lo_entity_type type ref to /iwbep/if_mgw_odata_entity_typ,

           lo_property    type ref to /iwbep/if_mgw_odata_property.

     

         call method super->define( ).

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

         lo_property = lo_entity_type->get_property( iv_property_name = 'SalesOrder_Text').

         lo_property->set_updatable( abap_true ).

     

    endmethod.

     

    • Click on Activate.
    • Confirm the activation popup.
    • Navigate back to the Service Builder by pressing the “Back-Button” several times
    • In the navigation tree right-click on GW_HUB and select SAP Gateway Client.

      Alternatively start the SAP Gateway Client in a separate window by starting transaction /n/IWFND/GW_CLIENT

      If we now test the update using the SAP Gateway Client this should work fine.


    • Enter the following URI

      /sap/opu/odata/SAP/ZE2E100_XX_2_SRV/Zsepm_C_Salesorder_Tpl('5000000<XX>')

      After pressing Execute button you see a single sales order.

      Replace ‘<XX>’ with your group name
    • Press the Use as Request button to create a proper http request body.
      Change the content of the field SalesOrder_Text for example to ‘Test Update Text’.
      Change the http method from GET to PUT.
      Press Execute

    rds_cud_03.jpg

    • As a result you get an empty http response with the return code 204.

    rds_cud_04.jpg

    • Now again perform a GET request to verify that the data has been changed
      Enter the following URI
      /sap/opu/odata/SAP/ZE2E100_XX_2_SRV/Zsepm_C_Salesorder_Tpl('5000000<XX>')
      After pressing Execute button you see a single sales order with the changed text.
      Replace ‘<XX>’ with your group name

    rds_cud_04a.jpg

     

    Testing with SAP Web IDE

     

    When testing with the CUD Master Detail Template in SAP Web IDE it turns out that the update of the field will not work.

     

    This is because to a small bug that is planned to be fixed with SAP NetWeaver 750 SP04.

     

    As a workaround we have to redefine the method /IWBEP/IF_MGW_CORE_SRV_RUNTIME~CHANGESET_BEGIN.

     

    After you have added the following code

     

      method /IWBEP/IF_MGW_CORE_SRV_RUNTIME~CHANGESET_BEGIN.

    cv_defer_mode
    = abap_false.

    endmethod.


    rds_cud_05.jpg

     

     

    The text will be updated as you can check with the SAP Gateway Client

     

    rds_cud_06.jpg


    0 0
  • 06/02/16--04:14: 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

     

    Get SAPGUI

    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 .

     

    SAP Web IDE

    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


    0 0

     

    Hello,

    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:

    http://scn.sap.com/docs/DOC-58760.

    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.

    SM04.jpg

    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.

    functionzdmsh_delete_odata_session.
     
    *"----------------------------------------------------------------------
     
    *"*"Local Interface:
     
    *"  IMPORTING
     
    *"     VALUE(IV_PATH) TYPE  STRING
     
    *"----------------------------------------------------------------------
     
       
    include: tskhincl.
     
       
    data: server_info  type ref to cl_server_info.
     
       
    data(lv_path) = iv_path.
       
    translatelv_pathto upper case.
     
       
    try.
           
    createobject server_info.
     
           
    data(session_list) = server_info->get_session_list( with_application_info = 1
                                                                tenant
    = 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.
     
             
    if<fs_session_info>-application_infocslv_path.
     
               
    call function 'TH_DELETE_USER'
                 
    exporting
                    user           
    = sy-uname
                   
    client          = sy-mandt
                    tid            
    = <fs_session_info>-logon_hdl
                    logon_id       
    = <fs_session_info>-logon_id
                 
    exceptions
                    authority_error
    = 1
                   
    others          = 2.
               
    ifsy-subrc<> 0.
                 
    continue.
               
    endif.
             
    endif.
           
    endloop.
     
         
    catchcx_root.
           
    exit.
       
    endtry.
     
     
    endfunction.

     

    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.

    functionzdmsh_delete_user_webrfc.
     
    *"----------------------------------------------------------------------
     
    *"*"Local Interface:
     
    *"  TABLES
     
    *"      QUERY_STRING STRUCTURE  W3QUERY
     
    *"      HTML STRUCTURE  W3HTML
     
    *"      MIME STRUCTURE  W3MIME
     
    *"  CHANGING
     
    *"     REFERENCE(CONTENT_TYPE) TYPE  W3PARAM-CONT_TYPE DEFAULT
     
    *"       'application/json'
     
    *"     REFERENCE(CONTENT_LENGTH) TYPE  W3PARAM-CONT_LEN
     
    *"     REFERENCE(RETURN_CODE) TYPE  W3PARAM-RET_CODE
     
    *"----------------------------------------------------------------------
     
       
    data: path type string.
       
    data: rctype numc5.
     
       
    sortquery_stringdescending.
       
    read table query_stringwith key name = '_OdataSrv'.
     
        path
    = query_string-value.
     
       
    call function 'ZDMSH_DELETE_ODATA_SESSION'
         
    exporting
            iv_path
    = path
         
    importing
            rc     
    = rc.
     
       
    data: htmldoclike line of html.
     
       
    concatenate'{"results": [ {"key": "path", "value": "' path '"},'
                                
    ' {"key": "error", "value": "' rc '"}]}' into htmldoc-line.
     
       
    inserthtmldocinto table html.
     
     
    endfunction.

     

    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

     

     


    0 0

    Introduction

     

    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.


    Slide1.PNG


    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.

     

    Slide2.PNG

     

    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

     

    IW_SPI====100

    IW_GIL====100 

    IW_SCS====200

    IW_CNT====200

    IW_CBS====200

    IW_FNDGC==100

     

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

     

    https://launchpad.support.sap.com/#/softwarecenter/search/IW_SPI====200

     

    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

     


    0 0

    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.

    02_Create_ABAP_Project.png

    • 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"

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

    06_start_sapgui_in_project.png

    • SAPGUI will be opened in a new tab. Here we can start SEGW
      07_start_segw.png
    • You can now follow the steps described in my blog OData service development with SAP Gateway - code-based service development - Part I
      08_develop_service.png
    • 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
      09_goto_abap_workbench.png
    • This will now start ABAP in Eclipse rather than SE24.
      10_edit_in_ADT.png

     

    Have fun using ABAP in Eclipse


    0 0

    The recent release of SAP Development Tools for Eclipse,Mars version, does not include the Gateway tool yet (GWPA) and to me it is an essential one.

     

    2016-06-16 11_38_57-SAP Development Tools.png

     

    Great thanks to this post "Gateway Productivity Accelerator (Developer Edition) Launched" by Thomas Meigen, the OData Modeler tool is contributed "under the Project Eclipse "Ogee" so now I can have my tool back in the latest version of Eclipse.

     

    2016-06-16 11_40_27-Ogee _ projects.eclipse.org.png


    0 0

    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


    2.7.jpg

    • 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

    1.1.jpg

     

     

    • 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)

    2.5.jpg

    • 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

     

     

    1.3.jpg

     

    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.


    2.3.jpg

     

    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.

     

    1.5.jpg

    • DATA CLASS PROVIDER

     

          Select ***_MPC_EXT class

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

    2.4.jpg

         Type decleration :

       

    types:

        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.

    2.2.jpg

     

    Include the following code in Define method.

     

    super->define( ).

    DATA:

    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' ).

    "#EC NOTEXT

     

     

    lo_entity_type->bind_structure( iv_structure_name  =

    '***CL_LI5_LBK__14_MPC_EXT=>TS_DEEP_ENTITY' ).

     

     

    • 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'.

     

    CODE SNIPPET

     

    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

                     ***cl_li5_lbk__14_mpc_ext=>tt_return,

           ls_ret_msg TYPE  /tcsmro/cl_li5_lbk__14_mpc_ext=>ts_return.

     

     

      DATA:

    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,

      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,

     

     

     

     

    ********MPOS

      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.

     

     

      FIELD-SYMBOLS:

      <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.

     

     

    ******message******

      DATA:

            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

     

      io_data_provider->read_entry_data(

      IMPORTING

      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 =

                                   lr_deep_entity-comp_replacement.

      ls_general_data-/smr/material_request =

                                    lr_deep_entity-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.

          CALL FUNCTION 'CONVERSION_EXIT_MATN1_INPUT'

            EXPORTING

              input        = <ls_ord_compf>-material

            IMPORTING

              output       = <ls_ord_compf>-material

            EXCEPTIONS

              length_error = 1

              OTHERS       = 2.

        ELSE.

          CONTINUE.

        ENDIF.

        IF sy-subrc <> 0.

    * Implement suitable error handling here

        ENDIF.

     

     

        ls_ord_comp_data1-material          = <ls_ord_compf>-material.

        ls_ord_comp_data1-matl_desc         = <ls_ord_compf>-material_desc.

        ls_ord_comp_data1-requirement_quantity

                                            = <ls_ord_compf>-req_quan.

     

     

        ls_ord_comp_data1-requirement_quantity_unit

                                           = <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.

     

     

      ENDLOOP.

     

     

    ********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.

        ELSE.

          CONTINUE.

        ENDIF.

        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.

        ENDIF.

        APPEND  ls_ord_opr_data1 TO lt_ord_opr_data1.

     

     

      ENDLOOP.

    ********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'.

      ENDCASE.

    **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.

      ELSE.

        ls_mpos_data1-plnty = ' '.

      ENDIF.

    ***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.

    *  ENDLOOP.

    **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'.

      ENDCASE.

     

     

      IF lv_func_name IS NOT INITIAL.

        CALL FUNCTION lv_func_name

          EXPORTING

            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

          IMPORTING

            e_msg_type      = e_msg_type

            e_msg_text      = e_msg_text

          TABLES

            et_return       = lt_return.

      ELSEIF lr_deep_entity-code = c_clsd.

        CALL FUNCTION '/TCSMRO/LI5_CLOSE_DEFECT'

          EXPORTING

            is_notification = ls_general_data

          IMPORTING

            e_msg_type      = e_msg_type

            e_msg_text      = e_msg_text

          TABLES

            et_return       = lt_return.

     

     

      ENDIF.

      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.

        CLEAR:ls_return,

              ls_ret_msg.

      ENDLOOP.

      er_deep_entity-notif_return_nav = lt_ret_msg.

     

     

    ENDMETHOD.

     

     

    • REQUEST PAYLOAD

     

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

    <atom:entry

    xmlns:atom="http://www.w3.org/2005/Atom"

    xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"

    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">

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

    <m:properties>

    <d:Qmnum></d:Qmnum>

    <d:code>CRT</d:code>

    <d:FLLOGID>N102131204</d:FLLOGID>

    <d:TLLOGID>TLAA077303</d:TLLOGID>

    <d:FUNCLOCATION>N-5679</d:FUNCLOCATION>

    <d:SECTREF>GA047101LHR20131204</d:SECTREF>

    <d:Erdat>20160425</d:Erdat>

    <d:Qmnam>345153</d:Qmnam>

    <d:Faultcode></d:Faultcode>

    <d:AsrGfor>false</d:AsrGfor>

    <d:Nildef>false</d:Nildef>

    <d:Defcode>2340</d:Defcode>

    <d:DefPos></d:DefPos>

    <d:Techlog></d:Techlog>

    <d:DdLtext>symptoms</d:DdLtext>

    <d:ActionText>action</d:ActionText>

    <d:Structural>false</d:Structural>

    <d:CompReplacement>false</d:CompReplacement>

    <d:MaterialRequest>false</d:MaterialRequest>

    <d:Source>MM</d:Source>

    <d:DueDate></d:DueDate>

    <d:Mech></d:Mech>

    <d:Inspection></d:Inspection>

    <d:License></d:License>

    <d:AddAuth></d:AddAuth>

    </m:properties>

    </atom:content>

    <atom:link

    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/notif_comp_nav"

    type="application/atom+xml;type=feed"

    title="***LI5_LBK_DEFECT_DET_SRV/ord_compset">

    <m:inline>

    <atom:feed>

    <atom:entry>

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

    <m:properties>

    <d:Qmnum></d:Qmnum>

    <d:ReservNo></d:ReservNo>

    <d:ResItem></d:ResItem>

    <d:Material>622-9252-001:4V792</d:Material>

    <d:MaterialDesc></d:MaterialDesc>

    <d:ReqQuan>4</d:ReqQuan>

    <d:Unit></d:Unit>

    <d:OrderNo></d:OrderNo>

    </m:properties>

    </atom:content>

    </atom:entry>

    <atom:entry>

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

    <m:properties>

    <d:Qmnum></d:Qmnum>

    <d:ReservNo></d:ReservNo>

    <d:ResItem></d:ResItem>

    <d:Material>622-9252-001:4V792</d:Material>

    <d:MaterialDesc></d:MaterialDesc>

    <d:ReqQuan>8</d:ReqQuan>

    <d:Unit></d:Unit>

    <d:OrderNo></d:OrderNo>

    </m:properties>

    </atom:content>

    </atom:entry>

    </atom:feed>

    </m:inline>

    </atom:link>

    <atom:link

    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/notif_opr_nav"

    type="application/atom+xml;type=feed"

    title="***LI5_LBK_DEFECT_DET_SRV/ord_oprset">

    <m:inline>

    <atom:feed>

    <atom:entry>

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

    <m:properties>

    <d:Qmnum></d:Qmnum>

    <d:Skill>B1</d:Skill>

    <d:WorkCntr>GALY10B1</d:WorkCntr>

    <d:WorkActivity>11.0</d:WorkActivity>

    <d:Unit>MIN</d:Unit>

    <d:OrderNo></d:OrderNo>

    <d:Activity></d:Activity>

    <d:SubActivity></d:SubActivity>

    <d:ControlKey>AM01</d:ControlKey>

    <d:FLAG>U</d:FLAG>

    </m:properties>

    </atom:content>

    </atom:entry>

    <atom:entry>

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

    <m:properties>

    <d:Qmnum></d:Qmnum>

    <d:Skill>B1</d:Skill>

    <d:WorkCntr>GALY10M5</d:WorkCntr>

    <d:WorkActivity>12.0</d:WorkActivity>

    <d:Unit>MIN</d:Unit>

    <d:OrderNo></d:OrderNo>

    <d:Activity></d:Activity>

    <d:SubActivity></d:SubActivity>

    <d:ControlKey>AM01</d:ControlKey>

    <d:FLAG>U</d:FLAG>

    </m:properties>

    </atom:content>

    </atom:entry>

    </atom:feed>

    </m:inline>

    </atom:link>

    </atom:entry>

     

     

     

    NOTE:

    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.




    2.1.jpg




    This is how we need to construct our payload.

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


    0 0

    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


    0 0

    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

        EXPORTING

          destination              = C_RFCHANA

        IMPORTING

          client                   = lo_http_client

        EXCEPTIONS

          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.

      ENDIF.

     

     

    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

        EXPORTING

          request = lo_http_client->request

          uri     = l_query.

     

     

    * update the HTTP Method

      CALL METHOD lo_http_client->request->set_method

        EXPORTING

          method = lo_http_client->request->co_request_method_get.

     

     

    * set Content type

      CALL METHOD lo_http_client->request->if_http_entity~set_content_type

        EXPORTING

          content_type =  'application/json'.

     

     

    * set header field for fetching X-CSRF token

      CALL METHOD lo_http_client->request->set_header_field

        EXPORTING

          name  = 'X-CSRF-Token'

          value = 'Fetch'.

     

    Step 3:- Trigger the GET Method

     

      lo_http_client->send(

          EXCEPTIONS

            http_communication_failure = 1

            http_invalid_state         = 2 ). "Send the HTTP request

     

     

      lo_http_client->receive(

        EXCEPTIONS

          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

      EXPORTING

        name  = 'X-CSRF-Token'

      RECEIVING

        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

      EXPORTING

        name  = 'X-CSRF-Token'

        value = l_token.

     

    * update the HTTP Method

    CALL METHOD lo_http_client->request->set_method

      EXPORTING

        method = lo_http_client->request->co_request_method_post.

     

     

    ****content type

    CALL METHOD lo_http_client->request->set_content_type

      EXPORTING

        content_type = 'application/json'.

     

    * create Body for the HTTP Post request

     

     

    CALL METHOD lo_http_client->request->set_cdata

      EXPORTING

        data = l_body.

     

    lo_http_client->send(

        EXCEPTIONS

          http_communication_failure = 1

          http_invalid_state         = 2 ). "Send the HTTP request

     

     

     

    lo_http_client->receive(

      EXCEPTIONS

        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,

    Vamsi

     



    0 0
  • 07/05/16--06:20: 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...

     

    o1.PNG

    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.

     

    o2.PNG

    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.

    o3.PNG

    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.

    .o5.PNG

     

    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.

    o7.PNG

     

    Thank you.....


    0 0

    Introduction

    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

     

     

    Prerequisites

    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

    ECC Status.png

     

    GW

    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:

     

    segw_create_project.PNG

     

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

    segw_import_entity.png

     

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

    segw_create_entity_airline.png

     

    Select the attributes to include:

    segw_import_airline.PNG

     

    And finally the key:

    segw_set_airline_key.PNG

     

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

    segw_generate.PNG

    segw_airline_struct.PNG

     

    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.

    addService.PNG

     

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

     

    /sap/opu/odata/sap/ZFLIGHT_SRV/$metadata

     

    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.

    attributes.PNG

     

    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.

    constructor.PNG

    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( ).
    endmethod.

     

    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.

     

    init.PNG

     

    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( ).
    ENDMETHOD.

    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.

     

    get_entity.PNG

     

    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.
    endmethod.

    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.

     

    get_entityset.PNG

     

    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.
    endmethod.

    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.

     

    dpc_ext_attributes.PNG

    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.

     

    dpc_ext_helper.PNG

     

    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.
    endmethod.

     

    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 ).
    endmethod.

     

    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 ).
    endmethod.

     

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

     

    Testing

    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()?$format=json

    /sap/opu/odata/sap/ZFLIGHT_SRV/AirlineSet('AA')?$format=json

    /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.

     


    0 0

    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:

     

    exceptions.png

     

    Now that's done, on to the operators.

     

    $select

    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 .

    types.PNG

     

    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.

     

    table_attribute.PNG

     

    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.
    endmethod.

    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.

     

    process_select.PNG

     

     

    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:

     

         /sap/opu/odata/sap/ZFLIGHT_SRV/AirlineSet()?$select=AirlineId,AirlineName&$format=json

     

     

    $orderby

    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:

     

    constants.PNG

     

    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.

     

    process_orderby.PNG

     

    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().

     

    page_attributes.PNG

     

     

    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.

     

    init_param.PNG

     

    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.

     

    process_paging.PNG

     

    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:

     

         http://services.odata.org/V2/Northwind/Northwind.svc/Products/$count?$top=5 

     

     

    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.

     

    get_entityset.PNG

     

    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:

     

         /sap/opu/odata/sap/ZFLIGHT_SRV/AirlineSet()?$format=json&$top=2

         /sap/opu/odata/sap/ZFLIGHT_SRV/AirlineSet()?$format=json&$top=2&$skip=2

     

     

     

    $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.
    ENDMETHOD.

     

    Let’s activate the changes and try it out:

     

     

      /sap/opu/odata/sap/ZFLIGHT_SRV/AirlineSet/$count

      /sap/opu/odata/sap/ZFLIGHT_SRV/AirlineSet/$count?$filter=startswith(AirlineId,'A')

      /sap/opu/odata/sap/ZFLIGHT_SRV/AirlineSet()?$inlinecount=allpages&$format=json

     

     

    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:

     

    zcl_zflight_dpc_ext->airlineset_get_entityset()

     

    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.


    0 0

    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 !


    0 0

    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:

    001.png

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

    002.png

     

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

    Flights.PNG

     

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