*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_OBJECT_SICF
*&---------------------------------------------------------------------*

*----------------------------------------------------------------------*
*       CLASS lcl_object_sicf DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_sicf DEFINITION INHERITING FROM lcl_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES lif_object.
    ALIASES mo_files FOR lif_object~mo_files.

  PRIVATE SECTION.
    TYPES: ty_icfhandler_tt TYPE STANDARD TABLE OF icfhandler WITH DEFAULT KEY.

    TYPES: BEGIN OF ty_sicf_key,
             icf_name   TYPE icfservice-icf_name,
             icfparguid TYPE icfservice-icfparguid,
           END OF ty_sicf_key.

    METHODS read
      EXPORTING es_icfservice TYPE icfservice
                es_icfdocu    TYPE icfdocu
                et_icfhandler TYPE ty_icfhandler_tt
                ev_url        TYPE string
      RAISING   lcx_exception.

    METHODS insert_sicf
      IMPORTING is_icfservice TYPE icfservice
                is_icfdocu    TYPE icfdocu
                it_icfhandler TYPE ty_icfhandler_tt
                iv_package    TYPE devclass
                iv_url        TYPE string
      RAISING   lcx_exception.

    METHODS change_sicf
      IMPORTING is_icfservice TYPE icfservice
                is_icfdocu    TYPE icfdocu
                it_icfhandler TYPE ty_icfhandler_tt
                iv_package    TYPE devclass
                iv_parent     TYPE icfparguid
      RAISING   lcx_exception.

    METHODS to_icfhndlist
      IMPORTING it_list        TYPE ty_icfhandler_tt
      RETURNING VALUE(rt_list) TYPE icfhndlist.

    METHODS find_parent
      IMPORTING iv_url           TYPE string
      RETURNING VALUE(rv_parent) TYPE icfparguid
      RAISING   lcx_exception.

ENDCLASS.                    "lcl_object_sicf DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_object_sicf IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_sicf IMPLEMENTATION.

  METHOD lif_object~has_changed_since.
    rv_changed = abap_true.
  ENDMETHOD.  "lif_object~has_changed_since

  METHOD lif_object~changed_by.

    DATA: ls_icfservice TYPE icfservice.

    read( IMPORTING es_icfservice = ls_icfservice ).

    rv_user = ls_icfservice-icf_muser.

  ENDMETHOD.

  METHOD lif_object~get_metadata.
    rs_metadata = get_metadata( ).
  ENDMETHOD.                    "lif_object~get_metadata

  METHOD lif_object~exists.

    DATA: ls_icfservice TYPE icfservice.

    read( IMPORTING es_icfservice = ls_icfservice ).
    rv_bool = boolc( NOT ls_icfservice IS INITIAL ).

  ENDMETHOD.                    "lif_object~exists

  METHOD lif_object~serialize.

    DATA: ls_icfservice TYPE icfservice,
          ls_icfdocu    TYPE icfdocu,
          lv_url        TYPE string,
          lt_icfhandler TYPE TABLE OF icfhandler.

    read( IMPORTING es_icfservice = ls_icfservice
                    es_icfdocu    = ls_icfdocu
                    et_icfhandler = lt_icfhandler
                    ev_url        = lv_url ).
    IF ls_icfservice IS INITIAL.
      RETURN.
    ENDIF.

    CLEAR ls_icfservice-icfnodguid.
    CLEAR ls_icfservice-icfparguid.
    CLEAR ls_icfservice-icf_user.
    CLEAR ls_icfservice-icf_cclnt.
    CLEAR ls_icfservice-icf_mclnt.

    io_xml->add( iv_name = 'URL'
                 ig_data = lv_url ).
    io_xml->add( iv_name = 'ICFSERVICE'
                 ig_data = ls_icfservice ).
    io_xml->add( iv_name = 'ICFDOCU'
                 ig_data = ls_icfdocu ).
    io_xml->add( iv_name = 'ICFHANDLER_TABLE'
                 ig_data = lt_icfhandler ).

  ENDMETHOD.                    "serialize

  METHOD read.

    DATA: lt_serv_info TYPE icfservtbl,
          ls_serv_info LIKE LINE OF lt_serv_info,
          ls_key       TYPE ty_sicf_key.

    FIELD-SYMBOLS: <ls_icfhandler> LIKE LINE OF et_icfhandler.

    CLEAR es_icfservice.
    CLEAR es_icfdocu.
    CLEAR et_icfhandler.
    CLEAR ev_url.

    ls_key = ms_item-obj_name.
    IF ls_key-icfparguid IS INITIAL.
