Открываем гугл, гуглим, разрабатываем, закрываем гугл. Примерно такой цикл разработки приложения по Agile для Fiori. Прошло буквально два года с момента, когда я сам писал первое приложение для себя, поиграться. Тогда это был старый и добрый Eclipse. Сейчас даже гугл уже не помнит примеры разработки Fiori приложений для Eclipse. Вендор активно стирает все в нашей памяти и тычет: вот облако, вот Web IDE, ходи туда.

Поэтому сегодня мы пишем простое приложение на WebIDE, а потом будем учиться его автоматизированно тестировать вдоль и поперек. Я обещал такую заметку, поэтому она будет.

Задача приложения – отображать системные журналы через веб. Системные журналы, это то, что разные программы пишут в базу, а мы можем посмотреть через транзакцию SLG1. Для разработки приложения нам нужны две вещи: OData сервис, который будет доставать данные из журнала, само приложение, которое будет визуализировать эти данные.

Очень упрощенная модель приложения, без проверок безопасности, авторизации, overflow, да и вообще уровня школьника, выглядит примерно так.

Сначала создаем структуру, которую будет возвращать сервис. У нас это будет табличка, которая вернет данные по нужным нам фильтрам.

Теперь в транзакции SEGW создаем сам сервис. У меня он выглядит примерно так.

И немного кода в методе LOGENTRYSET_GET_ENTITYSET.

  method LOGENTRYSET_GET_ENTITYSET.

    data ls_entry type zllogentry.
    DATA: P_NUMBER_OF_LOGS LIKE SY-TABIX.
    DATA: P_HEADER_DATA_TAB type table of BALHDR.
    DATA: P_HEADER_PARA_TAB type table of BALHDRP.
    data: ls_message type balm.
    DATA: P_MESSAGE_TAB type table of BALM.
    DATA: P_MESSAGE_PARA_TAB type table of BALMP.

    data: ls_object_filter(20) type c value '*'.
    data: ls_subobject_filter(20) type c value '*'.

    data: ls_filter type /iwbep/s_mgw_select_option.
    data: ls_option type /IWBEP/S_COD_SELECT_OPTION.

    loop at it_filter_select_options into ls_filter.
      case ls_filter-property.
        when 'OBJECT'.
          read table ls_filter-select_options index 1 into ls_option.

          if sy-subrc = 0.
            ls_object_filter = ls_option-low.
          endif.
        WHEN 'SUBOBJECT'.
          read table ls_filter-select_options index 1 into ls_option.

          if sy-subrc = 0.
            ls_subobject_filter = ls_option-low.
          endif.
      endcase.
    endloop.

    CALL FUNCTION 'APPL_LOG_READ_DB'
      EXPORTING
        OBJECT             = ls_object_filter
        SUBOBJECT          = ls_subobject_filter
      IMPORTING
        NUMBER_OF_LOGS     = P_NUMBER_OF_LOGS
      TABLES
        HEADER_DATA        = P_HEADER_DATA_TAB
        HEADER_PARAMETERS  = P_HEADER_PARA_TAB
        MESSAGES           = P_MESSAGE_TAB
        MESSAGE_PARAMETERS = P_MESSAGE_PARA_TAB.

    LOOP AT P_MESSAGE_TAB INTO ls_message.
      data: lv_msgnr type t100-MSGNR.
      data: lv_text type t100-text.
      data: wa_t100 type t100.
      FIELD-SYMBOLS <fs_header> TYPE balhdr.

      CLEAR : lv_msgnr,lv_text.
      lv_msgnr = ls_message-msgno.
      CALL FUNCTION 'T100_SINGLE_READ'
        EXPORTING
          t100_sprsl = sy-langu
          t100_arbgb = ls_message-msgid
          t100_msgnr = lv_msgnr
        IMPORTING
          wt100      = wa_t100
        EXCEPTIONS
          not_found  = 1
          OTHERS     = 2.

      IF sy-subrc = 0.
        lv_text = wa_t100-text.
        REPLACE '&1' WITH ls_message-msgv1 INTO lv_text.
        REPLACE '&2' WITH ls_message-msgv2 INTO lv_text.
        REPLACE '&3' WITH ls_message-msgv3 INTO lv_text.
        CONDENSE lv_text." NO-GAPS.
      ENDIF.

      ls_entry-lognumber = ls_message-lognumber.
      ls_entry-text = lv_text.

      read table P_HEADER_DATA_TAB
        with key lognumber = ls_message-lognumber
        ASSIGNING <fs_header>.

      if sy-subrc = 0.
        ls_entry-object = <fs_header>-object.
        ls_entry-subobject = <fs_header>-subobject.
      endif.

      append ls_entry to et_entityset.
    ENDLOOP.
  endmethod.

Что мы тут натворили? Мы на входе смотрим на параметры из адресной строчки. Если указаны фильтры для объектов OBJECT или SUBOBJECT, то мы возвращаем лог только по указанным объектам.

В транзакции /IWFND/MAINT_SERVICE нажимаем кнопочку Add Service, выбираем Alias LOCAL, и добавляем наш сервис в каталог.

Если теперь выбрать сервис и внизу нажать на кнопочку SAP GateWay Client, то мы окажемся в клиенте, где можно потестировать работу сервиса.

В строке запроса пишем вот такой код: /sap/opu/odata/sap/ZLOGGER_SRV/LogEntrySet?$filter=OBJECT eq ‘/IWFND/’
Мы хотим получить все записи журнала по объекту /IWFND/.

В следующей заметке мы попробуем создать Unit-тесты для этого OData сервиса.