Skip to Content
Technical Articles
Author's profile photo Andre Fischer

Generating and registering Business Configuration Objects with transport API support using the RAP Generator

Introduction

Since the View Maintenance Tools (SM30/SM34) are not available in SAP BTP ABAP Environment another solution had to be offered in order to store and transport customizing data.

The solution for this requirement are Business Configuration Objects that have been explained in detail in the following blog of Thomas Schneider.

Business Configuration for SAP Cloud Platform ABAP Environment | SAP Blogs

A Business Configuration Object is essentially a RAP Business Object. It defines the fields that can be changed by the user to influence the behavior of an app. SAP partners register their configuration objects via the ABAP API MBC_CP_API so they are shown in the Maintain Business Configurations Fiori app which is documented here:

Maintain Business Configurations App – SAP Help Portal

The RAP Business Object must be draft enabled and has to provide a service binding of type OData V4 – UI .

When creating a new Business Configuration Object Registration, the name of the OData v4 Service Binding must be supplied. The SMBC logical transport object, that is created during registration, is assigned to the package of the registered Service Binding.

How to create Business Configuration Objects ?

How to create a Business Configuration Object has been described in this tutorial. However, creating such an object still creates lots of manual steps so it was obvious that generating this type of boiler plate coding would be a perfect fit for the RAP Generator.

Please note, that it is planned to provide an out of the box solution based on the ABAP Development Tools in Eclipse with an upcoming release.

Nevertheless it is possible to use the RAP Generator to generate appropriate Business Configuration Objects already now.

The RAP Generator is described in the following blog and can be downloaded from GitHub from this repository.

Generating a Business Configuration

So lets look how you can generate a Business Configuration Object, register it automatically for the use in the Maintain Business Configuration App and have also the code generated so that your data can be transported.

1. Create tables

We will use the same data model as in the aforementioned tutorial and will start to create two tables ZFCAL_HOLI_344 and ZFCAL_HOLTXT_344. Be sure to use the delivery class C or S.

Table for root entity view: ZFCAL_HOLI_344 

@EndUserText.label : 'zfcal_holi_344'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #C
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zfcal_holi_344 {
  key client              : mandt not null;
  key holiday_id          : abap.char(30) not null;
  month_of_holiday        : abap.numc(2);
  day_of_holiday          : abap.numc(2);
  changedat               : timestampl;
  config_deprecation_code : config_deprecation_code;
  local_last_changed_at   : timestampl;
  created_by              : syuname;
  created_at              : timestampl;
  last_changed_by         : syuname;

}

Table for child view: ZFCAL_HOLTXT_344.

@EndUserText.label : 'ZFCAL_HOLTXT_344'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #C
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zfcal_holtxt_344 {
  key client       : mandt not null;
  @AbapCatalog.textLanguage
  key spras        : spras not null;
  key holiday_id   : abap.char(30) not null;
  fcal_description : abap.char(100);

}

2. Create JSON file

In order to use the RAP Generator you simply have to provide the following JSON string to the RAP Generator:

{
  "implementationType": "managed_semantic",
  "namespace": "ZFCAL",
  "suffix": "_344",
  "prefix": "",
  "package": "Z_CUST_344",
  "datasourcetype": "table",
  "bindingtype": "odata_v4_ui",
  "draftenabled": true,
  "transportrequest": "",
  "iscustomizingtable": true,
  "addbusinessconfigurationregistration": true,
  "hierarchy": {
    "entityName": "Holiday",
    "dataSource": "zfcal_holi_344",
    "drafttable": "zfcal_holid344",
    "objectId": "holiday_id",
    "lastChangedAt": "changedat",
    "lastChangedBy": "last_changed_by",
    "createdAt": "created_at",
    "createdBy": "created_by",
    "localInstanceLastChangedAt": "local_last_changed_at",
    "children": [
      {
        "entityName": "HolidayText",
        "dataSource": "zfcal_holtxt_344",
        "drafttable": "zfcal_holtxtD344",
        "objectId": "holiday_id",
        "localInstanceLastChangedAt": "local_last_changed_at"
      }
    ]
  }
}

 

"implementationType": "managed_semantic"

The implementation type we choose is managed with semantic key fields.

"namespace": "ZFCAL",
"suffix": "_003 "

The namespace of our tables is ZFCAL and we have used a suffix 003 for testing purposes.

"bindingtype": "odata_v4_ui",
"draftenabled": true,

The binding type must be OData V4 – UI and the RAP object has to be draft enabled.

"isCustomizingTable": true,
"addBusinessConfigurationRegistration": true,

The two new parameters that enable the generation and registration of a business object are the parameters isCustomizingTable and addBusinessConfigurationRegistration.

When setting isCustomizingTable to true the RAP Generator will generate the appropriate coding to call the transport API into the behavior definition classes.

The parameter addBusinessConfigurationRegistration instructs the RAP Generator to call the Maintain Business Configurations API to create Business Object registration.

