Wednesday 23 June 2021

Use of node class in BOPF

Introduction:

I tried searching the web regarding “node class” of BOPF framework, I found very little information. Hence, I explored it and thought to share my findings in the community, which will help someone who is new to the framework. So in this blog post, we will see the use of “Node Class” in a BOPF Node. We will discuss its functionality, the required API, and all related information. Below is the screenshot where the node class is maintained.

SAP ABAP Tutorial and Material, SAP ABAP Learning, SAP ABAP Exam Prep, SAP ABAP Preparation, SAP ABAP Career, SAP ABAP BOPF
Image depicting the place to mention node class for a node

Uses of the Node Class:


The use of the node class is to default the values in the attribute of the node. For example, let’s say for the BO “Purchase Order”, we want to default the document date as “System Date”. Or, for example, in the risk assessment, we want to default the status as ’01′(New). In this case, we should use the “Node Class”.

Node Class API:


A node class should implement the interface “/BOBF/IF_FRW_NODE”. It contains 2 methods.

◉ RETRIEVE_DEFAULT_VALUES
◉ SET_NODE_CATEGORY -> This method is obsolete now

The logic for the default value should be written in the method “RETRIEVE_DEFAULT_VALUES” method.

Important Parameter of method “RETRIEVE_DEFAULT_VALUES”


Parameter Name Description 
IS_CTX

Details about the BO and Node for which node class is being called. This parameter is a structure.

Some important attributes of the parameter are:

BO_KEY – BO Key of the node

ROOT_NODE_KEY – Node key of the BO. Please note, the key is not the node instance key, rather it’s the node key. We can use this key to compare the node key of the BO using <constant_interface>=>SC_NODE-ROOT

NODE_KEY – This is the node key of the BO. Please note, this is also not the instance of the node, rather the node key of the BO

IT_KEY  These are the node instances for which the node class is being called. This values can be used to retrieve the data using IO_READ parameter. 
IO_READ   Used to retrieve the data. Please use the above link for the example usage
IO_MODIFY   Used to modify the node data. In our case, we will use it to default the value in the node instance. 

Creating the node class:


In this section, we will create and implement the logic of “Node class”. I have already a BO “ZRISK_ASSESSMENT”. In the BO, we have a node “ROOT”. I will use this node and will specify the node class for it and will populate the “Title Field” of the root through the node class. If you want to populate default value for document date in the Purchase order, then in the node class, you have to populate the document date.

Step 1:

The class can be created directly in SE24 by implementing the interface /BOBF/IF_FRW_NODE manually or it can be created from the BO by double-clicking the class name. The system will ask to create the class on double click if the class is not existing. I will go through the second option.

SAP ABAP Tutorial and Material, SAP ABAP Learning, SAP ABAP Exam Prep, SAP ABAP Preparation, SAP ABAP Career, SAP ABAP BOPF
(Above screenshot is from BOBX)

Step 2:

Double click on the node class name been provide by you. If the class is not existing, you will get below pop-up, click on yes.

SAP ABAP Tutorial and Material, SAP ABAP Learning, SAP ABAP Exam Prep, SAP ABAP Preparation, SAP ABAP Career, SAP ABAP BOPF

Step 3:

Once you click on “yes”, the specified class will be created and you can see the interface is already implemented and you can see both the method available

SAP ABAP Tutorial and Material, SAP ABAP Learning, SAP ABAP Exam Prep, SAP ABAP Preparation, SAP ABAP Career, SAP ABAP BOPF
(We can see the required interface is implemented)

SAP ABAP Tutorial and Material, SAP ABAP Learning, SAP ABAP Exam Prep, SAP ABAP Preparation, SAP ABAP Career, SAP ABAP BOPF
(Both the method from the interface can be seen)

Fun fact:

Actually, if we will see with attention, we can found out the created class didn’t implement the interface “/BOBF/IF_FRW_NODE” directly. Rather it inherited the class “/BOBF/CL_LIB_N_SUPERCLASS” which implements the required interface.

Step 4:

Redefine the method “RETRIEVE_DEFAULT_VALUES” of the class.

SAP ABAP Tutorial and Material, SAP ABAP Learning, SAP ABAP Exam Prep, SAP ABAP Preparation, SAP ABAP Career, SAP ABAP BOPF
(redefinition of method RETRIEVE_DEFAULT_VALUES)

Step 5:

Implement the logic. I have not read the data using IO_READ, I know the value which needs to default.

SAP ABAP Tutorial and Material, SAP ABAP Learning, SAP ABAP Exam Prep, SAP ABAP Preparation, SAP ABAP Career, SAP ABAP BOPF
(logic implemented to default the value of the attribute)

    DATA:
      ls_root TYPE zras_d_root.

    LOOP AT it_key INTO DATA(ls_key).

      "Default values
      ls_root-title = |Title Defaulted in Node Class|.

      "Update default values
      io_modify->update(
        EXPORTING
          iv_node           = is_ctx-node_key           " Node
          iv_key            = ls_key-key                " Key
          is_data           = REF #( ls_root )          " Data
          it_changed_fields = VALUE #( ( |TITLE| ) )    " List of Names (e.g. Fieldnames)
      ).

    ENDLOOP.

You can see, I have looped for all the node instances and set the value in the ls_root work area. Then I have updated the node instance using the parameter io_modfiy, which will default the title of my risk assessment.

So, we have successfully created a node class and implemented the logic. But, the next big question is, who calls the class? Is the BOPF framework making a call?