* limitation: name must be unique
      SELECT SINGLE icfparguid FROM icfservice
        INTO ls_key-icfparguid
        WHERE icf_name = ls_key-icf_name
        AND icf_cuser <> 'SAP' ##warn_ok.
      IF sy-subrc <> 0.
        RETURN.
      ENDIF.
    ENDIF.

    cl_icf_tree=>if_icf_tree~get_info_from_serv(
      EXPORTING
        icf_name          = ls_key-icf_name
        icfparguid        = ls_key-icfparguid
        icf_langu         = mv_language
      IMPORTING
        serv_info         = lt_serv_info
        icfdocu           = es_icfdocu
        url               = ev_url
      EXCEPTIONS
        wrong_name        = 1
        wrong_parguid     = 2
        incorrect_service = 3
        no_authority      = 4
        OTHERS            = 5 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from get_info_from_serv' ).
    ENDIF.

    ASSERT lines( lt_serv_info ) = 1.
    READ TABLE lt_serv_info INDEX 1 INTO ls_serv_info.
    ASSERT sy-subrc = 0.

    MOVE-CORRESPONDING ls_serv_info-service TO es_icfservice.
    CLEAR es_icfservice-icf_cuser.
    CLEAR es_icfservice-icf_cdate.
    CLEAR es_icfservice-icf_muser.
    CLEAR es_icfservice-icf_mdate.

    CLEAR es_icfdocu-icfparguid.

    APPEND LINES OF ls_serv_info-handlertbl TO et_icfhandler.
    LOOP AT et_icfhandler ASSIGNING <ls_icfhandler>.
      CLEAR <ls_icfhandler>-icfparguid.
    ENDLOOP.

  ENDMETHOD.                    "read

  METHOD lif_object~deserialize.

    DATA: ls_icfservice TYPE icfservice,
          ls_read       TYPE icfservice,
          ls_icfdocu    TYPE icfdocu,
          lv_url        TYPE string,
          lt_icfhandler TYPE TABLE OF icfhandler.

    io_xml->read( EXPORTING iv_name = 'URL'
                  CHANGING cg_data = lv_url ).
    io_xml->read( EXPORTING iv_name = 'ICFSERVICE'
                  CHANGING cg_data = ls_icfservice ).
    io_xml->read( EXPORTING iv_name = 'ICFDOCU'
                  CHANGING cg_data = ls_icfdocu ).
    io_xml->read( EXPORTING iv_name = 'ICFHANDLER_TABLE'
                  CHANGING cg_data = lt_icfhandler ).

    read( IMPORTING es_icfservice = ls_read ).
    IF ls_read IS INITIAL.
      insert_sicf( is_icfservice = ls_icfservice
                   is_icfdocu    = ls_icfdocu
                   it_icfhandler = lt_icfhandler
                   iv_package    = iv_package
                   iv_url        = lv_url ).
    ELSE.
      change_sicf( is_icfservice = ls_icfservice
                   is_icfdocu    = ls_icfdocu
                   it_icfhandler = lt_icfhandler
                   iv_package    = iv_package
                   iv_parent     = ls_read-icfparguid ).
    ENDIF.

  ENDMETHOD.                    "deserialize

  METHOD to_icfhndlist.

    FIELD-SYMBOLS: <ls_list> LIKE LINE OF it_list.

* convert to sorted table
    LOOP AT it_list ASSIGNING <ls_list>.
      INSERT <ls_list>-icfhandler INTO TABLE rt_list.
    ENDLOOP.

  ENDMETHOD.                    "to_icfhndlist

  METHOD find_parent.

    cl_icf_tree=>if_icf_tree~service_from_url(
      EXPORTING
        url                   = iv_url
        hostnumber            = 0
      IMPORTING
        icfnodguid            = rv_parent
      EXCEPTIONS
        wrong_application     = 1
        no_application        = 2
        not_allow_application = 3
        wrong_url             = 4
        no_authority          = 5
        OTHERS                = 6 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from service_from_url' ).
    ENDIF.

  ENDMETHOD.                    "find_parent

  METHOD insert_sicf.

    DATA: lt_icfhndlist TYPE icfhndlist,
          ls_icfserdesc TYPE icfserdesc,
          ls_icfdocu    TYPE icfdocu,
          lv_parent     TYPE icfparguid.

    lt_icfhndlist = to_icfhndlist( it_icfhandler ).
    lv_parent = find_parent( iv_url ).

* nice, it seems that the structure should be mistreated
    ls_icfdocu = is_icfdocu-icf_docu.

    MOVE-CORRESPONDING is_icfservice TO ls_icfserdesc.

    cl_icf_tree=>if_icf_tree~insert_node(
      EXPORTING
        icf_name                  = is_icfservice-orig_name
        icfparguid                = lv_parent
        icfdocu                   = ls_icfdocu
        doculang                  = mv_language
        icfhandlst                = lt_icfhndlist
        package                   = iv_package
        application               = space
        icfserdesc                = ls_icfserdesc
        icfactive                 = abap_true
      EXCEPTIONS
        empty_icf_name            = 1
        no_new_virtual_host       = 2
        special_service_error     = 3
        parent_not_existing       = 4
        enqueue_error             = 5
        node_already_existing     = 6
        empty_docu                = 7
        doculang_not_installed    = 8
        security_info_error       = 9
        user_password_error       = 10
        password_encryption_error = 11
        invalid_url               = 12
        invalid_otr_concept       = 13
        formflg401_error          = 14
        handler_error             = 15
        transport_error           = 16
        tadir_error               = 17
        package_not_found         = 18
        wrong_application         = 19
        not_allow_application     = 20
        no_application            = 21
        invalid_icfparguid        = 22
        alt_name_invalid          = 23
        alternate_name_exist      = 24
        wrong_icf_name            = 25
        no_authority              = 26
        OTHERS                    = 27 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from insert_node' ).
    ENDIF.

  ENDMETHOD.                    "insert_sicf

  METHOD change_sicf.

    DATA: lt_icfhndlist TYPE icfhndlist,
          lt_existing   TYPE TABLE OF icfhandler,
          ls_icfserdesc TYPE icfserdesc.

    FIELD-SYMBOLS: <ls_existing> LIKE LINE OF lt_existing.

    lt_icfhndlist = to_icfhndlist( it_icfhandler ).

* Do not add handlers if they already exist, it will make the below
* call to SAP standard code raise an exception
    SELECT * FROM icfhandler INTO TABLE lt_existing
      WHERE icf_name = is_icfservice-icf_name.
    LOOP AT lt_existing ASSIGNING <ls_existing>.
      DELETE TABLE lt_icfhndlist FROM <ls_existing>-icfhandler.
    ENDLOOP.

    MOVE-CORRESPONDING is_icfservice TO ls_icfserdesc.

    cl_icf_tree=>if_icf_tree~change_node(
      EXPORTING
        icf_name                  = is_icfservice-orig_name
        icfparguid                = iv_parent
        icfdocu                   = is_icfdocu
        doculang                  = mv_language
        icfhandlst                = lt_icfhndlist
        package                   = iv_package
        application               = space
        icfserdesc                = ls_icfserdesc
        icfactive                 = abap_true
      EXCEPTIONS
        empty_icf_name            = 1
        no_new_virtual_host       = 2
        special_service_error     = 3
        parent_not_existing       = 4
        enqueue_error             = 5
        node_already_existing     = 6
        empty_docu                = 7
        doculang_not_installed    = 8
        security_info_error       = 9
        user_password_error       = 10
        password_encryption_error = 11
        invalid_url               = 12
        invalid_otr_concept       = 13
        formflg401_error          = 14
        handler_error             = 15
        transport_error           = 16
        tadir_error               = 17
        package_not_found         = 18
        wrong_application         = 19
        not_allow_application     = 20
        no_application            = 21
        invalid_icfparguid        = 22
        alt_name_invalid          = 23
        alternate_name_exist      = 24
        wrong_icf_name            = 25
        no_authority              = 26
        OTHERS                    = 27 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from change_node' ).
    ENDIF.

  ENDMETHOD.                    "change_sicf

  METHOD lif_object~delete.

    DATA: ls_icfservice TYPE icfservice.

    read( IMPORTING es_icfservice = ls_icfservice ).

    cl_icf_tree=>if_icf_tree~delete_node(
      EXPORTING
        icfparguid                  = ls_icfservice-icfparguid
      CHANGING
        icf_name                    = ls_icfservice-icf_name
      EXCEPTIONS
        no_virtual_host_delete      = 1
        special_service_error       = 2
        enqueue_error               = 3
        node_not_existing           = 4
        node_has_childs             = 5
        node_is_aliased             = 6
        node_not_in_original_system = 7
        transport_error             = 8
        tadir_error                 = 9
        db_error                    = 10
        no_authority                = 11
        OTHERS                      = 12 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from delete_node' ).
    ENDIF.

  ENDMETHOD.                    "delete

  METHOD lif_object~jump.
    lcx_exception=>raise( 'todo, SICF, jump' ).
  ENDMETHOD.                    "jump

  METHOD lif_object~compare_to_remote_version.
    CREATE OBJECT ro_comparison_result TYPE lcl_null_comparison_result.
  ENDMETHOD.

ENDCLASS.                    "lcl_object_sicf IMPLEMENTATION

*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_OBJECT_SICF
*&---------------------------------------------------------------------*

*----------------------------------------------------------------------*
*       CLASS lcl_object_sicf DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_sicf DEFINITION INHERITING FROM lcl_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES lif_object.
    ALIASES mo_files FOR lif_object~mo_files.

  PRIVATE SECTION.
    TYPES: ty_icfhandler_tt TYPE STANDARD TABLE OF icfhandler WITH DEFAULT KEY.

    TYPES: BEGIN OF ty_sicf_key,
             icf_name   TYPE icfservice-icf_name,
             icfparguid TYPE icfservice-icfparguid,
           END OF ty_sicf_key.

    METHODS read
      IMPORTING iv_clear      TYPE abap_bool DEFAULT abap_true
      EXPORTING es_icfservice TYPE icfservice
                es_icfdocu    TYPE icfdocu
                et_icfhandler TYPE ty_icfhandler_tt
                ev_url        TYPE string
      RAISING   lcx_exception.

    METHODS insert_sicf
      IMPORTING is_icfservice TYPE icfservice
                is_icfdocu    TYPE icfdocu
                it_icfhandler TYPE ty_icfhandler_tt
                iv_package    TYPE devclass
                iv_url        TYPE string
      RAISING   lcx_exception.

    METHODS change_sicf
      IMPORTING is_icfservice TYPE icfservice
                is_icfdocu    TYPE icfdocu
                it_icfhandler TYPE ty_icfhandler_tt
                iv_package    TYPE devclass
                iv_parent     TYPE icfparguid
      RAISING   lcx_exception.

    METHODS to_icfhndlist
      IMPORTING it_list        TYPE ty_icfhandler_tt
      RETURNING VALUE(rt_list) TYPE icfhndlist.

    METHODS find_parent
      IMPORTING iv_url           TYPE string
      RETURNING VALUE(rv_parent) TYPE icfparguid
      RAISING   lcx_exception.

ENDCLASS.                    "lcl_object_sicf DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_object_sicf IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_sicf IMPLEMENTATION.

  METHOD lif_object~has_changed_since.
    rv_changed = abap_true.
  ENDMETHOD.  "lif_object~has_changed_since

  METHOD lif_object~changed_by.

    DATA: ls_icfservice TYPE icfservice.

    read( EXPORTING iv_clear = abap_false
          IMPORTING es_icfservice = ls_icfservice ).

    rv_user = ls_icfservice-icf_muser.

  ENDMETHOD.

  METHOD lif_object~get_metadata.
    rs_metadata = get_metadata( ).
  ENDMETHOD.                    "lif_object~get_metadata

  METHOD lif_object~exists.

    DATA: ls_icfservice TYPE icfservice.

    read( IMPORTING es_icfservice = ls_icfservice ).
    rv_bool = boolc( NOT ls_icfservice IS INITIAL ).

  ENDMETHOD.                    "lif_object~exists

  METHOD lif_object~serialize.

    DATA: ls_icfservice TYPE icfservice,
          ls_icfdocu    TYPE icfdocu,
          lv_url        TYPE string,
          lt_icfhandler TYPE TABLE OF icfhandler.

    read( IMPORTING es_icfservice = ls_icfservice
                    es_icfdocu    = ls_icfdocu
                    et_icfhandler = lt_icfhandler
                    ev_url        = lv_url ).
    IF ls_icfservice IS INITIAL.
      RETURN.
    ENDIF.

    CLEAR ls_icfservice-icfnodguid.
    CLEAR ls_icfservice-icfparguid.
    CLEAR ls_icfservice-icf_user.
    CLEAR ls_icfservice-icf_cclnt.
    CLEAR ls_icfservice-icf_mclnt.

    io_xml->add( iv_name = 'URL'
                 ig_data = lv_url ).
    io_xml->add( iv_name = 'ICFSERVICE'
                 ig_data = ls_icfservice ).
    io_xml->add( iv_name = 'ICFDOCU'
                 ig_data = ls_icfdocu ).
    io_xml->add( iv_name = 'ICFHANDLER_TABLE'
                 ig_data = lt_icfhandler ).

  ENDMETHOD.                    "serialize

  METHOD read.

    DATA: lt_serv_info TYPE icfservtbl,
          ls_serv_info LIKE LINE OF lt_serv_info,
          ls_key       TYPE ty_sicf_key.

    FIELD-SYMBOLS: <ls_icfhandler> LIKE LINE OF et_icfhandler.

    CLEAR es_icfservice.
    CLEAR es_icfdocu.
    CLEAR et_icfhandler.
    CLEAR ev_url.

    ls_key = ms_item-obj_name.
    IF ls_key-icfparguid IS INITIAL.
* limitation: name must be unique
      SELECT SINGLE icfparguid FROM icfservice
        INTO ls_key-icfparguid
        WHERE icf_name = ls_key-icf_name
        AND icf_cuser <> 'SAP' ##warn_ok.
      IF sy-subrc <> 0.
        RETURN.
      ENDIF.
    ENDIF.

    cl_icf_tree=>if_icf_tree~get_info_from_serv(
      EXPORTING
        icf_name          = ls_key-icf_name
        icfparguid        = ls_key-icfparguid
        icf_langu         = mv_language
      IMPORTING
        serv_info         = lt_serv_info
        icfdocu           = es_icfdocu
        url               = ev_url
      EXCEPTIONS
        wrong_name        = 1
        wrong_parguid     = 2
        incorrect_service = 3
        no_authority      = 4
        OTHERS            = 5 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from get_info_from_serv' ).
    ENDIF.

    ASSERT lines( lt_serv_info ) = 1.
    READ TABLE lt_serv_info INDEX 1 INTO ls_serv_info.
    ASSERT sy-subrc = 0.

    MOVE-CORRESPONDING ls_serv_info-service TO es_icfservice.
    IF iv_clear = abap_true.
      CLEAR es_icfservice-icf_cuser.
      CLEAR es_icfservice-icf_cdate.
      CLEAR es_icfservice-icf_muser.
      CLEAR es_icfservice-icf_mdate.
    ENDIF.

    CLEAR es_icfdocu-icfparguid.

    APPEND LINES OF ls_serv_info-handlertbl TO et_icfhandler.
    LOOP AT et_icfhandler ASSIGNING <ls_icfhandler>.
      CLEAR <ls_icfhandler>-icfparguid.
    ENDLOOP.

  ENDMETHOD.                    "read

  METHOD lif_object~deserialize.

    DATA: ls_icfservice TYPE icfservice,
          ls_read       TYPE icfservice,
          ls_icfdocu    TYPE icfdocu,
          lv_url        TYPE string,
          lt_icfhandler TYPE TABLE OF icfhandler.

    io_xml->read( EXPORTING iv_name = 'URL'
                  CHANGING cg_data = lv_url ).
    io_xml->read( EXPORTING iv_name = 'ICFSERVICE'
                  CHANGING cg_data = ls_icfservice ).
    io_xml->read( EXPORTING iv_name = 'ICFDOCU'
                  CHANGING cg_data = ls_icfdocu ).
    io_xml->read( EXPORTING iv_name = 'ICFHANDLER_TABLE'
                  CHANGING cg_data = lt_icfhandler ).

    read( IMPORTING es_icfservice = ls_read ).
    IF ls_read IS INITIAL.
      insert_sicf( is_icfservice = ls_icfservice
                   is_icfdocu    = ls_icfdocu
                   it_icfhandler = lt_icfhandler
                   iv_package    = iv_package
                   iv_url        = lv_url ).
    ELSE.
      change_sicf( is_icfservice = ls_icfservice
                   is_icfdocu    = ls_icfdocu
                   it_icfhandler = lt_icfhandler
                   iv_package    = iv_package
                   iv_parent     = ls_read-icfparguid ).
    ENDIF.

  ENDMETHOD.                    "deserialize

  METHOD to_icfhndlist.

    FIELD-SYMBOLS: <ls_list> LIKE LINE OF it_list.

* convert to sorted table
    LOOP AT it_list ASSIGNING <ls_list>.
      INSERT <ls_list>-icfhandler INTO TABLE rt_list.
    ENDLOOP.

  ENDMETHOD.                    "to_icfhndlist

  METHOD find_parent.

    cl_icf_tree=>if_icf_tree~service_from_url(
      EXPORTING
        url                   = iv_url
        hostnumber            = 0
      IMPORTING
        icfnodguid            = rv_parent
      EXCEPTIONS
        wrong_application     = 1
        no_application        = 2
        not_allow_application = 3
        wrong_url             = 4
        no_authority          = 5
        OTHERS                = 6 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from service_from_url' ).
    ENDIF.

  ENDMETHOD.                    "find_parent

  METHOD insert_sicf.

    DATA: lt_icfhndlist TYPE icfhndlist,
          ls_icfserdesc TYPE icfserdesc,
          ls_icfdocu    TYPE icfdocu,
          lv_parent     TYPE icfparguid.

    lt_icfhndlist = to_icfhndlist( it_icfhandler ).
    lv_parent = find_parent( iv_url ).

* nice, it seems that the structure should be mistreated
    ls_icfdocu = is_icfdocu-icf_docu.

    MOVE-CORRESPONDING is_icfservice TO ls_icfserdesc.

    cl_icf_tree=>if_icf_tree~insert_node(
      EXPORTING
        icf_name                  = is_icfservice-orig_name
        icfparguid                = lv_parent
        icfdocu                   = ls_icfdocu
        doculang                  = mv_language
        icfhandlst                = lt_icfhndlist
        package                   = iv_package
        application               = space
        icfserdesc                = ls_icfserdesc
        icfactive                 = abap_true
      EXCEPTIONS
        empty_icf_name            = 1
        no_new_virtual_host       = 2
        special_service_error     = 3
        parent_not_existing       = 4
        enqueue_error             = 5
        node_already_existing     = 6
        empty_docu                = 7
        doculang_not_installed    = 8
        security_info_error       = 9
        user_password_error       = 10
        password_encryption_error = 11
        invalid_url               = 12
        invalid_otr_concept       = 13
        formflg401_error          = 14
        handler_error             = 15
        transport_error           = 16
        tadir_error               = 17
        package_not_found         = 18
        wrong_application         = 19
        not_allow_application     = 20
        no_application            = 21
        invalid_icfparguid        = 22
        alt_name_invalid          = 23
        alternate_name_exist      = 24
        wrong_icf_name            = 25
        no_authority              = 26
        OTHERS                    = 27 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from insert_node' ).
    ENDIF.

  ENDMETHOD.                    "insert_sicf

  METHOD change_sicf.

    DATA: lt_icfhndlist TYPE icfhndlist,
          lt_existing   TYPE TABLE OF icfhandler,
          ls_icfserdesc TYPE icfserdesc.

    FIELD-SYMBOLS: <ls_existing> LIKE LINE OF lt_existing.

    lt_icfhndlist = to_icfhndlist( it_icfhandler ).

* Do not add handlers if they already exist, it will make the below
* call to SAP standard code raise an exception
    SELECT * FROM icfhandler INTO TABLE lt_existing
      WHERE icf_name = is_icfservice-icf_name.
    LOOP AT lt_existing ASSIGNING <ls_existing>.
      DELETE TABLE lt_icfhndlist FROM <ls_existing>-icfhandler.
    ENDLOOP.

    MOVE-CORRESPONDING is_icfservice TO ls_icfserdesc.

    cl_icf_tree=>if_icf_tree~change_node(
      EXPORTING
        icf_name                  = is_icfservice-orig_name
        icfparguid                = iv_parent
        icfdocu                   = is_icfdocu
        doculang                  = mv_language
        icfhandlst                = lt_icfhndlist
        package                   = iv_package
        application               = space
        icfserdesc                = ls_icfserdesc
        icfactive                 = abap_true
      EXCEPTIONS
        empty_icf_name            = 1
        no_new_virtual_host       = 2
        special_service_error     = 3
        parent_not_existing       = 4
        enqueue_error             = 5
        node_already_existing     = 6
        empty_docu                = 7
        doculang_not_installed    = 8
        security_info_error       = 9
        user_password_error       = 10
        password_encryption_error = 11
        invalid_url               = 12
        invalid_otr_concept       = 13
        formflg401_error          = 14
        handler_error             = 15
        transport_error           = 16
        tadir_error               = 17
        package_not_found         = 18
        wrong_application         = 19
        not_allow_application     = 20
        no_application            = 21
        invalid_icfparguid        = 22
        alt_name_invalid          = 23
        alternate_name_exist      = 24
        wrong_icf_name            = 25
        no_authority              = 26
        OTHERS                    = 27 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from change_node' ).
    ENDIF.

  ENDMETHOD.                    "change_sicf

  METHOD lif_object~delete.

    DATA: ls_icfservice TYPE icfservice.

    read( IMPORTING es_icfservice = ls_icfservice ).

    cl_icf_tree=>if_icf_tree~delete_node(
      EXPORTING
        icfparguid                  = ls_icfservice-icfparguid
      CHANGING
        icf_name                    = ls_icfservice-icf_name
      EXCEPTIONS
        no_virtual_host_delete      = 1
        special_service_error       = 2
        enqueue_error               = 3
        node_not_existing           = 4
        node_has_childs             = 5
        node_is_aliased             = 6
        node_not_in_original_system = 7
        transport_error             = 8
        tadir_error                 = 9
        db_error                    = 10
        no_authority                = 11
        OTHERS                      = 12 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from delete_node' ).
    ENDIF.

  ENDMETHOD.                    "delete

  METHOD lif_object~jump.
    lcx_exception=>raise( 'todo, SICF, jump' ).
  ENDMETHOD.                    "jump

  METHOD lif_object~compare_to_remote_version.
    CREATE OBJECT ro_comparison_result TYPE lcl_null_comparison_result.
  ENDMETHOD.

ENDCLASS.                    "lcl_object_sicf IMPLEMENTATION

fix changed_by

SICF: fix changed_by


CLASS zcl_abapgit_gui_page DEFINITION PUBLIC ABSTRACT
  INHERITING FROM zcl_abapgit_gui_component
  CREATE PUBLIC.

  PUBLIC SECTION.
    INTERFACES:
      zif_abapgit_gui_renderable,
      zif_abapgit_gui_event_handler,
      zif_abapgit_gui_error_handler.

    METHODS:
      constructor RAISING zcx_abapgit_exception.

  PROTECTED SECTION.

    TYPES:
      BEGIN OF ty_control,
        page_title TYPE string,
        page_menu  TYPE REF TO zcl_abapgit_html_toolbar,
      END OF  ty_control .

    DATA ms_control TYPE ty_control .

    METHODS render_content
          ABSTRACT
      RETURNING
        VALUE(ri_html) TYPE REF TO zif_abapgit_html
      RAISING
        zcx_abapgit_exception .
  PRIVATE SECTION.

    DATA mo_settings TYPE REF TO zcl_abapgit_settings .
    DATA mx_error TYPE REF TO zcx_abapgit_exception .
    DATA mo_exception_viewer TYPE REF TO zcl_abapgit_exception_viewer .

    METHODS render_deferred_parts
      IMPORTING
        !ii_html          TYPE REF TO zif_abapgit_html
        !iv_part_category TYPE string
      RAISING
        zcx_abapgit_exception .
    METHODS html_head
      RETURNING
        VALUE(ri_html) TYPE REF TO zif_abapgit_html .
    METHODS title
      RETURNING
        VALUE(ri_html) TYPE REF TO zif_abapgit_html .
    METHODS footer
      RETURNING
        VALUE(ri_html) TYPE REF TO zif_abapgit_html .
    METHODS render_link_hints
      IMPORTING
        !ii_html TYPE REF TO zif_abapgit_html
      RAISING
        zcx_abapgit_exception .
    METHODS render_command_palettes
      IMPORTING
        !ii_html TYPE REF TO zif_abapgit_html
      RAISING
        zcx_abapgit_exception .
    METHODS render_hotkey_overview
      RETURNING
        VALUE(ro_html) TYPE REF TO zif_abapgit_html
      RAISING
        zcx_abapgit_exception .
    METHODS render_error_message_box
      RETURNING
        VALUE(ri_html) TYPE REF TO zif_abapgit_html
      RAISING
        zcx_abapgit_exception .
    METHODS scripts
      RETURNING
        VALUE(ri_html) TYPE REF TO zif_abapgit_html
      RAISING
        zcx_abapgit_exception .
ENDCLASS.

CLASS ZCL_ABAPGIT_GUI_PAGE IMPLEMENTATION.

  METHOD constructor.

    super->constructor( ).
    mo_settings = zcl_abapgit_persist_settings=>get_instance( )->read( ).

  ENDMETHOD.

  METHOD footer.

    CREATE OBJECT ri_html TYPE zcl_abapgit_html.

    ri_html->add( '
' ).
    ri_html->add( '

' ).

    ri_html->add( '	' ).  " spacer

    ri_html->add( '' ).
    ri_html->add( '
' ).
    ri_html->add( ri_html->icon( 'git-alt' ) ).
    ri_html->add( ri_html->icon( 'abapgit' ) ).
    ri_html->add( '
' ).
    ri_html->add( |
{ zif_abapgit_version=>gc_abap_version }
| ).
    ri_html->add( '	' ).

    ri_html->add( '	' ).

    ri_html->add( '

' ).
    ri_html->add( '
' ).

  ENDMETHOD.

  METHOD html_head.

    CREATE OBJECT ri_html TYPE zcl_abapgit_html.

    ri_html->add( '' ).

    ri_html->add( '<meta http-equiv="content-type" content="text/html; charset=utf-8">' ).
    ri_html->add( '<meta http-equiv="X-UA-Compatible" content="IE=11,10,9,8" />' ).

    ri_html->add( '<title>abapGit</title>' ).
    ri_html->add( '<link rel="stylesheet" type="text/css" href="css/common.css">' ).
    ri_html->add( '<link rel="stylesheet" type="text/css" href="css/ag-icons.css">' ).

    " Themes
    ri_html->add( '<link rel="stylesheet" type="text/css" href="css/theme-default.css">' ). " Theme basis
    CASE mo_settings->get_ui_theme( ).
      WHEN zcl_abapgit_settings=>c_ui_theme-dark.
        ri_html->add( '<link rel="stylesheet" type="text/css" href="css/theme-dark.css">' ).
      WHEN zcl_abapgit_settings=>c_ui_theme-belize.
        ri_html->add( '<link rel="stylesheet" type="text/css" href="css/theme-belize-blue.css">' ).
    ENDCASE.

    ri_html->add( '' ).

    CASE mo_settings->get_icon_scaling( ). " Enforce icon scaling
      WHEN mo_settings->c_icon_scaling-large.
        ri_html->add( '' ).
      WHEN mo_settings->c_icon_scaling-small.
        ri_html->add( '' ).
    ENDCASE.

    ri_html->add( '' ).

  ENDMETHOD.

  METHOD render_command_palettes.

    ii_html->add( 'var gCommandPalette = new CommandPalette(enumerateToolbarActions, {' ).
    ii_html->add( '  toggleKey: "F1",' ).
    ii_html->add( '  hotkeyDescription: "Command ..."' ).
    ii_html->add( '});' ).

  ENDMETHOD.

  METHOD render_deferred_parts.

    DATA lt_parts TYPE zif_abapgit_html=>ty_table_of.
    DATA li_part LIKE LINE OF lt_parts.

    lt_parts = gui_services( )->get_html_parts( )->get_parts( iv_part_category ).
    LOOP AT lt_parts INTO li_part.
      ii_html->add( li_part ).
    ENDLOOP.

  ENDMETHOD.

  METHOD render_error_message_box.

    " You should remember that the we have to instantiate ro_html even
    " it's overwritten further down. Because ADD checks whether it's
    " bound.
    CREATE OBJECT ri_html TYPE zcl_abapgit_html.

    " You should remember that we render the message panel only
    " if we have an error.
    IF mx_error IS NOT BOUND.
      RETURN.
    ENDIF.

    ri_html = zcl_abapgit_gui_chunk_lib=>render_error_message_box( mx_error ).

    " You should remember that the exception viewer dispatches the events of
    " error message panel
    CREATE OBJECT mo_exception_viewer
      EXPORTING
        ix_error = mx_error.

    " You should remember that we render the message panel just once
    " for each exception/error text.
    CLEAR:
      mx_error.

  ENDMETHOD.

  METHOD render_hotkey_overview.

    DATA lo_hotkeys_component TYPE REF TO zif_abapgit_gui_renderable.

    lo_hotkeys_component ?= gui_services( )->get_hotkeys_ctl( ). " Mmmm ...
    ro_html = lo_hotkeys_component->render( ).

  ENDMETHOD.

  METHOD render_link_hints.

    DATA: lv_link_hint_key TYPE c LENGTH 1.

    lv_link_hint_key = mo_settings->get_link_hint_key( ).

    IF mo_settings->get_link_hints_enabled( ) = abap_true AND lv_link_hint_key IS NOT INITIAL.

      ii_html->add( |activateLinkHints("{ lv_link_hint_key }");| ).
      ii_html->add( |setInitialFocusWithQuerySelector('a span', true);| ).
      ii_html->add( |enableArrowListNavigation();| ).

    ENDIF.

  ENDMETHOD.

  METHOD scripts.

    CREATE OBJECT ri_html TYPE zcl_abapgit_html.

    render_deferred_parts(
      ii_html          = ri_html
      iv_part_category = c_html_parts-scripts ).

    render_link_hints( ri_html ).
    render_command_palettes( ri_html ).

  ENDMETHOD.

  METHOD title.

    CREATE OBJECT ri_html TYPE zcl_abapgit_html.

    ri_html->add( '
' ).

    ri_html->add( '
' ).
    ri_html->add( ri_html->icon( 'git-alt' ) ).
    ri_html->add( ri_html->icon( 'abapgit' ) ).
    ri_html->add( '
' ).

    ri_html->add( |
►{ ms_control-page_title }
| ).

    IF ms_control-page_menu IS BOUND.
      ri_html->add( '
' ).
      ri_html->add( ms_control-page_menu->render( iv_right = abap_true ) ).
      ri_html->add( '
' ).
    ENDIF.

    ri_html->add( '
' ).

  ENDMETHOD.

  METHOD zif_abapgit_gui_error_handler~handle_error.

    mx_error = ix_error.
    rv_handled = abap_true.

  ENDMETHOD.

  METHOD zif_abapgit_gui_event_handler~on_event.

    CASE ii_event->mv_action.
      WHEN zif_abapgit_definitions=>c_action-goto_source.

        IF mo_exception_viewer IS BOUND.
          mo_exception_viewer->goto_source( ).
        ENDIF.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-no_more_act.

      WHEN zif_abapgit_definitions=>c_action-show_callstack.

        IF mo_exception_viewer IS BOUND.
          mo_exception_viewer->show_callstack( ).
        ENDIF.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-no_more_act.

      WHEN zif_abapgit_definitions=>c_action-goto_message.

        IF mo_exception_viewer IS BOUND.
          mo_exception_viewer->goto_message( ).
        ENDIF.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-no_more_act.

    ENDCASE.

  ENDMETHOD.

  METHOD zif_abapgit_gui_renderable~render.

    DATA: li_script TYPE REF TO zif_abapgit_html.

    gui_services( )->register_event_handler( me ).

    " Real page
    CREATE OBJECT ri_html TYPE zcl_abapgit_html.

    ri_html->add( '<!DOCTYPE html>' ).
    ri_html->add( '' ).
    ri_html->add( html_head( ) ).
    ri_html->add( '' ).
    ri_html->add( title( ) ).

    ri_html->add( render_content( ) ). " TODO -> render child

    ri_html->add( render_hotkey_overview( ) ).
    ri_html->add( render_error_message_box( ) ).

    render_deferred_parts(
      ii_html          = ri_html
      iv_part_category = c_html_parts-hidden_forms ).

    ri_html->add( footer( ) ).

    li_script = scripts( ).

    IF li_script IS BOUND AND li_script->is_empty( ) = abap_false.
      ri_html->add( '' ).
    ENDIF.

    ri_html->add( '' ).
    ri_html->add( '' ).

  ENDMETHOD.
ENDCLASS.

UI: Fix HTML validation warnings and error (#4173)

* UI: Fix HTML validation warnings and error

* Back to previous ie=

Co-authored-by: Lars Hvam <721d1b171982cd84b755f6b25130d2b88cd1f696@hotmail.com>


"! Database table logger
"!

"! This logger class is designed as an abstract base class to inherit from to define concrete
"! logger classes, that can log to custom database tables with a compatible structure definition.
"!

"! Features:
"!

"!
Mapping of log entry text / type / username / timestamp

"!
Custom key configuration (e. g. using UUIDs or number range objects)

"!
Support for secondary database connections

"!

CLASS zcl_alog_dbtab_logger DEFINITION
  PUBLIC
  ABSTRACT
  INHERITING FROM zcl_alog_msg_logger_base
  CREATE PUBLIC.

  PUBLIC SECTION.
    TYPES:
      BEGIN OF gty_mapping,
        text_target      TYPE fieldname,
        type_target      TYPE fieldname,
        username_target  TYPE fieldname,
        timestamp_target TYPE fieldname,
      END OF gty_mapping,
      gty_key_component_tab TYPE STANDARD TABLE OF fieldname.
    METHODS:
      "! @parameter iv_tabname | Name of the database table
      "! @parameter is_mapping | Mapping configuration
      "! @parameter it_key_components | Key columns
      "! @parameter iv_secondary_conn_key | Key for secondary database connection
      "! @parameter iv_use_secondary_connection | Use secondary database connection
      "! @parameter iv_always_implicit_commit | Always commit after adding a log entry
      "! @raising zcx_alog_illegal_argument | Illegal argument
      constructor IMPORTING iv_tabname                  TYPE tabname
                            is_mapping                  TYPE gty_mapping
                            it_key_components           TYPE gty_key_component_tab
                            iv_secondary_conn_key       TYPE string OPTIONAL
                            iv_use_secondary_connection TYPE abap_bool DEFAULT abap_false
                            iv_always_implicit_commit   TYPE abap_bool DEFAULT abap_false
                  RAISING   zcx_alog_illegal_argument.
  PROTECTED SECTION.
    METHODS:
      entry_internal REDEFINITION,
      get_next_key ABSTRACT RETURNING VALUE(rv_key) TYPE string,
      "! Persist the new log entry
      "!

      "! The default implementation of this method uses a dynamic OpenSQL db insert based on the
      "! current configuration regarding target table and secondary connection settings. If other
      "! logic should be used by the logger you may override this method and instead for example
      "! call an update function module to make use of update tasks.
      "!

      "! @parameter ig_row | New log entry (type is the structure type of the db table)
      "! @raising zcx_alog_logging_failed | Logging failed
      insert_entry_in_db IMPORTING ig_row TYPE any
                         RAISING   zcx_alog_logging_failed.
  PRIVATE SECTION.
    CLASS-METHODS:
      write_to_component IMPORTING iv_component_name TYPE abap_compname
                                   iv_text           TYPE csequence
                         CHANGING  cg_structure      TYPE data,
      validate_mapping IMPORTING is_mapping TYPE gty_mapping
                                 io_descr   TYPE REF TO cl_abap_structdescr
                       RAISING   zcx_alog_illegal_argument,
      validate_key IMPORTING it_key   TYPE gty_key_component_tab
                             io_descr TYPE REF TO cl_abap_structdescr
                   RAISING   zcx_alog_illegal_argument.
    DATA:
      mv_tabname                  TYPE tabname,
      mo_descr                    TYPE REF TO cl_abap_structdescr,
      ms_mapping                  TYPE gty_mapping,
      mv_connection_key           TYPE string,
      mv_always_implicit_commit   TYPE abap_bool,
      mv_use_secondary_connection TYPE abap_bool,
      mt_key_components           TYPE gty_key_component_tab,
      mo_key_descr                TYPE REF TO cl_abap_structdescr.
ENDCLASS.

CLASS zcl_alog_dbtab_logger IMPLEMENTATION.
  METHOD constructor.
    super->constructor( ).

    mv_tabname = iv_tabname.
    mv_connection_key = iv_secondary_conn_key.
    mv_always_implicit_commit = iv_always_implicit_commit.
    mv_use_secondary_connection = iv_use_secondary_connection.
    mt_key_components = it_key_components.

    CALL FUNCTION 'DDIF_TABT_GET'
      EXPORTING
        name          = iv_tabname
      EXCEPTIONS
        illegal_input = 1
        OTHERS        = 2.

    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE zcx_alog_illegal_argument
        EXPORTING
          iv_reason = |{ iv_tabname } is not an active database table.|
          iv_value  = iv_tabname ##NO_TEXT.
    ENDIF.

    mo_descr = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name(  iv_tabname ) ).
    ASSERT mo_descr IS BOUND.

    validate_key( it_key = it_key_components io_descr = mo_descr ).
    mo_key_descr = cl_abap_structdescr=>get( VALUE #(
                     FOR comp IN mt_key_components
                     ( name = comp type = mo_descr->get_component_type( comp ) )
                   ) ).

    validate_mapping( is_mapping = is_mapping io_descr = mo_descr ).
    ms_mapping = is_mapping.
  ENDMETHOD.

  METHOD entry_internal.
    DATA: lr_table_line TYPE REF TO data,
          lr_key        TYPE REF TO data.
    FIELD-SYMBOLS: <lg_row> TYPE data,
                   <lg_key> TYPE data.

    CREATE DATA lr_table_line TYPE HANDLE mo_descr.
    ASSERT lr_table_line IS BOUND.

    ASSIGN lr_table_line->* TO <lg_row>.
    ASSERT <lg_row> IS ASSIGNED.

    CREATE DATA lr_key TYPE HANDLE mo_key_descr.
    ASSERT lr_key IS BOUND.
    ASSIGN lr_key->* TO <lg_key>.
    <lg_key> = get_next_key( ).

    <lg_row> = CORRESPONDING #( <lg_key> ).

    IF ms_mapping-text_target IS NOT INITIAL.
      write_to_component(
        EXPORTING
          iv_component_name = ms_mapping-text_target
          iv_text           = iv_text
        CHANGING
          cg_structure      = <lg_row>
      ).
    ENDIF.

    IF ms_mapping-timestamp_target IS NOT INITIAL.
      GET TIME STAMP FIELD DATA(lv_timestamp).
      write_to_component(
        EXPORTING
          iv_component_name = ms_mapping-timestamp_target
          iv_text           = CONV string( lv_timestamp )
        CHANGING
          cg_structure      = <lg_row>
      ).
    ENDIF.

    IF ms_mapping-type_target IS NOT INITIAL.
      write_to_component(
        EXPORTING
          iv_component_name = ms_mapping-type_target
          iv_text           = io_type->mv_message_type
        CHANGING
          cg_structure      = <lg_row>
      ).
    ENDIF.

    IF ms_mapping-username_target IS NOT INITIAL.
      write_to_component(
        EXPORTING
          iv_component_name = ms_mapping-username_target
          iv_text           = cl_abap_syst=>get_user_name( )
        CHANGING
          cg_structure      = <lg_row>
      ).
    ENDIF.

    insert_entry_in_db( <lg_row> ).

    IF mv_always_implicit_commit = abap_true.
      IF mv_use_secondary_connection = abap_false OR mv_connection_key IS INITIAL.
        COMMIT WORK.
      ELSE.
        COMMIT CONNECTION (mv_connection_key).
      ENDIF.
    ENDIF.
  ENDMETHOD.

  METHOD insert_entry_in_db.
    IF mv_use_secondary_connection = abap_false OR mv_connection_key IS INITIAL.
      INSERT (mv_tabname) CONNECTION default FROM ig_row.
    ELSE.
      INSERT (mv_tabname) CONNECTION (mv_connection_key) FROM ig_row.
    ENDIF.

    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE zcx_alog_logging_failed
        EXPORTING
          iv_reason = |Dynamic INSERT into table '{ mv_tabname }' failed: { sy-subrc }| ##NO_TEXT.
    ENDIF.
  ENDMETHOD.

  METHOD write_to_component.
    ASSIGN COMPONENT iv_component_name OF STRUCTURE cg_structure TO FIELD-SYMBOL(<lg_comp>).
    ASSERT <lg_comp> IS ASSIGNED.
    <lg_comp> = iv_text.
*    WRITE iv_text TO <lg_comp>.
  ENDMETHOD.

  METHOD validate_mapping.
    DATA(lo_mapping_descr) = CAST cl_abap_structdescr(
                               cl_abap_typedescr=>describe_by_data( is_mapping )
                             ).

    LOOP AT lo_mapping_descr->components ASSIGNING FIELD-SYMBOL(<ls_component>).
      ASSIGN COMPONENT <ls_component>-name OF STRUCTURE is_mapping TO FIELD-SYMBOL(<lg_target>).
      ASSERT <lg_target> IS ASSIGNED.

      IF <lg_target> IS NOT INITIAL
          AND NOT line_exists( io_descr->components[ name = <lg_target> ] ).

        RAISE EXCEPTION TYPE zcx_alog_illegal_argument
          EXPORTING
            iv_reason = |Column '{ <lg_target> }' is missing in table | &&
                        |{ io_descr->get_relative_name( ) }.|
            iv_value  = CONV string( is_mapping ) ##NO_TEXT.
      ENDIF.

      UNASSIGN <lg_target>.
    ENDLOOP.
  ENDMETHOD.

  METHOD validate_key.
    LOOP AT it_key ASSIGNING FIELD-SYMBOL(<lv_comp>).
      IF NOT line_exists( io_descr->components[ name = <lv_comp> ] ).
        RAISE EXCEPTION TYPE zcx_alog_illegal_argument
          EXPORTING
            iv_reason = |Column '{ <lv_comp> }' of key is missing in table | &&
                        |{ io_descr->get_relative_name( ) }.| ##NO_TEXT.
      ENDIF.
    ENDLOOP.

    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE zcx_alog_illegal_argument
        EXPORTING
          iv_reason = 'Key cannot be empty.' ##NO_TEXT.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

"! Database table logger
"!

"! This logger class is designed as an abstract base class to inherit from to define concrete
"! logger classes, that can log to custom database tables with a compatible structure definition.
"!

"! Features:
"!

"!
Mapping of log entry text / type / username / timestamp

"!
Custom key configuration (e. g. using UUIDs or number range objects)

"!
Support for secondary database connections

"!

CLASS zcl_alog_dbtab_logger DEFINITION
  PUBLIC
  ABSTRACT
  INHERITING FROM zcl_alog_msg_logger_base
  CREATE PUBLIC.

  PUBLIC SECTION.
    TYPES:
      BEGIN OF gty_mapping,
        text_target      TYPE fieldname,
        type_target      TYPE fieldname,
        username_target  TYPE fieldname,
        timestamp_target TYPE fieldname,
      END OF gty_mapping,
      gty_key_component_tab TYPE STANDARD TABLE OF fieldname WITH DEFAULT KEY.
    METHODS:
      "! @parameter iv_tabname | Name of the database table
      "! @parameter is_mapping | Mapping configuration
      "! @parameter it_key_components | Key columns
      "! @parameter iv_secondary_conn_key | Key for secondary database connection
      "! @parameter iv_use_secondary_connection | Use secondary database connection
      "! @parameter iv_always_implicit_commit | Always commit after adding a log entry
      "! @raising zcx_alog_illegal_argument | Illegal argument
      constructor IMPORTING iv_tabname                  TYPE tabname
                            is_mapping                  TYPE gty_mapping
                            it_key_components           TYPE gty_key_component_tab
                            iv_secondary_conn_key       TYPE string OPTIONAL
                            iv_use_secondary_connection TYPE abap_bool DEFAULT abap_false
                            iv_always_implicit_commit   TYPE abap_bool DEFAULT abap_false
                  RAISING   zcx_alog_illegal_argument.
  PROTECTED SECTION.
    METHODS:
      entry_internal REDEFINITION,
      get_next_key ABSTRACT RETURNING VALUE(rv_key) TYPE string,
      "! Persist the new log entry
      "!

      "! The default implementation of this method uses a dynamic OpenSQL db insert based on the
      "! current configuration regarding target table and secondary connection settings. If other
      "! logic should be used by the logger you may override this method and instead for example
      "! call an update function module to make use of update tasks.
      "!

      "! @parameter ig_row | New log entry (type is the structure type of the db table)
      "! @raising zcx_alog_logging_failed | Logging failed
      insert_entry_in_db IMPORTING ig_row TYPE any
                         RAISING   zcx_alog_logging_failed.
  PRIVATE SECTION.
    CLASS-METHODS:
      write_to_component IMPORTING iv_component_name TYPE abap_compname
                                   iv_text           TYPE csequence
                         CHANGING  cg_structure      TYPE data,
      validate_mapping IMPORTING is_mapping TYPE gty_mapping
                                 io_descr   TYPE REF TO cl_abap_structdescr
                       RAISING   zcx_alog_illegal_argument,
      validate_key IMPORTING it_key   TYPE gty_key_component_tab
                             io_descr TYPE REF TO cl_abap_structdescr
                   RAISING   zcx_alog_illegal_argument.
    DATA:
      mv_tabname                  TYPE tabname,
      mo_descr                    TYPE REF TO cl_abap_structdescr,
      ms_mapping                  TYPE gty_mapping,
      mv_connection_key           TYPE string,
      mv_always_implicit_commit   TYPE abap_bool,
      mv_use_secondary_connection TYPE abap_bool,
      mt_key_components           TYPE gty_key_component_tab,
      mo_key_descr                TYPE REF TO cl_abap_structdescr.
ENDCLASS.

CLASS zcl_alog_dbtab_logger IMPLEMENTATION.
  METHOD constructor.
    super->constructor( ).

    mv_tabname = iv_tabname.
    mv_connection_key = iv_secondary_conn_key.
    mv_always_implicit_commit = iv_always_implicit_commit.
    mv_use_secondary_connection = iv_use_secondary_connection.
    mt_key_components = it_key_components.

    CALL FUNCTION 'DDIF_TABT_GET'
      EXPORTING
        name          = iv_tabname
      EXCEPTIONS
        illegal_input = 1
        OTHERS        = 2.

    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE zcx_alog_illegal_argument
        EXPORTING
          iv_reason = |{ iv_tabname } is not an active database table.|
          iv_value  = iv_tabname ##NO_TEXT.
    ENDIF.

    mo_descr = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name(  iv_tabname ) ).
    ASSERT mo_descr IS BOUND.

    validate_key( it_key = it_key_components io_descr = mo_descr ).
    mo_key_descr = cl_abap_structdescr=>get( VALUE #(
                     FOR comp IN mt_key_components
                     ( name = comp type = mo_descr->get_component_type( comp ) )
                   ) ).

    validate_mapping( is_mapping = is_mapping io_descr = mo_descr ).
    ms_mapping = is_mapping.
  ENDMETHOD.

  METHOD entry_internal.
    DATA: lr_table_line TYPE REF TO data,
          lr_key        TYPE REF TO data.
    FIELD-SYMBOLS: <lg_row> TYPE data,
                   <lg_key> TYPE data.

    CREATE DATA lr_table_line TYPE HANDLE mo_descr.
    ASSERT lr_table_line IS BOUND.

    ASSIGN lr_table_line->* TO <lg_row>.
    ASSERT <lg_row> IS ASSIGNED.

    CREATE DATA lr_key TYPE HANDLE mo_key_descr.
    ASSERT lr_key IS BOUND.
    ASSIGN lr_key->* TO <lg_key>.
    <lg_key> = get_next_key( ).

    MOVE-CORRESPONDING <lg_key> TO <lg_row>.

    IF ms_mapping-text_target IS NOT INITIAL.
      write_to_component(
        EXPORTING
          iv_component_name = ms_mapping-text_target
          iv_text           = iv_text
        CHANGING
          cg_structure      = <lg_row>
      ).
    ENDIF.

    IF ms_mapping-timestamp_target IS NOT INITIAL.
      GET TIME STAMP FIELD DATA(lv_timestamp).
      write_to_component(
        EXPORTING
          iv_component_name = ms_mapping-timestamp_target
          iv_text           = CONV string( lv_timestamp )
        CHANGING
          cg_structure      = <lg_row>
      ).
    ENDIF.

    IF ms_mapping-type_target IS NOT INITIAL.
      write_to_component(
        EXPORTING
          iv_component_name = ms_mapping-type_target
          iv_text           = io_type->mv_message_type
        CHANGING
          cg_structure      = <lg_row>
      ).
    ENDIF.

    IF ms_mapping-username_target IS NOT INITIAL.
      write_to_component(
        EXPORTING
          iv_component_name = ms_mapping-username_target
          iv_text           = cl_abap_syst=>get_user_name( )
        CHANGING
          cg_structure      = <lg_row>
      ).
    ENDIF.

    insert_entry_in_db( <lg_row> ).

    IF mv_always_implicit_commit = abap_true.
      IF mv_use_secondary_connection = abap_false OR mv_connection_key IS INITIAL.
        COMMIT WORK.
      ELSE.
        COMMIT CONNECTION (mv_connection_key).
      ENDIF.
    ENDIF.
  ENDMETHOD.

  METHOD insert_entry_in_db.
    IF mv_use_secondary_connection = abap_false OR mv_connection_key IS INITIAL.
      INSERT (mv_tabname) CONNECTION default FROM ig_row.
    ELSE.
      INSERT (mv_tabname) CONNECTION (mv_connection_key) FROM ig_row.
    ENDIF.

    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE zcx_alog_logging_failed
        EXPORTING
          iv_reason = |Dynamic INSERT into table '{ mv_tabname }' failed: { sy-subrc }| ##NO_TEXT.
    ENDIF.
  ENDMETHOD.

  METHOD write_to_component.
    ASSIGN COMPONENT iv_component_name OF STRUCTURE cg_structure TO FIELD-SYMBOL(<lg_comp>).
    ASSERT <lg_comp> IS ASSIGNED.
    <lg_comp> = iv_text.
*    WRITE iv_text TO <lg_comp>.
  ENDMETHOD.

  METHOD validate_mapping.
    DATA(lo_mapping_descr) = CAST cl_abap_structdescr(
                               cl_abap_typedescr=>describe_by_data( is_mapping )
                             ).

    LOOP AT lo_mapping_descr->components ASSIGNING FIELD-SYMBOL(<ls_component>).
      ASSIGN COMPONENT <ls_component>-name OF STRUCTURE is_mapping TO FIELD-SYMBOL(<lg_target>).
      ASSERT <lg_target> IS ASSIGNED.

      IF <lg_target> IS NOT INITIAL
          AND NOT line_exists( io_descr->components[ name = <lg_target> ] ).

        RAISE EXCEPTION TYPE zcx_alog_illegal_argument
          EXPORTING
            iv_reason = |Column '{ <lg_target> }' is missing in table | &&
                        |{ io_descr->get_relative_name( ) }.|
            iv_value  = CONV string( is_mapping ) ##NO_TEXT.
      ENDIF.

      UNASSIGN <lg_target>.
    ENDLOOP.
  ENDMETHOD.

  METHOD validate_key.
    LOOP AT it_key ASSIGNING FIELD-SYMBOL(<lv_comp>).
      IF NOT line_exists( io_descr->components[ name = <lv_comp> ] ).
        RAISE EXCEPTION TYPE zcx_alog_illegal_argument
          EXPORTING
            iv_reason = |Column '{ <lv_comp> }' of key is missing in table | &&
                        |{ io_descr->get_relative_name( ) }.| ##NO_TEXT.
      ENDIF.
    ENDLOOP.

    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE zcx_alog_illegal_argument
        EXPORTING
          iv_reason = 'Key cannot be empty.' ##NO_TEXT.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

Fix syntax errors

Fix syntax errors


CLASS zcl_abapgit_object_sprx DEFINITION PUBLIC INHERITING FROM zcl_abapgit_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES:
      zif_abapgit_object.

    METHODS:
      constructor
        IMPORTING
          is_item     TYPE zif_abapgit_definitions=>ty_item
          iv_language TYPE spras
        RAISING
          zcx_abapgit_exception.

  PROTECTED SECTION.
  PRIVATE SECTION.

    CONSTANTS:
      BEGIN OF c_proxy,
        data   TYPE string VALUE 'PROXY_DATA' ##NO_TEXT,
        header TYPE string VALUE 'PROXY_HEADER' ##NO_TEXT,
      END OF c_proxy .
    DATA mv_object TYPE sproxhdr-object .
    DATA mv_obj_name TYPE sproxhdr-obj_name .

    METHODS load_db
      RETURNING
        VALUE(rs_data) TYPE sprx_db_data .
    METHODS get_object_and_name
      EXPORTING
        !ev_object   TYPE sproxhdr-object
        !ev_obj_name TYPE sproxhdr-obj_name .
    METHODS delta_handling
      IMPORTING
        !ii_xml          TYPE REF TO zif_abapgit_xml_input
      EXPORTING
        !et_sproxhdr_new TYPE sprx_hdr_t
        !et_sproxdat_new TYPE sprx_dat_t
      RAISING
        zcx_abapgit_exception .
    METHODS check_sprx_tadir
      RAISING
        zcx_abapgit_exception .
    METHODS save
      IMPORTING
        !it_sproxhdr_new TYPE sprx_hdr_t
        !it_sproxdat_new TYPE sprx_dat_t .
ENDCLASS.

CLASS zcl_abapgit_object_sprx IMPLEMENTATION.

  METHOD check_sprx_tadir.

    DATA: lt_abap_keys TYPE prx_abapobjects,
          ls_abap_key  LIKE LINE OF lt_abap_keys,
          lx_error     TYPE REF TO cx_proxy_gen_error.

    ls_abap_key-object   = mv_object.
    ls_abap_key-obj_name = mv_obj_name.
    APPEND ls_abap_key TO lt_abap_keys.

    TRY.
        cl_proxy_utils=>check_sprx_tadir(
            objects = lt_abap_keys
            repair  = abap_true ).

      CATCH cx_proxy_gen_error INTO lx_error.
        zcx_abapgit_exception=>raise_with_text( lx_error ).
    ENDTRY.

  ENDMETHOD.

  METHOD constructor.

    super->constructor( is_item     = is_item
                        iv_language = iv_language ).

    get_object_and_name(
      IMPORTING
        ev_object   = mv_object
        ev_obj_name = mv_obj_name ).

  ENDMETHOD.

  METHOD delta_handling.

    DATA: lo_proxy   TYPE REF TO cl_proxy,
          lt_delta   TYPE sprx_t_delta,
          ls_db_data TYPE sprx_db_data.

    "add Delta-Handling to avoid that single objects created without the dependent objects.
    "Thereby the dependent objects will be deleted
    TRY.
        lo_proxy = cl_proxy_fact=>load_by_abap_name(
                       object   = mv_object
                       obj_name = mv_obj_name ).

        lt_delta = lo_proxy->get_delta_all( ).

        ls_db_data = cl_proxy_db=>serialize(
                         proxy    = lo_proxy
                         inactive = abap_false
                         delta    = lt_delta ).

        et_sproxhdr_new = ls_db_data-sproxhdr.
        et_sproxdat_new = ls_db_data-sproxdat.

      CATCH cx_proxy_gen_error.
        "No delta for this object -> create

        ii_xml->read(
          EXPORTING
            iv_name = c_proxy-header
          CHANGING
            cg_data = et_sproxhdr_new ).

        IF et_sproxhdr_new IS INITIAL.
          zcx_abapgit_exception=>raise( |SPRX - error deserialize: { ms_item-obj_name }| ).
        ENDIF.

        ii_xml->read(
          EXPORTING
            iv_name = c_proxy-data
          CHANGING
            cg_data = et_sproxdat_new ).

    ENDTRY.

  ENDMETHOD.

  METHOD get_object_and_name.

    ev_object   = ms_item-obj_name(4).
    ev_obj_name = ms_item-obj_name+4.

  ENDMETHOD.

  METHOD load_db.

* method cl_proxy_db=>load_by_abap_name does not exist in lower releases

    DATA: lt_packages TYPE prx_t_namespace_package,
          ls_package  LIKE LINE OF lt_packages,
          ls_hdr      TYPE prx_s_proxy_hdr,
          lv_package  TYPE tadir-devclass,
          lt_ids      TYPE prx_ids.

    cl_proxy_query=>get_hdr_by_abap_name(
      EXPORTING
        object   = mv_object
        obj_name = mv_obj_name
      IMPORTING
        hdr      = ls_hdr ).
    APPEND ls_hdr-id TO lt_ids.

    IF ls_hdr-gen_appl = 'WEBSERVICES'.
      cl_proxy_utils=>get_package(
        EXPORTING
          object   = mv_object
          obj_name = mv_obj_name
        RECEIVING
          rval     = lv_package
        EXCEPTIONS
          OTHERS   = 0 ).

      ls_package-namespace = ls_hdr-esr_nspce.
      ls_package-prefix    = ls_hdr-prefix.
      ls_package-package   = lv_package.
      APPEND ls_package TO lt_packages.
    ENDIF.

    rs_data = cl_proxy_db=>load(
      inactive               = abap_false
      ids                    = lt_ids
      generating_application = ls_hdr-gen_appl
      packages               = lt_packages ).

  ENDMETHOD.

  METHOD save.

    DATA:
      lt_sproxhdr_old  TYPE sprx_hdr_t,
      lt_sproxdat_old  TYPE sprx_dat_t,
      lt_sproxsvar_old TYPE sprx_svar_t,
      lt_sproxintf_old TYPE sprx_matchintf_t,
      lt_sproxsvar_new TYPE sprx_svar_t,
      lt_sproxintf_new TYPE sprx_matchintf_t.

    cl_proxy_data=>db_save(
        sproxhdr_old  = lt_sproxhdr_old
        sproxdat_old  = lt_sproxdat_old
        sproxsvar_old = lt_sproxsvar_old
        sproxintf_old = lt_sproxintf_old
        sproxhdr_new  = it_sproxhdr_new
        sproxdat_new  = it_sproxdat_new
        sproxsvar_new = lt_sproxsvar_new
        sproxintf_new = lt_sproxintf_new ).

  ENDMETHOD.

  METHOD zif_abapgit_object~changed_by.

    DATA lv_changed_by TYPE sproxhdr-changed_by.

    rv_user = c_user_unknown.

    SELECT SINGLE changed_by
      FROM sproxhdr
      INTO lv_changed_by
      WHERE object = mv_object
      AND obj_name = mv_obj_name
      AND inactive = abap_false.

    IF sy-subrc = 0 AND lv_changed_by IS NOT INITIAL.
      rv_user = lv_changed_by.
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~delete.

    DATA:
      lv_object      TYPE sproxhdr-object,
      lv_obj_name    TYPE sproxhdr-obj_name,
      lv_return_code TYPE i,
      lt_log         TYPE sprx_log_t.

    corr_insert( iv_package ).

    get_object_and_name(
      IMPORTING
        ev_object   = lv_object
        ev_obj_name = lv_obj_name ).

    TRY.
        CALL METHOD ('CL_PROXY_DATA')=>('DELETE_SINGLE_PROXY')
          EXPORTING
            object           = lv_object
            obj_name         = lv_obj_name
            suppress_dialogs = abap_true
          CHANGING
            c_return_code    = lv_return_code
            ct_log           = lt_log.
      CATCH cx_root.
        cl_proxy_data=>delete_single_proxy(
           EXPORTING
             object           = lv_object
             obj_name         = lv_obj_name
           CHANGING
             c_return_code    = lv_return_code
             ct_log           = lt_log ).
    ENDTRY.
    IF lv_return_code <> 0.
      zcx_abapgit_exception=>raise( 'SPRX: Error from DELETE_SINGLE_PROXY' ).
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~deserialize.

    DATA: lt_sproxhdr_new TYPE sprx_hdr_t,
          lt_sproxdat_new TYPE sprx_dat_t.

    tadir_insert( iv_package ).

    delta_handling(
      EXPORTING
        ii_xml = io_xml
      IMPORTING
        et_sproxhdr_new = lt_sproxhdr_new
        et_sproxdat_new = lt_sproxdat_new ).

    save(
      it_sproxhdr_new = lt_sproxhdr_new
      it_sproxdat_new = lt_sproxdat_new ).

    COMMIT WORK.

    check_sprx_tadir( ).

  ENDMETHOD.

  METHOD zif_abapgit_object~exists.

    DATA:
      lv_status      TYPE prx_status,
      lv_status_text TYPE prx_status_t.

    cl_proxy_data=>db_get_status(
      EXPORTING
        object      = mv_object
        obj_name    = mv_obj_name
      IMPORTING
        status      = lv_status
        status_text = lv_status_text ).

    rv_bool = boolc( lv_status = if_proxy=>c_state_active ).

  ENDMETHOD.

  METHOD zif_abapgit_object~get_comparator.
    RETURN.
  ENDMETHOD.

  METHOD zif_abapgit_object~get_deserialize_steps.
    APPEND zif_abapgit_object=>gc_step_id-abap TO rt_steps.
  ENDMETHOD.

  METHOD zif_abapgit_object~get_metadata.
    rs_metadata = get_metadata( ).
  ENDMETHOD.

  METHOD zif_abapgit_object~is_active.
    rv_active = abap_true. "dummy implementation
  ENDMETHOD.

  METHOD zif_abapgit_object~is_locked.
    rv_is_locked = abap_false.
  ENDMETHOD.

  METHOD zif_abapgit_object~jump.
    " Covered by ZCL_ABAPGIT_OBJECTS=>JUMP
  ENDMETHOD.

  METHOD zif_abapgit_object~serialize.

    DATA:
      ls_sprx_db_data TYPE sprx_db_data.

    FIELD-SYMBOLS:
      <ls_sproxheader> LIKE LINE OF ls_sprx_db_data-sproxhdr,
      <ls_sproxdat>    LIKE LINE OF ls_sprx_db_data-sproxdat.

    IF zif_abapgit_object~exists( ) = abap_false.
      RETURN.
    ENDIF.

    ls_sprx_db_data = load_db( ).

    DELETE ls_sprx_db_data-sproxhdr WHERE object <> mv_object OR obj_name <> mv_obj_name.
    DELETE ls_sprx_db_data-sproxdat WHERE object <> mv_object OR obj_name <> mv_obj_name.
    DELETE ls_sprx_db_data-sproxsvar WHERE object <> mv_object OR obj_name <> mv_obj_name.
    DELETE ls_sprx_db_data-sproxpck WHERE object <> mv_object OR obj_name <> mv_obj_name.
    DELETE ls_sprx_db_data-sproxintf WHERE object <> mv_object OR obj_name <> mv_obj_name.

    IF lines( ls_sprx_db_data-sproxhdr ) <> 1.
      zcx_abapgit_exception=>raise( |SPRX, no header found, { mv_object }, { mv_obj_name }| ).
    ENDIF.

    LOOP AT ls_sprx_db_data-sproxhdr ASSIGNING <ls_sproxheader>.

      CLEAR:
        <ls_sproxheader>-created_by,
        <ls_sproxheader>-created_on,
        <ls_sproxheader>-changed_by,
        <ls_sproxheader>-changed_on.

    ENDLOOP.

    LOOP AT ls_sprx_db_data-sproxdat ASSIGNING <ls_sproxdat>.

      CLEAR <ls_sproxdat>-warnings.

    ENDLOOP.

    io_xml->add(
        iv_name = c_proxy-header
        ig_data = ls_sprx_db_data-sproxhdr ).

    io_xml->add(
        iv_name = c_proxy-data
        ig_data = ls_sprx_db_data-sproxdat ).

  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_object_sprx DEFINITION PUBLIC INHERITING FROM zcl_abapgit_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES:
      zif_abapgit_object.

    METHODS:
      constructor
        IMPORTING
          is_item     TYPE zif_abapgit_definitions=>ty_item
          iv_language TYPE spras
        RAISING
          zcx_abapgit_exception.

  PROTECTED SECTION.
  PRIVATE SECTION.

    CONSTANTS:
      BEGIN OF c_proxy,
        data   TYPE string VALUE 'PROXY_DATA' ##NO_TEXT,
        header TYPE string VALUE 'PROXY_HEADER' ##NO_TEXT,
      END OF c_proxy .
    DATA mv_object TYPE sproxhdr-object .
    DATA mv_obj_name TYPE sproxhdr-obj_name .

    METHODS load_db
      RETURNING
        VALUE(rs_data) TYPE sprx_db_data .
    METHODS get_object_and_name
      EXPORTING
        !ev_object   TYPE sproxhdr-object
        !ev_obj_name TYPE sproxhdr-obj_name .
    METHODS delta_handling
      IMPORTING
        !ii_xml          TYPE REF TO zif_abapgit_xml_input
      EXPORTING
        !et_sproxhdr_new TYPE sprx_hdr_t
        !et_sproxdat_new TYPE sprx_dat_t
      RAISING
        zcx_abapgit_exception .
    METHODS check_sprx_tadir
      RAISING
        zcx_abapgit_exception .
    METHODS save
      IMPORTING
        !it_sproxhdr_new TYPE sprx_hdr_t
        !it_sproxdat_new TYPE sprx_dat_t .
ENDCLASS.

CLASS zcl_abapgit_object_sprx IMPLEMENTATION.

  METHOD check_sprx_tadir.

    DATA: lt_abap_keys TYPE prx_abapobjects,
          ls_abap_key  LIKE LINE OF lt_abap_keys,
          lx_error     TYPE REF TO cx_proxy_gen_error.

    ls_abap_key-object   = mv_object.
    ls_abap_key-obj_name = mv_obj_name.
    APPEND ls_abap_key TO lt_abap_keys.

    TRY.
        cl_proxy_utils=>check_sprx_tadir(
            objects = lt_abap_keys
            repair  = abap_true ).

      CATCH cx_proxy_gen_error INTO lx_error.
        zcx_abapgit_exception=>raise_with_text( lx_error ).
    ENDTRY.

  ENDMETHOD.

  METHOD constructor.

    super->constructor( is_item     = is_item
                        iv_language = iv_language ).

    get_object_and_name(
      IMPORTING
        ev_object   = mv_object
        ev_obj_name = mv_obj_name ).

  ENDMETHOD.

  METHOD delta_handling.

    DATA: lo_proxy   TYPE REF TO cl_proxy,
          lt_delta   TYPE sprx_t_delta,
          ls_db_data TYPE sprx_db_data.

    "add Delta-Handling to avoid that single objects created without the dependent objects.
    "Thereby the dependent objects will be deleted
    TRY.
        lo_proxy = cl_proxy_fact=>load_by_abap_name(
                       object   = mv_object
                       obj_name = mv_obj_name ).

        lt_delta = lo_proxy->get_delta_all( ).

        ls_db_data = cl_proxy_db=>serialize(
                         proxy    = lo_proxy
                         inactive = abap_false
                         delta    = lt_delta ).

        et_sproxhdr_new = ls_db_data-sproxhdr.
        et_sproxdat_new = ls_db_data-sproxdat.

      CATCH cx_proxy_gen_error.
        "No delta for this object -> create

        ii_xml->read(
          EXPORTING
            iv_name = c_proxy-header
          CHANGING
            cg_data = et_sproxhdr_new ).

        IF et_sproxhdr_new IS INITIAL.
          zcx_abapgit_exception=>raise( |SPRX - error deserialize: { ms_item-obj_name }| ).
        ENDIF.

        ii_xml->read(
          EXPORTING
            iv_name = c_proxy-data
          CHANGING
            cg_data = et_sproxdat_new ).

    ENDTRY.

  ENDMETHOD.

  METHOD get_object_and_name.

    ev_object   = ms_item-obj_name(4).
    ev_obj_name = ms_item-obj_name+4.

  ENDMETHOD.

  METHOD load_db.

* method cl_proxy_db=>load_by_abap_name does not exist in lower releases

    DATA: lt_packages TYPE prx_t_namespace_package,
          ls_package  LIKE LINE OF lt_packages,
          ls_hdr      TYPE prx_s_proxy_hdr,
          lv_package  TYPE tadir-devclass,
          lt_ids      TYPE prx_ids.

    cl_proxy_query=>get_hdr_by_abap_name(
      EXPORTING
        object   = mv_object
        obj_name = mv_obj_name
      IMPORTING
        hdr      = ls_hdr ).
    APPEND ls_hdr-id TO lt_ids.

    IF ls_hdr-gen_appl = 'WEBSERVICES'.
      cl_proxy_utils=>get_package(
        EXPORTING
          object   = mv_object
          obj_name = mv_obj_name
        RECEIVING
          rval     = lv_package
        EXCEPTIONS
          OTHERS   = 0 ).

      ls_package-namespace = ls_hdr-esr_nspce.
      ls_package-prefix    = ls_hdr-prefix.
      ls_package-package   = lv_package.
      APPEND ls_package TO lt_packages.
    ENDIF.

    rs_data = cl_proxy_db=>load(
      inactive               = abap_false
      ids                    = lt_ids
      generating_application = ls_hdr-gen_appl
      packages               = lt_packages ).

  ENDMETHOD.

  METHOD save.

    DATA:
      lt_sproxhdr_old  TYPE sprx_hdr_t,
      lt_sproxdat_old  TYPE sprx_dat_t,
      lt_sproxsvar_old TYPE sprx_svar_t,
      lt_sproxintf_old TYPE sprx_matchintf_t,
      lt_sproxsvar_new TYPE sprx_svar_t,
      lt_sproxintf_new TYPE sprx_matchintf_t.

    cl_proxy_data=>db_save(
        sproxhdr_old  = lt_sproxhdr_old
        sproxdat_old  = lt_sproxdat_old
        sproxsvar_old = lt_sproxsvar_old
        sproxintf_old = lt_sproxintf_old
        sproxhdr_new  = it_sproxhdr_new
        sproxdat_new  = it_sproxdat_new
        sproxsvar_new = lt_sproxsvar_new
        sproxintf_new = lt_sproxintf_new ).

  ENDMETHOD.

  METHOD zif_abapgit_object~changed_by.

    DATA lv_changed_by TYPE sproxhdr-changed_by.

    rv_user = c_user_unknown.

    SELECT SINGLE changed_by
      FROM sproxhdr
      INTO lv_changed_by
      WHERE object = mv_object
      AND obj_name = mv_obj_name
      AND inactive = abap_false.

    IF sy-subrc = 0 AND lv_changed_by IS NOT INITIAL.
      rv_user = lv_changed_by.
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~delete.

    DATA:
      lv_object      TYPE sproxhdr-object,
      lv_obj_name    TYPE sproxhdr-obj_name,
      lv_transp_flag TYPE abap_bool,
      lv_return_code TYPE i,
      lt_log         TYPE sprx_log_t.

    corr_insert( iv_package ).

    IF iv_package(1) <> '$'.
      lv_transp_flag = abap_true.
    ENDIF.

    get_object_and_name(
      IMPORTING
        ev_object   = lv_object
        ev_obj_name = lv_obj_name ).

    TRY.
        CALL METHOD ('CL_PROXY_DATA')=>('DELETE_SINGLE_PROXY')
          EXPORTING
            object           = lv_object
            obj_name         = lv_obj_name
            i_transport      = lv_transp_flag
            suppress_dialogs = abap_true
          CHANGING
            c_return_code    = lv_return_code
            ct_log           = lt_log.
      CATCH cx_root.
        cl_proxy_data=>delete_single_proxy(
           EXPORTING
             object           = lv_object
             obj_name         = lv_obj_name
             i_transport      = lv_transp_flag
           CHANGING
             c_return_code    = lv_return_code
             ct_log           = lt_log ).
    ENDTRY.
    IF lv_return_code <> 0.
      zcx_abapgit_exception=>raise( 'SPRX: Error from DELETE_SINGLE_PROXY' ).
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~deserialize.

    DATA: lt_sproxhdr_new TYPE sprx_hdr_t,
          lt_sproxdat_new TYPE sprx_dat_t.

    tadir_insert( iv_package ).

    corr_insert( iv_package ).

    delta_handling(
      EXPORTING
        ii_xml = io_xml
      IMPORTING
        et_sproxhdr_new = lt_sproxhdr_new
        et_sproxdat_new = lt_sproxdat_new ).

    save(
      it_sproxhdr_new = lt_sproxhdr_new
      it_sproxdat_new = lt_sproxdat_new ).

    COMMIT WORK.

    check_sprx_tadir( ).

  ENDMETHOD.

  METHOD zif_abapgit_object~exists.

    DATA:
      lv_status      TYPE prx_status,
      lv_status_text TYPE prx_status_t.

    cl_proxy_data=>db_get_status(
      EXPORTING
        object      = mv_object
        obj_name    = mv_obj_name
      IMPORTING
        status      = lv_status
        status_text = lv_status_text ).

    rv_bool = boolc( lv_status = if_proxy=>c_state_active ).

  ENDMETHOD.

  METHOD zif_abapgit_object~get_comparator.
    RETURN.
  ENDMETHOD.

  METHOD zif_abapgit_object~get_deserialize_steps.
    APPEND zif_abapgit_object=>gc_step_id-abap TO rt_steps.
  ENDMETHOD.

  METHOD zif_abapgit_object~get_metadata.
    rs_metadata = get_metadata( ).
  ENDMETHOD.

  METHOD zif_abapgit_object~is_active.
    rv_active = abap_true. "dummy implementation
  ENDMETHOD.

  METHOD zif_abapgit_object~is_locked.
    rv_is_locked = abap_false.
  ENDMETHOD.

  METHOD zif_abapgit_object~jump.
    " Covered by ZCL_ABAPGIT_OBJECTS=>JUMP
  ENDMETHOD.

  METHOD zif_abapgit_object~serialize.

    DATA:
      ls_sprx_db_data TYPE sprx_db_data.

    FIELD-SYMBOLS:
      <ls_sproxheader> LIKE LINE OF ls_sprx_db_data-sproxhdr,
      <ls_sproxdat>    LIKE LINE OF ls_sprx_db_data-sproxdat.

    IF zif_abapgit_object~exists( ) = abap_false.
      RETURN.
    ENDIF.

    ls_sprx_db_data = load_db( ).

    DELETE ls_sprx_db_data-sproxhdr WHERE object <> mv_object OR obj_name <> mv_obj_name.
    DELETE ls_sprx_db_data-sproxdat WHERE object <> mv_object OR obj_name <> mv_obj_name.
    DELETE ls_sprx_db_data-sproxsvar WHERE object <> mv_object OR obj_name <> mv_obj_name.
    DELETE ls_sprx_db_data-sproxpck WHERE object <> mv_object OR obj_name <> mv_obj_name.
    DELETE ls_sprx_db_data-sproxintf WHERE object <> mv_object OR obj_name <> mv_obj_name.

    IF lines( ls_sprx_db_data-sproxhdr ) <> 1.
      zcx_abapgit_exception=>raise( |SPRX, no header found, { mv_object }, { mv_obj_name }| ).
    ENDIF.

    LOOP AT ls_sprx_db_data-sproxhdr ASSIGNING <ls_sproxheader>.

      CLEAR:
        <ls_sproxheader>-created_by,
        <ls_sproxheader>-created_on,
        <ls_sproxheader>-changed_by,
        <ls_sproxheader>-changed_on.

    ENDLOOP.

    LOOP AT ls_sprx_db_data-sproxdat ASSIGNING <ls_sproxdat>.

      CLEAR <ls_sproxdat>-warnings.

    ENDLOOP.

    io_xml->add(
        iv_name = c_proxy-header
        ig_data = ls_sprx_db_data-sproxhdr ).

    io_xml->add(
        iv_name = c_proxy-data
        ig_data = ls_sprx_db_data-sproxdat ).

  ENDMETHOD.
ENDCLASS.

Add objects to transport (#5521)

SPRX: Add objects to transport (#5521)

- Add proxy to transport in deserialize
- Add objects to transport in delete

Co-authored-by: Lars Hvam <721d1b171982cd84b755f6b25130d2b88cd1f696@hotmail.com>


CLASS zcl_ags_obj_commit DEFINITION
  PUBLIC
  CREATE PUBLIC.

  PUBLIC SECTION.

    INTERFACES zif_ags_object.

    ALIASES c_newline
      FOR zif_ags_object~c_newline.
    ALIASES deserialize
      FOR zif_ags_object~deserialize.
    ALIASES save
      FOR zif_ags_object~save.
    ALIASES serialize
      FOR zif_ags_object~serialize.
    ALIASES sha1
      FOR zif_ags_object~sha1.

    TYPES:
      BEGIN OF ty_userfield,
        name  TYPE string,
        email TYPE string,
        time  TYPE zags_unix_time,
      END OF ty_userfield.
    TYPES:
      BEGIN OF ty_pretty,
        sha1      TYPE zags_sha1,
        tree      TYPE zags_sha1,
        parent    TYPE zags_sha1,
        author    TYPE ty_userfield,
        committer TYPE ty_userfield,
        text      TYPE string,
        body      TYPE string,
      END OF ty_pretty.
    TYPES:
      ty_pretty_tt TYPE STANDARD TABLE OF ty_pretty WITH DEFAULT KEY.
    TYPES:
      BEGIN OF ty_commit,
        tree      TYPE zags_sha1,
        parent    TYPE zags_sha1,
        author    TYPE string,
        committer TYPE string,
        body      TYPE string,
      END OF ty_commit.
    TYPES:
      ty_commits_tt TYPE STANDARD TABLE OF ty_commit WITH DEFAULT KEY.

    METHODS constructor
      IMPORTING
        !iv_sha1 TYPE zags_sha1 OPTIONAL
      RAISING
        zcx_ags_error.
    METHODS get
      RETURNING
        VALUE(rs_data) TYPE ty_commit.
    METHODS get_pretty
      RETURNING
        VALUE(rs_data) TYPE ty_pretty
      RAISING
        zcx_ags_error.
    METHODS set_author
      IMPORTING
        !iv_author TYPE ty_commit-author
      RAISING
        zcx_ags_error.
    METHODS set_body
      IMPORTING
        !iv_body TYPE ty_commit-body.
    METHODS set_committer
      IMPORTING
        !iv_committer TYPE ty_commit-committer
      RAISING
        zcx_ags_error.
    METHODS set_parent
      IMPORTING
        !iv_parent TYPE ty_commit-parent.
    METHODS set_tree
      IMPORTING
        !iv_tree TYPE zags_sha1.
  PROTECTED SECTION.
  PRIVATE SECTION.

    DATA ms_data TYPE ty_commit.
    DATA mv_new TYPE abap_bool.

    METHODS parse_userfield
      IMPORTING
        !iv_field           TYPE string
      RETURNING
        VALUE(rs_userfield) TYPE ty_userfield
      RAISING
        zcx_ags_error.
ENDCLASS.

CLASS ZCL_AGS_OBJ_COMMIT IMPLEMENTATION.

  METHOD constructor.

    IF iv_sha1 IS INITIAL.
      mv_new = abap_true.
    ELSE.
      mv_new = abap_false.
      deserialize( zcl_ags_lookup=>read_object( iv_sha1 )-data_raw ).
    ENDIF.

  ENDMETHOD.

  METHOD get.

    rs_data = ms_data.

  ENDMETHOD.

  METHOD get_pretty.

    DATA: ls_data TYPE ty_commit,
          lt_body TYPE TABLE OF string,
          lv_body LIKE LINE OF lt_body.

    ls_data = get( ).

    rs_data-sha1      = sha1( ).
    rs_data-tree      = ls_data-tree.
    rs_data-parent    = ls_data-parent.
    rs_data-author    = parse_userfield( ls_data-author ).
    rs_data-committer = parse_userfield( ls_data-committer ).

    SPLIT ls_data-body AT cl_abap_char_utilities=>newline INTO TABLE lt_body.

    READ TABLE lt_body INDEX 1 INTO lv_body.              "#EC CI_SUBRC
    rs_data-text = lv_body.

    DELETE lt_body INDEX 1.
    CONCATENATE LINES OF lt_body
      INTO rs_data-body
      SEPARATED BY cl_abap_char_utilities=>newline.

  ENDMETHOD.

  METHOD parse_userfield.

    DATA: lv_time TYPE string.

    FIND REGEX '^(\w+) <(.*)> (\d{10}) .\d{4}$' IN iv_field
      SUBMATCHES
      rs_userfield-name
      rs_userfield-email
      lv_time ##NO_TEXT.
    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE zcx_ags_error
        EXPORTING
          textid = zcx_ags_error=>m012.
    ENDIF.

    rs_userfield-time = lv_time.

  ENDMETHOD.

  METHOD set_author.

    parse_userfield( iv_author ).

    ms_data-author = iv_author.

  ENDMETHOD.

  METHOD set_body.

    ms_data-body = iv_body.

  ENDMETHOD.

  METHOD set_committer.

    parse_userfield( iv_committer ).

    ms_data-committer = iv_committer.

  ENDMETHOD.

  METHOD set_parent.

    ms_data-parent = iv_parent.

  ENDMETHOD.

  METHOD set_tree.

    ms_data-tree = iv_tree.

  ENDMETHOD.

  METHOD zif_ags_object~deserialize.

    DATA: lv_string TYPE string,
          lv_char40 TYPE c LENGTH 40,
          lv_mode   TYPE string,
          lv_len    TYPE i,
          lt_string TYPE TABLE OF string.

    FIELD-SYMBOLS: <lv_string> LIKE LINE OF lt_string.

    lv_string = zcl_ags_util=>xstring_to_string_utf8( iv_data ).

    SPLIT lv_string AT c_newline INTO TABLE lt_string.

    lv_mode = 'tree'.                                       "#EC NOTEXT
    LOOP AT lt_string ASSIGNING <lv_string>.
      lv_len = strlen( lv_mode ).

      IF NOT lv_mode IS INITIAL AND <lv_string>(lv_len) = lv_mode.
        CASE lv_mode.
          WHEN 'tree'.
            lv_char40 = <lv_string>+5.
            ms_data-tree = lv_char40.
            lv_mode = 'parent'.                             "#EC NOTEXT
          WHEN 'parent'.
            lv_char40 = <lv_string>+7.
            ms_data-parent = lv_char40.
            lv_mode = 'author'.                             "#EC NOTEXT
          WHEN 'author'.
            ms_data-author = <lv_string>+7.
            lv_mode = 'committer'.                          "#EC NOTEXT
          WHEN 'committer'.
            ms_data-committer = <lv_string>+10.
            CLEAR lv_mode.
        ENDCASE.
      ELSEIF lv_mode = 'parent' AND <lv_string>(6) = 'author'. "#EC NOTEXT
* first commit doesnt have parent
        ms_data-author = <lv_string>+7.
        lv_mode = 'committer'.                              "#EC NOTEXT
      ELSE.
* body
        CONCATENATE ms_data-body <lv_string> INTO ms_data-body
          SEPARATED BY c_newline.
      ENDIF.
    ENDLOOP.

* strip first newline
    IF strlen( ms_data-body ) >= 2.
      ms_data-body = ms_data-body+2.
    ENDIF.

    IF ms_data-author IS INITIAL
        OR ms_data-committer IS INITIAL
        OR ms_data-tree IS INITIAL.
* multiple parents? not supported
      ASSERT 1 = 2.
    ENDIF.

  ENDMETHOD.

  METHOD zif_ags_object~save.

    DATA: ls_object TYPE zags_objects.

    ASSERT mv_new = abap_true.

    ls_object-sha1 = sha1( ).
    ls_object-type = zif_ags_constants=>c_type-commit.
    ls_object-data_raw = serialize( ).

    MODIFY zags_objects FROM ls_object.

  ENDMETHOD.

  METHOD zif_ags_object~serialize.

    DATA: lv_string       TYPE string,
          lv_tmp          TYPE string,
          lv_tree_lower   TYPE string,
          lv_parent_lower TYPE string.

    lv_tree_lower = ms_data-tree.
    TRANSLATE lv_tree_lower TO LOWER CASE.

    lv_parent_lower = ms_data-parent.
    TRANSLATE lv_parent_lower TO LOWER CASE.

    lv_string = ''.

    CONCATENATE 'tree' lv_tree_lower INTO lv_tmp SEPARATED BY space. "#EC NOTEXT
    CONCATENATE lv_string lv_tmp c_newline INTO lv_string.

    IF NOT ms_data-parent IS INITIAL.
      CONCATENATE 'parent' lv_parent_lower
        INTO lv_tmp SEPARATED BY space.                     "#EC NOTEXT
      CONCATENATE lv_string lv_tmp c_newline INTO lv_string.
    ENDIF.

    CONCATENATE 'author' ms_data-author
      INTO lv_tmp SEPARATED BY space.                       "#EC NOTEXT
    CONCATENATE lv_string lv_tmp c_newline INTO lv_string.

    CONCATENATE 'committer' ms_data-committer
      INTO lv_tmp SEPARATED BY space.                       "#EC NOTEXT
    CONCATENATE lv_string lv_tmp c_newline INTO lv_string.

    CONCATENATE lv_string c_newline ms_data-body INTO lv_string.

    rv_data = zcl_ags_util=>string_to_xstring_utf8( lv_string ).

  ENDMETHOD.

  METHOD zif_ags_object~sha1.

    rv_sha1 = zcl_ags_util=>sha1(
        iv_type = zif_ags_constants=>c_type-commit
        iv_data = serialize( ) ) ##NO_TEXT.

  ENDMETHOD.

  METHOD zif_ags_object~type.
    rv_type = zif_ags_constants=>c_type-commit.
  ENDMETHOD.
ENDCLASS.

CLASS zcl_ags_obj_commit DEFINITION
  PUBLIC
  CREATE PUBLIC.

  PUBLIC SECTION.

    INTERFACES zif_ags_object.

    ALIASES c_newline
      FOR zif_ags_object~c_newline.
    ALIASES deserialize
      FOR zif_ags_object~deserialize.
    ALIASES save
      FOR zif_ags_object~save.
    ALIASES serialize
      FOR zif_ags_object~serialize.
    ALIASES sha1
      FOR zif_ags_object~sha1.

    TYPES:
      BEGIN OF ty_userfield,
        name  TYPE string,
        email TYPE string,
        time  TYPE zags_unix_time,
      END OF ty_userfield.
    TYPES:
      BEGIN OF ty_pretty,
        sha1      TYPE zags_sha1,
        tree      TYPE zags_sha1,
        parent    TYPE zags_sha1,
        author    TYPE ty_userfield,
        committer TYPE ty_userfield,
        text      TYPE string,
        body      TYPE string,
      END OF ty_pretty.
    TYPES:
      ty_pretty_tt TYPE STANDARD TABLE OF ty_pretty WITH DEFAULT KEY.
    TYPES:
      BEGIN OF ty_commit,
        tree      TYPE zags_sha1,
        parent    TYPE zags_sha1,
        parent2   TYPE zags_sha1,
        author    TYPE string,
        committer TYPE string,
        body      TYPE string,
      END OF ty_commit.
    TYPES:
      ty_commits_tt TYPE STANDARD TABLE OF ty_commit WITH DEFAULT KEY.

    METHODS constructor
      IMPORTING
        !iv_sha1 TYPE zags_sha1 OPTIONAL
      RAISING
        zcx_ags_error.
    METHODS get
      RETURNING
        VALUE(rs_data) TYPE ty_commit.
    METHODS get_pretty
      RETURNING
        VALUE(rs_data) TYPE ty_pretty
      RAISING
        zcx_ags_error.
    METHODS set_author
      IMPORTING
        !iv_author TYPE ty_commit-author
      RAISING
        zcx_ags_error.
    METHODS set_body
      IMPORTING
        !iv_body TYPE ty_commit-body.
    METHODS set_committer
      IMPORTING
        !iv_committer TYPE ty_commit-committer
      RAISING
        zcx_ags_error.
    METHODS set_parent
      IMPORTING
        !iv_parent TYPE ty_commit-parent.
    METHODS set_tree
      IMPORTING
        !iv_tree TYPE zags_sha1.
  PROTECTED SECTION.
  PRIVATE SECTION.

    DATA ms_data TYPE ty_commit.
    DATA mv_new TYPE abap_bool.

    METHODS parse_userfield
      IMPORTING
        !iv_field           TYPE string
      RETURNING
        VALUE(rs_userfield) TYPE ty_userfield
      RAISING
        zcx_ags_error.
ENDCLASS.

CLASS ZCL_AGS_OBJ_COMMIT IMPLEMENTATION.

  METHOD constructor.

    IF iv_sha1 IS INITIAL.
      mv_new = abap_true.
    ELSE.
      mv_new = abap_false.
      deserialize( zcl_ags_lookup=>read_object( iv_sha1 )-data_raw ).
    ENDIF.

  ENDMETHOD.

  METHOD get.

    rs_data = ms_data.

  ENDMETHOD.

  METHOD get_pretty.

    DATA: ls_data TYPE ty_commit,
          lt_body TYPE TABLE OF string,
          lv_body LIKE LINE OF lt_body.

    ls_data = get( ).

    rs_data-sha1      = sha1( ).
    rs_data-tree      = ls_data-tree.
    rs_data-parent    = ls_data-parent.
    rs_data-author    = parse_userfield( ls_data-author ).
    rs_data-committer = parse_userfield( ls_data-committer ).

    SPLIT ls_data-body AT cl_abap_char_utilities=>newline INTO TABLE lt_body.

    READ TABLE lt_body INDEX 1 INTO lv_body.              "#EC CI_SUBRC
    rs_data-text = lv_body.

    DELETE lt_body INDEX 1.
    CONCATENATE LINES OF lt_body
      INTO rs_data-body
      SEPARATED BY cl_abap_char_utilities=>newline.

  ENDMETHOD.

  METHOD parse_userfield.

    DATA: lv_time TYPE string.

    FIND REGEX '^(\w+) <(.*)> (\d{10}) .\d{4}$' IN iv_field
      SUBMATCHES
      rs_userfield-name
      rs_userfield-email
      lv_time ##NO_TEXT.
    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE zcx_ags_error
        EXPORTING
          textid = zcx_ags_error=>m012.
    ENDIF.

    rs_userfield-time = lv_time.

  ENDMETHOD.

  METHOD set_author.

    parse_userfield( iv_author ).

    ms_data-author = iv_author.

  ENDMETHOD.

  METHOD set_body.

    ms_data-body = iv_body.

  ENDMETHOD.

  METHOD set_committer.

    parse_userfield( iv_committer ).

    ms_data-committer = iv_committer.

  ENDMETHOD.

  METHOD set_parent.

    ms_data-parent = iv_parent.

  ENDMETHOD.

  METHOD set_tree.

    ms_data-tree = iv_tree.

  ENDMETHOD.

  METHOD zif_ags_object~deserialize.

    CALL METHOD ('\PROGRAM=ZABAPGIT\CLASS=LCL_GIT_PACK')=>decode_commit
      EXPORTING
        iv_data   = iv_data
      RECEIVING
        rs_commit = ms_data.

  ENDMETHOD.

  METHOD zif_ags_object~save.

    DATA: ls_object TYPE zags_objects.

    ASSERT mv_new = abap_true.

    ls_object-sha1 = sha1( ).
    ls_object-type = zif_ags_constants=>c_type-commit.
    ls_object-data_raw = serialize( ).

    MODIFY zags_objects FROM ls_object.

  ENDMETHOD.

  METHOD zif_ags_object~serialize.

    CALL METHOD ('\PROGRAM=ZABAPGIT\CLASS=LCL_GIT_PACK')=>encode_commit
      EXPORTING
        is_commit = ms_data
      RECEIVING
        rv_data   = rv_data.

  ENDMETHOD.

  METHOD zif_ags_object~sha1.

    rv_sha1 = zcl_ags_util=>sha1(
        iv_type = zif_ags_constants=>c_type-commit
        iv_data = serialize( ) ) ##NO_TEXT.

  ENDMETHOD.

  METHOD zif_ags_object~type.
    rv_type = zif_ags_constants=>c_type-commit.
  ENDMETHOD.
ENDCLASS.

handle merging, close #22

handle merging, close #22