Maintain Business Configurations API – SAP Help Portal

3. Create console application

The above mentioned JSON file can be used in the following command line application

CLASS zcl_rap_generator_cust_344 DEFINITION
  PUBLIC
   INHERITING FROM cl_xco_cp_adt_simple_classrun
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
  PROTECTED SECTION.
    METHODS: main REDEFINITION.
  PRIVATE SECTION.
ENDCLASS.



CLASS zcl_rap_generator_cust_344 IMPLEMENTATION.
  METHOD main.

    DATA(json_string) = '{' && |\r\n|  &&
                        '  "implementationType": "managed_semantic",' && |\r\n|  &&
                        '  "namespace": "ZFCAL",' && |\r\n|  &&
                        '  "suffix": "_344",' && |\r\n|  &&
                        '  "prefix": "",' && |\r\n|  &&
                        '  "package": "Z_CUST_344",' && |\r\n|  &&
                        '  "datasourcetype": "table",' && |\r\n|  &&
                        '  "bindingtype": "odata_v4_ui",' && |\r\n|  &&
                        '  "draftenabled": true,' && |\r\n|  &&
                        '  "transportrequest": "",' && |\r\n|  &&
                        '  "iscustomizingtable": true,' && |\r\n|  &&
                        '  "addbusinessconfigurationregistration": true,' && |\r\n|  &&
                        '  "hierarchy": {' && |\r\n|  &&
                        '    "entityName": "Holiday",' && |\r\n|  &&
                        '    "dataSource": "zfcal_holi_344",' && |\r\n|  &&
                        '    "drafttable": "zfcal_holid344",' && |\r\n|  &&
                        '    "objectId": "holiday_id",' && |\r\n|  &&
                        '    "lastChangedAt": "changedat",' && |\r\n|  &&
                        '    "lastChangedBy": "last_changed_by",' && |\r\n|  &&
                        '    "createdAt": "created_at",' && |\r\n|  &&
                        '    "createdBy": "created_by",' && |\r\n|  &&
                        '    "localInstanceLastChangedAt": "local_last_changed_at",' && |\r\n|  &&
                        '    "children": [' && |\r\n|  &&
                        '      {' && |\r\n|  &&
                        '        "entityName": "HolidayText",' && |\r\n|  &&
                        '        "dataSource": "zfcal_holtxt_344",' && |\r\n|  &&
                        '        "drafttable": "zfcal_holtxtD344",' && |\r\n|  &&
                        '        "objectId": "holiday_id",' && |\r\n|  &&
                        '        "localInstanceLastChangedAt": "local_last_changed_at"' && |\r\n|  &&
                        '      }' && |\r\n|  &&
                        '    ]' && |\r\n|  &&
                        '  }' && |\r\n|  &&
                        '}'.

    DATA(rap_generator) = NEW /dmo/cl_rap_generator( json_string ).
    DATA(todos) = rap_generator->generate_bo(  ).
    DATA(rap_bo_name) = rap_generator->root_node->rap_root_node_objects-service_binding.
    out->write( |RAP BO { rap_bo_name }  generated successfully| ).
    out->write( |Todo's:| ).
    LOOP AT todos INTO DATA(todo).
      out->write( todo ).
    ENDLOOP.
  ENDMETHOD.

ENDCLASS.

 

As a result you will see that the following in our package.

 

 

 

4. Run console application

When we let the class run by pressing F9 we get the following output

RAP BO ZFCALUI_Holiday_344_O4 generated successfully
Todo's:
Messages from XCO framework
Type: BDEF Object name: ZFCALC_HOLIDAY_344 Message: The field "HOLIDAYID" is used for "parent" dependency (in the ON clause 
Type: BDEF Object name: ZFCALC_HOLIDAY_344 Message: of the association "_Holiday"). This means it should be flagged as 
Type: BDEF Object name: ZFCALC_HOLIDAY_344 Message: "readonly / readonly:update". 
Type: BDEF Object name: ZFCALI_HOLIDAY_344 Message: The field "HOLIDAYID" is used for "parent" dependency (in the ON clause 
Type: BDEF Object name: ZFCALI_HOLIDAY_344 Message: of the association "_Holiday"). This means it should be flagged as 
Type: BDEF Object name: ZFCALI_HOLIDAY_344 Message: "readonly / readonly:update". 
Messages from XCO framework (Service Binding)
Type: Object name: Message: To enable publish of local service endpoint, activate the Service Binding 
Messages from business configuration registration
ZFCALI_Holiday_344 registered successfully.

We see that the following objects have been generated for our convenience:

 

 

5. Publish Business Configuration object

Do not forget to publish the Service Binding of the generated Business Configuration

6. Run Maintain Business Configuration App

When we run the Maintain Business Configuration App we see that our service is listed here :

When we click on the registration entry a Fiori Elements App is started on the fly that allows us to enter Business Configuration Data for our convenience.

Transport support

The SAP Cloud Platform ABAP Environment exposes an API that you can use for managing customizing requests and the content in customizing requests cl_a4c_bc_factory. The RAP Generator generates the appropriate coding in the behavior implementation classes for the root and the child entities.

Please note that an appropriate software component of type Business Configuration must be present in your system because otherwise the transport API will fail.

When having saved the data as shown above we can see a new entry in the Customizing Transport Organizer App.

Drilling down into the details we find the information about the two tables to which data has been written to.

 

When checking the code of the code of the local handler class of the behavior implementation class you will find code such as the following that has been generated by the RAP Generator that adds data to a transport request.

 

CLASS lcl_handler IMPLEMENTATION.
  METHOD get_instance_features.
  ENDMETHOD.
  METHOD val_transport.
    CHECK lines( keys ) > 0.
    DATA table_keys TYPE TABLE OF zfcal_holi_344 .
    table_keys = VALUE #( FOR key IN keys (
             holiday_id = key-HolidayID
    ) ).
    TRY.
        cl_a4c_bc_factory=>get_handler( )->add_to_transport_request(
              EXPORTING
                iv_check_mode         = abap_true
                it_object_tables      = VALUE #( ( objname = 'ZFCAL_HOLI_344'
                                                   tabkeys = REF #( table_keys )  ) )
                iv_mandant_field_name = 'CLIENT'
              IMPORTING
                rt_messages           = DATA(messages)
                rv_success            = DATA(success) ).
      CATCH cx_a4c_bc_exception INTO DATA(exc).
        success = abap_false.
    ENDTRY.
    IF success NE 'S'.
      failed-Holiday = CORRESPONDING #( keys ).
      DATA report LIKE LINE OF reported-Holiday.
      report = CORRESPONDING #( keys[ 1 ] ).
      IF exc IS BOUND.
        report-%msg = new_message_with_text( text = exc->get_text( ) ).
        INSERT report INTO TABLE reported-Holiday.
      ENDIF.
      LOOP AT messages ASSIGNING FIELD-SYMBOL(<msg>).
        report-%msg = new_message(
                        id       = <msg>-msgid
                        number   = <msg>-msgno
                        severity = CONV #( <msg>-msgty )
                        v1       = <msg>-msgv1
                        v2       = <msg>-msgv2
                        v3       = <msg>-msgv3
                        v4       = <msg>-msgv4 ).
        INSERT report INTO TABLE reported-Holiday.
      ENDLOOP.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

 

