Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
Showing results for 
Search instead for 
Did you mean: 


SAP Gateway SP9+ is required.

You should have done the following steps:

#2 - How To Implement $skiptoken

#3 - How To Implement Lightening Fast OData Services with Exchange Table

How It Works

This H2G will explain how to implement both Server Side Paging and Delta Query altogether in SAP Gateway.

Why do we need to use both? - because, for Offline Store, the Server Side Paging is for avoiding the HTTP timeout with the large volume of entities, while Delta Query is for optimizing the payload volume after the Offline Store is initialized and created. Both technique complements each other.

Here's a quick idea how to do it:

One important remark - you have to be aware of the fact that the Table data (= entity set) being "paged" by Server Side Paging can be out of date immediately. This means during the Server Side Paging calculation, the pages downloaded into an Offline Store is not the latest data anymore. So it is very important that (1) you obtain both a Table data AND a deltatoken as a "snapshot". And a next fetch via Delta Query can provide you the correct delta data since you took that snapshot.

In order to take a correct snapshot data, (2) we need to keep both Table data and deltatoken in a stateful session - until the delta token is sent to the Offline Store. This ensures the data consistency so that the Offline Store can do the Delta Query for the right delta data after the snapshot is taken.

Once you keep a snapshot in the stateful session, (3) you can split the Table data by means of Server Side Paging. And the last page should contain the deltatoken for the Offline Store. The Offline Store will use it in the next Delta Query for the delta data.

So we need to learn how to use a Stateful Session in OData services. "Soft State" feature introduced in SAP Gateway SP9 can do the job.

Step-by-Step Procedure

- Obtaining Table and Skiptoken Value

1. Your Query operation should have the code as written here. So the current code already obtains both the TravelAgency table and a delta token string.

- Activating Soft State

1. Let's activate Soft State. First off go to SEGW and find the "..._MPC_EXT" artifact and choose Go to ABAP Workbench.

2. Here you'll add one method implementation. Find the "DEFINE" method press Redefine icon.

3. You'll have following implementation - this enables your MPC class to handle Soft State.

01 method DEFINE.
02   super->define( ).
03   model->set_soft_state_enabled( abap_true ).
04 endmethod.

Activate it.

4. Go back SEGW and select GetEntitySet.

5. Open it in ABAP Workbench - and find the "/IWBEP/IF_MGW_SOST_SRV_RUNTIME~OPERATION_START" method and press Redefine icon.

6. You'll have an empty implementation. This method will be called back when a soft state session starts. You can insert any code whenever necessary however for this use case, we can keep it empty. Just save it.

7. Do the same redefinition for the "/IWBEP/IF_MGW_SOST_SRV_RUNTIME~OPERATION_END" method. This is another call back method when the soft state session ends. Leave it empty and save it. Both Start and End methods are required for the Soft State activation later.

8. Go back to SEGW and choose your service maintenance item and select "Maintain".

9. Now you have the current Sesssion Timeout value as "00:00:00". We need to change it.

10. Select ICF Node button and Configure (SICF).

11. Find the node and double click on it.

12. Here you can change the Session Timeout value - enter the value of how long you want to hold a stateful session.

13. Save it and you'll find the new Session Timeout value.

14. Find "Load Metadata" button and press it. You would find the "Soft-state status" column turns from "Not Supported" to "Inactive".

Tip: If you don't see the status change, clear the cache by the two transactions "/IWFND/CACHE_CLEANUP" and "/IWBEP/CACHE_CLEANUP".

16. Additionally - make sure if your Security Session Status is activated via the transaction "SICF_SESSIONS". This is a must checkpoint even though you have successfully activated the Soft State.

17. Now find the "Soft State" button and press it.

18. You should see the Soft-state status "Active". Now your stateful session is activated!

- Keeping Values in a Stateful OData Session by Soft State

1. How do we keep the Table and deltatoken in a stateful session? Declare them as Static Atttributes of OData class - we can keep it in the session via Soft State. The static values in Soft State persist data in a user specific session. 

Go to SEGW and open ABAP Workbench.

2. Select the "Attributes" tab. Declare a class attribute "MT_ENTITYSET". This class member variable will hold the table data during the session.

Enter the following values:

Attribute Name: MT_ENTITYSET

Level: Static Attribute

Visibility: Protected

Typing: Type

Associated Type: STRAVELAG

3. The entered values in the previous step declared it as a structure. We need to declare it as table structure - here's how to do it. Click on the arrow icon next to the Associated Type column. You'll go to the code declaration - and add "table of" statement as highlighted in blue in the capture.

Save it - now you have MT_ENTITYSET attribute in STRAVELAG table structure.

4. Add another attribute for keeping a delta token value.

Attribute Name: MV_DELTA_TOKEN

Level: Static Attribute

Visibility: Protected

Typing: Type

Associated Type: TIMESTAMP

Now you can keep both Table and Deltatoken in a stateful session!

5. Let's enhance your current Query operation code so that it keeps both Table and Deltatoken as class attributes. Your Query operation should have the code as written here. Replace the lines of #05 to #10 with following codes:

05 * load the entityset into the session variables
06   IF me->mt_entityset IS INITIAL.
07     SELECT * FROM stravelag INTO TABLE lt_entityset.
08     me->mt_entityset = lt_entityset.
09 * delta token value during the session
10     GET TIME STAMP FIELD me->mv_delta_token.
11   ENDIF.

