Skip to Content
Technical Articles
Author's profile photo Mahesh Palavalli

Locking the GUI apps from the Fiori/UI5 has never been so easier (via the Durable Locks for ABAP programming model for Fiori)

Note: This scenario is not officially supported from SAP

Hi Everyone,

 

This blog is about understanding how the durable locks works in the new ABAP programming model for Fiori in creating the pessimistic locking for the Fiori apps which will also lock the GUI application.

I’ve seen people (including myself) struggling to answer the customers when they talk about pessimistic locking in Fiori apps as SAP officially given only ETAG functionality is optimistic based locking. But not anymore thanks to the durable locks which will create pessimistic locking for Fiori and GUI apps together at a time.

Please check the below blog about the locking mechanisms available for the UI5 apps and why the durable locks are introduced.

Note: Below blog talks about overriding the durable locks and processing locks in the second part, so you can skip that part and come here to see how the locking works without going in depth technically as it might be a bit confusing :).

Locking in S4HANA via the Durable Locks & CDS View ObjectModel.Lifecycle annotation

 

Overview:

Durable locks are long lasting locks because they don’t depend on the session/commit work. They depend on the context and will persist for a longer time(based on the configured expiry time). So what is this new context I just mentioned??

From the SAP Help link

A durable lock is requested using a context. A context is a lock phase in which durable locks are assigned to this context. A context belongs to a draft document and is bound to this draft or to a shorter lifespan.

Durable locks are only available for specific SAP applications or frameworks.

So the context is based on the draft document and like sap mentioned, these are only available for few frameworks and one such is ABAP Programming model for Fiori with draft and might probably for the RAP as well.

So for the people who are not very familiar to this framework, please check my other blog as the below example is based on it and If you try that example once, it will be very easy to understand the below process.

Blogpost

 

Let’s see it in action

We will use the same example from the above blog.

Scenario: There will be two users DUSER1 and DUSER2 who will simultaneously open the sales order app and edit the same sales order entry in the Fiori launchpad.

Note: Till now we haven’t configured any locking here, they are auto implemented.

 

First DUSER1 opens the below salesorder and clicks on Edit button.

When clicked on the Edit button, a request will be sent to the backend and will create a draft document and from there onwards the user will work on the draft document and once saved, the data will be copied to the active document and draft will be deleted.

Along with the draft document, a lock will also be created in the SM12 this is called as the Durable lock. This will be auto created for the draft entry by the durable lock class which is part of APM framework. You can also notice that lock is not created for SO header key, it is only for the Draft entry.

 

Now when DUSER2 opens the same application then he will see the status that it is locked by ‘DUSER1’.

If the DURER2 opens the SO and edits it, he will get the below error as the lock still exists in SM12.

 

So till now we have seen how the locking works for the normal draft entry. If you observe, there is no lock created for the SO header key, it is only created for the draft entry in the SM12.

Now what will happen if there is a legacy GUI app which is still being used? Or If any interface calls comes from outside the SAP system and tries to update or delete the entry in the SAP system.

So somehow both the Draft entry locking and active entry locking should be linked right as in some cases user might lock the active entry from Fiori app and maybe some interface calls or gui app or some background job or some other process might try to update the same entry in the meantime.

For this SAP made it so easy, we just need to create or use an existing lock object and call it in the action(which is also auto created by SAP when the BOPF object is created). So simple right? Let’s do it then.

 

Go to the Lock class and in the below method, implement the locking

METHOD /bobf/if_lib_lock_active~lock_active_entity.

    DATA: lt_root        TYPE ztisalesordersheadtp,
          ls_root        LIKE LINE OF lt_root,
          lv_lock_failed TYPE abap_bool,
          ls_failed_key  TYPE /bobf/s_frw_key.

    io_read->retrieve(
      EXPORTING
        iv_node                 = is_ctx-node_key
        it_key                  = it_key
      IMPORTING
        et_data                 = lt_root
        et_failed_key           = et_failed_key
    ).

    READ TABLE lt_root INTO ls_root INDEX 1.
    IF sy-subrc EQ 0.
      CALL FUNCTION 'ENQUEUE_EZSOHEADLOCK'
        EXPORTING
          mode_zso_head  = 'E'
          salesorder     = ls_root-salesorder                 " 02th enqueue argument
          x_salesorder   = space            " Fill argument 02 with initial value?
          _scope         = '2'
          _wait          = space
          _collect       = ' '              " Initially only collect lock
        EXCEPTIONS
          foreign_lock   = 1                " Object already locked
          system_failure = 2                " Internal error from enqueue server
          OTHERS         = 3.
      IF sy-subrc <> 0.
        ls_failed_key-key = ls_root-salesorder.
        APPEND ls_failed_key TO et_failed_key.
      ENDIF.
    ENDIF.

  ENDMETHOD.