And we also see coding in the local saver class that calls the transport API cl_a4c_bc_factory.

CLASS lcl_saver IMPLEMENTATION.
  METHOD save_modified.
    DATA table_keys TYPE TABLE OF zfcal_holi_344.
    DATA object_tables TYPE if_a4c_bc_handler=>tt_object_tables.
    table_keys = VALUE #( FOR key IN create-Holiday (
            holiday_id = key-HolidayID
    ) ).
    LOOP AT update-holiday ASSIGNING FIELD-SYMBOL(<update>).
      INSERT VALUE #(
            holiday_id = <update>-HolidayID
    ) INTO TABLE table_keys.
    ENDLOOP.
    LOOP AT delete-Holiday ASSIGNING FIELD-SYMBOL(<delete>).
      INSERT VALUE #(
            holiday_id = <delete>-HolidayID
    ) INTO TABLE table_keys.
    ENDLOOP.
    IF table_keys IS NOT INITIAL.
      INSERT VALUE #( objname = 'ZFCAL_HOLI_344'
                      tabkeys = REF #( table_keys ) ) INTO TABLE object_Tables.
    ENDIF.
    CHECK object_tables IS NOT INITIAL.
    TRY.
        cl_a4c_bc_factory=>get_handler( )->add_to_transport_request(
              EXPORTING
                iv_check_mode         = abap_false
                it_object_tables      = object_tables
                iv_mandant_field_name = 'CLIENT'
              IMPORTING
                rv_success            = DATA(success) ).
      CATCH cx_a4c_bc_exception.
        success = abap_false.
    ENDTRY.
    ASSERT success = 'S'. "point of no return - previous validation must catch all exceptions
  ENDMETHOD.
ENDCLASS.

In an upcoming release the code it is planned to provide a simplified API that allows to write the data that is stored in the tables of your Business Configuration App in just two lines of code. Once this API is available I will adapt the RAP Generator to use this new API.

Troubleshooting

No authorization

When you forget to publish the generated Business Configuration Object you will get the following error message when clicking on the entry

No authorization for configuration Holiday_344 maintenance.

 

No usable repository found

When you forget to create and clone a suitable software component of type Business Configuration you will get the following error when saving data with your Business Configuration app.

 

 

 

Assigned Tags

      1 Comment
      You must be Logged on to comment or reply to a post.
      Author's profile photo Prabhjot Bhatia
      Prabhjot Bhatia

      I have a question

      Will this transport api also capture the key records when we delete some existing record of the table like SM30?