So, the answer is, the BOPF framework does not call the “node class” to default the values. It is the work of the consumer layer(for example FBI, SAP Gateway, generic consumer, etc or an ENA class(Easy node access class) to call the node API and default the value before the field is diplayed on the UI.

So, the obvious next question is – How to call the node class? 

The service manager interface “/BOBF/IF_TRA_SERVICE_MANAGER” has a method “RETRIEVE_DEFAULT_NODE_VALUES”. So, this method should be called, which will ultimately call the respective node class based on the Node_KEY been provided and defaults the value.

SAP ABAP Tutorial and Material, SAP ABAP Learning, SAP ABAP Exam Prep, SAP ABAP Preparation, SAP ABAP Career, SAP ABAP BOPF
(Image depicting the service manager interface which is used to call the node class)

So, if you are using FBI(FPM-BOPF Integration), the feeder class for FBI will have a call to this method, so no need to call it explicitly. But, for demonstration, I will use a report program to show how to call in the subsequent section.

Calling the node class to default the value in the node:


Please refer to below screenshot. The object “MO_SMNGR_RAS” is the service manager of the BO “Risk Assessment”, which is used to call the method “RETRIEVE_DEFAULT_NODE_VALUES”, which will provide the defaulted values based on the logic written in node class(discussed earlier in this blog post).

Note:

◉ Please note, the CT_DATA parameter expects the table type of the combined struture

◉ If the table CT_DATA is blank, it will not return the default value. It better to generate the UUID and append it to the CT_DATA(i did the same in below example).

SAP ABAP Tutorial and Material, SAP ABAP Learning, SAP ABAP Exam Prep, SAP ABAP Preparation, SAP ABAP Career, SAP ABAP BOPF

Complete Report Source code:

*&---------------------------------------------------------------------*
*& Report ZRAS_DATA_NODE_CLASS
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zras_call_node_class.

CLASS lcl_ras_data DEFINITION.

  PUBLIC SECTION.

    METHODS:
      constructor,
      create_new_root
        IMPORTING im_s_root           TYPE zras_s_root_d
        RETURNING VALUE(rt_o_message) TYPE REF TO /bobf/if_frw_message.

  PRIVATE SECTION.

    DATA:
      mo_smngr_ras TYPE REF TO /bobf/if_tra_service_manager,
      mo_tmngr     TYPE REF TO /bobf/if_tra_transaction_mgr.

ENDCLASS.


START-OF-SELECTION.

  "Create object of local class
  DATA(lo_ras_data) = NEW lcl_ras_data( ).

  "Fill the node
  DATA(lo_message) = lo_ras_data->create_new_root(
    im_s_root = VALUE #(
      status        = '01'
      type          = 'WA_RAS'
      is_simulated  = abap_false
    )
  ).

  IF lo_message IS BOUND.
    IF lo_message->check( ) EQ abap_true.
      MESSAGE 'Creation failed' TYPE 'S' DISPLAY LIKE 'E'.
    ELSE.
      MESSAGE 'Creation successful' TYPE 'S'.
    ENDIF.
  ELSE.
    MESSAGE 'Creation successful' TYPE 'S'.
  ENDIF.

CLASS lcl_ras_data IMPLEMENTATION.

  METHOD constructor.

    "Get reference of the service manager
    mo_smngr_ras = /bobf/cl_tra_serv_mgr_factory=>get_service_manager( zif_risk_assessment_c=>sc_bo_key ).

    "Get reference of transactional manager
    mo_tmngr = /bobf/cl_tra_trans_mgr_factory=>get_transaction_manager( ).

  ENDMETHOD.

  METHOD create_new_root.

    FREE rt_o_message.

    DATA:
      lt_root TYPE zras_t_root.

    "Move corresponding values
    DATA(ls_ras_root) = CORRESPONDING zras_d_root( im_s_root ).

    "Get new UUID
    ls_ras_root-db_key = /bobf/cl_frw_factory=>get_new_key( ).

    APPEND CONV zras_s_root(
      CORRESPONDING #(
        ls_ras_root
          MAPPING key = db_key
      )
    ) TO lt_root.

    "Retrive default value --> Point to keep in mind, here LT_ROOT is the table type of the COMBINED Structure
    mo_smngr_ras->retrieve_default_node_values(
      EXPORTING
        iv_node_key                  = zif_risk_assessment_c=>sc_node-root    " Node
      CHANGING
        ct_data                      = lt_root
    ).

    LOOP AT lt_root INTO DATA(ls_root_dt).

      ls_ras_root = CORRESPONDING #( ls_root_dt MAPPING db_key = key ).

      "Assign value to modificationt table
      DATA(lt_modif) = VALUE /bobf/t_frw_modification(
        ( node          = zif_risk_assessment_c=>sc_node-root
          change_mode   = /bobf/if_frw_c=>sc_modify_create
          key           = ls_ras_root-db_key
          data          = REF #( ls_ras_root ) )
      ).

    ENDLOOP.

    "Modify the data
    mo_smngr_ras->modify(
      EXPORTING
        it_modification = lt_modif    " Changes
      IMPORTING
        eo_change       = DATA(lo_change)    " Interface of Change Object
        eo_message      = rt_o_message    " Interface of Message Object
    ).

    IF rt_o_message IS BOUND.
      IF rt_o_message->check( ) EQ abap_true.
        RETURN.
      ENDIF.
    ENDIF.

    "Save data to data base
    mo_tmngr->save(
      IMPORTING
        eo_message  = rt_o_message
    ).

  ENDMETHOD.

ENDCLASS.

Data in the database:

SAP ABAP Tutorial and Material, SAP ABAP Learning, SAP ABAP Exam Prep, SAP ABAP Preparation, SAP ABAP Career, SAP ABAP BOPF

Source: sap.com

No comments:

Post a Comment