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.
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.
- SET_NODE_CATEGORY -> This method is obsolete now
The logic for the default value should be written in the method “RETRIEVE_DEFAULT_VALUES” method.
More information on the Node API can be found from below SAP Help Documentation
Important Parameter of method “RETRIEVE_DEFAULT_VALUES”
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
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.
Refer to the below link for example:
|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.
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.
(Above screenshot is from BOBX)
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
(We can see the required interface is implemented)
(Both the method from the interface can be seen)
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.
Redefine the method “RETRIEVE_DEFAULT_VALUES” of the class.
Implement the logic. I have not read the data using IO_READ, I know the value which needs to default.
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.
You can also follow the below link for the example implementation
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.
(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).
- 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).
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.
So, in this blog post, we saw that “node class” are used to default the values in some of the attribute of the node instance, such as document date or a title. We also explored the Node API and implemented the logic. We also discussed that, node class is not called by BOPF rather by the consumer layer such as FBI, SAP Gateway or a ENA class. We also saw how to call the node class using the service manager.
Hope this helps to understand the node class of the BOPF framework.