Monday, 2 July 2018

BOPF: Custom Lock/Unlock Action for Legacy DAC

1.  Objective


Objective of this document is to explain how to create custom lock/unlock action in case you are using legacy DAC. In my previous blog I have explain how to configure BOPF using Legacy tables. Refer to below link for more details on BOPF: Using Non-UUIDs (DB_KEY) keys DB tables

http://sapabapcentral.blogspot.com/2018/06/bopf-using-non-uuids-dbkey-keys-db.html

2. Why do we need Custom Lock/Unlock Action for Legacy DAC


The standard lock action will acquire a lock based on the instance UUID. Since the transient keys used by the legacy DAC start counting from ‘1’ for each session, it is very likely to experience locking issues. You can check in SM12 if the lock argument shows such a transient key instead of a proper UUID.

SAP ABAP Development, SAP ABAP Study Materials, SAP ABAP Learning, SAP ABAP Certifications

3.  How to Implement Custom Lock/Unlock Action


Implementation of Custom Lock/unlock action for legacy DAC requires the following steps:

3.1  BOPF Configuration

BOPF frameworks handles the enqueue and dequeue as well as lock-result implicitly at runtime. 

If you just need to change Lock/Unlock configuration for Legacy DAC there should not be any issues. You have to make sure no other fields should be changed. For a developer it won’t be difficult to find a way to replace default locking/unlocking implementing Class /BOBF/CL_LIB_A_LOCK.

3.1.1 Enable visibility of Technical Entities

By default, Lock/Unlock Actions are not visible in the transaction Code /BOBF/CONF_UI. You can enable visibility of the technical entities responsible for locking in the display-options (Utilities -> Settings):

SAP ABAP Development, SAP ABAP Study Materials, SAP ABAP Learning, SAP ABAP Certifications

3.1.2 Change Implementing Class /BOBF/CL_LIB_A_LOCK


Click on the ROOT Node under then Node Elements then expand ACTION folder. You would be able to find LOCK_ROOT & UNLOCK_ROOT actions. Taking example from my previous blog, see below screenshot of default LOCK_ROOT and UNLOCK_ROOT action implementing class. You need to change configuration and add a custom class.

SAP ABAP Development, SAP ABAP Study Materials, SAP ABAP Learning, SAP ABAP Certifications

SAP ABAP Development, SAP ABAP Study Materials, SAP ABAP Learning, SAP ABAP Certifications

Configure same custom class for UNLOCK_ROOT.

3.2  Coding

Now you need to write your own custom Enqueue/Dequeue logic in the custom class. Custom Logic should be written inside method EXECUTE only.

SAP ABAP Development, SAP ABAP Study Materials, SAP ABAP Learning, SAP ABAP Certifications

3.2.1 Sample Code

Taking example from my previous blog BOPF: Using Non-UUIDs (DB_KEY) keys DB tables


Locking is done for two custom field Quota Number and company code instead of Transient keys. The following steps provide example codes with step by step approach for enqueue dequeue call.

Step 1: check edit mode is correct else raise exception using BOPF framework

    DATA lr_parameter     TYPE REF TO /bobf/s_frw_lock_parameters.
    DATA ls_location      TYPE /bobf/s_frw_location.
    DATA lr_cm            TYPE REF TO /bobf/cm_lib.
    DATA ls_key           TYPE /bobf/s_frw_key.

    lr_parameter ?= is_parameters.

* check lock mode
    IF lr_parameter->edit_mode <> /bobf/if_conf_c=>sc_edit_exclusive  AND
       lr_parameter->edit_mode <> /bobf/if_conf_c=>sc_edit_shared     AND
       lr_parameter->edit_mode <> /bobf/if_conf_c=>sc_edit_optimistic AND
       lr_parameter->edit_mode <> /bobf/if_conf_c=>sc_edit_promote    AND
       lr_parameter->edit_mode <> /bobf/if_conf_c=>sc_edit_check_optimistic.

      eo_message = /bobf/cl_frw_factory=>get_message( ).
      ls_location-node_key = is_ctx-node_key.
      LOOP AT it_key INTO ls_key.
        ls_location-key = ls_key-key.
        CREATE OBJECT lr_cm
          EXPORTING
            textid             = /bobf/cm_lib=>invalid_lock_mode
            severity           = /bobf/cm_frw=>co_severity_error
            ms_origin_location = ls_location.
        eo_message->add_cm( lr_cm ).
      ENDLOOP.
      et_failed_key = it_key.
      RETURN.
    ENDIF.

Step 2:  Based on Action Category Implement Lock and Unlock