This code keeps the variables in a stateful session. And now that we declared these variables as class attributes, you can delete the existing declaration of the lv_delta_token now.

You can activate it. We'll tweak the current code so that Server Side Paging and deltatoken logic can live together in the next step.

- Splitting a Table into Pages

1. Essentially you can simply put the Server Side Paging logic as you learned. However you should replace the "lt_entityset" with "me->mt_entityset", as we want to remember the fact that it is a "snapshot". The code in Appendix has the entire GET_ENTITYSET implementation. The lines between "Skiptoken starts" and "Skiptoken ends" shows you how the "me->entityset" variable is being used.

The thing we should note here is the way to clean up the Table and Deltatoken in the last page. 

01 * if the skiptoken is empty, it is the end of chunk
02   IF es_response_context-skiptoken IS INITIAL.
03     es_response_context-deltatoken = me->mv_delta_token.
04 * the table content & delta token should be valid til the delta token sent
05     CLEAR: me->mt_entityset,
06            me->mv_delta_token.
07   ENDIF.

#02 checks if "es_response_context-skiptoken" is empty or not - if it is empty, that indicates the page you're cropping is the last one. You need to send the deltatoken instead of skiptoken.

#03 set the delta token value, which has been in the stateful session (as a snapshot).

#05 and #06 does a very important job to clean up the snapshot data in the stateful session - so the entire Table is being sent to the Offline Store!

- Testing Server Side Paging and Delta Token

Just like you had tested the $skiptoken before, try running the Query operation from either the browser or REST Client. Have a look at the <link> data at the bottom of the OData payload – there should be a $skiptoken we have implemented. You can try copy this generated $skiptoken URL as the OData URL and see how the next $skiptoken data looks like – for this example it continues to show the next chunk starting from the 51st entity.

...and in the last page, you'll see the deltatoken value instead of $skiptoken. Offline Store will understand the sequence of $skiptoken and deltatoken and loads the entityset in the store for offline usage.

...congratulations, now your Query operation has Server Side Paging and Delta Query!

Note: during the EFI implementation, we had embedded a few lines of code for Soft State as commented. These codes are required in order to properly commit record data in Exchange Table with Soft State.

- Further Reading

How to use Soft-State support for OData services - Introductory H2G of Soft State. It also talks about the response time benefit too.


List of H2Gs

Blog - SMP3 OData SDK - Performance Tuning with Offline Store

Appendix – Query Operation with Server Side Paging and Delta Token


  DATA: lt_entityset   TYPE TABLE OF stravelag,
* variables for $skiptoken
        ls_entity           TYPE stravelag,
        iv_paging_max_chunk TYPE i VALUE 50,
        lv_index_beg        TYPE i,
        lv_index_end        TYPE i,
        lv_skiptoken        TYPE string,
        lv_token_len        TYPE i,
        lv_token_beg        TYPE c,
        lv_token_end        TYPE c,
        lv_table_size       TYPE i.

* load the entityset into the session variables
  IF me->mt_entityset IS INITIAL.
    SELECT * FROM stravelag INTO TABLE lt_entityset.
    me->mt_entityset = lt_entityset.
* delta token value during the session
    GET TIME STAMP FIELD me->mv_delta_token.

* Skiptoken starts *
  lv_skiptoken = io_tech_request_context->get_skiptoken( ).

* Get number of entries
  DESCRIBE TABLE me->mt_entityset LINES lv_table_size.
  IF lv_table_size IS INITIAL.
    CLEAR es_response_context-skiptoken.

* Set Skiptoken only if more entries than Paging max number
  IF lv_table_size < iv_paging_max_chunk.
    lv_index_beg = 1.
    lv_index_end = lv_table_size + 1.

    IF lv_skiptoken IS NOT INITIAL.
      lv_token_len = STRLEN( lv_skiptoken ) - 1.
      IF lv_token_len > 0.
        lv_token_beg = lv_skiptoken(1).
        lv_token_end = lv_skiptoken+lv_token_len(1).
        IF lv_token_beg = '''' AND lv_token_end = ''''.
          lv_token_len = lv_token_len - 1.
          lv_skiptoken = lv_skiptoken+1(lv_token_len).

* Determine indices for BEG and END
      lv_token_len = STRLEN( lv_skiptoken ).
      IF lv_token_len > 0   AND
         lv_token_len < 10  AND
         lv_skiptoken CO '0123456789'.
        lv_index_beg = lv_skiptoken.
        lv_index_beg = 1.

      lv_index_beg = 1.
    lv_index_end = lv_index_beg + iv_paging_max_chunk.

  IF lv_index_end <= lv_table_size.
    es_response_context-skiptoken = lv_index_end.
  CONDENSE es_response_context-skiptoken.

  LOOP AT me->mt_entityset INTO ls_entity.
    IF sy-tabix <  lv_index_beg. CONTINUE. ENDIF.
    IF sy-tabix >= lv_index_end. EXIT. ENDIF.
    INSERT ls_entity INTO TABLE et_entityset.
* Skiptoken ends   *

* if the skiptoken is empty, it is the end of chunk
  IF es_response_context-skiptoken IS INITIAL.
    es_response_context-deltatoken = me->mv_delta_token.
* the table content & delta token should be valid til the delta token sent
    CLEAR: me->mt_entityset,