"! Statically accessible logger
"!

"! This is a static facade interface for ZIF_ALOG_LOGGER and ZIF_ALOG_MSG_LOGGER.
"! The logger used is specified by using ZCL_ALOG_STATIC_CONFIGURATION.
"!

CLASS zcl_alog_static_logger DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    CLASS-METHODS:
      "! Get a (prefixed) logger instance
      "! @parameter iv_prefix | Prefix to use (e. g. class name)
      "! @parameter ri_logger | Logger instance
      get_logger IMPORTING iv_prefix        TYPE csequence OPTIONAL
                 RETURNING VALUE(ri_logger) TYPE REF TO zif_alog_logger,
      "! Get a (prefixed) logger instance
      "! @parameter ig_any | Variable whose relative type name will be the logger prefix
      "! @parameter ri_logger | Logger instance
      get_logger_for_any IMPORTING ig_any           TYPE any
                         RETURNING VALUE(ri_logger) TYPE REF TO zif_alog_logger,
      "! Get a (prefixed) message logger instance
      "! @parameter iv_prefix | Prefix to use (e. g. class name)
      "! @parameter ri_msg_logger | Logger instance
      get_msg_logger IMPORTING iv_prefix            TYPE csequence OPTIONAL
                     RETURNING VALUE(ri_msg_logger) TYPE REF TO zif_alog_msg_logger,
      "! Get a prefixed logger for a variable
      "! @parameter ig_any | Variable whose relative type name will be the logger prefix
      "! @parameter ri_msg_logger | Message logger instance
      get_msg_logger_for_any IMPORTING ig_any               TYPE any
                             RETURNING VALUE(ri_msg_logger) TYPE REF TO zif_alog_msg_logger,
      "! Log an informational message
      "! @parameter iv_text | Message text
      "! @raising zcx_alog_logging_failed | Logging failed
      info IMPORTING iv_text TYPE csequence
           RAISING   zcx_alog_logging_failed,
      "! Log a warning
      "! @parameter iv_text | Message text
      "! @raising zcx_alog_logging_failed | Logging failed
      warning IMPORTING iv_text TYPE csequence
              RAISING   zcx_alog_logging_failed,
      "! Log an error
      "! @parameter iv_text | Message text
      "! @raising zcx_alog_logging_failed | Logging failed
      error IMPORTING iv_text TYPE csequence
            RAISING   zcx_alog_logging_failed,
      "! Log a debug message
      "! @parameter iv_text | Message text
      "! @raising zcx_alog_logging_failed | Logging failed
      debug IMPORTING iv_text TYPE csequence
            RAISING   zcx_alog_logging_failed,
      "! Log a message of the specified type
      "! @parameter iv_text | Message text
      "! @parameter io_type | Type of the message
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_unsupported_msgty | Unsupported message type
      "! @raising zcx_alog_argument_null | io_type cannot be null
      entry IMPORTING iv_text TYPE csequence
                      io_type TYPE REF TO zcl_alog_entry_type
            RAISING   zcx_alog_logging_failed
                      zcx_alog_unsupported_msgty
                      zcx_alog_argument_null,
      "! Log an exception (as an error)
      "! @parameter ix_ex | The exception to log
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_argument_null | ix_ex cannot be null
      exception IMPORTING ix_ex TYPE REF TO cx_root
                RAISING   zcx_alog_logging_failed
                          zcx_alog_argument_null,
      "! Log an informational message using message classes
      "! @parameter iv_msgid | Message id
      "! @parameter iv_msgno | Message number
      "! @parameter iv_msgv1 | Message variable 1
      "! @parameter iv_msgv2 | Message variable 2
      "! @parameter iv_msgv3 | Message variable 3
      "! @parameter iv_msgv4 | Message variable 4
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_unsupported_operation | Configured logger does not support message
      "!                                           classes
      info_msg IMPORTING VALUE(iv_msgid) TYPE syst_msgid DEFAULT sy-msgid
                         VALUE(iv_msgno) TYPE syst_msgno DEFAULT sy-msgno
                         VALUE(iv_msgv1) TYPE syst_msgv DEFAULT sy-msgv1
                         VALUE(iv_msgv2) TYPE syst_msgv DEFAULT sy-msgv2
                         VALUE(iv_msgv3) TYPE syst_msgv DEFAULT sy-msgv3
                         VALUE(iv_msgv4) TYPE syst_msgv DEFAULT sy-msgv4
               RAISING   zcx_alog_logging_failed
                         zcx_alog_unsupported_operation,
      "! Log a warning using message classes
      "! @parameter iv_msgid | Message id
      "! @parameter iv_msgno | Message number
      "! @parameter iv_msgv1 | Message variable 1
      "! @parameter iv_msgv2 | Message variable 2
      "! @parameter iv_msgv3 | Message variable 3
      "! @parameter iv_msgv4 | Message variable 4
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_unsupported_operation | Configured logger does not support message
      "!                                           classes
      warning_msg IMPORTING VALUE(iv_msgid) TYPE syst_msgid DEFAULT sy-msgid
                            VALUE(iv_msgno) TYPE syst_msgno DEFAULT sy-msgno
                            VALUE(iv_msgv1) TYPE syst_msgv DEFAULT sy-msgv1
                            VALUE(iv_msgv2) TYPE syst_msgv DEFAULT sy-msgv2
                            VALUE(iv_msgv3) TYPE syst_msgv DEFAULT sy-msgv3
                            VALUE(iv_msgv4) TYPE syst_msgv DEFAULT sy-msgv4
                  RAISING   zcx_alog_logging_failed
                            zcx_alog_unsupported_operation,
      "! Log an error using message classes
      "! @parameter iv_msgid | Message id
      "! @parameter iv_msgno | Message number
      "! @parameter iv_msgv1 | Message variable 1
      "! @parameter iv_msgv2 | Message variable 2
      "! @parameter iv_msgv3 | Message variable 3
      "! @parameter iv_msgv4 | Message variable 4
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_unsupported_operation | Configured logger does not support message
      "!                                           classes
      error_msg IMPORTING VALUE(iv_msgid) TYPE syst_msgid DEFAULT sy-msgid
                          VALUE(iv_msgno) TYPE syst_msgno DEFAULT sy-msgno
                          VALUE(iv_msgv1) TYPE syst_msgv DEFAULT sy-msgv1
                          VALUE(iv_msgv2) TYPE syst_msgv DEFAULT sy-msgv2
                          VALUE(iv_msgv3) TYPE syst_msgv DEFAULT sy-msgv3
                          VALUE(iv_msgv4) TYPE syst_msgv DEFAULT sy-msgv4
                RAISING   zcx_alog_logging_failed
                          zcx_alog_unsupported_operation,
      "! Log a debug message using message classes
      "! @parameter iv_msgid | Message id
      "! @parameter iv_msgno | Message number
      "! @parameter iv_msgv1 | Message variable 1
      "! @parameter iv_msgv2 | Message variable 2
      "! @parameter iv_msgv3 | Message variable 3
      "! @parameter iv_msgv4 | Message variable 4
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_unsupported_operation | Configured logger does not support message
      "!                                           classes
      debug_msg IMPORTING VALUE(iv_msgid) TYPE syst_msgid DEFAULT sy-msgid
                          VALUE(iv_msgno) TYPE syst_msgno DEFAULT sy-msgno
                          VALUE(iv_msgv1) TYPE syst_msgv DEFAULT sy-msgv1
                          VALUE(iv_msgv2) TYPE syst_msgv DEFAULT sy-msgv2
                          VALUE(iv_msgv3) TYPE syst_msgv DEFAULT sy-msgv3
                          VALUE(iv_msgv4) TYPE syst_msgv DEFAULT sy-msgv4
                RAISING   zcx_alog_logging_failed
                          zcx_alog_unsupported_operation,
      "! Log a message of the specified type using message classes
      "! @parameter iv_msgid | Message id
      "! @parameter iv_msgno | Message number
      "! @parameter iv_msgty | Message type
      "! @parameter iv_msgv1 | Message variable 1
      "! @parameter iv_msgv2 | Message variable 2
      "! @parameter iv_msgv3 | Message variable 3
      "! @parameter iv_msgv4 | Message variable 4
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_unsupported_msgty | Message type unsupported
      "! @raising zcx_alog_unsupported_operation | Configured logger does not support message
      "!                                           classes
      entry_msg IMPORTING VALUE(iv_msgid) TYPE syst_msgid DEFAULT sy-msgid
                          VALUE(iv_msgno) TYPE syst_msgno DEFAULT sy-msgno
                          VALUE(iv_msgty) TYPE syst_msgty DEFAULT sy-msgty
                          VALUE(iv_msgv1) TYPE syst_msgv DEFAULT sy-msgv1
                          VALUE(iv_msgv2) TYPE syst_msgv DEFAULT sy-msgv2
                          VALUE(iv_msgv3) TYPE syst_msgv DEFAULT sy-msgv3
                          VALUE(iv_msgv4) TYPE syst_msgv DEFAULT sy-msgv4
                RAISING   zcx_alog_logging_failed
                          zcx_alog_unsupported_msgty
                          zcx_alog_unsupported_operation.
  PROTECTED SECTION.
  PRIVATE SECTION.
    CLASS-METHODS:
      get_logger_internal RETURNING VALUE(ri_logger) TYPE REF TO zif_alog_logger,
      get_msg_logger_internal RETURNING VALUE(ri_msg_logger) TYPE REF TO zif_alog_msg_logger
                              RAISING   zcx_alog_unsupported_operation,
      resolve_type_name IMPORTING ig_any         TYPE any
                        RETURNING VALUE(rv_type) TYPE string.
ENDCLASS.

CLASS zcl_alog_static_logger IMPLEMENTATION.
  METHOD error.
    entry( iv_text = iv_text io_type = zcl_alog_entry_type=>go_error ).
  ENDMETHOD.

  METHOD debug.
    entry( iv_text = iv_text io_type = zcl_alog_entry_type=>go_debug ).
  ENDMETHOD.

  METHOD exception.
    entry( iv_text = ix_ex->get_text( ) io_type = zcl_alog_entry_type=>go_error ).
  ENDMETHOD.

  METHOD info.
    entry( iv_text = iv_text io_type = zcl_alog_entry_type=>go_info ).
  ENDMETHOD.

  METHOD warning.
    entry( iv_text = iv_text io_type = zcl_alog_entry_type=>go_warning ).
  ENDMETHOD.

  METHOD entry.
    get_logger_internal( )->entry( iv_text = iv_text io_type = io_type ).
  ENDMETHOD.

  METHOD entry_msg.
    get_msg_logger_internal( )->entry_msg( iv_msgid = iv_msgid
                                           iv_msgno = iv_msgno
                                           iv_msgty = iv_msgty
                                           iv_msgv1 = iv_msgv1
                                           iv_msgv2 = iv_msgv2
                                           iv_msgv3 = iv_msgv3
                                           iv_msgv4 = iv_msgv4 ).
  ENDMETHOD.

  METHOD debug_msg.
    entry_msg( iv_msgid = iv_msgid
               iv_msgno = iv_msgno
               iv_msgty = 'I'
               iv_msgv1 = iv_msgv1
               iv_msgv2 = iv_msgv2
               iv_msgv3 = iv_msgv3
               iv_msgv4 = iv_msgv4 ).
  ENDMETHOD.

  METHOD error_msg.
    entry_msg( iv_msgid = iv_msgid
               iv_msgno = iv_msgno
               iv_msgty = 'E'
               iv_msgv1 = iv_msgv1
               iv_msgv2 = iv_msgv2
               iv_msgv3 = iv_msgv3
               iv_msgv4 = iv_msgv4 ).
  ENDMETHOD.

  METHOD info_msg.
    entry_msg( iv_msgid = iv_msgid
               iv_msgno = iv_msgno
               iv_msgty = 'I'
               iv_msgv1 = iv_msgv1
               iv_msgv2 = iv_msgv2
               iv_msgv3 = iv_msgv3
               iv_msgv4 = iv_msgv4 ).
  ENDMETHOD.

  METHOD warning_msg.
    entry_msg( iv_msgid = iv_msgid
               iv_msgno = iv_msgno
               iv_msgty = 'W'
               iv_msgv1 = iv_msgv1
               iv_msgv2 = iv_msgv2
               iv_msgv3 = iv_msgv3
               iv_msgv4 = iv_msgv4 ).
  ENDMETHOD.

  METHOD get_msg_logger_internal.
    DATA(li_logger) = get_logger_internal( ).

    IF zcl_alog_static_configuration=>get_active_configuration( )->mv_supports_t100_msg = abap_true.
      ri_msg_logger ?= li_logger.
    ELSE.
      RAISE EXCEPTION TYPE zcx_alog_unsupported_operation
        EXPORTING
          iv_operation = 'message logging' ##NO_TEXT.
    ENDIF.
  ENDMETHOD.

  METHOD get_logger_internal.
    ri_logger = zcl_alog_static_configuration=>get_active_configuration( )->mi_logger.
  ENDMETHOD.

  METHOD get_logger.
    ri_logger = NEW lcl_logger_proxy( iv_prefix ).
  ENDMETHOD.

  METHOD get_logger_for_any.
    ri_logger = get_logger( resolve_type_name( ig_any ) ).
  ENDMETHOD.

  METHOD get_msg_logger.
    ri_msg_logger = NEW lcl_logger_proxy( iv_prefix ).
  ENDMETHOD.

  METHOD get_msg_logger_for_any.
    ri_msg_logger = get_msg_logger( resolve_type_name( ig_any ) ).
  ENDMETHOD.

  METHOD resolve_type_name.
    DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( ig_any ).

    TRY.
        rv_type = CAST cl_abap_refdescr( lo_descr )->get_referenced_type( )->get_relative_name( ).
      CATCH cx_sy_move_cast_error.
        rv_type = lo_descr->get_relative_name( ).
    ENDTRY.
  ENDMETHOD.