IF is_ctx-act_cat = /bobf/if_conf_c=>sc_action_lock.
lock( EXPORTING is_ctx        = is_ctx
it_key        = it_key
is_parameters = lr_parameter->*
IMPORTING et_failed_key = et_failed_key
er_message    = eo_message ).
ELSE.
unlock( EXPORTING is_ctx        = is_ctx
it_key        = it_key
is_parameters = lr_parameter->*
IMPORTING er_message    = eo_message ).
ENDIF.

Step 3: Determine Key from Transient Key GUID using Class /BOBF/CL_LIB_LEGACY_KEY

FIELD-SYMBOLS: <fs_bukrs>   TYPE bukrs,
<fs_quotano> TYPE /bsk/quotano.
DATA ls_location            TYPE /bobf/s_frw_location.
DATA lr_cm                  TYPE REF TO /bobf/cm_lib.
DATA: lt_legacy_key         TYPE Ztt_k_db_key.”Legacy DAC Key (used in  alternative root key)
DATA: lv_user               TYPE syuname.

ls_location-node_key = is_ctx-node_key.
"Prepare Legacy key
/bobf/cl_lib_legacy_key=>get_instance( is_ctx-bo_key )->convert_bopf_to_legacy_keys(
EXPORTING
iv_node_key   = is_ctx-node_key    " Key of BOPF node
it_bopf_key   = it_key    " BOPF keys to convert
IMPORTING
et_legacy_key = lt_legacy_key    " Resulting legacy keys
).
er_message = /bobf/cl_frw_factory=>get_message( ).

Step 4: Call Enqueue & Dequeue using Legacy Keys (for Example Company Code, Quota number)

"Lock
LOOP AT lt_legacy_key ASSIGNING FIELD-SYMBOL(<fs_legacy_key>).
"Enqueue
TRY.
call_enqueue( EXPORTING iv_bukrs = <fs_legacy_key>-bukrs iv_quotano = <fs_legacy_key>-quotano ).
CATCH /bsk/cx_dsd_exceptions INTO DATA(lr_exception).
CLEAR: lv_user.
lv_user = lr_exception->if_t100_dyn_msg~msgv1.
"Raise
CREATE OBJECT lr_cm
EXPORTING
textid             = /bobf/cm_lib=>retrieve_foreign_lock
severity           = /bobf/cm_frw=>co_severity_error
ms_origin_location = ls_location
symptom            = /bobf/if_frw_message_symptoms=>co_foreign_lock
mv_user            = lv_user.
er_message->add_cm( lr_cm ).
ENDTRY.
ENDLOOP.

Step 5: Enqueue Method

METHOD call_enqueue.
CALL FUNCTION 'ENQUEUE_ZE_TQUOTAH'
EXPORTING
*       MODE_ZTQUOTAH       = 'E'
*       MANDT          = SY-MANDT
bukrs          = iv_bukrs
quotano        = iv_quotano
*       X_BUKRS        = ' '
*       X_QUOTANO      = ' '
*       _SCOPE         = '2'
*       _WAIT          = ' '
*       _COLLECT       = ' '
EXCEPTIONS
foreign_lock   = 1
system_failure = 2
OTHERS         = 3.
IF sy-subrc <> 0.
" Raise exception
RAISE EXCEPTION TYPE zcx_dsd_exceptions
MESSAGE ID sy-msgid
TYPE sy-msgty
NUMBER sy-msgno
WITH sy-msgv1
sy-msgv2
sy-msgv3
sy-msgv4.
ENDIF.

ENDMETHOD.

Step 6: Unlock Method

METHOD unlock.
DATA: lt_legacy_key TYPE ztt_k_db_key.

"Prepare Legacy key
/bobf/cl_lib_legacy_key=>get_instance( is_ctx-bo_key )->convert_bopf_to_legacy_keys(
EXPORTING
iv_node_key   = is_ctx-node_key    " Key of BOPF node
it_bopf_key   = it_key    " BOPF keys to convert
IMPORTING
et_legacy_key = lt_legacy_key    " Resulting legacy keys
).
"Lock
LOOP AT lt_legacy_key ASSIGNING FIELD-SYMBOL(<fs_legacy_key>).
"Dequeue
call_dequeue( EXPORTING iv_bukrs = <fs_legacy_key>-bukrs iv_quotano = <fs_legacy_key>-quotano ).
ENDLOOP.

ENDMETHOD.

Step 7: Dequeue Method

METHOD call_dequeue.
CALL FUNCTION 'DEQUEUE_ZE_TQUOTAH'
EXPORTING
*       MODE_ZTQUOTAH       = 'E'
*       MANDT   = SY-MANDT
bukrs   = iv_bukrs
quotano = iv_quotano
*       X_BUKRS = ' '
*       X_QUOTANO               = ' '
*       _SCOPE  = '3'
*       _SYNCHRON               = ' '
*       _COLLECT                = ' '
.

ENDMETHOD.

2 comments: