Skip to Content
Technical Articles
Author's profile photo Bharat Pemmireddy

Pessimistic Lock in SAP Netweaver Gateway OData without using soft state

We are building our own App for SAP S4HANA 1909. The frontend is built in a Microsoft based tool. We integrated the App to S4HANA using OData protocol.

One of the requirement is to lock the object, once the user clicks on edit in the App. So that nobody else can edit, either from the app, or in SAP GUI.

Talking about lock in SAP NetWeaver Gateway-OData(on-premise), till date I could not find any solution which will behave similar way as in SAP GUI because of rest property(as rest is stateless) so cant store the state there.
So possible solution is either use optimistic lock(Etag, Hash) or we can achieve using soft state. Soft state is where we are changing rest property from stateless to statefull for particular time, which is not good as it will consume lot of resources and advantages of REST like light weight, will be compromised.
For better information please refer to blogs below

https://blogs.sap.com/2020/08/29/custom-e-tag-for-optimistic-lock-in-sap-gateway-odata-for-deep-update/

Another option I tried is, to use the enqueue module (Ex: ENQUEUE_EMEKKOE ), in a OData service which the App can call once the user hits edit. But the problem is, these function modules release the lock once the Service call ends. The locks are not persisted with this logic.

So after doing lot of debugging the standard lock mechanism, at last I was able to achieve lock which is at kernel level(not sure about any drawback) but it will behave same as in SAP GUI, So without wasting more time on theory let me show you the code below.

CALL 'C_ENQUEUE' "#EC CI_CCALL
ID 'OPCODE' FIELD '1' " enqueue request
ID 'ENQOBJ' FIELD iv_enqueue_object
ID 'GRANULES' FIELD it_lock_list
ID 'DELAY_ON_REJECT' FIELD ' '
ID 'USTP' FIELD '2'
ID 'COLLISION_UNAME' FIELD ev_user
ID 'COLLISION_OBJECT' FIELD ev_object
ID 'SYNCHRON' FIELD 'X'
ID 'USER' FIELD sy-uname
ID 'USVB' FIELD '00000000000000_OWNER_PERSIST'.

For removing the lock the code is as below

CALL 'C_ENQUEUE' "#EC CI_CCALL
ID 'OPCODE' FIELD '3' " Dequeue request
ID 'ENQOBJ' FIELD iv_enqueue_object
ID 'GRANULES' FIELD it_lock_list
ID 'DELAY_ON_REJECT' FIELD ' '
ID 'USTP' FIELD '2'
ID 'COLLISION_UNAME' FIELD ev_user
ID 'COLLISION_OBJECT' FIELD ev_object
ID 'SYNCHRON' FIELD 'X'
ID 'USER' FIELD sy-uname
ID 'USVB' FIELD '00000000000000_OWNER_PERSIST'.

We also wrapped this in OData service which the App can use to remove locks.

Below is the lock service.

 

Below are the lock entries after running the service.

Below is the service for unlocking.

Below is the result after running the unlock service.

Example for working with Purchase Order with complete code below .

lwa_lock_list-gname = 'EKKO'.           "Tablename
lwa_lock_list-gmode = 'E'.              "Lockmode
lwa_lock_list-garg  =  lv_arg.          "Argument
APPEND lwa_lock_list TO it_lock_list.
CLEAR lv_arg.

lv_arg = sy-mandt && lv_ebeln && cgarg. "Arguments
lwa_lock_list-gname = 'EKPO'.           "Tablename
lwa_lock_list-gmode = 'E'.              "Lockmode
lwa_lock_list-garg  =  lv_arg.          "Argument
APPEND lwa_lock_list TO it_lock_list.

iv_enqueue_object = 'EMEKKOE'.          "Name of Lock Object in the Lock Entry

*CALL - System Function Call

CALL 'C_ENQUEUE' "#EC CI_CCALL
ID 'OPCODE' FIELD '1' " enqueue request
ID 'ENQOBJ' FIELD iv_enqueue_object
ID 'GRANULES' FIELD it_lock_list
ID 'DELAY_ON_REJECT' FIELD ' '
ID 'USTP' FIELD '2'
ID 'COLLISION_UNAME' FIELD ev_user
ID 'COLLISION_OBJECT' FIELD ev_object
ID 'SYNCHRON' FIELD 'X'
ID 'USER' FIELD sy-uname "'00000000000000_OWNER_PERSIST'
ID 'USVB' FIELD '00000000000000_OWNER_PERSIST'.

IF sy-subrc IS NOT INITIAL.

lv_message = "PO locked with other user."
REPLACE '&' IN lv_message WITH ev_user.

RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
textid           = /iwbep/cx_mgw_busi_exception=>business_error
message          =  lv_message
http_status_code = /iwbep/cx_mgw_busi_exception=>gcs_http_status_codes-not_acceptable.

ELSE.
"PO locked succesfully
lo_message_container = me->mo_context->get_message_container( ).
lo_message_container->add_message(
EXPORTING
iv_msg_id     = 'PO'
iv_msg_number = '283'
iv_msg_type   = 'S'  "Refer to GCS_MESSAGE_TYPE
iv_msg_v1     = CONV #( lv_ebeln )
iv_msg_v2     = 'PO Locked Succesfully'(001)
iv_add_to_response_header = abap_true ).

ENDIF.

 

If for some reason the locks are stuck you can use the standard Tcode:SM12 to delete these locks.

Note that, this is generic logic, which can not only be used for OData, but wherever you need persistent locks. For our case I wrapped this logic in a OData service which the App calls.

Hope you enjoyed reading this blog. Kindly let me know your feedback and leave your comments.

Assigned tags

      5 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Shai Sinai
      Shai Sinai

      It is highly advised to avoid of direct CALL statements (for internal use only).

       

      P.S.

      In newer NW releases, SAP introduced a new concept of Durable locks (Check Locking in S4HANA via the Durable Locks & CDS View ObjectModel.Lifecycle annotation for example).

      Author's profile photo Bharat Pemmireddy
      Bharat Pemmireddy
      Blog Post Author

      Hi Shai,

      Thank you for your comments.  I read the SAP help website and it says that it is currently released for SAP application.  Please note that my app is not Fiori instead it is a custom front-end application.  Do you have any idea if OData V4 supports durable locks ? Also tried a search on SCN for disadvantages of using C functions and couldn't find any.  Can you point out to me any content on internet on this topic?

      Author's profile photo Shai Sinai
      Shai Sinai

      Regrading the usage of C functions, this is the first statement in the official documentation:

      "This statement is for internal use only.
      It must not be used in application programs."

      Author's profile photo Prabaharan Asokan
      Prabaharan Asokan

      Shai,

      In my current customer implementation, landscape is not on newer releases(<NW 7.51) where durable locks cannot be achieved, we then discussed with SAP and adapted soft state with few custom enhancements. This is a good alternative but creates performance overhead and occupies more server resources. There are times where a sales order took utmost 30 minutes to finish processing.

      If you have got any improvements / viable methods, please share. Much appreciated. Thanks

       

      Regards

      Prabha

      Author's profile photo roberto rodriguez
      roberto rodriguez

      Hi Bharat Pemmireddy,

      You can create a service to lock objects. In this service you can do ENQUEUE_XXXXX and if you set the stateful enabled the session is holded.

      When you finish the process you can call again your service and disable the stateful, session in finished and objects unlocked.

      You can see in this link:

      https://blogs.sap.com/2015/06/29/using-stateful-session-for-pessimistic-objects-locking/

      Regards.