ENDCLASS.

"! Statically accessible logger
"!

"! This is a static facade interface for ZIF_ALOG_LOGGER and ZIF_ALOG_MSG_LOGGER.
"! The logger used is specified by using ZCL_ALOG_STATIC_CONFIGURATION.
"!

CLASS zcl_alog_static_logger DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    CLASS-METHODS:
      "! Get a (prefixed) logger instance
      "! @parameter iv_prefix | Prefix to use (e. g. class name)
      "! @parameter ri_logger | Logger instance
      get_logger IMPORTING iv_prefix        TYPE csequence OPTIONAL
                 RETURNING VALUE(ri_logger) TYPE REF TO zif_alog_logger,
      "! Get a (prefixed) logger instance
      "! @parameter ig_any | Variable whose relative type name will be the logger prefix
      "! @parameter ri_logger | Logger instance
      get_logger_for_any IMPORTING ig_any           TYPE any
                         RETURNING VALUE(ri_logger) TYPE REF TO zif_alog_logger,
      "! Get a (prefixed) message logger instance
      "! @parameter iv_prefix | Prefix to use (e. g. class name)
      "! @parameter ri_msg_logger | Logger instance
      get_msg_logger IMPORTING iv_prefix            TYPE csequence OPTIONAL
                     RETURNING VALUE(ri_msg_logger) TYPE REF TO zif_alog_msg_logger,
      "! Get a prefixed logger for a variable
      "! @parameter ig_any | Variable whose relative type name will be the logger prefix
      "! @parameter ri_msg_logger | Message logger instance
      get_msg_logger_for_any IMPORTING ig_any               TYPE any
                             RETURNING VALUE(ri_msg_logger) TYPE REF TO zif_alog_msg_logger,
      "! Log an informational message
      "! @parameter iv_text | Message text
      "! @raising zcx_alog_logging_failed | Logging failed
      info IMPORTING iv_text TYPE csequence
           RAISING   zcx_alog_logging_failed,
      "! Log a warning
      "! @parameter iv_text | Message text
      "! @raising zcx_alog_logging_failed | Logging failed
      warning IMPORTING iv_text TYPE csequence
              RAISING   zcx_alog_logging_failed,
      "! Log an error
      "! @parameter iv_text | Message text
      "! @raising zcx_alog_logging_failed | Logging failed
      error IMPORTING iv_text TYPE csequence
            RAISING   zcx_alog_logging_failed,
      "! Log a debug message
      "! @parameter iv_text | Message text
      "! @raising zcx_alog_logging_failed | Logging failed
      debug IMPORTING iv_text TYPE csequence
            RAISING   zcx_alog_logging_failed,
      "! Log a message of the specified type
      "! @parameter iv_text | Message text
      "! @parameter io_type | Type of the message
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_unsupported_msgty | Unsupported message type
      "! @raising zcx_alog_argument_null | io_type cannot be null
      entry IMPORTING iv_text TYPE csequence
                      io_type TYPE REF TO zcl_alog_entry_type
            RAISING   zcx_alog_logging_failed
                      zcx_alog_unsupported_msgty
                      zcx_alog_argument_null,
      "! Log an exception (as an error)
      "! @parameter ix_ex | The exception to log
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_argument_null | ix_ex cannot be null
      exception IMPORTING ix_ex TYPE REF TO cx_root
                RAISING   zcx_alog_logging_failed
                          zcx_alog_argument_null,
      "! Log an informational message using message classes
      "! @parameter iv_msgid | Message id
      "! @parameter iv_msgno | Message number
      "! @parameter iv_msgv1 | Message variable 1
      "! @parameter iv_msgv2 | Message variable 2
      "! @parameter iv_msgv3 | Message variable 3
      "! @parameter iv_msgv4 | Message variable 4
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_unsupported_operation | Configured logger does not support message
      "!                                           classes
      info_msg IMPORTING VALUE(iv_msgid) TYPE syst_msgid DEFAULT sy-msgid
                         VALUE(iv_msgno) TYPE syst_msgno DEFAULT sy-msgno
                         VALUE(iv_msgv1) TYPE syst_msgv DEFAULT sy-msgv1
                         VALUE(iv_msgv2) TYPE syst_msgv DEFAULT sy-msgv2
                         VALUE(iv_msgv3) TYPE syst_msgv DEFAULT sy-msgv3
                         VALUE(iv_msgv4) TYPE syst_msgv DEFAULT sy-msgv4
               RAISING   zcx_alog_logging_failed
                         zcx_alog_unsupported_operation,
      "! Log a warning using message classes
      "! @parameter iv_msgid | Message id
      "! @parameter iv_msgno | Message number
      "! @parameter iv_msgv1 | Message variable 1
      "! @parameter iv_msgv2 | Message variable 2
      "! @parameter iv_msgv3 | Message variable 3
      "! @parameter iv_msgv4 | Message variable 4
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_unsupported_operation | Configured logger does not support message
      "!                                           classes
      warning_msg IMPORTING VALUE(iv_msgid) TYPE syst_msgid DEFAULT sy-msgid
                            VALUE(iv_msgno) TYPE syst_msgno DEFAULT sy-msgno
                            VALUE(iv_msgv1) TYPE syst_msgv DEFAULT sy-msgv1
                            VALUE(iv_msgv2) TYPE syst_msgv DEFAULT sy-msgv2
                            VALUE(iv_msgv3) TYPE syst_msgv DEFAULT sy-msgv3
                            VALUE(iv_msgv4) TYPE syst_msgv DEFAULT sy-msgv4
                  RAISING   zcx_alog_logging_failed
                            zcx_alog_unsupported_operation,
      "! Log an error using message classes
      "! @parameter iv_msgid | Message id
      "! @parameter iv_msgno | Message number
      "! @parameter iv_msgv1 | Message variable 1
      "! @parameter iv_msgv2 | Message variable 2
      "! @parameter iv_msgv3 | Message variable 3
      "! @parameter iv_msgv4 | Message variable 4
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_unsupported_operation | Configured logger does not support message
      "!                                           classes
      error_msg IMPORTING VALUE(iv_msgid) TYPE syst_msgid DEFAULT sy-msgid
                          VALUE(iv_msgno) TYPE syst_msgno DEFAULT sy-msgno
                          VALUE(iv_msgv1) TYPE syst_msgv DEFAULT sy-msgv1
                          VALUE(iv_msgv2) TYPE syst_msgv DEFAULT sy-msgv2
                          VALUE(iv_msgv3) TYPE syst_msgv DEFAULT sy-msgv3
                          VALUE(iv_msgv4) TYPE syst_msgv DEFAULT sy-msgv4
                RAISING   zcx_alog_logging_failed
                          zcx_alog_unsupported_operation,
      "! Log a debug message using message classes
      "! @parameter iv_msgid | Message id
      "! @parameter iv_msgno | Message number
      "! @parameter iv_msgv1 | Message variable 1
      "! @parameter iv_msgv2 | Message variable 2
      "! @parameter iv_msgv3 | Message variable 3
      "! @parameter iv_msgv4 | Message variable 4
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_unsupported_operation | Configured logger does not support message
      "!                                           classes
      debug_msg IMPORTING VALUE(iv_msgid) TYPE syst_msgid DEFAULT sy-msgid
                          VALUE(iv_msgno) TYPE syst_msgno DEFAULT sy-msgno
                          VALUE(iv_msgv1) TYPE syst_msgv DEFAULT sy-msgv1
                          VALUE(iv_msgv2) TYPE syst_msgv DEFAULT sy-msgv2
                          VALUE(iv_msgv3) TYPE syst_msgv DEFAULT sy-msgv3
                          VALUE(iv_msgv4) TYPE syst_msgv DEFAULT sy-msgv4
                RAISING   zcx_alog_logging_failed
                          zcx_alog_unsupported_operation,
      "! Log a message of the specified type using message classes
      "! @parameter iv_msgid | Message id
      "! @parameter iv_msgno | Message number
      "! @parameter iv_msgty | Message type
      "! @parameter iv_msgv1 | Message variable 1
      "! @parameter iv_msgv2 | Message variable 2
      "! @parameter iv_msgv3 | Message variable 3
      "! @parameter iv_msgv4 | Message variable 4
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_unsupported_msgty | Message type unsupported
      "! @raising zcx_alog_unsupported_operation | Configured logger does not support message
      "!                                           classes
      entry_msg IMPORTING VALUE(iv_msgid) TYPE syst_msgid DEFAULT sy-msgid
                          VALUE(iv_msgno) TYPE syst_msgno DEFAULT sy-msgno
                          VALUE(iv_msgty) TYPE syst_msgty DEFAULT sy-msgty
                          VALUE(iv_msgv1) TYPE syst_msgv DEFAULT sy-msgv1
                          VALUE(iv_msgv2) TYPE syst_msgv DEFAULT sy-msgv2
                          VALUE(iv_msgv3) TYPE syst_msgv DEFAULT sy-msgv3
                          VALUE(iv_msgv4) TYPE syst_msgv DEFAULT sy-msgv4
                RAISING   zcx_alog_logging_failed
                          zcx_alog_unsupported_msgty
                          zcx_alog_unsupported_operation.
  PROTECTED SECTION.
  PRIVATE SECTION.
    CLASS-METHODS:
      get_logger_internal RETURNING VALUE(ri_logger) TYPE REF TO zif_alog_logger,
      get_msg_logger_internal RETURNING VALUE(ri_msg_logger) TYPE REF TO zif_alog_msg_logger
                              RAISING   zcx_alog_unsupported_operation,
      resolve_type_name IMPORTING ig_any         TYPE any
                        RETURNING VALUE(rv_type) TYPE string.
ENDCLASS.