So for our legacy applications and for the active document, the locking is implemented. Let’s go back to the fiori app and click on cancel button, which will deletes the draft and removes the lock on the draft entry.

Now again open the sales order and click on edit button, which will create the draft document and along with it creates the lock entry for the draft document and now for the active document as well. Lets check the SM12 lock

We can see two locks are created, one for the draft entry and one for the active entry but both are linked with the draft document. But we never passed any draft document to the ENQUEUE object then how it automatically passes the draft id to it.

There is a class which will first sets the enqueue context and any enqueue object lock that is created afterwards will have the draft id attached to it. I couldn’t find it in the ABAP code, it might be that they are setting the draft id to the active entry lock at the kernal level.

Below is the code where the enqueue context is created for the draft document and will be attached to any lock that is created in that session. Even if you call BU_PARTNER enqueue FM, the BU Partner lock will be linked with the SO_HEAD Draft ID. But yeah, it is pretty useful in case if you want to lock any depended objects when the draft entry is created in the Fiori app.

Just to test if the locking works in the GUI, I created the below report program

Locking code from GUI application:

PARAMETERS:
  p_so TYPE zso_head-salesorder.

AT SELECTION-SCREEN.
  CALL FUNCTION 'ENQUEUE_EZSOHEADLOCK'
    EXPORTING
      salesorder     = p_so                 " 02th enqueue argument
    EXCEPTIONS
      foreign_lock   = 1                " Object already locked
      system_failure = 2                " Internal error from enqueue server
      OTHERS         = 3.
  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
      WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.


END-OF-SELECTION.
  WRITE: 'Locked Successfully'.

Now when we execute it, we will get the lock error.

Similarly if we lock is successfully obtained for the Sales order in the GUI app then in the Fiori app we will get the error.

 

BTW if the user creates the draft entry and doesn’t perform any action on it, after 15 min the locks will be auto removed by the framework and if you want to override this behavior or to know how it works then check out the below blog in the section “How the Durable locks works”.

https://blogs.sap.com/2019/01/09/abap-programming-model-for-sap-fioridraft-durable-locks-cds-view-objectmodel.lifecycle-annotation/

 

Let me know if you have any queries regarding this. I am also exploring this new programming model so any tips, corrections or suggestions are much appreciated.

 

Update:

Tip from Young Hwan Kim 

while calling a BAPI which will implicity lock again inside, this will cause locking error as the lock is not created in the new durable lock enqueue context. So we need to call the below code.

DATA(enqueue_context) = /bobf/cl_lib_enqueue_context=>get_instance( ).
enqueue_context->attach( ls_head-key ) .
" Any BAPI or FM call which will lock inside again
CALL FUNCTION 'BAPI_SALESORDER_CHANGE' ...
enqueue_context->detach( ) .

 

Thanks,

Mahesh

