While SAP BRF+ offers versioning of its objects, we decided to create an additional backup of the decision tables via Git. For this backup we used our existing GitLab API in combination with the BRF+ API (for extracting the decision table data to XML).

Basic setup

To make this work, we need a Z-table which contains all relevant BRF+ applications. We created the table ZBC_BRF_GIT_APPL with the following fields:

  • MANDT TYPE MANDT
  • APPLICATION TYPE FDT_APPLICATION

and a table where we store the timestamp of the last export (to avoid unnecessary duplicates) ZBC_BRF_GIT_TIME

  • MANDT TYPE MANDT
  • APPLICATION TYPE FDT_APPLICATION
  • NAME TYPE FDT_NAME
  • TIMESTAMP TYPE FTD_TIMESTAMP

Furthermore we needed to create a GitLab repository which will contain all backups.

Get the decision tables for each application

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
METHOD get_decision_tables.
  DATA: ls_sel    TYPE if_fdt_query=>s_selection.

  DATA: lt_sel   TYPE if_fdt_query=>ts_selection,
        lt_names TYPE if_fdt_query=>ts_name.

  DATA: lo_decision_table TYPE REF TO cl_fdt_decision_table.

  " all decision tables for that application
  ls_sel-queryfield = if_fdt_admin_data_query=>gc_fn_application_id.
  ls_sel-sign   = 'I'.
  ls_sel-option = 'EQ'.
  ls_sel-low    = gv_application_id.
  INSERT ls_sel
    INTO TABLE lt_sel.

  ls_sel-queryfield = if_fdt_admin_data_query=>gc_fn_object_type.
  ls_sel-sign = 'I' .
  ls_sel-option = 'EQ'.
  ls_sel-low = if_fdt_constants=>gc_object_type_expression.
  INSERT ls_sel
    INTO TABLE lt_sel.

  go_factory->get_query( )->select_data(
    EXPORTING
        its_selection = lt_sel
    IMPORTING
      eta_data       = lt_names ).

  " filter out unchanged decision tables
  LOOP AT lt_names ASSIGNING FIELD-SYMBOL(<lt_name>).
    TRY.
        " check if that expression is a decision table
        lo_decision_table ?= go_factory->get_expression( <lt_name>-id ).

        " check if it has been changed since the last backup
        lo_decision_table->if_fdt_admin_data~get_versions( 
          IMPORTING 
            ets_version = DATA(lt_version) ).

        " use highest version
        LOOP AT lt_version ASSIGNING FIELD-SYMBOL(<version>) WHERE state = 'A'.
        ENDLOOP.

        CHECK sy-subrc EQ 0.

        " check the last backup
        SELECT SINGLE *
          FROM zbc_brf_git_time
          INTO @DATA(ls_zbc_brf_git_time)
          WHERE application EQ @gv_application_name
            AND name EQ @<lt_name>-name.
        IF sy-subrc EQ 0 AND ls_zbc_brf_git_time-timestamp EQ <version>-trtimestamp.
          CONTINUE.

        ENDIF.

        APPEND VALUE #( id = <lt_name>-id name = <lt_name>-name timestamp = <version>-trtimestamp )
          TO rt_tables.

      CATCH cx_root.

    ENDTRY.

  ENDLOOP.

ENDMETHOD.

Export the decision table as XML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
DATA(lo_dxch) = go_factory->get_data_exchange( ).

TRY.
    lo_dxch->export_xml(
        EXPORTING 
          its_object_id  = VALUE #( ( <table>-id ) )
          iv_xml_version = if_fdt_data_exchange=>gc_xml_version
          iv_schema      = if_fdt_data_exchange=>gc_xml_schema_type_external
          iv_deep        = abap_false
        IMPORTING 
          ev_string      = DATA(lv_string)
          et_message     = DATA(lt_msg) ).

    " create a well formatted XML
    DATA(lo_reader) = cl_sxml_string_reader=>create( 
      cl_bcs_convert=>string_to_xstring( lv_string ) ).
    DATA(lo_writer) = CAST if_sxml_writer( 
      cl_sxml_string_writer=>create( 
        type     = if_sxml=>co_xt_xml10
        encoding = 'UTF-8' ) ).
    lo_writer->set_option( if_sxml_writer=>co_opt_linebreaks ).
    lo_writer->set_option( if_sxml_writer=>co_opt_indent ).

    lo_reader->next_node( ).
    lo_reader->skip_node( lo_writer ).

    " and write it back to a xstring
    DATA(lv_xml) = CAST cl_sxml_string_writer( lo_writer )->get_output( ).

    " and send it to git
    ls_file-path_and_name = |{ gv_application_name }/{ <table>-name }.xml|.
    ls_file-content = lv_xml.
    APPEND ls_file
      TO lt_files.

    " and remember last saved version
    ls_zbc_brf_git_time-application = gv_application_name.
    ls_zbc_brf_git_time-name = <table>-name.
    ls_zbc_brf_git_time-timestamp = <table>-timestamp.
    MODIFY zbc_brf_git_time
      FROM ls_zbc_brf_git_time.

  CATCH cx_root.

ENDTRY.

Send the files via GitLab API

1
2
3
4
5
6
7
8
9
10
11
12
 IF lt_files IS NOT INITIAL.
  TRY.
      lo_gitlab->send_files( iv_commit_message = |Backup of decision tables for application { gv_application_name }|
                              it_files          = lt_files ).
    CATCH zcx_gitlab INTO DATA(lo_excp).
      FORMAT COLOR COL_NEGATIVE.
      WRITE: / 'Could not export files:', lo_excp->get_text( ).
      FORMAT COLOR OFF.

  ENDTRY.

ENDIF.