CLASS zcl_alog_static_logger IMPLEMENTATION.
  METHOD error.
    entry( iv_text = iv_text io_type = zcl_alog_entry_type=>go_error ).
  ENDMETHOD.

  METHOD debug.
    entry( iv_text = iv_text io_type = zcl_alog_entry_type=>go_debug ).
  ENDMETHOD.

  METHOD exception.
    entry( iv_text = ix_ex->get_text( ) io_type = zcl_alog_entry_type=>go_error ).
  ENDMETHOD.

  METHOD info.
    entry( iv_text = iv_text io_type = zcl_alog_entry_type=>go_info ).
  ENDMETHOD.

  METHOD warning.
    entry( iv_text = iv_text io_type = zcl_alog_entry_type=>go_warning ).
  ENDMETHOD.

  METHOD entry.
    get_logger_internal( )->entry( iv_text = iv_text io_type = io_type ).
  ENDMETHOD.

  METHOD entry_msg.
    get_msg_logger_internal( )->entry_msg( iv_msgid = iv_msgid
                                           iv_msgno = iv_msgno
                                           iv_msgty = iv_msgty
                                           iv_msgv1 = iv_msgv1
                                           iv_msgv2 = iv_msgv2
                                           iv_msgv3 = iv_msgv3
                                           iv_msgv4 = iv_msgv4 ).
  ENDMETHOD.

  METHOD debug_msg.
    entry_msg( iv_msgid = iv_msgid
               iv_msgno = iv_msgno
               iv_msgty = 'I'
               iv_msgv1 = iv_msgv1
               iv_msgv2 = iv_msgv2
               iv_msgv3 = iv_msgv3
               iv_msgv4 = iv_msgv4 ).
  ENDMETHOD.

  METHOD error_msg.
    entry_msg( iv_msgid = iv_msgid
               iv_msgno = iv_msgno
               iv_msgty = 'E'
               iv_msgv1 = iv_msgv1
               iv_msgv2 = iv_msgv2
               iv_msgv3 = iv_msgv3
               iv_msgv4 = iv_msgv4 ).
  ENDMETHOD.

  METHOD info_msg.
    entry_msg( iv_msgid = iv_msgid
               iv_msgno = iv_msgno
               iv_msgty = 'I'
               iv_msgv1 = iv_msgv1
               iv_msgv2 = iv_msgv2
               iv_msgv3 = iv_msgv3
               iv_msgv4 = iv_msgv4 ).
  ENDMETHOD.

  METHOD warning_msg.
    entry_msg( iv_msgid = iv_msgid
               iv_msgno = iv_msgno
               iv_msgty = 'W'
               iv_msgv1 = iv_msgv1
               iv_msgv2 = iv_msgv2
               iv_msgv3 = iv_msgv3
               iv_msgv4 = iv_msgv4 ).
  ENDMETHOD.

  METHOD get_msg_logger_internal.
    TRY.
        ri_msg_logger ?= get_logger_internal( ).
      CATCH cx_sy_move_cast_error INTO DATA(lx_ex).
        RAISE EXCEPTION TYPE zcx_alog_unsupported_operation
          EXPORTING
            iv_operation = 'message logging' ##NO_TEXT
            ix_previous  = lx_ex.
    ENDTRY.
  ENDMETHOD.

  METHOD get_logger_internal.
    ri_logger = zcl_alog_static_configuration=>get_active_configuration( )->mi_logger.
  ENDMETHOD.

  METHOD get_logger.
    ri_logger = NEW lcl_logger_proxy( iv_prefix ).
  ENDMETHOD.

  METHOD get_logger_for_any.
    ri_logger = get_logger( resolve_type_name( ig_any ) ).
  ENDMETHOD.

  METHOD get_msg_logger.
    ri_msg_logger = NEW lcl_logger_proxy( iv_prefix ).
  ENDMETHOD.

  METHOD get_msg_logger_for_any.
    ri_msg_logger = get_msg_logger( resolve_type_name( ig_any ) ).
  ENDMETHOD.

  METHOD resolve_type_name.
    DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( ig_any ).

    TRY.
        rv_type = CAST cl_abap_refdescr( lo_descr )->get_referenced_type( )->get_relative_name( ).
      CATCH cx_sy_move_cast_error.
        rv_type = lo_descr->get_relative_name( ).
    ENDTRY.
  ENDMETHOD.
ENDCLASS.

Fix msg_logger access from static logger

Fixes #53


CLASS zcl_abapgit_gui_page_codi_base DEFINITION PUBLIC ABSTRACT INHERITING FROM zcl_abapgit_gui_page.
  PUBLIC SECTION.
    METHODS:
      zif_abapgit_gui_event_handler~on_event
        REDEFINITION.

  PROTECTED SECTION.

    CONSTANTS:
      BEGIN OF c_actions,
        rerun  TYPE string VALUE 'rerun' ##NO_TEXT,
        sort_1 TYPE string VALUE 'sort_1'  ##NO_TEXT,
        sort_2 TYPE string VALUE 'sort_2'  ##NO_TEXT,
        sort_3 TYPE string VALUE 'sort_3'  ##NO_TEXT,
        stage  TYPE string VALUE 'stage' ##NO_TEXT,
        commit TYPE string VALUE 'commit' ##NO_TEXT,
      END OF c_actions .
    DATA mo_repo TYPE REF TO zcl_abapgit_repo .
    DATA mt_result TYPE scit_alvlist .

    METHODS render_variant
      IMPORTING
        !iv_variant    TYPE sci_chkv
      RETURNING
        VALUE(ri_html) TYPE REF TO zif_abapgit_html .
    METHODS render_result
      IMPORTING
        !ii_html   TYPE REF TO zif_abapgit_html
        !it_result TYPE scit_alvlist .
    METHODS render_result_line
      IMPORTING
        !ii_html   TYPE REF TO zif_abapgit_html
        !is_result TYPE scir_alvlist .
    METHODS build_nav_link
      IMPORTING
        !is_result     TYPE scir_alvlist
      RETURNING
        VALUE(rv_link) TYPE string .
    METHODS jump
      IMPORTING
        !is_item        TYPE zif_abapgit_definitions=>ty_item
        !is_sub_item    TYPE zif_abapgit_definitions=>ty_item
        !iv_line_number TYPE i
      RAISING
        zcx_abapgit_exception .
    METHODS build_base_menu
      RETURNING
        VALUE(ro_menu) TYPE REF TO zcl_abapgit_html_toolbar .
  PRIVATE SECTION.
    CONSTANTS c_object_separator TYPE c LENGTH 1 VALUE '|'.
    CONSTANTS c_ci_sig TYPE string VALUE 'cinav:'.
ENDCLASS.