Assigned Tags

      19 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Alexander K
      Alexander K

      Thanks, Mahesh. Very useful.

      And without your code. If first user starts edit "so_header" from gui and second from Fiori (same record)? What happen?

      Author's profile photo Mahesh Palavalli
      Mahesh Palavalli
      Blog Post Author

      Hi Alexander, Thanks for the comment.

      I didn't test this scenario and I will test and update you. But I can tell you from the code that I've seen in the backend that If you mention the annotation "ObjectModel.entityChangeStateId"  for lastChangedAt field (timestamp) then the optimistic error handling will gets triggered.

      Once the Optimistic handling is triggered, it will check the timestamp for the draft entry and the active entry. As the user changes it from the backend, etag check will fail and it will not allow the user to change the data in the UI.

      Anyways I will check and update you once. Thanks Again !!!

      BR,

      Mahesh

      Author's profile photo Alexander K
      Alexander K

      Thanks, Mahesh.

      And whether transaction GUI transaction checks etag?

      Author's profile photo Mahesh Palavalli
      Mahesh Palavalli
      Blog Post Author

      No, GUI will not check, If you look closely it doesn't need to handle it. Let's see this example.

      If the user clicks on edit , it will create a draft entry for the active entry and the etag for the draft entry will be the 'lastChagedBy' or some timestamp of the active entry.

      Now if the user goes and edit the backend, it will update the active entry data along with the timestamp. Now the other user clicks on save in the UI then the the draftframework will check if the timestamp for the draft and active is changed and it will stop the save from the UI.

       

      You have a valid question but if we think in real time uses case, we will always call the enqueue fm to lock the active entry (we have to) as that is the best practice in normal GUI or in the Draft based apps.

       

      BR,

      Mahesh

      Author's profile photo Alexander K
      Alexander K

      Thanks, Mahesh.

      I understand your example.and draftframework behavior

       

      Author's profile photo Dhiraj More
      Dhiraj More

      HI Mahesh,

      Thanks for such a nice blog on locking in Fiori.

      I had a query for your comment on annotation “ObjectModel.entityChangeStateId”  for lastChangedAt field (timestamp) then the optimistic error handling will gets triggered.

      Since “ObjectModel.entityChangeStateId” works with etag we need to know do we have to handle this optimistic error handling explicitly in BOPF based draft application.  Or Adding this annotation in CDS will take care of handling.

      We have a scenario where we have draft entry in fiori app for existing order and some user updates the same order from GUI transaction from backend. We want to show popup to fiori user when he opens the draft entry that order modified by other user in backend. Your changes will overwrite the existing changes. So if he confirms we will overwrite order otherwise current draft entry will be discarded.

      Thanks,

      Dhiraj M

      Author's profile photo Mahesh Palavalli
      Mahesh Palavalli
      Blog Post Author

      Thanks for the feedback Dhiraj More

      You can check my another blog about durable locking. What it does basically is achieving the optimistic locking.. In the draft bopf object, you need to just lock the object using a lock object FM. Everything else will be taken care by SAP.

      Check out my other blog:

      https://blogs.sap.com/2019/01/09/abap-programming-model-for-sap-fioridraft-durable-locks-cds-view-objectmodel.lifecycle-annotation/

       

      Regards,

      Mahesh

       

       

      Author's profile photo Masashi Uruse
      Masashi Uruse

      Thanks, Mahesh.

      And if I lock the Sales Order from UI5,  how to unlock the durable lock of the Sales Order from UI5.

      Because I used the BAPI tries to lock the Sales Order again which will cause the BAPI to fail.

      Author's profile photo Mahesh Palavalli
      Mahesh Palavalli
      Blog Post Author

      If you delete the draft from the ui5 app, then the durable lock will be automatically deleted, which is the only option. Or you need to wait for the draft to get expired.

      Author's profile photo Masashi Uruse
      Masashi Uruse

      Mahesh, Thank you for your answer.

       

      I did some practice with reference to this series of blogs.

      Creating a draft enabled Sales Order Fiori App using the new ABAP Programming Model

      https://blogs.sap.com/2019/03/11/creating-a-draft-enabled-sales-order-fiori-app-using-the-new-abap-programming-model-part-1-overview/

       

      But in part 6, the author told me that the durable locking needs to be disabled which Implemented at part 4. If I don’t disable the durable lock, I can’ t update the draft to an active instance.

      So there’s no other way to solve this problem, right? Except delete the code of lock which implement at part 4.

       

       

      Author's profile photo Mahesh Palavalli
      Mahesh Palavalli
      Blog Post Author

      Ideally it shoudn't cause any issue.. Unless if the lock is being set in the update task..

      If the lock is set it will automatically get the draft context, atleast at the locking class, not sure if the context is passed to lock at the time of draft to active method.

      Did you try this and got an error at the time of draft delete?

      BR,

      Mahesh

      Author's profile photo Masashi Uruse
      Masashi Uruse

      Mahesh, Thank you for your answer.

      Draft delete is not have issue.

      I shared the detail of the issue, could you please give me some advice of it.

      I Implemented the class ZCL_A_LOCK_SD_SOHEADER that set a lock for Sales Order, when I update the Sales Order, the Sales Order will has been locked.

      then I update the Sales Order, the Sales Order is locked normally.

      But unfortunately, if I want to save the change with 'BAPI_SALESORDER_CHANGE'. the issue happened, the Sales Order has been locked by other user , even I used same user or implemented the function 'DEQUEUE_EVVBAKE' before 'BAPI_SALESORDER_CHANGE'.

      I think updating and saving sessions are different, so I don’t disable the durable lock.

      But if I click cancel, the lock has been disabled.

      Thanks.

      Author's profile photo Mahesh Palavalli
      Mahesh Palavalli
      Blog Post Author

      This is some weird behavior, I will check it out and let u know if i find any solution..

      Author's profile photo Masashi Uruse
      Masashi Uruse

      Mahesh, Thank you.

      Waiting for you reply.

      Author's profile photo MANOHAR VELAPALEM
      MANOHAR VELAPALEM

      I am also facing the same Issue. Unable to dequeue the Workorder Using DEQUEUE_ESORDER before calling the BAPI for change.

      Any solution for this issue.

      Thanks & Regards

       

      Author's profile photo Young Hwan Kim
      Young Hwan Kim

      I also had the same problem with sales order change BAPI, but I found out the solution to share.

      The solution is simple, just need enque context in draft to active method.

      DATA(enqueue_context) = /bobf/cl_lib_enqueue_context=>get_instance( ).
      enqueue_context->attach( ls_head-key ) .
      CALL FUNCTION 'BAPI_SALESORDER_CHANGE' ...
      enqueue_context->detach( ) .
      

       

       

      Author's profile photo Mahesh Palavalli
      Mahesh Palavalli
      Blog Post Author

      Awesome and That's really great!! I've checked it while I was writing the durable locks blog and now completely forgot about it. Thanks for sharing this. Will include this in the blog!!.

      Author's profile photo Samson Moses
      Samson Moses

      Hi Mahesh,

      Kudos again for another insightful and awesome blog !

      We are currently on SAP 7.50 version and our front-end application's developed is in SAPUI5 ( not Fiori ). I have defined my Business Object Views and Consumption views based on my semantic key-based object model. They are not having GUID keys.

      On activation of Business Object View, I do see an action LOCK_<Business object View> created only for my root node. The implementation class is generated as ZCL_A_LOCK_<Business object View>, as a base class of /BOBF/CL_LIB_A_LOCK_ACTIVE.

      I have the below questions regarding the durable locks :

      • I have read in one of your blogs and also from one by SAP, that they are not released for customers. So should we consider this as an option for implementing locks in our case?
      • Secondly, on what condition the CDS activation results in the LOCK Action being created. Is there any CDS annotation which automatically creates the underlying class? Strangely, for another of my self learning business object view, it had not created the Lock action.

      Your expert opinion will really be helpful !!!

      Regards,

      Samson

      Author's profile photo Mahesh Palavalli
      Mahesh Palavalli
      Blog Post Author

      Hi Samson,

      Really appreciate the feedback 🙂 Thanks 🙂 🙂

      You can check more about the durable locks in this blog.

       

      You are right, they are not released to customers, but by default it will be handled by SAP in ABAP Programming model for fiori. So I don't think it would cause any issues in future (per my understating).

      Only the base code might change, but the usage from the top layers will remain.   As you can see, I am not creating any durable locks explicitly, they are automatically created by our normal lock object. Again there is some code which will set the context for that session, which is again handled by SAP, so even if they change it, it will not be any issue for us. You can check more about that in this comment.

      For semantic keys it will not work, I mean it will work but the locking is based on the Draft GUID key, So the durable locks are applicable only for the draft based scenarios. BTW that blog approach is also not officially supported by SAP 😀 😀 but most of the standard fiori draft based apps uses the approach described in that blog.

      Now to your lock object creation, I think it should be created automatically, I am not aware of any scenario that will skip it's creation,  Maybe a scenario where the activePersistance annotation is used, so SAP will only insert the data into table automatically, so they only will handle locking?? not sure though.

       

      Thanks,

      Mahesh