Skip to Content

After finally upgrading Gateway to SP07, I decided to look into the new Delta Query Support functionality. I found a really great document written by Andre Fischer, How to Implement Basic Delta Query Support in SAP Netweaver Gateway, which gave me all the direction I needed. I recommend reading it to get a better understanding of Delta Query Support and the different techniques.

As I am currently working on incorporating offline OData support using the new OData SDK’s included in the SMP 3.0 SDK, I needed to add in Delta Query Support to my Gateway Service. However, in my case the service I am consuming is a standard service, namely WFSERVICE (Workflow Service).

The technique and code I applied to get this working with WFSERVICE can be applied to any service.

Follow the following steps to redefine and add Delta Query Support:

Step 1

Create a new Gateway Project in transaction SEGW

1.PNG

2.PNG

Step 2

Right click on the Data Model under your new project and go to Redefine->OData Service GW

3.PNG



Step 3


Select the service you would like to redefine and click Next

4.PNG



Step 4

Select the entities and associations you would like to redefine. Although in this case I am only going to add the Delta Query Support to the WorkflowTaskCollection entity set which uses the WorkflowTask entity, it seems to error when I don’t include all the associated entities.

5.PNG

6.PNG

Step 5

Generate Runtime by right clicking on the project and selecting Generate Runtime.

7.PNG

Give the Technical Service a new name

8.PNG

Step 6

Now we need to redefine the GET_ENTITYSET and GET_ENTITYSET_DELTA methods for the Entity Collection.

Start by right clicking the GetEntitySet of the Service Implementation for WorkflowTaskCollection and click on Go to ABAP Workbench

9.PNG

In the ABAP Workbench, we need to redefine both GET_ENTITYSET and GET_ENTITYSET_DELTA methods.

10.PNG

Once both methods have been redefined, go into their Redefinitions and paste the following code:


METHOD /iwbep/if_mgw_appl_srv_runtime~get_entityset.
DATA: lo_dp_facade   TYPE REF TO /iwbep/if_mgw_dp_facade.

DATA: lv_delta_token TYPE        string.

FIELD-SYMBOLS:
      <fs_entityset>
TYPE ANY TABLE.

TRY.
     
CALL METHOD super->/iwbep/if_mgw_appl_srv_runtime~get_entityset
          
EXPORTING
                iv_entity_name          
= iv_entity_name
                iv_entity_set_name      
= iv_entity_set_name
                iv_source_name          
= iv_source_name
                it_filter_select_options
= it_filter_select_options
                it_order                
= it_order
                is_paging               
= is_paging
                it_navigation_path      
= it_navigation_path
                it_key_tab              
= it_key_tab
                iv_filter_string        
= iv_filter_string
                iv_search_string        
= iv_search_string
                io_tech_request_context 
= io_tech_request_context
          
IMPORTING
                er_entityset            
= er_entityset
                es_response_context     
= es_response_context.

* get the data provider facade
     
TRY.
           lo_dp_facade
= /iwbep/if_mgw_conv_srv_runtime~get_dp_facade( ).
     
CATCH /iwbep/cx_mgw_tech_exception.
          
RAISE EXCEPTION TYPE /iwbep/cx_mgw_tech_exception.
     
ENDTRY.

ASSIGN er_entityset->* TO <fs_entityset>.

* call the delta token functionality
     
TRY.
          
CALL METHOD /iwbep/cl_query_result_log=>create_update_log_entry_hash
               
EXPORTING
                     io_tech_request_context 
= io_tech_request_context
                     io_dp_facade            
= lo_dp_facade
                     ir_service_document_name
= mr_service_document_name
                     ir_service_version      
= mr_service_version
                     it_entityset            
= <fs_entityset>
               
CHANGING
                     ev_delta_token          
= lv_delta_token.

           es_response_contextdeltatoken = lv_delta_token.

      CATCH /iwbep/cx_qrl_locked.
          
RAISE EXCEPTION TYPE /iwbep/cx_qrl_locked.
     
CATCH /iwbep/cx_qrl_delta_unavailabl.
          
RAISE EXCEPTION TYPE /iwbep/cx_qrl_delta_unavailabl.
     
ENDTRY.

      CATCH /iwbep/cx_mgw_busi_exception .
     
CATCH /iwbep/cx_mgw_tech_exception .
ENDTRY.

ENDMETHOD.




and….

METHOD /iwbep/if_mgw_appl_srv_runtime~get_entityset_delta.
DATA: lo_dp_facade           TYPE REF TO /iwbep/if_mgw_dp_facade.

DATA: lv_delta_token         TYPE        string.

FIELD-SYMBOLS:
      <fs_entityset>         TYPE ANY TABLE,
      <fs_deleted_entityset>
TYPE ANY TABLE.

TRY.
     
CALL METHOD super->/iwbep/if_mgw_appl_srv_runtime~get_entityset_delta
          
EXPORTING
                io_tech_request_context
= io_tech_request_context
          
IMPORTING
                er_entityset           
= er_entityset
                er_deleted_entityset   
= er_deleted_entityset
                es_response_context    