CLASS zcl_abapgit_gui_page_codi_base IMPLEMENTATION.

  METHOD build_base_menu.

    DATA:
      lo_sort_menu TYPE REF TO zcl_abapgit_html_toolbar.

    CREATE OBJECT lo_sort_menu.

    lo_sort_menu->add(
      iv_txt = 'By Object, Check, Sub-object'
      iv_act = c_actions-sort_1
    )->add(
      iv_txt = 'By Object, Sub-object, Line'
      iv_act = c_actions-sort_2
    )->add(
      iv_txt = 'By Check, Object, Sub-object'
      iv_act = c_actions-sort_3 ).

    CREATE OBJECT ro_menu.

    ro_menu->add( iv_txt = 'Sort'
                  io_sub = lo_sort_menu ).

    ro_menu->add( iv_txt = 'Re-Run'
                  iv_act = c_actions-rerun
                  iv_cur = abap_false ).

  ENDMETHOD.

  METHOD build_nav_link.

    rv_link = |{ c_ci_sig }| &&
      |{ is_result-objtype }{ is_result-objname }| &&
      |{ c_object_separator }{ is_result-sobjtype }{ is_result-sobjname }| &&
      |{ c_object_separator }{ is_result-line }|.

  ENDMETHOD.

  METHOD jump.

    DATA: lo_test             TYPE REF TO cl_ci_test_root,
          ls_info             TYPE scir_rest,
          lo_result           TYPE REF TO cl_ci_result_root,
          lv_adt_jump_enabled TYPE abap_bool,
          lv_line_number      TYPE i,
          ls_item             TYPE zif_abapgit_definitions=>ty_item,
          ls_sub_item         TYPE zif_abapgit_definitions=>ty_item.

    FIELD-SYMBOLS: <ls_result> TYPE scir_alvlist.

    IF is_sub_item IS NOT INITIAL.
      READ TABLE mt_result WITH KEY objtype  = is_item-obj_type
                                    objname  = is_item-obj_name
                                    sobjtype = is_sub_item-obj_type
                                    sobjname = is_sub_item-obj_name
                                    line     = iv_line_number
                           ASSIGNING <ls_result>.
    ELSE.
      READ TABLE mt_result WITH KEY objtype = is_item-obj_type
                                    objname = is_item-obj_name
                                    line    = iv_line_number
                           ASSIGNING <ls_result>.
    ENDIF.
    ASSERT <ls_result> IS ASSIGNED.
    ls_item-obj_name = <ls_result>-objname.
    ls_item-obj_type = <ls_result>-objtype.

    ls_sub_item-obj_name = <ls_result>-sobjname.
    ls_sub_item-obj_type = <ls_result>-sobjtype.

    " see SCI_LCL_DYNP_530 / HANDLE_DOUBLE_CLICK

    lv_adt_jump_enabled = zcl_abapgit_persist_factory=>get_settings( )->read( )->get_adt_jump_enabled( ).

    TRY.
        IF lv_adt_jump_enabled = abap_true.

          lv_line_number = <ls_result>-line.

          zcl_abapgit_objects=>jump(
            is_item         = ls_item
            iv_sub_obj_name = ls_sub_item-obj_name
            iv_line_number  = lv_line_number ).
          RETURN.

        ENDIF.
      CATCH zcx_abapgit_exception.
    ENDTRY.

    TRY.
        CALL METHOD ('CL_CI_TESTS')=>('GET_TEST_REF')
          EXPORTING
            p_test   = <ls_result>-test
          RECEIVING
            p_result = lo_test.
      CATCH cx_root.
        zcx_abapgit_exception=>raise( |Jump to object not supported in your NW release| ).
    ENDTRY.

    lo_result = lo_test->get_result_node( <ls_result>-kind ).

    MOVE-CORRESPONDING <ls_result> TO ls_info.

    lo_result->set_info( ls_info ).
    lo_result->if_ci_test~navigate( ).

  ENDMETHOD.

  METHOD render_result.

    CONSTANTS: lc_limit TYPE i VALUE 500.
    FIELD-SYMBOLS: <ls_result> TYPE scir_alvlist.

    ii_html->add( '
' ).

    LOOP AT it_result ASSIGNING <ls_result> TO lc_limit.
      render_result_line(
        ii_html = ii_html
        is_result = <ls_result> ).
    ENDLOOP.

    ii_html->add( '
' ).

    IF lines( it_result ) > lc_limit.
      ii_html->add( '
' ).
      ii_html->add( ii_html->icon( 'exclamation-triangle' ) ).
      ii_html->add( |Only first { lc_limit } findings shown in list!| ).
      ii_html->add( '
' ).
    ENDIF.

  ENDMETHOD.

  METHOD render_result_line.

    DATA: lv_class   TYPE string,
          lv_obj_txt TYPE string,
          lv_msg     TYPE string,
          lv_line    TYPE i,
          ls_mtdkey  TYPE seocpdkey.

    CASE is_result-kind.
      WHEN 'E'.
        lv_class = 'ci-error'.
      WHEN 'W'.
        lv_class = 'ci-warning'.
      WHEN OTHERS.
        lv_class = 'ci-info'.
    ENDCASE.

    lv_msg = escape( val = is_result-text
                     format = cl_abap_format=>e_html_attr ).

    IF is_result-sobjname IS INITIAL OR
       ( is_result-sobjname = is_result-objname AND
         is_result-sobjtype = is_result-sobjtype ).
      lv_obj_txt = |{ is_result-objtype } { is_result-objname }|.
    ELSEIF is_result-objtype = 'CLAS' OR
         ( is_result-objtype = 'PROG' AND NOT is_result-sobjname+30(*) IS INITIAL ).
      TRY.
          CASE is_result-sobjname+30(*).
            WHEN 'CCDEF'.
              lv_obj_txt = |CLAS { is_result-objname } : Local Definitions|.
            WHEN 'CCIMP'.
              lv_obj_txt = |CLAS { is_result-objname } : Local Implementations|.
            WHEN 'CCMAC'.
              lv_obj_txt = |CLAS { is_result-objname } : Macros|.
            WHEN 'CCAU'.
              lv_obj_txt = |CLAS { is_result-objname } : Test Classes|.
            WHEN 'CU'.
              lv_obj_txt = |CLAS { is_result-objname } : Public Section|.
            WHEN 'CO'.
              lv_obj_txt = |CLAS { is_result-objname } : Protected Section|.
            WHEN 'CI'.
              lv_obj_txt = |CLAS { is_result-objname } : Private Section|.
            WHEN OTHERS.
              cl_oo_classname_service=>get_method_by_include(
                EXPORTING
                  incname             = is_result-sobjname
                RECEIVING
                  mtdkey              = ls_mtdkey
                EXCEPTIONS
                  class_not_existing  = 1
                  method_not_existing = 2
                  OTHERS              = 3 ).
              IF sy-subrc = 0.
                lv_obj_txt = |CLAS { ls_mtdkey-clsname }->{ ls_mtdkey-cpdname }|.
              ELSE.
                lv_obj_txt = |{ is_result-objtype } { is_result-sobjname }|.
              ENDIF.

          ENDCASE.
        CATCH cx_root.
          lv_obj_txt = ''. "use default below
      ENDTRY.
    ENDIF.
    IF lv_obj_txt IS INITIAL.
      lv_obj_txt = |{ is_result-objtype } { is_result-objname } > { is_result-sobjtype } { is_result-sobjname }|.
    ENDIF.
    lv_line = is_result-line. " convert from numc to integer
    lv_obj_txt = |{ lv_obj_txt } [ @{ lv_line } ]|.

    ii_html->add( |
| ).
    ii_html->add_a(
      iv_txt = lv_obj_txt
      iv_act = build_nav_link( is_result )
      iv_typ = zif_abapgit_html=>c_action_type-sapevent ).
    ii_html->add( |{ lv_msg }| ).
    ii_html->add( '
' ).

  ENDMETHOD.

  METHOD render_variant.

    CREATE OBJECT ri_html TYPE zcl_abapgit_html.

    ri_html->add( '
' ).
    ri_html->add( |Code inspector check variant: { iv_variant }| ).
    ri_html->add( `</div>` ).

  ENDMETHOD.

  METHOD zif_abapgit_gui_event_handler~on_event.
    DATA: ls_item          TYPE zif_abapgit_definitions=>ty_item,
          ls_sub_item      TYPE zif_abapgit_definitions=>ty_item,
          lv_temp          TYPE string,
          lv_main_object   TYPE string,
          lv_sub_object    TYPE string,
          lv_line_number_s TYPE string,
          lv_line_number   TYPE i.

    lv_temp = replace( val   = ii_event->mv_action
                       regex = |^{ c_ci_sig }|
                       with  = `` ).

    IF lv_temp <> ii_event->mv_action. " CI navigation request detected

      SPLIT lv_temp AT c_object_separator INTO lv_main_object lv_sub_object lv_line_number_s.
      ls_item-obj_type = lv_main_object(4).
      ls_item-obj_name = lv_main_object+4(*).

      IF lv_sub_object IS NOT INITIAL.
        ls_sub_item-obj_type = lv_sub_object(4).
        ls_sub_item-obj_name = lv_sub_object+4(*).
      ENDIF.

      lv_line_number = lv_line_number_s.

      jump( is_item        = ls_item
            is_sub_item    = ls_sub_item
            iv_line_number = lv_line_number ).

      rs_handled-state = zcl_abapgit_gui=>c_event_state-no_more_act.

    ENDIF.

    CASE ii_event->mv_action.

      WHEN c_actions-sort_1.
        SORT mt_result BY objtype objname test code sobjtype sobjname line col.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
      WHEN c_actions-sort_2.
        SORT mt_result BY objtype objname sobjtype sobjname line col test code.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
      WHEN c_actions-sort_3.
        SORT mt_result BY test code objtype objname sobjtype sobjname line col.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.

    ENDCASE.

  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_gui_page_codi_base DEFINITION PUBLIC ABSTRACT INHERITING FROM zcl_abapgit_gui_page.
  PUBLIC SECTION.
    METHODS:
      zif_abapgit_gui_event_handler~on_event
        REDEFINITION.

  PROTECTED SECTION.

    CONSTANTS:
      BEGIN OF c_actions,
        rerun  TYPE string VALUE 'rerun' ##NO_TEXT,
        sort_1 TYPE string VALUE 'sort_1'  ##NO_TEXT,
        sort_2 TYPE string VALUE 'sort_2'  ##NO_TEXT,
        sort_3 TYPE string VALUE 'sort_3'  ##NO_TEXT,
        stage  TYPE string VALUE 'stage' ##NO_TEXT,
        commit TYPE string VALUE 'commit' ##NO_TEXT,
      END OF c_actions .
    DATA mo_repo TYPE REF TO zcl_abapgit_repo .
    DATA mt_result TYPE scit_alvlist .

    METHODS render_variant
      IMPORTING
        !iv_variant    TYPE sci_chkv
      RETURNING
        VALUE(ri_html) TYPE REF TO zif_abapgit_html .
    METHODS render_result
      IMPORTING
        !ii_html   TYPE REF TO zif_abapgit_html
        !it_result TYPE scit_alvlist .
    METHODS render_result_line
      IMPORTING
        !ii_html   TYPE REF TO zif_abapgit_html
        !is_result TYPE scir_alvlist .
    METHODS build_nav_link
      IMPORTING
        !is_result     TYPE scir_alvlist
      RETURNING
        VALUE(rv_link) TYPE string .
    METHODS jump
      IMPORTING
        !is_item        TYPE zif_abapgit_definitions=>ty_item
        !is_sub_item    TYPE zif_abapgit_definitions=>ty_item
        !iv_line_number TYPE i
      RAISING
        zcx_abapgit_exception .
    METHODS build_base_menu
      RETURNING
        VALUE(ro_menu) TYPE REF TO zcl_abapgit_html_toolbar .
  PRIVATE SECTION.
    CONSTANTS c_object_separator TYPE c LENGTH 1 VALUE '|'.
    CONSTANTS c_ci_sig TYPE string VALUE 'cinav:'.
ENDCLASS.

CLASS zcl_abapgit_gui_page_codi_base IMPLEMENTATION.

  METHOD build_base_menu.

    DATA:
      lo_sort_menu TYPE REF TO zcl_abapgit_html_toolbar.

    CREATE OBJECT lo_sort_menu.

    lo_sort_menu->add(
      iv_txt = 'By Object, Check, Sub-object'
      iv_act = c_actions-sort_1
    )->add(
      iv_txt = 'By Object, Sub-object, Line'
      iv_act = c_actions-sort_2
    )->add(
      iv_txt = 'By Check, Object, Sub-object'
      iv_act = c_actions-sort_3 ).

    CREATE OBJECT ro_menu.

    ro_menu->add( iv_txt = 'Sort'
                  io_sub = lo_sort_menu ).

    ro_menu->add( iv_txt = 'Re-Run'
                  iv_act = c_actions-rerun
                  iv_cur = abap_false ).

  ENDMETHOD.

  METHOD build_nav_link.

    rv_link = |{ c_ci_sig }| &&
      |{ is_result-objtype }{ is_result-objname }| &&
      |{ c_object_separator }{ is_result-sobjtype }{ is_result-sobjname }| &&
      |{ c_object_separator }{ is_result-line }|.

  ENDMETHOD.

  METHOD jump.

    DATA: lo_test             TYPE REF TO cl_ci_test_root,
          ls_info             TYPE scir_rest,
          lo_result           TYPE REF TO cl_ci_result_root,
          lv_adt_jump_enabled TYPE abap_bool,
          lv_line_number      TYPE i,
          ls_item             TYPE zif_abapgit_definitions=>ty_item,
          ls_sub_item         TYPE zif_abapgit_definitions=>ty_item.

    FIELD-SYMBOLS: <ls_result> TYPE scir_alvlist.

    IF is_sub_item IS NOT INITIAL.
      READ TABLE mt_result WITH KEY objtype  = is_item-obj_type
                                    objname  = is_item-obj_name
                                    sobjtype = is_sub_item-obj_type
                                    sobjname = is_sub_item-obj_name
                                    line     = iv_line_number
                           ASSIGNING <ls_result>.
    ELSE.
      READ TABLE mt_result WITH KEY objtype = is_item-obj_type
                                    objname = is_item-obj_name
                                    line    = iv_line_number
                           ASSIGNING <ls_result>.
    ENDIF.
    ASSERT <ls_result> IS ASSIGNED.
    ls_item-obj_name = <ls_result>-objname.
    ls_item-obj_type = <ls_result>-objtype.

    ls_sub_item-obj_name = <ls_result>-sobjname.
    ls_sub_item-obj_type = <ls_result>-sobjtype.

    " see SCI_LCL_DYNP_530 / HANDLE_DOUBLE_CLICK

    lv_adt_jump_enabled = zcl_abapgit_persist_factory=>get_settings( )->read( )->get_adt_jump_enabled( ).

    TRY.
        IF lv_adt_jump_enabled = abap_true.

          lv_line_number = <ls_result>-line.

          zcl_abapgit_objects=>jump(
            is_item         = ls_item
            iv_sub_obj_name = ls_sub_item-obj_name
            iv_line_number  = lv_line_number ).
          RETURN.

        ENDIF.
      CATCH zcx_abapgit_exception.
    ENDTRY.

    TRY.
        CALL METHOD ('CL_CI_TESTS')=>('GET_TEST_REF')
          EXPORTING
            p_test   = <ls_result>-test
          RECEIVING
            p_result = lo_test.
      CATCH cx_root.
        zcx_abapgit_exception=>raise( |Jump to object not supported in your NW release| ).
    ENDTRY.

    lo_result = lo_test->get_result_node( <ls_result>-kind ).

    MOVE-CORRESPONDING <ls_result> TO ls_info.

    lo_result->set_info( ls_info ).
    lo_result->if_ci_test~navigate( ).

  ENDMETHOD.

  METHOD render_result.

    CONSTANTS: lc_limit TYPE i VALUE 500.
    FIELD-SYMBOLS: <ls_result> TYPE scir_alvlist.

    ii_html->add( '
' ).

    LOOP AT it_result ASSIGNING <ls_result> TO lc_limit.
      render_result_line(
        ii_html = ii_html
        is_result = <ls_result> ).
    ENDLOOP.

    ii_html->add( '
' ).

    IF lines( it_result ) > lc_limit.
      ii_html->add( '
' ).
      ii_html->add( ii_html->icon( 'exclamation-triangle' ) ).
      ii_html->add( |Only first { lc_limit } findings shown in list!| ).
      ii_html->add( '
' ).
    ENDIF.

  ENDMETHOD.

  METHOD render_result_line.

    DATA: lv_class   TYPE string,
          lv_obj_txt TYPE string,
          lv_msg     TYPE string,
          lv_line    TYPE i,
          ls_mtdkey  TYPE seocpdkey.

    CASE is_result-kind.
      WHEN 'E'.
        lv_class = 'ci-error'.
      WHEN 'W'.
        lv_class = 'ci-warning'.
      WHEN OTHERS.
        lv_class = 'ci-info'.
    ENDCASE.

    lv_msg = escape( val = is_result-text
                     format = cl_abap_format=>e_html_attr ).

    IF is_result-sobjname IS INITIAL OR
       ( is_result-sobjname = is_result-objname AND
         is_result-sobjtype = is_result-objtype ).
      lv_obj_txt = |{ is_result-objtype } { is_result-objname }|.
    ELSEIF is_result-objtype = 'CLAS' OR
         ( is_result-objtype = 'PROG' AND NOT is_result-sobjname+30(*) IS INITIAL ).
      TRY.
          CASE is_result-sobjname+30(*).
            WHEN 'CCDEF'.
              lv_obj_txt = |CLAS { is_result-objname } : Local Definitions|.
            WHEN 'CCIMP'.
              lv_obj_txt = |CLAS { is_result-objname } : Local Implementations|.
            WHEN 'CCMAC'.
              lv_obj_txt = |CLAS { is_result-objname } : Macros|.
            WHEN 'CCAU'.
              lv_obj_txt = |CLAS { is_result-objname } : Test Classes|.
            WHEN 'CU'.
              lv_obj_txt = |CLAS { is_result-objname } : Public Section|.
            WHEN 'CO'.
              lv_obj_txt = |CLAS { is_result-objname } : Protected Section|.
            WHEN 'CI'.
              lv_obj_txt = |CLAS { is_result-objname } : Private Section|.
            WHEN OTHERS.
              cl_oo_classname_service=>get_method_by_include(
                EXPORTING
                  incname             = is_result-sobjname
                RECEIVING
                  mtdkey              = ls_mtdkey
                EXCEPTIONS
                  class_not_existing  = 1
                  method_not_existing = 2
                  OTHERS              = 3 ).
              IF sy-subrc = 0.
                lv_obj_txt = |CLAS { ls_mtdkey-clsname }->{ ls_mtdkey-cpdname }|.
              ELSE.
                lv_obj_txt = |{ is_result-objtype } { is_result-sobjname }|.
              ENDIF.

          ENDCASE.
        CATCH cx_root.
          lv_obj_txt = ''. "use default below
      ENDTRY.
    ENDIF.
    IF lv_obj_txt IS INITIAL.
      lv_obj_txt = |{ is_result-objtype } { is_result-objname } > { is_result-sobjtype } { is_result-sobjname }|.
    ENDIF.
    lv_line = is_result-line. " convert from numc to integer
    lv_obj_txt = |{ lv_obj_txt } [ @{ lv_line } ]|.

    ii_html->add( |
| ).
    ii_html->add_a(
      iv_txt = lv_obj_txt
      iv_act = build_nav_link( is_result )
      iv_typ = zif_abapgit_html=>c_action_type-sapevent ).
    ii_html->add( |{ lv_msg }| ).
    ii_html->add( '
' ).

  ENDMETHOD.

  METHOD render_variant.

    CREATE OBJECT ri_html TYPE zcl_abapgit_html.

    ri_html->add( '
' ).
    ri_html->add( |Code inspector check variant: { iv_variant }| ).
    ri_html->add( `</div>` ).

  ENDMETHOD.

  METHOD zif_abapgit_gui_event_handler~on_event.
    DATA: ls_item          TYPE zif_abapgit_definitions=>ty_item,
          ls_sub_item      TYPE zif_abapgit_definitions=>ty_item,
          lv_temp          TYPE string,
          lv_main_object   TYPE string,
          lv_sub_object    TYPE string,
          lv_line_number_s TYPE string,
          lv_line_number   TYPE i.

    lv_temp = replace( val   = ii_event->mv_action
                       regex = |^{ c_ci_sig }|
                       with  = `` ).

    IF lv_temp <> ii_event->mv_action. " CI navigation request detected

      SPLIT lv_temp AT c_object_separator INTO lv_main_object lv_sub_object lv_line_number_s.
      ls_item-obj_type = lv_main_object(4).
      ls_item-obj_name = lv_main_object+4(*).

      IF lv_sub_object IS NOT INITIAL.
        ls_sub_item-obj_type = lv_sub_object(4).
        ls_sub_item-obj_name = lv_sub_object+4(*).
      ENDIF.

      lv_line_number = lv_line_number_s.

      jump( is_item        = ls_item
            is_sub_item    = ls_sub_item
            iv_line_number = lv_line_number ).

      rs_handled-state = zcl_abapgit_gui=>c_event_state-no_more_act.

    ENDIF.

    CASE ii_event->mv_action.

      WHEN c_actions-sort_1.
        SORT mt_result BY objtype objname test code sobjtype sobjname line col.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
      WHEN c_actions-sort_2.
        SORT mt_result BY objtype objname sobjtype sobjname line col test code.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
      WHEN c_actions-sort_3.
        SORT mt_result BY test code objtype objname sobjtype sobjname line col.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.

    ENDCASE.

  ENDMETHOD.
ENDCLASS.

Fix code inspection output (#5211)

Fix code inspection output (#5211)

Fix typo in comparison of object and sub-object


CLASS zcl_abapgit_background DEFINITION
  PUBLIC
  CREATE PUBLIC .

  PUBLIC SECTION.

    TYPES: BEGIN OF ty_method,
             class       TYPE seoclsname,
             description TYPE string,
           END OF ty_method.

    TYPES: ty_methods TYPE SORTED TABLE OF ty_method WITH UNIQUE KEY class.

    CLASS-METHODS run
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS list_methods
      RETURNING VALUE(rt_methods) TYPE ty_methods.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS ZCL_ABAPGIT_BACKGROUND IMPLEMENTATION.

  METHOD list_methods.

    DATA: ls_method       LIKE LINE OF rt_methods,
          ls_key          TYPE seoclskey,
          lt_implementing TYPE seor_implementing_keys,
          ls_implementing LIKE LINE OF lt_implementing.

    FIELD-SYMBOLS: <ls_method> LIKE LINE OF rt_methods.

* in order to handle local classes in the compiled report
    ls_method-class = 'ZCL_ABAPGIT_BACKGROUND_PULL'.
    INSERT ls_method INTO TABLE rt_methods.
    ls_method-class = 'ZCL_ABAPGIT_BACKGROUND_PUSH_AU'.
    INSERT ls_method INTO TABLE rt_methods.
    ls_method-class = 'ZCL_ABAPGIT_BACKGROUND_PUSH_FI'.
    INSERT ls_method INTO TABLE rt_methods.

    ls_key-clsname = 'ZIF_ABAPGIT_BACKGROUND'.

    CALL FUNCTION 'SEO_INTERFACE_IMPLEM_GET_ALL'
      EXPORTING
        intkey       = ls_key
      IMPORTING
        impkeys      = lt_implementing
      EXCEPTIONS
        not_existing = 1
        OTHERS       = 2 ##FM_SUBRC_OK.
    LOOP AT lt_implementing INTO ls_implementing.
      ls_method-class = ls_implementing-clsname.
      INSERT ls_method INTO TABLE rt_methods.
    ENDLOOP.

    LOOP AT rt_methods ASSIGNING <ls_method>.
      CALL METHOD (<ls_method>-class)=>zif_abapgit_background~get_description
        RECEIVING
          rv_description = <ls_method>-description.
    ENDLOOP.

  ENDMETHOD.

  METHOD run.

    CONSTANTS: lc_enq_type TYPE c LENGTH 12 VALUE 'BACKGROUND'.

    DATA: lo_per        TYPE REF TO zcl_abapgit_persist_background,
          lo_repo       TYPE REF TO zcl_abapgit_repo_online,
          lt_list       TYPE zcl_abapgit_persist_background=>ty_background_keys,
          li_background TYPE REF TO zif_abapgit_background,
          li_log        TYPE REF TO zif_abapgit_log,
          lx_error      TYPE REF TO zcx_abapgit_exception,
          lv_repo_name  TYPE string.

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

    CALL FUNCTION 'ENQUEUE_EZABAPGIT'
      EXPORTING
        mode_zabapgit  = 'E'
        type           = lc_enq_type
        _scope         = '3'
      EXCEPTIONS
        foreign_lock   = 1
        system_failure = 2
        OTHERS         = 3.
    IF sy-subrc <> 0.
      WRITE: / 'Another intance of the program is already running'.
      RETURN.
    ENDIF.

    CREATE OBJECT lo_per.
    lt_list = lo_per->list( ).

    WRITE: / 'Background mode'.

    LOOP AT lt_list ASSIGNING <ls_list>.
      TRY.
          lo_repo ?= zcl_abapgit_repo_srv=>get_instance( )->get( <ls_list>-key ).
          lv_repo_name = lo_repo->get_name( ).
          WRITE: / <ls_list>-method, lv_repo_name.

          zcl_abapgit_login_manager=>set(
            iv_uri      = lo_repo->get_url( )
            iv_username = <ls_list>-username
            iv_password = <ls_list>-password ).

          CREATE OBJECT li_log TYPE zcl_abapgit_log.
          CREATE OBJECT li_background TYPE (<ls_list>-method).

          li_background->run(
            io_repo     = lo_repo
            ii_log      = li_log
            it_settings = <ls_list>-settings ).
        CATCH zcx_abapgit_exception INTO lx_error.
          li_log->add_exception( lx_error ).
      ENDTRY.

      zcl_abapgit_log_viewer=>write_log( li_log ).
    ENDLOOP.

    IF lines( lt_list ) = 0.
      WRITE: / 'Nothing configured'.
    ENDIF.

    CALL FUNCTION 'DEQUEUE_EZABAPGIT'
      EXPORTING
        type = lc_enq_type.

  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_background DEFINITION
  PUBLIC
  CREATE PUBLIC .

  PUBLIC SECTION.

    TYPES: BEGIN OF ty_method,
             class       TYPE seoclsname,
             description TYPE string,
           END OF ty_method.

    TYPES: ty_methods TYPE SORTED TABLE OF ty_method WITH UNIQUE KEY class.

    CLASS-METHODS run
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS list_methods
      RETURNING VALUE(rt_methods) TYPE ty_methods.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS ZCL_ABAPGIT_BACKGROUND IMPLEMENTATION.

  METHOD list_methods.

    DATA: ls_method       LIKE LINE OF rt_methods,
          ls_key          TYPE seoclskey,
          lt_implementing TYPE seor_implementing_keys,
          ls_implementing LIKE LINE OF lt_implementing.

    FIELD-SYMBOLS: <ls_method> LIKE LINE OF rt_methods.

* in order to handle local classes in the compiled report
    ls_method-class = 'ZCL_ABAPGIT_BACKGROUND_PULL'.
    INSERT ls_method INTO TABLE rt_methods.
    ls_method-class = 'ZCL_ABAPGIT_BACKGROUND_PUSH_AU'.
    INSERT ls_method INTO TABLE rt_methods.
    ls_method-class = 'ZCL_ABAPGIT_BACKGROUND_PUSH_FI'.
    INSERT ls_method INTO TABLE rt_methods.

    ls_key-clsname = 'ZIF_ABAPGIT_BACKGROUND'.

    CALL FUNCTION 'SEO_INTERFACE_IMPLEM_GET_ALL'
      EXPORTING
        intkey       = ls_key
      IMPORTING
        impkeys      = lt_implementing
      EXCEPTIONS
        not_existing = 1
        OTHERS       = 2 ##FM_SUBRC_OK.
    LOOP AT lt_implementing INTO ls_implementing.
      ls_method-class = ls_implementing-clsname.
      INSERT ls_method INTO TABLE rt_methods.
    ENDLOOP.

    LOOP AT rt_methods ASSIGNING <ls_method>.
      CALL METHOD (<ls_method>-class)=>zif_abapgit_background~get_description
        RECEIVING
          rv_description = <ls_method>-description.
    ENDLOOP.

  ENDMETHOD.

  METHOD run.

    CONSTANTS: lc_enq_type TYPE c LENGTH 12 VALUE 'BACKGROUND'.

    DATA: lo_per        TYPE REF TO zcl_abapgit_persist_background,
          lo_repo       TYPE REF TO zcl_abapgit_repo_online,
          lt_list       TYPE zcl_abapgit_persist_background=>ty_background_keys,
          li_background TYPE REF TO zif_abapgit_background,
          li_log        TYPE REF TO zif_abapgit_log,
          lx_error      TYPE REF TO zcx_abapgit_exception,
          lv_repo_name  TYPE string.

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

    CALL FUNCTION 'ENQUEUE_EZABAPGIT'
      EXPORTING
        mode_zabapgit  = 'E'
        type           = lc_enq_type
        _scope         = '3'
      EXCEPTIONS
        foreign_lock   = 1
        system_failure = 2
        OTHERS         = 3.
    IF sy-subrc <> 0.
      WRITE: / 'Another intance of the program is already running'.
      RETURN.
    ENDIF.

    CREATE OBJECT lo_per.
    lt_list = lo_per->list( ).

    WRITE: / 'Background mode'.

    LOOP AT lt_list ASSIGNING <ls_list>.
      TRY.
          lo_repo ?= zcl_abapgit_repo_srv=>get_instance( )->get( <ls_list>-key ).
          lv_repo_name = lo_repo->get_name( ).
          WRITE: / <ls_list>-method, lv_repo_name.

          zcl_abapgit_login_manager=>set(
            iv_uri      = lo_repo->get_url( )
            iv_username = <ls_list>-username
            iv_password = <ls_list>-password ).

          CREATE OBJECT li_log TYPE zcl_abapgit_log.
          CREATE OBJECT li_background TYPE (<ls_list>-method).

          li_background->run(
            io_repo     = lo_repo
            ii_log      = li_log
            it_settings = <ls_list>-settings ).

          " Clear auth buffer to allow different user/password per repository in background mode
          zcl_abapgit_login_manager=>clear( ).

        CATCH zcx_abapgit_exception INTO lx_error.
          li_log->add_exception( lx_error ).
      ENDTRY.

      zcl_abapgit_log_viewer=>write_log( li_log ).
    ENDLOOP.

    IF lines( lt_list ) = 0.
      WRITE: / 'Nothing configured'.
    ENDIF.

    CALL FUNCTION 'DEQUEUE_EZABAPGIT'
      EXPORTING
        type = lc_enq_type.

  ENDMETHOD.
ENDCLASS.

Allow different user/password per repository in background mode (#5488)

* Allow different user/password per repository

Clear auth buffer to allow different user/password per repository in background mode

* Uppercase for class name

Co-authored-by: Marc Bernard <b87df29b98274de0b03db8f81c149b8b52bd050e@users.noreply.github.com>


CLASS zcl_abapgit_services_abapgit DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    CONSTANTS: c_abapgit_repo     TYPE string   VALUE 'https://github.com/larshp/abapGit'     ##NO_TEXT,
               c_abapgit_homepage TYPE string   VALUE 'https://www.abapgit.org'                ##NO_TEXT,
               c_abapgit_wikipage TYPE string   VALUE 'https://docs.abapgit.org'               ##NO_TEXT,
               c_dotabap_homepage TYPE string   VALUE 'https://dotabap.org'               ##NO_TEXT,
               c_abapgit_package  TYPE devclass VALUE '$ABAPGIT'                              ##NO_TEXT,
               c_abapgit_url      TYPE string   VALUE 'https://github.com/larshp/abapGit.git' ##NO_TEXT,
               c_abapgit_tcode    TYPE tcode    VALUE `ZABAPGIT`                              ##NO_TEXT.

    CLASS-METHODS open_abapgit_homepage
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS open_abapgit_wikipage
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS open_dotabap_homepage
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS open_abapgit_changelog
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS install_abapgit
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS is_installed
      RETURNING
        VALUE(rv_devclass) TYPE tadir-devclass .
    CLASS-METHODS prepare_gui_startup
      RAISING
        zcx_abapgit_exception .
  PROTECTED SECTION.
  PRIVATE SECTION.
    CLASS-METHODS do_install
      IMPORTING iv_title   TYPE c
                iv_text    TYPE c
                iv_url     TYPE string
                iv_package TYPE devclass
      RAISING   zcx_abapgit_exception.

    CLASS-METHODS set_start_repo_from_package
      IMPORTING
        iv_package TYPE devclass
      RAISING
        zcx_abapgit_exception.

    CLASS-METHODS get_package_from_adt
      RETURNING
        VALUE(rv_package) TYPE devclass.
    CLASS-METHODS check_sapgui
      RAISING
        zcx_abapgit_exception.

ENDCLASS.

CLASS zcl_abapgit_services_abapgit IMPLEMENTATION.

  METHOD check_sapgui.

    CONSTANTS:
      lc_hide_sapgui_hint TYPE string VALUE '2' ##NO_TEXT.

    DATA:
      lv_answer           TYPE char1,
      ls_settings         TYPE zif_abapgit_definitions=>ty_s_user_settings,
      li_user_persistence TYPE REF TO zif_abapgit_persist_user.

    li_user_persistence = zcl_abapgit_persistence_user=>get_instance( ).

    ls_settings = li_user_persistence->get_settings( ).

    IF ls_settings-hide_sapgui_hint = abap_true.
      RETURN.
    ENDIF.

    IF zcl_abapgit_ui_factory=>get_gui_functions( )->is_sapgui_for_java( ) = abap_false.
      RETURN.
    ENDIF.

    lv_answer = zcl_abapgit_ui_factory=>get_popups( )->popup_to_confirm(
                    iv_titlebar              = 'Not supported SAPGUI'
                    iv_text_question         = 'SAPGUI for Java is not supported! There might be some issues.'
                    iv_text_button_1         = 'Got it'
                    iv_icon_button_1         = |{ icon_okay }|
                    iv_text_button_2         = 'Hide'
                    iv_icon_button_2         = |{ icon_set_state }|
                    iv_display_cancel_button = abap_false ).

    IF lv_answer = lc_hide_sapgui_hint.
      ls_settings-hide_sapgui_hint = abap_true.
      li_user_persistence->set_settings( ls_settings ).
    ENDIF.

  ENDMETHOD.

  METHOD do_install.

    DATA: lo_repo   TYPE REF TO zcl_abapgit_repo_online,
          lv_answer TYPE c LENGTH 1.

    lv_answer = zcl_abapgit_ui_factory=>get_popups( )->popup_to_confirm(
      iv_titlebar              = iv_title
      iv_text_question         = iv_text
      iv_text_button_1         = 'Continue'
      iv_text_button_2         = 'Cancel'
      iv_default_button        = '2'
      iv_display_cancel_button = abap_false ).              "#EC NOTEXT

    IF lv_answer <> '1'.
      RETURN.
    ENDIF.

    IF abap_false = zcl_abapgit_repo_srv=>get_instance( )->is_repo_installed(
        iv_url              = iv_url
        iv_target_package   = iv_package ).

      zcl_abapgit_factory=>get_sap_package( iv_package )->create_local( ).

      lo_repo = zcl_abapgit_repo_srv=>get_instance( )->new_online(
        iv_url         = iv_url
        iv_branch_name = 'refs/heads/master'
        iv_package     = iv_package ) ##NO_TEXT.

      zcl_abapgit_services_repo=>gui_deserialize( lo_repo ).

      zcl_abapgit_services_repo=>toggle_favorite( lo_repo->get_key( ) ).
    ENDIF.

    COMMIT WORK.

  ENDMETHOD.

  METHOD get_package_from_adt.

    DATA: ls_item    TYPE zif_abapgit_definitions=>ty_item,
          lr_context TYPE REF TO data,
          lt_fields  TYPE tihttpnvp.

    FIELD-SYMBOLS: <lg_context>    TYPE any,
                   <lv_parameters> TYPE string,
                   <ls_field>      LIKE LINE OF lt_fields.

    ls_item-obj_type = 'CLAS'.
    ls_item-obj_name = 'CL_ADT_GUI_INTEGRATION_CONTEXT'.

    IF zcl_abapgit_objects=>exists( ls_item ) = abap_false.
      " ADT is not supported in this NW release
      RETURN.
    ENDIF.

    TRY.
        CREATE DATA lr_context TYPE ('CL_ADT_GUI_INTEGRATION_CONTEXT=>TY_CONTEXT_INFO').

        ASSIGN lr_context->* TO <lg_context>.
        ASSERT sy-subrc = 0.

        CALL METHOD ('CL_ADT_GUI_INTEGRATION_CONTEXT')=>read_context
          RECEIVING
            result = <lg_context>.

        ASSIGN COMPONENT 'PARAMETERS'
               OF STRUCTURE <lg_context>
               TO <lv_parameters>.
        ASSERT sy-subrc = 0.

        lt_fields = cl_http_utility=>string_to_fields( cl_http_utility=>unescape_url( <lv_parameters> ) ).

        READ TABLE lt_fields ASSIGNING <ls_field>
                             WITH KEY name = 'p_package_name'.
        IF sy-subrc = 0.
          rv_package = <ls_field>-value.

          " We want to open the repo just once. Therefore we delete the parameters
          " and initialize the ADT context.
          CLEAR <lv_parameters>.
          CALL METHOD ('CL_ADT_GUI_INTEGRATION_CONTEXT')=>initialize_instance
            EXPORTING
              context_info = <lg_context>.

        ENDIF.

      CATCH cx_root.
        " Some problems with dynamic ADT access.
        " Let's ignore it for now and fail silently
    ENDTRY.

  ENDMETHOD.

  METHOD install_abapgit.

    CONSTANTS lc_title TYPE c LENGTH 40 VALUE 'Install abapGit'.
    DATA lv_text       TYPE c LENGTH 100.

    IF NOT is_installed( ) IS INITIAL.
      lv_text = 'Seems like abapGit package is already installed. No changes to be done'.
      zcl_abapgit_ui_factory=>get_popups( )->popup_to_inform(
        iv_titlebar     = lc_title
        iv_text_message = lv_text ).
      RETURN.
    ENDIF.

    lv_text = |Confirm to install current version of abapGit to package { c_abapgit_package }|.

    do_install( iv_title   = lc_title
                iv_text    = lv_text
                iv_url     = c_abapgit_url
                iv_package = c_abapgit_package ).

  ENDMETHOD.

  METHOD is_installed.

    SELECT SINGLE devclass FROM tadir INTO rv_devclass
      WHERE object = 'TRAN' AND obj_name = c_abapgit_tcode.

  ENDMETHOD.

  METHOD open_abapgit_changelog.

    cl_gui_frontend_services=>execute(
      EXPORTING document = c_abapgit_repo && '/blob/master/changelog.txt'
      EXCEPTIONS OTHERS = 1 ).
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'Opening page in external browser failed.' ).
    ENDIF.

  ENDMETHOD.

  METHOD open_abapgit_homepage.

    cl_gui_frontend_services=>execute(
      EXPORTING document = c_abapgit_homepage
      EXCEPTIONS OTHERS = 1 ).
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'Opening page in external browser failed.' ).
    ENDIF.

  ENDMETHOD.

  METHOD open_abapgit_wikipage.

    cl_gui_frontend_services=>execute(
      EXPORTING document = c_abapgit_wikipage
      EXCEPTIONS OTHERS = 1 ).
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'Opening page in external browser failed.' ).
    ENDIF.

  ENDMETHOD.

  METHOD open_dotabap_homepage.

    cl_gui_frontend_services=>execute(
      EXPORTING document = c_dotabap_homepage
      EXCEPTIONS OTHERS = 1 ).
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'Opening page in external browser failed.' ).
    ENDIF.

  ENDMETHOD.

  METHOD prepare_gui_startup.

    DATA: lv_repo_key    TYPE zif_abapgit_persistence=>ty_value,
          lv_package     TYPE devclass,
          lv_package_adt TYPE devclass.

    check_sapgui( ).

    IF zcl_abapgit_persist_settings=>get_instance( )->read( )->get_show_default_repo( ) = abap_false.
      " Don't show the last seen repo at startup
      zcl_abapgit_persistence_user=>get_instance( )->set_repo_show( || ).
    ENDIF.

    " We have three special cases for gui startup
    "   - open a specific repo by repo key
    "   - open a specific repo by package name
    "   - open a specific repo by package name provided by ADT
    " These overrule the last shown repo

    GET PARAMETER ID zif_abapgit_definitions=>c_spagpa_param_repo_key FIELD lv_repo_key.
    GET PARAMETER ID zif_abapgit_definitions=>c_spagpa_param_package  FIELD lv_package.
    lv_package_adt = get_package_from_adt( ).

    IF lv_repo_key IS NOT INITIAL.

      SET PARAMETER ID zif_abapgit_definitions=>c_spagpa_param_repo_key FIELD ''.
      zcl_abapgit_persistence_user=>get_instance( )->set_repo_show( lv_repo_key ).

    ELSEIF lv_package IS NOT INITIAL.

      SET PARAMETER ID zif_abapgit_definitions=>c_spagpa_param_package FIELD ''.
      set_start_repo_from_package( lv_package ).

    ELSEIF lv_package_adt IS NOT INITIAL.

      set_start_repo_from_package( lv_package_adt ).

    ENDIF.

  ENDMETHOD.

  METHOD set_start_repo_from_package.

    DATA: lo_repo          TYPE REF TO zcl_abapgit_repo,
          lt_r_package     TYPE RANGE OF devclass,
          ls_r_package     LIKE LINE OF lt_r_package,
          lt_superpackages TYPE zif_abapgit_sap_package=>ty_devclass_tt,
          li_package       TYPE REF TO zif_abapgit_sap_package,
          lt_repo_list     TYPE zif_abapgit_definitions=>ty_repo_ref_tt.

    FIELD-SYMBOLS: <lo_repo>         TYPE LINE OF zif_abapgit_definitions=>ty_repo_ref_tt,
                   <lv_superpackage> LIKE LINE OF lt_superpackages.

    li_package = zcl_abapgit_factory=>get_sap_package( iv_package ).

    IF li_package->exists( ) = abap_false.
      RETURN.
    ENDIF.

    ls_r_package-sign   = 'I'.
    ls_r_package-option = 'EQ'.
    ls_r_package-low    = iv_package.
    INSERT ls_r_package INTO TABLE lt_r_package.

    " Also consider superpackages. E.g. when some open $abapgit_ui, abapGit repo
    " should be found via package $abapgit
    lt_superpackages = li_package->list_superpackages( ).
    LOOP AT lt_superpackages ASSIGNING <lv_superpackage>.
      ls_r_package-low = <lv_superpackage>.
      INSERT ls_r_package INTO TABLE lt_r_package.
    ENDLOOP.

    lt_repo_list = zcl_abapgit_repo_srv=>get_instance( )->list( ).

    LOOP AT lt_repo_list ASSIGNING <lo_repo>.

      IF <lo_repo>->get_package( ) IN lt_r_package.
        lo_repo = <lo_repo>.
        EXIT.
      ENDIF.

    ENDLOOP.

    IF lo_repo IS BOUND.
      zcl_abapgit_persistence_user=>get_instance( )->set_repo_show( lo_repo->get_key( ) ).
    ENDIF.

  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_services_abapgit DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    CONSTANTS: c_abapgit_repo     TYPE string   VALUE 'https://github.com/larshp/abapGit'     ##NO_TEXT,
               c_abapgit_homepage TYPE string   VALUE 'https://www.abapgit.org'                ##NO_TEXT,
               c_abapgit_wikipage TYPE string   VALUE 'https://docs.abapgit.org'               ##NO_TEXT,
               c_dotabap_homepage TYPE string   VALUE 'https://dotabap.org'               ##NO_TEXT,
               c_abapgit_package  TYPE devclass VALUE '$ABAPGIT'                              ##NO_TEXT,
               c_abapgit_url      TYPE string   VALUE 'https://github.com/larshp/abapGit.git' ##NO_TEXT,
               c_abapgit_class    TYPE tcode    VALUE `ZCL_ABAPGIT_REPO`                      ##NO_TEXT,
               c_abapgit_tcode    TYPE tcode    VALUE `ZABAPGIT`                              ##NO_TEXT.

    CLASS-METHODS open_abapgit_homepage
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS open_abapgit_wikipage
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS open_dotabap_homepage
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS open_abapgit_changelog
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS install_abapgit
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS is_installed
      RETURNING
        VALUE(rv_devclass) TYPE tadir-devclass .
    CLASS-METHODS prepare_gui_startup
      RAISING
        zcx_abapgit_exception .
  PROTECTED SECTION.
  PRIVATE SECTION.
    CLASS-METHODS do_install
      IMPORTING iv_title   TYPE c
                iv_text    TYPE c
                iv_url     TYPE string
                iv_package TYPE devclass
      RAISING   zcx_abapgit_exception.

    CLASS-METHODS set_start_repo_from_package
      IMPORTING
        iv_package TYPE devclass
      RAISING
        zcx_abapgit_exception.

    CLASS-METHODS get_package_from_adt
      RETURNING
        VALUE(rv_package) TYPE devclass.
    CLASS-METHODS check_sapgui
      RAISING
        zcx_abapgit_exception.

ENDCLASS.

CLASS zcl_abapgit_services_abapgit IMPLEMENTATION.

  METHOD check_sapgui.

    CONSTANTS:
      lc_hide_sapgui_hint TYPE string VALUE '2' ##NO_TEXT.

    DATA:
      lv_answer           TYPE char1,
      ls_settings         TYPE zif_abapgit_definitions=>ty_s_user_settings,
      li_user_persistence TYPE REF TO zif_abapgit_persist_user.

    li_user_persistence = zcl_abapgit_persistence_user=>get_instance( ).

    ls_settings = li_user_persistence->get_settings( ).

    IF ls_settings-hide_sapgui_hint = abap_true.
      RETURN.
    ENDIF.

    IF zcl_abapgit_ui_factory=>get_gui_functions( )->is_sapgui_for_java( ) = abap_false.
      RETURN.
    ENDIF.

    lv_answer = zcl_abapgit_ui_factory=>get_popups( )->popup_to_confirm(
                    iv_titlebar              = 'Not supported SAPGUI'
                    iv_text_question         = 'SAPGUI for Java is not supported! There might be some issues.'
                    iv_text_button_1         = 'Got it'
                    iv_icon_button_1         = |{ icon_okay }|
                    iv_text_button_2         = 'Hide'
                    iv_icon_button_2         = |{ icon_set_state }|
                    iv_display_cancel_button = abap_false ).

    IF lv_answer = lc_hide_sapgui_hint.
      ls_settings-hide_sapgui_hint = abap_true.
      li_user_persistence->set_settings( ls_settings ).
    ENDIF.

  ENDMETHOD.

  METHOD do_install.

    DATA: lo_repo   TYPE REF TO zcl_abapgit_repo_online,
          lv_answer TYPE c LENGTH 1.

    lv_answer = zcl_abapgit_ui_factory=>get_popups( )->popup_to_confirm(
      iv_titlebar              = iv_title
      iv_text_question         = iv_text
      iv_text_button_1         = 'Continue'
      iv_text_button_2         = 'Cancel'
      iv_default_button        = '2'
      iv_display_cancel_button = abap_false ).              "#EC NOTEXT

    IF lv_answer <> '1'.
      RETURN.
    ENDIF.

    IF abap_false = zcl_abapgit_repo_srv=>get_instance( )->is_repo_installed(
        iv_url              = iv_url
        iv_target_package   = iv_package ).

      zcl_abapgit_factory=>get_sap_package( iv_package )->create_local( ).

      lo_repo = zcl_abapgit_repo_srv=>get_instance( )->new_online(
        iv_url         = iv_url
        iv_branch_name = 'refs/heads/master'
        iv_package     = iv_package ) ##NO_TEXT.

      zcl_abapgit_services_repo=>gui_deserialize( lo_repo ).

      zcl_abapgit_services_repo=>toggle_favorite( lo_repo->get_key( ) ).
    ENDIF.

    COMMIT WORK.

  ENDMETHOD.

  METHOD get_package_from_adt.

    DATA: ls_item    TYPE zif_abapgit_definitions=>ty_item,
          lr_context TYPE REF TO data,
          lt_fields  TYPE tihttpnvp.

    FIELD-SYMBOLS: <lg_context>    TYPE any,
                   <lv_parameters> TYPE string,
                   <ls_field>      LIKE LINE OF lt_fields.

    ls_item-obj_type = 'CLAS'.
    ls_item-obj_name = 'CL_ADT_GUI_INTEGRATION_CONTEXT'.

    IF zcl_abapgit_objects=>exists( ls_item ) = abap_false.
      " ADT is not supported in this NW release
      RETURN.
    ENDIF.

    TRY.
        CREATE DATA lr_context TYPE ('CL_ADT_GUI_INTEGRATION_CONTEXT=>TY_CONTEXT_INFO').

        ASSIGN lr_context->* TO <lg_context>.
        ASSERT sy-subrc = 0.

        CALL METHOD ('CL_ADT_GUI_INTEGRATION_CONTEXT')=>read_context
          RECEIVING
            result = <lg_context>.

        ASSIGN COMPONENT 'PARAMETERS'
               OF STRUCTURE <lg_context>
               TO <lv_parameters>.
        ASSERT sy-subrc = 0.

        lt_fields = cl_http_utility=>string_to_fields( cl_http_utility=>unescape_url( <lv_parameters> ) ).

        READ TABLE lt_fields ASSIGNING <ls_field>
                             WITH KEY name = 'p_package_name'.
        IF sy-subrc = 0.
          rv_package = <ls_field>-value.

          " We want to open the repo just once. Therefore we delete the parameters
          " and initialize the ADT context.
          CLEAR <lv_parameters>.
          CALL METHOD ('CL_ADT_GUI_INTEGRATION_CONTEXT')=>initialize_instance
            EXPORTING
              context_info = <lg_context>.

        ENDIF.

      CATCH cx_root.
        " Some problems with dynamic ADT access.
        " Let's ignore it for now and fail silently
    ENDTRY.

  ENDMETHOD.

  METHOD install_abapgit.

    CONSTANTS lc_title TYPE c LENGTH 40 VALUE 'Install abapGit'.
    DATA lv_text       TYPE c LENGTH 100.

    IF NOT is_installed( ) IS INITIAL.
      lv_text = 'Seems like abapGit package is already installed. No changes to be done'.
      zcl_abapgit_ui_factory=>get_popups( )->popup_to_inform(
        iv_titlebar     = lc_title
        iv_text_message = lv_text ).
      RETURN.
    ENDIF.

    lv_text = |Confirm to install current version of abapGit to package { c_abapgit_package }|.

    do_install( iv_title   = lc_title
                iv_text    = lv_text
                iv_url     = c_abapgit_url
                iv_package = c_abapgit_package ).

  ENDMETHOD.

  METHOD is_installed.

    SELECT SINGLE devclass FROM tadir INTO rv_devclass
      WHERE object = 'CLAS' AND obj_name = c_abapgit_class.

  ENDMETHOD.

  METHOD open_abapgit_changelog.

    cl_gui_frontend_services=>execute(
      EXPORTING document = c_abapgit_repo && '/blob/master/changelog.txt'
      EXCEPTIONS OTHERS = 1 ).
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'Opening page in external browser failed.' ).
    ENDIF.

  ENDMETHOD.

  METHOD open_abapgit_homepage.

    cl_gui_frontend_services=>execute(
      EXPORTING document = c_abapgit_homepage
      EXCEPTIONS OTHERS = 1 ).
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'Opening page in external browser failed.' ).
    ENDIF.

  ENDMETHOD.

  METHOD open_abapgit_wikipage.

    cl_gui_frontend_services=>execute(
      EXPORTING document = c_abapgit_wikipage
      EXCEPTIONS OTHERS = 1 ).
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'Opening page in external browser failed.' ).
    ENDIF.

  ENDMETHOD.

  METHOD open_dotabap_homepage.

    cl_gui_frontend_services=>execute(
      EXPORTING document = c_dotabap_homepage
      EXCEPTIONS OTHERS = 1 ).
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'Opening page in external browser failed.' ).
    ENDIF.

  ENDMETHOD.

  METHOD prepare_gui_startup.

    DATA: lv_repo_key    TYPE zif_abapgit_persistence=>ty_value,
          lv_package     TYPE devclass,
          lv_package_adt TYPE devclass.

    check_sapgui( ).

    IF zcl_abapgit_persist_settings=>get_instance( )->read( )->get_show_default_repo( ) = abap_false.
      " Don't show the last seen repo at startup
      zcl_abapgit_persistence_user=>get_instance( )->set_repo_show( || ).
    ENDIF.

    " We have three special cases for gui startup
    "   - open a specific repo by repo key
    "   - open a specific repo by package name
    "   - open a specific repo by package name provided by ADT
    " These overrule the last shown repo

    GET PARAMETER ID zif_abapgit_definitions=>c_spagpa_param_repo_key FIELD lv_repo_key.
    GET PARAMETER ID zif_abapgit_definitions=>c_spagpa_param_package  FIELD lv_package.
    lv_package_adt = get_package_from_adt( ).

    IF lv_repo_key IS NOT INITIAL.

      SET PARAMETER ID zif_abapgit_definitions=>c_spagpa_param_repo_key FIELD ''.
      zcl_abapgit_persistence_user=>get_instance( )->set_repo_show( lv_repo_key ).

    ELSEIF lv_package IS NOT INITIAL.

      SET PARAMETER ID zif_abapgit_definitions=>c_spagpa_param_package FIELD ''.
      set_start_repo_from_package( lv_package ).

    ELSEIF lv_package_adt IS NOT INITIAL.

      set_start_repo_from_package( lv_package_adt ).

    ENDIF.

  ENDMETHOD.

  METHOD set_start_repo_from_package.

    DATA: lo_repo          TYPE REF TO zcl_abapgit_repo,
          lt_r_package     TYPE RANGE OF devclass,
          ls_r_package     LIKE LINE OF lt_r_package,
          lt_superpackages TYPE zif_abapgit_sap_package=>ty_devclass_tt,
          li_package       TYPE REF TO zif_abapgit_sap_package,
          lt_repo_list     TYPE zif_abapgit_definitions=>ty_repo_ref_tt.

    FIELD-SYMBOLS: <lo_repo>         TYPE LINE OF zif_abapgit_definitions=>ty_repo_ref_tt,
                   <lv_superpackage> LIKE LINE OF lt_superpackages.

    li_package = zcl_abapgit_factory=>get_sap_package( iv_package ).

    IF li_package->exists( ) = abap_false.
      RETURN.
    ENDIF.

    ls_r_package-sign   = 'I'.
    ls_r_package-option = 'EQ'.
    ls_r_package-low    = iv_package.
    INSERT ls_r_package INTO TABLE lt_r_package.

    " Also consider superpackages. E.g. when some open $abapgit_ui, abapGit repo
    " should be found via package $abapgit
    lt_superpackages = li_package->list_superpackages( ).
    LOOP AT lt_superpackages ASSIGNING <lv_superpackage>.
      ls_r_package-low = <lv_superpackage>.
      INSERT ls_r_package INTO TABLE lt_r_package.
    ENDLOOP.

    lt_repo_list = zcl_abapgit_repo_srv=>get_instance( )->list( ).

    LOOP AT lt_repo_list ASSIGNING <lo_repo>.

      IF <lo_repo>->get_package( ) IN lt_r_package.
        lo_repo = <lo_repo>.
        EXIT.
      ENDIF.

    ENDLOOP.

    IF lo_repo IS BOUND.
      zcl_abapgit_persistence_user=>get_instance( )->set_repo_show( lo_repo->get_key( ) ).
    ENDIF.

  ENDMETHOD.
ENDCLASS.

Fix detection of abapGit installation (#3425)

Old logic was failing if transaction ZABAPGIT already existed - typically because it was created manually for the merged version. Testing for program ZABAPGIT would not be any better since that might have been used for the merged version as well. It's more reliable to check a class.

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


CLASS zcl_abapgit_folder_logic DEFINITION
  PUBLIC
  CREATE PUBLIC .

  PUBLIC SECTION.

    METHODS package_to_path
      IMPORTING
        !iv_top        TYPE devclass
        !io_dot        TYPE REF TO zcl_abapgit_dot_abapgit
        !iv_package    TYPE devclass
      RETURNING
        VALUE(rv_path) TYPE string
      RAISING
        zcx_abapgit_exception .
    METHODS path_to_package
      IMPORTING
        !iv_top                  TYPE devclass
        !io_dot                  TYPE REF TO zcl_abapgit_dot_abapgit
        !iv_path                 TYPE string
        !iv_create_if_not_exists TYPE abap_bool DEFAULT abap_true
      RETURNING
        VALUE(rv_package)        TYPE devclass
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS get_instance
      RETURNING
        VALUE(ro_instance) TYPE REF TO zcl_abapgit_folder_logic .
  PROTECTED SECTION.
    METHODS get_parent
      IMPORTING
        !iv_package      TYPE devclass
      RETURNING
        VALUE(rv_parent) TYPE devclass.
  PRIVATE SECTION.
    TYPES:
      BEGIN OF ty_devclass_info,
        devclass  TYPE devclass,
        namespace TYPE namespace,
        parentcl  TYPE parentcl,
      END OF ty_devclass_info .
    TYPES:
      ty_devclass_info_tt TYPE SORTED TABLE OF ty_devclass_info
        WITH UNIQUE KEY devclass .
    DATA mt_parent TYPE ty_devclass_info_tt .
ENDCLASS.

CLASS ZCL_ABAPGIT_FOLDER_LOGIC IMPLEMENTATION.

  METHOD get_instance.
    CREATE OBJECT ro_instance.
  ENDMETHOD.

  METHOD get_parent.
    DATA: ls_parent LIKE LINE OF mt_parent.

    "Determine Parent Package
    READ TABLE mt_parent INTO ls_parent
      WITH TABLE KEY devclass = iv_package.
    IF sy-subrc <> 0.
      rv_parent = zcl_abapgit_factory=>get_sap_package( iv_package )->read_parent( ).
      ls_parent-devclass = iv_package.
      ls_parent-parentcl = rv_parent.
      INSERT ls_parent INTO TABLE mt_parent.
    ELSE.
      rv_parent = ls_parent-parentcl.
    ENDIF.
  ENDMETHOD.

  METHOD package_to_path.

    DATA: lv_len          TYPE i,
          lv_path         TYPE string,
          lv_message      TYPE string,
          lv_parentcl     TYPE tdevc-parentcl,
          lv_folder_logic TYPE string.

    IF iv_top = iv_package.
      rv_path = io_dot->get_starting_folder( ).
    ELSE.
      lv_parentcl = get_parent( iv_package ).

      IF lv_parentcl IS INITIAL.
        zcx_abapgit_exception=>raise( |error, expected parent package, { iv_package }| ).
      ELSE.
        lv_folder_logic = io_dot->get_folder_logic( ).
        CASE lv_folder_logic.
          WHEN zif_abapgit_dot_abapgit=>c_folder_logic-full.
            lv_len = 0.
            IF iv_package(1) = '$'.
              lv_len = 1.
            ENDIF.
          WHEN zif_abapgit_dot_abapgit=>c_folder_logic-prefix.
            lv_len = strlen( lv_parentcl ).

            IF iv_package(lv_len) <> lv_parentcl.
* if abapGit project is installed in package ZZZ, all subpackages should be named
* ZZZ_something. This will define the folder name in the zip file to be "something",
* similarily with online projects. Alternatively change to FULL folder logic
              lv_message = 'PREFIX: Unexpected package naming (' && iv_package && ')'
                           && 'you might switch to FULL folder logic' ##no_text.
              zcx_abapgit_exception=>raise( lv_message ).
            ENDIF.
          WHEN OTHERS.
            zcx_abapgit_exception=>raise( |Invalid folder logic: { lv_folder_logic }| ).
        ENDCASE.

        lv_path = iv_package+lv_len.
        IF strlen( lv_path ) = 0.
          zcx_abapgit_exception=>raise( |Folder logic: length = 0, parent: {
            lv_parentcl }, child: { iv_package }| ).
        ENDIF.

        IF lv_path(1) = '_'.
          lv_path = lv_path+1.
        ENDIF.
        IF strlen( lv_path ) = 0.
          zcx_abapgit_exception=>raise( |Folder logic: length = 0, parent: {
            lv_parentcl }, child: { iv_package }| ).
        ENDIF.

        TRANSLATE lv_path USING '/#'.
        TRANSLATE lv_path TO LOWER CASE.
        CONCATENATE lv_path '/' INTO lv_path.

        rv_path = package_to_path( iv_top     = iv_top
                                   io_dot     = io_dot
                                   iv_package = lv_parentcl ).

        CONCATENATE rv_path lv_path INTO rv_path.
      ENDIF.
    ENDIF.

  ENDMETHOD.

  METHOD path_to_package.

    DATA: lv_length TYPE i,
          lv_parent TYPE devclass,
          lv_new    TYPE string,
          lv_path   TYPE string,
          lv_top    TYPE devclass.

    lv_top = iv_top.

    lv_length  = strlen( io_dot->get_starting_folder( ) ).
    IF lv_length > strlen( iv_path ).
* treat as not existing locally
      RETURN.
    ENDIF.
    lv_path    = iv_path+lv_length.
    lv_parent  = lv_top.
    rv_package = lv_top.

    WHILE lv_path CA '/'.
      SPLIT lv_path AT '/' INTO lv_new lv_path.

      CASE io_dot->get_folder_logic( ).
        WHEN zif_abapgit_dot_abapgit=>c_folder_logic-full.
          rv_package = lv_new.
          TRANSLATE rv_package USING '#/'.
          IF iv_top(1) = '$'.
            CONCATENATE '$' rv_package INTO rv_package.
          ENDIF.
        WHEN zif_abapgit_dot_abapgit=>c_folder_logic-prefix.
          CONCATENATE rv_package '_' lv_new INTO rv_package.
        WHEN OTHERS.
          ASSERT 0 = 1.
      ENDCASE.

      TRANSLATE rv_package TO UPPER CASE.

      IF zcl_abapgit_factory=>get_sap_package( rv_package )->exists( ) = abap_false AND
          iv_create_if_not_exists = abap_true.

        zcl_abapgit_factory=>get_sap_package( lv_parent )->create_child( rv_package ).
      ENDIF.

      lv_parent = rv_package.
    ENDWHILE.

  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_folder_logic DEFINITION
  PUBLIC
  CREATE PUBLIC .

  PUBLIC SECTION.

    METHODS package_to_path
      IMPORTING
        !iv_top        TYPE devclass
        !io_dot        TYPE REF TO zcl_abapgit_dot_abapgit
        !iv_package    TYPE devclass
      RETURNING
        VALUE(rv_path) TYPE string
      RAISING
        zcx_abapgit_exception .
    METHODS path_to_package
      IMPORTING
        !iv_top                  TYPE devclass
        !io_dot                  TYPE REF TO zcl_abapgit_dot_abapgit
        !iv_path                 TYPE string
        !iv_create_if_not_exists TYPE abap_bool DEFAULT abap_true
      RETURNING
        VALUE(rv_package)        TYPE devclass
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS get_instance
      RETURNING
        VALUE(ro_instance) TYPE REF TO zcl_abapgit_folder_logic .
  PROTECTED SECTION.
    METHODS get_parent
      IMPORTING
        !iv_package      TYPE devclass
      RETURNING
        VALUE(rv_parent) TYPE devclass.
  PRIVATE SECTION.
    TYPES:
      BEGIN OF ty_devclass_info,
        devclass  TYPE devclass,
        namespace TYPE namespace,
        parentcl  TYPE parentcl,
      END OF ty_devclass_info .
    TYPES:
      ty_devclass_info_tt TYPE SORTED TABLE OF ty_devclass_info
        WITH UNIQUE KEY devclass .
    DATA mt_parent TYPE ty_devclass_info_tt .
ENDCLASS.

CLASS ZCL_ABAPGIT_FOLDER_LOGIC IMPLEMENTATION.

  METHOD get_instance.
    CREATE OBJECT ro_instance.
  ENDMETHOD.

  METHOD get_parent.
    DATA: ls_parent LIKE LINE OF mt_parent.

    "Determine Parent Package
    READ TABLE mt_parent INTO ls_parent
      WITH TABLE KEY devclass = iv_package.
    IF sy-subrc <> 0.
      rv_parent = zcl_abapgit_factory=>get_sap_package( iv_package )->read_parent( ).
      ls_parent-devclass = iv_package.
      ls_parent-parentcl = rv_parent.
      INSERT ls_parent INTO TABLE mt_parent.
    ELSE.
      rv_parent = ls_parent-parentcl.
    ENDIF.
  ENDMETHOD.

  METHOD package_to_path.

    DATA: lv_len          TYPE i,
          lv_path         TYPE string,
          lv_message      TYPE string,
          lv_parentcl     TYPE tdevc-parentcl,
          lv_folder_logic TYPE string.

    IF iv_top = iv_package.
      rv_path = io_dot->get_starting_folder( ).
    ELSE.
      lv_parentcl = get_parent( iv_package ).

      IF lv_parentcl IS INITIAL.
        zcx_abapgit_exception=>raise( |error, expected parent package, { iv_package }| ).
      ELSE.
        lv_folder_logic = io_dot->get_folder_logic( ).
        CASE lv_folder_logic.
          WHEN zif_abapgit_dot_abapgit=>c_folder_logic-full.
            lv_len = 0.
            IF iv_package(1) = '$'.
              lv_len = 1.
            ENDIF.
          WHEN zif_abapgit_dot_abapgit=>c_folder_logic-prefix.
            lv_len = strlen( lv_parentcl ).

            IF iv_package(lv_len) <> lv_parentcl.
* if abapGit project is installed in package ZZZ, all subpackages should be named
* ZZZ_something. This will define the folder name in the zip file to be "something",
* similarily with online projects. Alternatively change to FULL folder logic
              lv_message = 'PREFIX: Unexpected package naming (' && iv_package && ')'
                           && 'you might switch to FULL folder logic' ##no_text.
              zcx_abapgit_exception=>raise( lv_message ).
            ENDIF.
          WHEN OTHERS.
            zcx_abapgit_exception=>raise( |Invalid folder logic: { lv_folder_logic }| ).
        ENDCASE.

        lv_path = iv_package+lv_len.
        IF strlen( lv_path ) = 0.
          zcx_abapgit_exception=>raise( |Folder logic: length = 0, parent: {
            lv_parentcl }, child: { iv_package }| ).
        ENDIF.

        IF lv_path(1) = '_'.
          lv_path = lv_path+1.
        ENDIF.
        IF strlen( lv_path ) = 0.
          zcx_abapgit_exception=>raise( |Folder logic: length = 0, parent: {
            lv_parentcl }, child: { iv_package }| ).
        ENDIF.

        TRANSLATE lv_path USING '/#'.
        TRANSLATE lv_path TO LOWER CASE.
        CONCATENATE lv_path '/' INTO lv_path.

        rv_path = package_to_path( iv_top     = iv_top
                                   io_dot     = io_dot
                                   iv_package = lv_parentcl ).

        CONCATENATE rv_path lv_path INTO rv_path.
      ENDIF.
    ENDIF.

  ENDMETHOD.

  METHOD path_to_package.

    DATA: lv_length               TYPE i,
          lv_parent               TYPE devclass,
          lv_new                  TYPE string,
          lv_path                 TYPE string,
          lv_absolute_name        TYPE string,
          lv_top                  TYPE devclass,
          lt_unique_package_names TYPE HASHED TABLE OF devclass WITH UNIQUE KEY table_line.

    lv_top = iv_top.

    lv_length  = strlen( io_dot->get_starting_folder( ) ).
    IF lv_length > strlen( iv_path ).
* treat as not existing locally
      RETURN.
    ENDIF.
    lv_path    = iv_path+lv_length.
    lv_parent  = lv_top.
    rv_package = lv_top.

    INSERT iv_top INTO TABLE lt_unique_package_names.

    WHILE lv_path CA '/'.
      SPLIT lv_path AT '/' INTO lv_new lv_path.

      CASE io_dot->get_folder_logic( ).
        WHEN zif_abapgit_dot_abapgit=>c_folder_logic-full.
          lv_absolute_name = lv_new.
          TRANSLATE lv_absolute_name USING '#/'.
          IF iv_top(1) = '$'.
            CONCATENATE '$' lv_absolute_name INTO lv_absolute_name.
          ENDIF.
        WHEN zif_abapgit_dot_abapgit=>c_folder_logic-prefix.
          CONCATENATE rv_package '_' lv_new INTO lv_absolute_name.
        WHEN OTHERS.
          ASSERT 0 = 1.
      ENDCASE.

      TRANSLATE lv_absolute_name TO UPPER CASE.

      IF strlen( lv_absolute_name ) > 30.
        zcx_abapgit_exception=>raise( |Package { lv_absolute_name } exceeds ABAP 30-characters-name limit| ).
      ENDIF.

      READ TABLE lt_unique_package_names TRANSPORTING NO FIELDS
        WITH TABLE KEY table_line = lv_absolute_name.
      IF sy-subrc = 0.
        zcx_abapgit_exception=>raise( |Package { lv_absolute_name } has a subpackage with the same name| ).
      ELSE.
        rv_package = lv_absolute_name.
        INSERT rv_package INTO TABLE lt_unique_package_names.
      ENDIF.

      IF zcl_abapgit_factory=>get_sap_package( rv_package )->exists( ) = abap_false AND
          iv_create_if_not_exists = abap_true.

        zcl_abapgit_factory=>get_sap_package( lv_parent )->create_child( rv_package ).
      ENDIF.

      lv_parent = rv_package.
    ENDWHILE.

  ENDMETHOD.
ENDCLASS.

Package names validations (#2163)

Package names validations (#2163)

* Package names validations

validate if package has more than 30 characters name and if root packages does not contain a package with the same name as his.

* Validate grandchildren package names