= es_response_context.

      ASSIGN er_entityset->* TO <fs_entityset>.

      IF er_deleted_entityset IS NOT BOUND.
          
CREATE DATA er_deleted_entityset LIKE <fs_entityset>.
     
ENDIF.

      ASSIGN er_deleted_entityset->* TO <fs_deleted_entityset>.

* get the data provider facade
     
TRY.
           lo_dp_facade
= /iwbep/if_mgw_conv_srv_runtime~get_dp_facade( ).
     
CATCH /iwbep/cx_mgw_tech_exception.
          
RAISE EXCEPTION TYPE /iwbep/cx_mgw_tech_exception.
     
ENDTRY.

*  call the delta token functionality
     
TRY.
          
CALL METHOD /iwbep/cl_query_result_log=>create_update_log_entry_hash
               
EXPORTING
                     io_tech_request_context 
= io_tech_request_context
                     io_dp_facade            
= lo_dp_facade
                     ir_service_document_name
= mr_service_document_name
                     ir_service_version      
= mr_service_version
                     it_entityset            
= <fs_entityset>
               
IMPORTING
                     et_deleted_entityset    
= <fs_deleted_entityset>
                     et_entityset            
= <fs_entityset>
               
CHANGING
                     ev_delta_token          
= lv_delta_token.

           es_response_contextdeltatoken = lv_delta_token.

      CATCH /iwbep/cx_qrl_locked.
          
RAISE EXCEPTION TYPE /iwbep/cx_qrl_locked.
            CATCH /iwbep/cx_qrl_delta_unavailabl.
          
RAISE EXCEPTION TYPE /iwbep/cx_qrl_delta_unavailabl.
     
ENDTRY.

CATCH /iwbep/cx_mgw_busi_exception .
CATCH /iwbep/cx_mgw_tech_exception .
ENDTRY.

ENDMETHOD.



Step 7

Add the new service in transaction /IWFND/MAINT_SERVICE

11.PNG

12.PNG

Click on ZWFSERVICE to add it

13.PNG

Step 8

Run the service in a browser via its URL: http://my.domain.com:8200/sap/opu/odata/sap/ZWFSERVICE/WorkflowTaskCollection

The difference you will notice is that there is the following additional tag at the second last line of the response:

<link rel=”delta href=”WorkflowTaskCollection?!deltatoken=’22000AB22B051EE397AFF3B8EE42B356_20131205073405′/>

Now on subsequent calls you will use the new delta token retrieved from the latest response to make sure that only new/updated and deleted entries are returned like follows: http://my.domain.com:8200/sap/opu/odata/sap/ZWFSERVICE/WorkflowTaskCollection?!deltatoken=’22000AB22B051EE397AFF3B8EE42B356_20131205073405′

In the case where an entry has been deleted since the last service call and in the case of Workflow, when a work item has been approved and is no longer in the approvers worklist, the following will appear in the response:

<at:deleted-entry ref=”http://my.domain.com:8200/sap/opu/odata/sap/ZWFSERVICE/WorkflowTaskCollection(‘000001224760‘) when=”2013-12-05T07:33:41Z/>



And that is all you need to do from the backend side, the rest would be handled on the client side.

To report this post you need to login first.

5 Comments

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

  1. Mark Teichmann

    Hi Brad,

    thank you for another informative blog.

    I have implemented the solution you describe here. It worked well but I use additional fields in my workflow. Now when I call the WFService including delta queries I get a dump in a method call to /IWBEP/CL_QUERY_RESULT_LOG=>CREATE_UPDATE_LOG_ENTRY_HASH when I try to open the /ExtensibleElements path.

       LOOP AT it_entityset ASSIGNING <fs_entity>.

       MOVE-CORRESPONDING <fs_entity> TO <fs_key>.

       ls_objkey-objkey = <fs_key>.

    Here in ExtensibleElements <fs_key> is populated with a structure containing WORKITEM_ID and NAME. This generates the error OBJECTS_MOVE_NOT_SUPPORTED.

    Do you also use ExtensibleElements? Does it work for you?

    EDIT: I just found SNOTE regarding my error:

    1926946 – Delta Query dumps in /IWBEP/CL_QUERY_RESULT_LOG

    (0) 
    1. Mark Teichmann

      ok, after implementing the SNOTE the error message changes but the root cause is still there.

      Problem is now, that the key fields are of type String with variable length. I tried to change the length to fixed length but this is not possible (maybe because we are inheriting the entity from standard WFSERVICE).

      In SNOTE 1932247 several non-supported things are listed:

      Hint: in case your service was generated with the transaction SEGW it is possible (in some cases) to change key field types within SEGW from a variable length to a fixed length. Important: changes in SEGW should be performed only by the application developer.

      I think the developments around OData Offline and Delta Queries are far from stable at the moment. E.g. JSON format is not supported, $expand is not supported.

      (0) 
      1. Ron Sargeant

        Hi Mark,

        I don’t think redefinition of the key is possible as the base classes of the WFSERVICE service are not SEGW compliant. However, I am pretty sure some hacking around in the new MPC could manage it.

        If you can manage it, the workitem_id should be 12 chars and name property should be 32 chars – this matches the form they are in when the BEP methods reads the container.

        Regards

        Ron.

        (0) 
      2. Brad Pokroy Post author

        Hi Mark,

        Happy its useful, just figuring out a lot of this new functionality at the moment, so thought it may help others to document it.

        Thanks for the info and note for Extensible elements issue. I actually hadn’t gotten to use the extensible elements yet since adding the delta query support, so had not hit that problem, but found that when I did call it I experienced the same issue as you did. I did implement the note which resolved one issue but then there is the other issue regarding the key having a string value of variable length which you are having as well.

        So after much debugging, I came up with a fix to this issue. I discovered that in the method: cl_abap_container_utilities=>fill_container_c the type of im_value passed in is of type ‘v’ (deep structure) because of the string data elements. And currently the SAP standard code raises and illegal_parameter_type exception for deep structures.

        There is no reason why a deep structure that is a type ‘F’ (Flat structure) shouldn’t work, providing the key doesnt exceed the 200 character limit. So as a bit of a dirty fix, I added an enhancement to method cl_abap_container_utilities=>fill_container_c at the very top of the method.

        Basically what I am doing is I am checking if the type of IM_VALUE is ‘v’ then create a structure type object to see if its a flat structure or nested structure. If its nested then raise the exception. If its a flat type then loop through the components table constructing the key into ex_container field.

        see code pasted below:

        ENHANCEMENT 1  ZENH_FILL_CONTAINER.    “active version

          data: l_ztype_value     type c,

                l_ztype_container type c,

                l_zlen_value      type i,

                l_zlen_container  type i,

                l_zref            type ref to data.

          field-symbols: <xzvalue>     type x,

                         <xzcontainer> type x,

                         <czcontainer> type c.

        * added in to cater for deep structure

        data: lo_deep_struct  type ref to cl_abap_structdescr.

        data: lv_offset       type        i.

        field-symbols:

             <component>      type        abap_compdescr,

             <field>          type        any.

        *end of addition

          describe field im_value type l_ztype_value.

          case l_ztype_value.

            when ‘u’ .

              describe field ex_container type l_ztype_container.

              case l_ztype_container.

                when ‘C’.

                  assign im_value     to <xzvalue>     casting.

                  assign ex_container to <xzcontainer> casting.

                  <xzcontainer> = <xzvalue>.

                when ‘g’.

                  describe field im_value length l_zlen_value in byte mode.

                  l_zlen_container =

                    l_zlen_value div cl_abap_char_utilities=>charsize +

                    sign( l_zlen_value mod cl_abap_char_utilities=>charsize ).

                  create data l_zref type c length l_zlen_container.

                  assign l_zref->* to <xzcontainer> casting.

                  assign im_value     to <xzvalue>     casting.

                  <xzcontainer> = <xzvalue>.

                  assign l_zref->* to <czcontainer>.

                  concatenate space space into ex_container separated by <czcontainer>.

                when others.

                  message x002(sy).

              endcase.

            when ‘h’ or ‘r’ or ‘l’. ” table, deep struc, object

              ” referenc, data reference

              raise illegal_parameter_type.

            when ‘v’.

              lo_deep_struct ?= cl_abap_typedescr=>describe_by_data( im_value ).

                if lo_deep_struct->struct_kind = ‘F’.

                  loop at lo_deep_struct->components assigning <component>.

                    assign component <component>-name of structure im_value to <field>.

                    ex_container+lv_offset(<component>-length) = <field>.

                    add <component>-length to lv_offset.

                  endloop.

                else.

                  raise illegal_parameter_type.

                endif.

            when others.   ” single field

              ex_container = im_value.

          endcase.

          return.

        ENDENHANCEMENT.

        Obviously enhancing SAP standard is not a great idea and is just a temp fix. It may be worth raising an oss message around this?

        The above code seems to get the delta token working in this scenario, however theres the possibility it may be flawed in other scenarios.

        I agree about the offline data and delta query functionality being a bit unstable at the moment, with it being so new and probably not used much yet. I also hope they add in JSON support as well as $expanded query support soon, as in the case of WFSERVICE it is definitely more efficient to be using $expanded queries instead of retrieving each navigational property individually.

        I’m busy playing around with the Offline OData SDK at the moment. First impression is that it seems alright for basic scenarios, but far from being ideal for extremely complex apps, or complex data storage requirements.

        Cheers,

        Brad

        (0) 
        1. Ahmed Shakeel

          Hi Brad,


          thank you for the great blog.


          Your blog Helped me a lot.


          I have Implemented your above code in cl_abap_container_utilities=>fill_container_c it works fine for me.


          But there is a issue in cl_abap_container_utilities=>READ_CONTAINER_C while I am trying to get the updated records and getting below Error .

          <code>

          HTTP/500/E/Internal Server Error

          </code>


          Conversion of type C to type v not supported.


          kindly, provide me some inputs, in solving this Issue.


          Thanks,

          Shakeel

          (0) 

Leave a Reply