О разработке интерактивных приложений под ОС IBM i (aka AS/400)

    Здравствуйте, уважаемые читатели. Меня зовут Владимир Лебедев, я работаю в Альфа-Банке и занимаюсь тем, что пытаюсь максимально упростить жизнь разработчиков АБС Equation, занимающихся разработкой приложений под операционную систему IBM i.

    Сразу скажу, что литературный слог – точно не мой конек. Я больше про исследования и скрупулезное изучение технических возможностей, про поиск инженерных решений. Однако у нас в сообществе разработчиков IBMi в банке принято, что по итогам года выбираются законченные реализации, которыми мы делимся с читателями и за пределами Альфа-Банка. В этом году в их число попала и моя работа.

    Также скажу, что пытливый читатель не найдет в статье сногсшибательных прорывов и идей, которые кардинально меняют мир вокруг. Скорее, работу можно рискнуть сравнить с процессом доказательства теоремы Ферма. Известно, что Пьер Ферма еще в 1637 году сформулировал свою великую теорему. Почти четыре столетия ученые пытались расколоть этот орешек. Но удалось это сделать только в 1994 году Эндрю Уайлсу, а в 2016 году этот гениальный норвежец получил за дело своей жизни Абелевскую премию. Доказательство теоремы Ферма не несет за собой исключительной практической ценности или стремления к славе и успеху, но в процессе решения задачи были найдены интересные идеи, выросли целые поколения ученых.

    Мой скромный (но, похвалю себя =), честный и кропотливый) труд — он не про решения во фронтовом программном обеспечении Альфа-Банка. Хотя, надо признать, что мои коллеги здесь крайне преуспели, и банк занимает свое заслуженное место в рейтингах. Мой труд про исследования, которые являются неотъемлемой историей любого профессионального сообщества, стремящегося к саморазвитию на всех уровнях.

    Итак, начнем. ОС IBM i и ее предшественницы — aka AS/400 — известны тем, что все ее интерактивные приложения до сих пор работают через так называемый зеленый экран (green screen или GS). Выглядит это примерно так:


    Пример Green Screen-а

    Если вы разработчик под IBMi, то, несомненно, согласитесь, что разработка такого рода приложений вызывает неудобства (а, если прямо сказать, то большую головную боль и внутреннее раздражение). Даже для продвинутых разработчиков (особенно для них) привыкших к разработке современных пользовательских интерфейсов на базе веб-технологий.

    Надо признать, что при всем неудобстве интерактивные приложения с консольным GS до сих пор очень нужны многим зрелым, многолетним предприятиям. И Альфа-Банк не исключение. Такую «зеленую» картинку можно наблюдать на мониторе большинства сотрудников бэк-офиса. Green Screen для IBM i — это как SSH и SHELL для Unix-а. К слову, SSH и SHELL есть в IBM i. Но здесь вы попадаете в особый runtime, именуемый PASE, со своими правилами игры.

    Важно отметить, что платформа IBMi поддерживает 2 базовых программных модели – уже устаревшую OPM (Original Program Model) и активно развиваемую на данный момент ILE (Integrated Language Environment). Если кратко, то под программной моделью здесь понимается совокупность решений операционной системы по квотированию ресурсов, возможностям кросс-языковых реализаций и т.д. Но при всех преимуществах новой ILE-концепции эффективность рекомендуемых IBM-ом способов разработки Green Screens оставляет желать лучшего.

    Так как же разрабатываются интерактивные приложения IBM i?


    Я уже упомянул, что разработка интерактивных приложений под IBM i с использованием традиционных подходов — занятие не самое увлекательное. А уж детальный рассказ про эту разработку вызовет зевоту или бурное негодование среди видавших виды. Однако, я не могу опустить это описание, так как это важно для общего понимания проблематики. Насколько подробно следить за мыслью — решайте сами.

    Объекты, типы, подтипы


    Стоит обратить внимание, что IBMi является одной из самых ранних объектных операционных систем. В отличие от традиционных Unix/Windows, здесь нет файлов в обычном понимании. Система оперирует специализированными объектами разных по назначению типов – файлы (БД и интерфейсы I/O), программы (исполняемый код), профайлы (учетные записи) и т.д. Внутри этих объектов прячутся как сами данные (согласно назначению), так и все необходимые метаданные, позволяющие правильно интерпретировать объект и правильно им воспользоваться.

    Некоторые типы объектов имеют подтипы. Например, объект типа *FILE, подтипа PF – т.н. физический файл — инкапсулирует внутри себя все необходимое для работы с ним, как с таблицей БД. А тип *FILE c подтипом LF (логический файл) реализует индекс таблицы.
    Обратим внимание на важный для описываемой истории подтип объекта *FILE — дисплейный файл (DSPF). Его предназначение как раз в описании пользовательского интерфейса (терминальный green screen). Интерактивное взаимодействие программы и пользователя выполняется именно через этот объект.

    Форматы записи


    Основное содержимое дисплейного файла — форматы записи. Каждый такой формат записи определяет шаблон внешнего вида пользовательского экрана или его части. Т.е. типизирует поля (например, только для вывода или ввода/вывода, текст или число), фиксирует их размерность и расположение на экране.

    Поле — это наименьшая единица данных, которая распознается и обрабатывается системой управления данными. Форматы записи в дисплейных файлах определяются с помощью спецификации описания данных (DDS).

    Описание файла описывает данные на трех разных уровнях:

    1. Уровень поля
    2. Уровень записи
    3. Уровень файла

    Описание уровня поля позволяет дать системе подробные характеристики поля, такие как расположение на экране, допустимый тип данных, представление поля при операциях ввода и вывода, тип поля, возможность редактирования, выравнивание данных в поле и прочее.

    Запись — это упорядоченный набор из одного или нескольких полей. Описание уровня записи позволяет вам сказать системе, как выглядит конкретная запись или ее формат записи. Запись является минимальной единицей обмена данными между системой и прикладной программой, независимо от наличия полей.

    Описание уровня файла — это описание, которое применяется к файлу в целом. Для файла дисплея вы можете указать используемые форматы записи, дисплейную станцию, набор графических символов.

    Использование дисплейных файлов


    Формирование исходного файла дисплея осуществляется с помощью кодирования DDS.


    Пример дисплейного файла в редакторе SEU

    Да, печально, но дисплейный файл имеет только позиционную форму записи. Других форм на 2020-й год нет. Однако, давайте все же пройдем не самый увлекательный путь, которым ходили и в прошлом веке, чтобы двигаться дальше и искать пути решения.

    Пример примером, давайте рассмотрим задачку.

    Создадим дисплейный файл для некоторой программы WINDEMOR:

    1. программа принимает на вход два параметра
    2. если второй аргумент равен ‘A’, выводит окно с сообщением «Внештатная ситуация №1»
    3. если второй аргумент равен ‘B’, то выводит окно с сообщением «Внештатная ситуация №2»
    4. при любом другом аргументе выводит «Ошибка вызова».
    5. Окно можно закрыть клавишей F3. Нажатие любых других клавиш приводят к сообщению «Функциональная клавиша недопустима».
    6. В верхней рамке, окно должно содержать базовую информацию о модуле среды АБС Equation:
      <ИМЯ ПРОГРАММЫ> <ВЕРСИЯ> <ТЕКУЩАЯ БИЗНЕС-ДАТА>


    Пример окна с выводом сообщения

    Текст программы
      A*----------------------------------------------------------------
         A*              System Name - PUB400
         A*
         A*                File Name - WINDEMOD
         A*         File Description - Демонстрация работы с окном
         A*                File Type - Display
         A*L                   Level - 100
         A*
         A*            Creation Date - 2020/02/25
         A*      Last Amendment Date - 2020/02/25
         A*----------------------------------------------------------------
         A*   Change Control
         A*   ~~~~~~~~~~~~~~
         A*   Date            Initials      Amendment
         A*   ~~~~            ~~~~~~~~      ~~~~~~~~~
         A*   2020/02/25      USRXXX        Создано
         A*
         A*----------------------------------------------------------------
         A*   Purpose
         A*   ~~~~~~
         A*   Демонстрация работы с экраном
         A*----------------------------------------------------------------
         A*   Indicators
         A*   ~~~~~~~~~~
         A*   Number    Description
         A*   ~~~~~~    ~~~~~~~~~~~
         A*   01-04     Attribute control indicators (message to display)
         A*   10-13     External account number indicators
         A*      71     Modify data tag
         A*      73     Errors to display
         A*      74     Warnings to display
         A*      76     Protect branch
         A*      83     Load message subfile
         A*      90     Keyboard key pressed
         A*      91     Rollup
         A*      92     Rolldown
         A*      93     Help key pressed
         A*      94     Home key pressed
         A*      95     Clear key pressed
         A*----------------------------------------------------------------
         A                                      DSPSIZ(24 80 *DS3)
         A                                      REF(*LIBL/EQFREF)
         A                                      INDARA
         A                                      PRINT
         A                                      VLDCMDKEY(90)
         A                                      HOME(94)
         A                                      CLEAR(95)
         A                                      ALTHELP
         A                                      HELP
         A                                      CF02
         A                                      CF03
         A                                      CF04
         A                                      CF05
         A                                      CF06
         A                                      CF09
         A                                      CF10
         A                                      CF11
         A                                      CF12
         A                                      CF13
         A                                      CF14
         A                                      CF15
         A                                      CF16
         A                                      CF17
         A                                      CF18
         A                                      CF19
         A                                      CF20
         A                                      CF21
         A                                      CF22
         A                                      CF23
         A                                      CF24
         A*----------------------------------------------------------------
         A          R HEADER
         A                                      WINDOW(7 10 7 59)
         A                                      BLINK
         A                                      LOCK
         A            KAPPG7         7A  O  1  1COLOR(BLU)
         A            KAPLVL    R        O  1  9REFFLD(FPL)
         A                                      COLOR(BLU)
         A            ZLTITL    R        O  1 13REFFLD(ONM)
         A                                      DSPATR(HI)
         A            ZUDATE    R        O  1 49REFFLD(DAZ)
         A*
         A*----------------------------------------------------------------
         A          R WINDEMODA
         A                                      WINDOW(HEADER)
         A                                      CHANGE(84)
         A                                      RTNCSRLOC(&ZHRFMT &ZHFLD)
         A                                      BLINK
         A                                      INVITE
         A                                      OVERLAY
         A                                      PUTOVR
         A                                      RMVWDW
         A*
         A            ZHFLD         10A  H
         A            ZHRFMT        10A  H
         A  01N02                           3 15'Внештатная ситуация №1'
         A                                      DSPATR(HI)
         A N01N02                           3 17'Внештатная ситуация №2'
         A                                      DSPATR(HI)
         A N01 02                           3 24'Ошибка вызова'
         A                                      DSPATR(HI)
         A                                  6  1'F3=Выход'
         A                                      COLOR(BLU)
         A*
         A*----------------------------------------------------------------
         A          R OPTION
         A                                      CHANGE(84)
         A                                      BLINK
         A                                      LOCK
         A                                      OVERLAY
         A                                      PUTOVR
         A N83                                  ERASE(MSGSFL)
         A                                      WINDOW(HEADER)
         A            ZLCMD         58A  O  6  1COLOR(BLU)
         A                                      OVRDTA
         A*
         A*----------------------------------------------------------------
         A          R MSGSFL                    SFL SFLMSGRCD(06)
         A            FLDKEY                    SFLMSGKEY
         A            FLDPGM                    SFLPGMQ
         A*
         A*
         A          R MSGCTL                    SFLCTL(MSGSFL)
         A                                      WINDOW(HEADER)
         A                                      BLINK
         A                                      LOCK
         A                                      OVERLAY
         A                                      PUTOVR
         A                                      SFLDSP
         A                                      SFLINZ
         A  83                                  SFLEND
         A                                      SFLSIZ(0020)
         A                                      SFLPAG(0001)
         A            FLDPGM                    SFLPGMQ(10)
         A*
         A*----------------------------------------------------------------
         A          R CLEAN
         A                                      ASSUME
         A                                 24  2' '
    
    


    Функции-расширения


    В операционной системе существуют функции-расширения стандартного API для С/С++ или встроенные в языки инструкции, которые позволяют открывать дисплейные файлы и взаимодействовать с ними.

    Важно отметить, что строки «R HEADER», «R WINDEMODA», «R OPTION» и другие определяют то, что называется записью дисплейного файла, или по-другому Record-форматом. Этот формат определяет структуру буфера, через который будет происходить обмен данными между эмулятором терминала пользователя и программой, которая работает с «дисплейником».

    Если программе необходимо интерактивное взаимодействие с терминалом пользователя, то она должна записать в Record-формат, что хочет вывести в поля экрана (если программа ничего не хочет выводить на экран, ей все равно нужно записать пустые бланковые поля). После этого необходимо произвести чтение Record-формата, при этом управление передается операционной системе, которая выводит пользователю статическое содержимое (например, фраза «Внештатная ситуация №1» в позицию 3/15»).

    Под спойлером можете посмотреть код программы на языке IBM RPG, который демонстрирует работу с данным окном и реализует логику приложения.

    Текст программы
      /TITLE Демонстрация работы с окном
          *---------------------------------------------------------------------
          *              System Name - PUB400
          *
          *             Program Name - WINDEMOR
          *            Program Title - Демонстрация работы с окном
          *
          *L                   Level - 100
          *
          *            Creation Date - 25FEB20
          *      Last Amendment Date - 25FEB20
          *---------------------------------------------------------------------
          *P Purpose
          *P ~~~~~~~
          *P Демонстрация работы с окном
          *P
          *---------------------------------------------------------------------
          *H Change Control
          *H ~~~~~~~~~~~~~~
          *H Project     Programmer    Date         Level
          *H ~~~~~~~     ~~~~~~~~~~    ~~~~         ~~~~~
          *H WINDEMO     USERXXX       25FEB20       100
          *H  Создано
          *---------------------------------------------------------------------
          /COPY EQCPYLESRC,HSPEC
         H DFTNAME(WINDEMOR)                                                        WINDEMO
          *
          *---------------------------------------------------------------------
          *  FILES
          *---------------------------------------------------------------------
         FWINDEMOD  CF   E             WORKSTN INFSR(*PSSR) USROPN
          *
          *---------------------------------------------------------------------
          *  DATA STRUCTURES
          *---------------------------------------------------------------------
          *
         D @EM             S             37    DIM(20)
         D #Check1         S              1A
          *---------------------------------------------------------------------
          *  PRE-INITIALISED DATA STRUCTURES
          *---------------------------------------------------------------------
          *
          *  KAPROG data structure
         D KAPROG          DS
         D  MISYS                  1      6    INZ('MISYS ')
         D  KAPLVL                 8     10    INZ('100')
         D  KAPPGM                12     17
         D  KAPPG7                12     18
          *
          /COPY EQCPYLESRC,DSJOBE_A
          /COPY EQCPYLESRC,DSSYSE
          *
          /COPY EQCPYLESRC,DSEPMS
          /COPY EQCPYLESRC,DPGMDS                    Data structure for progra
          /COPY EQCPYLESRC,DMSGDS_A                  DS for dump message *
          *---------------------------------------------------------------------
          *  NAMED CONSTANTS
          *---------------------------------------------------------------------
          /COPY EQCPYLESRC,STDCNST                   Standard program constant
          *---------------------------------------------------------------------
          /COPY EQCPYLESRC,STDFLDS
          /COPY EQCPYLESRC,CMRINZS
          /COPY EQCPYLESRC,CMRMAIN
          /COPY EQCPYLESRC,CMRABRT
          /COPY EQCPYLESRC,CMRPSSR
         ?*---------------------------------------------------------------------
         ?*  C SPEC START
         ?*---------------------------------------------------------------------
         C     CSpecStart    TAG
          /COPY EQCPYLESRC,MAIN
          *
          *---------------------------------------------------------------------
          *  PARAMETER AND KEY LISTS
          *---------------------------------------------------------------------
          *
          *  Parameter lists
         C     *ENTRY        PLIST
         C                   PARM                    @Exit             1
         C                   PARM                    @Chk1             1            № сообщ. для вывода
          *=====================================================================
          *  MAINLINE
          *=====================================================================
         C                   MOVE      #NO           @Exit
         C                   If        %PARMS = 2
         C                   Eval      #Check1 = @Chk1
         C                   Else
         C                   Eval      #Check1 = *Blanks
         C                   EndIf
          *
          * Если #Check1 = 'A' => первое сообщение, #Check2 = 'B' => второе сообщение
          * иначе - сообщение об ошибке вызова
          *
         C                   If        #Check1 <> 'A' And #Check1 <> 'B'
         C* если неверный параметр, устанавливаем флаг завершения
         C                   MOVE      #YES          @Exit
         C                   EndIf
         C*
         C                   MOVE      #NO           #EOP              1
          *
         C                   IF        not %OPEN(WINDEMOD)
         C                   OPEN      WINDEMOD
         C                   ENDIF
         C                   Z-ADD     *ZERO         S3
         C                   EXSR      Z000
          *
         C                   DOW       #EOP = #NO
         C                   EXSR      B000
         C                   ENDDO
          *
          *  Return to caller
         C                   EXSR      C000
          *
         C                   RETURN
          *=====================================================================
          *  SUBROUTINES
          *=====================================================================
          *---------------------------------------------------------------------
         C     *INZSR        BEGSR
          /COPY EQCPYLESRC,INZSR
          *---------------------------------------------------------------------
          *
          *S Program initialization
          *
          *---------------------------------------------------------------------
          *
         C     *Dtaara       Define    DAJOBCTLE     DSJOBE
         C     *Dtaara       Define    DASYSCTL      DSSYSE
         C                   IN        *DTAARA
          *
         C                   MOVEL(P)  @PGMID        @PGM
         C                   MOVEL(P)  @PGMID        FLDPGM
         C                   MOVEL(P)  @PGMID        KAPPG7
          *
         C                   MOVE      $ZDATE        ZUDATE
          *
         C                   ENDSR
          /EJECT
          *---------------------------------------------------------------------
         C     B000          BEGSR
          *---------------------------------------------------------------------
          *
         C                   READ      WINDEMODA
          *
         C                   Z-ADD     *ZERO         S3
          *
         C                   MOVE      *BLANKS       #CMDKY            2
         C                   MOVE      '0'           #TAGNO            1
          *
         C     *IN90         CASEQ     *ON           B100
         C                   END
         C     #TAGNO        CABEQ     '2'           B000XT
          *
          *
    B001 C                   IF        #EOP = #NO
         C                   EXSR      Z000
    E001 C                   ENDIF
          *
         C     B000XT        ENDSR
          /EJECT
          *---------------------------------------------------------------------
         C     B100          BEGSR
          *---------------------------------------------------------------------
          *
    B001 C                   IF        *INKC = *ON
         C                   MOVEL(P)  '03'          #CMDKY
         C                   MOVE      #YES          #EOP
         C                   MOVE      '2'           #TAGNO
    E001 C                   ENDIF
          *
          *
         C                   MOVEL(P)  'KSM0807'     DSEPMS
         C                   EXSR      USA10R
          *
         C                   ENDSR
          /EJECT
          *---------------------------------------------------------------------
         C     Z000          BEGSR
          *---------------------------------------------------------------------
          *
          *  Write header format
         C                   WRITE     HEADER
          *
         C                   Z-ADD     *ZERO         S3
          *
         C                   MOVE      #YES          @CLRQ
         C                   CALLB     'UTM14C'
         C                   PARM                    @PGM             10
         C                   PARM                    @EM
         C                   PARM                    S3                2 0
         C                   PARM                    @CLRQ             1
          *
          *  Write detail format
    S001 C                   SELECT
    W001 C                   WHEN      #Check1 = 'A'
         C                   MOVE      *ON           *IN01
         C                   MOVE      *OFF          *IN02
    W001 C                   WHEN      #Check1 = 'B'
         C                   MOVE      *OFF          *IN01
         C                   MOVE      *OFF          *IN02
    B001 C                   OTHER
         C                   MOVE      *OFF          *IN01
         C                   MOVE      *ON           *IN02
    E001 C                   ENDSL
         C                   WRITE     WINDEMODA
          *
         C                   ENDSR
          /EJECT
          *---------------------------------------------------------------------
         C     C000          BEGSR
          *---------------------------------------------------------------------
          *
    B001 C                   IF        %OPEN(WINDEMOD)
         C                   CLOSE     WINDEMOD
    E001 C                   ENDIF
          *
         C                   RETURN
          *
         C                   ENDSR
          /EJECT
          *---------------------------------------------------------------------
         C     USA10R        BEGSR
          *---------------------------------------------------------------------
          *
         C                   MOVEL(P)  @ERM          @MSGID
         C                   MOVEL(P)  @PMALL        @MSGDA
          *
         C                   CALLB     'UTM02C'
         C                   PARM                    @MSGID            7
         C                   PARM                    @MSGDA           30
         C                   PARM                    @MSGDT          132
         C                   PARM                    @MSGSV            2 0
          *
    B001 C                   IF        S3 < 20
         C                   ADD       1             S3
         C                   EVAL      @EM(S3) = DSEPMS
    E001 C                   ENDIF
          *
         C                   MOVE      *BLANKS       DSEPMS
          *
         C                   ENDSR
         ?*
          /COPY EQCPYLESRC,PSSR_B
          *
          *---------------------------------------------------------------------
          * COMPILE TIME ARRAY DATA
          *---------------------------------------------------------------------
          *
    


    Итоги по DDS и недостатки


    DDS представляет широкие возможности по работе с экраном дисплея и взаимодействия с прикладной программой, реализуя возможности протокола обмена данными терминала 5250 для IBM i. Несмотря на то, что кодирование файлов дисплея является фактически стандартом для взаимодействия с экраном, этот способ, на мой взгляд, имеет и ряд недостатков:

    • Статическое определение атрибутов экрана (полей и записей) и, как следствие, невозможность динамического переопределения представления экрана.
    • DDS является позиционным языком, то есть атрибуты и ключевые слова вводятся в определенных позициях (как на перфокарте).
    • Сложность визуального восприятия и понимания исходных файлов.
    • DDS довольно сложен и непривычен для изучения, содержит большое количество ключевых слов.
    • DDS непривычен для большинства программистов, не знакомых с таким стилем кодирования.
    • Сложность создания нетривиальных экранных конструкций и реализации манипуляций с экраном, не предусмотренных DDS.

    Итак, мы с вами прошлись по головной боли. Посмотрели каких «милых позиционных монстров» разработчикам приходится, скрепя сердце, создавать для реализации даже простейших задач, при этом понимая, что к созданным изваяниям придется еще не раз возвращаться и вносить изменения по новым требованиям к задаче. Настало время осознать всю тяжесть темного прошлого и посмотреть в светлое будущее.

    Альтернатива стандарту


    Есть ли альтернатива DDS? Безусловно, есть. Внимание привлек интерфейс (API) менеджера динамического экрана (Dynamic Screen Manager — DSM), реализующий протокол потока данных терминала 5250 для IBM i.

    Давайте поподробнее и подотошнее познакомимся с ним. Далее разберемся, какие же выгоды можно извлечь по сравнению с DDS. Читать именно этот пункт подробно или нет — зависит от того, собираетесь ли вы использовать результаты или захотите погрузиться в реализацию.

    DSM API


    DSM API представляет собой набор экранных интерфейсов ввода/вывода, которые обеспечивают возможности динамического создания и управления экранами для языков программирования ILE. Поскольку DSM-интерфейсы являются связанными, они доступны только для ILE-программ.

    DSM API обеспечивает альтернативу существующему способу определения представления экрана вне программы посредством кодирования в DDS или UIM. Вместо этого программисты могут использовать в своих программах последовательность обращений к DSM для динамического определения и управления представлением экрана. В отличие от статических методов, интерфейс DSM обеспечивает приложениям, нуждающимся в более динамичном управлении экраном, необходимую гибкость.

    Поддержка, предоставляемая DSM, варьируется от низкоуровневых интерфейсов для непосредственных манипуляций с экраном до работы с окнами.

    DSM API состоит из следующих функциональных групп:

    1. Низкоуровневые сервисы (Low-level services), обеспечивают непосредственный интерфейс к командам потока данных 5250 для выполнения базовых операций экранного ввода/вывода и состоят из следующих функциональных групп:
      • Screen Manipulation and Query APIs, для осуществления запросов и манипулирования состоянием экрана.
      • Buffer Manipulation and Query APIs, для создания, опроса и манипулирования буферами ввода и команд, использующимися для взаимодействия с экраном.
      • Screen Input APIs, для чтения данных полей и другой информации с экрана.
      • Screen Output APIs, для определения полей и записи данных на экран.
    2. Window services, оконные сервисы, используемые для создания, удаления, перемещения и изменения размеров окон.
    3. Session services, сервисы сессии, обеспечивающие общий интерфейс прокрутки, который может использоваться для создания, опроса и манипулирования сессиями, для выполнения операций ввода и вывода с сессиями.

    Атрибуты


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

    В общем случае вывод информации на экран не отличается от других подобных устройств. Информация выводится блоками из одного или более символов цветом предшествующего ей атрибута. Атрибут определяет цвет всех выводимых за ним символов, пока не встретится следующий атрибут, и так далее. При отсутствии атрибутов применяется атрибут зеленого цвета. Каждый атрибут занимает одну позицию и на экране выглядит как пустая позиция (пробел).

    Например:



    X — символ
    R — атрибут красного цвета
    G — атрибут зеленого цвета
    B — атрибут синего цвета

    На экране это может выглядеть так:



    Ввод информации осуществляется с помощью полей ввода, создаваемых и обслуживаемых терминалом. Количество полей ввода ограничено, допускается одновременное существование не более 256 полей. Характеристиками полей (цветом лидирующего атрибута, длиной, типом и способом ввода данных, выравниванием и т.д.) можно управлять. Имеется набор клавиш перемещения внутри полей и между полями, а также набор клавиш завершения редактирования. Поля могут быть простыми и композитными, т.е. состоящими из нескольких простых полей и ведущими себя как одно целое. Поля предваряются лидирующим атрибутом, определяющим цвет поля, и завершаются атрибутом конца поля (всегда “зеленый на черном”).

    Так выглядят на экране поля ввода:



    Окна


    Если вы разработчик и собираетесь «залезть» в DSM, то при работе с DSM важно понимать структуру и порядок формирования окон, а также порядок вывода и отображения информации на экране. Невнимание к этому аспекту может привести к удивительным или даже весьма комичным ошибкам, которые легко устраняются, когда педантично все разложишь по полочкам.
    Окном является прямоугольная область экрана, не выходящая за его пределы. Положение и размеры окна определяются координатами левого верхнего угла окна и количеством строк и столбцов окна. Окно может иметь или не иметь рамку. В наличии могут быть не все элементы, составляющие окно.

    Окно может не иметь рамки, но если она есть, то возможно определение атрибутов рамки. Атрибуты рамки одинаковы и определяют ее цвет. Лидирующий атрибут окна определяет цвет символов, выводимых в окно. Правый атрибут завершения – это не жестко определенный атрибут, а признак необходимости расчета завершающего атрибута и место для его вывода на экран.


    Пример структуры окна


    Окно с атрибутами

    Так выглядит окно, созданное программой с учетом представленной структуры. Зеленое окно с синей рамкой на белом экране. Для наглядности выбраны инверсные цвета. Хочу напомнить, что символы имеют цвет, определяемый предваряющим их атрибутом. Цвет символов сохраняется, пока не встретится следующий атрибут. На этой картинке правый атрибут завершения окна во всех строках имеет значение “белый инверсный”. Таким образом восстанавливается цвет экрана.

    Наличие атрибутов обеспечивает правильное закрашивание рамки и информации в окне. Правильные цвета всех окон на экране обеспечивает программа управления окнами (терминал).
    В наличии могут быть не все элементы, составляющие окно. Каждый элемент, относящийся к окну занимает одну позицию экрана, как лидирующий или завершающий атрибут, или две позиции экрана, как рамка или атрибуты рамки. В случае наличия всех элементов окна его ширина не будет превышать ширины экрана минус 6 позиций, а высота – высоты экрана минус 2 позиции.


    Пример структуры окна без рамки и ее атрибутов


    Окно без атрибутов

    Терминал 5250 и DSM


    Терминал 5250 имеет блочно-ориентированную организацию потока данных, а атрибуты на экране располагаются отдельно от символов информации. К тому же терминал сам исполняет функцию менеджера окон, отслеживает их взаимное расположение, перемещение и обеспечивает правильное отображение элементов окон в соответствии с их иерархией.

    DSM в явном виде поддерживает все необходимые операции с экраном, хотя и довольно специфичен и непривычен в применении, что объясняется особенностями потока данных 5250. Первоначально была предпринята попытка максимально использовать возможности DSM в плане, касающемся оконных конструкций. Но это оказалось не лучшим вариантом, поскольку система управления окнами, восстановления содержимого окон и экрана была не самой удобной и не обеспечивала необходимых требований к визуальному восприятию, иногда передаче подлежал излишне большой объем информации, что в конце концов сказывалось на удобстве использования и быстроте программы. В то же время попытка реализации экранных окон своими силами показала неплохие результаты в плане быстродействия и удобства работы. В этом направлении и было принято решение двигаться далее.

    Безусловно, базовые вопросы взаимодействия с терминалом 5250 никуда не делись и лежат в основе нашей разработки. Основными особенностями работы при этом является блочно-ориентированное взаимодействие с терминалом и наличие высоких функциональных возможностей последнего. Можно сказать, что терминал выполняет роль полноценного менеджера экрана, а DSM – обертки над протоколом обмена данными, скрывающей детали его реализации

    ASDU для 5250. Решение или приговор?


    Так получилось, что к моменту исследования у меня был достаточно богатый положительный опыт использования библиотеки CURSES. Этот опыт был для проекта Enterprise-уровня. Я взял на себя смелость посмотреть, насколько прежние мысли ложатся на требования, возможности и ограничения, предъявляемые со стороны DSM.

    Кроме того, библиотека CURSES в UNIX-системах фактически является стандартом текстового ввода/вывода, и было принято решение попытаться использовать имеющийся опыт для написания функционала ввода/вывода для терминала 5250.

    Снова погрузимся в теорию и терминологию. А куда без нее?

    Элементы


    Элементы, составляющие окно в нашей системе, не отличаются от аналогичных в терминале. При этом возможно создание следующих экранных конструкций:

    • WIN – Прямоугольная область экрана, не превышающая его размеров, в которую возможен вывод данных, и с которой могут быть связаны поля ввода терминала. Фактически окно отражает область памяти, соответствующую его координатам на экране.
    • SUBWIN – Прямоугольная область экрана, не выходящая за пределы окна (WIN) и разделяющая с ним одну и ту же область памяти. Использование SUBWIN бывает очень удобно при осуществлении сегментации окна (WIN).
    • PAD – Область памяти, не имеющая привязки к окну или экрану, и способная отличаться от них по размерам в любую сторону. Синхронизация PAD и экрана может осуществляться отдельной командой. В остальном поведении PAD аналогичен окну WIN.
    • SUBPAD – Структура, которая разделяет одну и ту же область памяти с PAD и не может превышать его по размерам. Аналогична SUBWIN, но для PAD.

    Структуры


    И если окна (WIN, SUBWIN) проецируются в содержащую их структуру целиком, то проекция PADа зависит от соотношения его размеров и внешней структуры. В случае, например, когда PAD больше экрана, на экран проецируется только часть PADа.



    Основные конструкции


    На базе структур созданы предопределенные конструкции:

    • STDSCR – Имитирует всю область экрана, лежащую на самом нижнем уровне иерархии окон.
    • NEWSCR – Виртуальный экран, содержащий в себе содержимое всех окон и STDSCR, для которых была выполнена операция обновления. Порядок обновления окон при выполнении этой операции будет определять содержимое экрана NEWSCR.
    • CURSCR – Виртуальный экран, предположительно соответствующий физическому экрану терминала после выполнения операции обновления.
    • STDSCR доступен для всех оконных операций, в то время, как использование NEWSCR и CURSCR носит, скорее, служебный характер.

    Операции с окнами


    Определены следующие операции с окнами:

    • создание, удаление, изменение размеров, перемещение, обновление.
    • копирование областей окон.
    • определение областей прокрутки, прокрутка содержимого окна.
    • вывод данных в окно и получение данных из окна.
    • удаление и вставка строк в окно.
    • получение информации о курсоре и управление положением курсора в окне.
    • получение характеристик окна и управление ими.



    Особенности ввода данных


    Ввод данных обеспечивается терминалом. Это связано с тем, что эта функциональность реализована терминалом, и подавляющая часть клавиш недоступна для иного использования, кроме как для ввода информации в поля ввода терминала. Информация, введенная в поля ввода, становится доступной только по завершении редактирования. Таким образом идеология вывода информации в значительной степени базируется на идеях библиотеки CURSES, в то время как ввод обеспечивается исключительно терминалом. Эта ситуация порождает некоторые особенности синхронизации данных между прикладной программой и терминалом, к тому же переносит акцент в организации управления экраном и вывода данных в прикладную задачу.



    Поля ввода на экране терминала создаются с помощью API DSM и инициализируются значениями с виртуального экрана.

    Данные, введенные в поля ввода с клавиатуры, не отображаются ни в одном окне, а, следовательно, и в виртуальном экране программы. Поэтому необходимо прочитать введенную информацию, учесть ее изменения в программе, модифицировать переменные и отобразить ее в виртуальном экране программы, чтобы его содержимое совпало с экраном терминала.

    Фигуры с выделенным красным цветом контуром отображают синхронизированные состояния терминала и виртуального экрана.



    Создание FRAME


    Для учета иерархии окон и более удобного управления ими была создана структура FRAME.

    В своем составе FRAME имеет окна WIN и SUBWIN и, возможно, PAD. Окна разделяют одну и ту же область памяти, но SUBWIN меньше на величину рамки и сопутствующих элементов. Фактически это изолированная область вывода. Фреймы же поддерживают иерархию окон и позволяют обновлять их в нужном порядке, что обеспечивает целостность результирующего экрана. Кроме того, осуществляется надзор за атрибутами всей выводимой на экран информации с учетом иерархии окон. Каждый фрейм характеризуется наличием или отсутствием рамки, ее формой, строки заголовка и сноски, атрибутами (цветами элементов). В дополнение к операциям с окнами, фрейм позволяет работать с иерархией окон, перемещать окна в ней, делать их невидимыми и наоборот.

    Вывод информации в окна осуществляется с некоторой оптимизацией, с отметкой измененных символов, чтобы в дальнейшем уменьшить объем передаваемых данных.

    Вывод информации в эти оконные конструкции не приводит к изменению состояния экрана до вызова команды синхронизации содержимого окна и виртуального экрана и команды обновления физического экрана терминала. Фактически работа строится на предположении, что виртуальный и физический экраны соответствуют друг другу, и на мерах по обеспечению этого.

    Поля ввода, управляемые терминалом, несколько выбиваются из этого порядка. Во-первых, поля ввода способны принимать данные не только с клавиатуры, но и с экрана. Это позволяет инициализировать их нужными значениями и изменять их содержимое при необходимости. Во-вторых, необходимо обеспечить синхронизацию полей ввода с соответствующими оконными структурами. Иначе возникает достаточно труднонаходимая неоднозначность. В связи с тем, что об окнах ASDU терминалу ничего не известно, а поля ввода создаются по определенным правилам и с заданными ограничениями (в частности, слева направо и сверху вниз, без возможности наложения), вопрос создания, удаления и изменения полей решается динамически при соответствующих изменениях окон. Так, при создании нескольких окон с полями ввода поля удаляются из нижележащего окна и создаются в окне, лежащем выше по стеку. Фактически в каждый момент времени существуют только те поля, которые относятся к последнему окну в иерархии. Поля, относящиеся к одному окну, объединяются в FIELD_SET, что позволяет в том числе и управлять ими одновременно и однообразно.

    Процесс вывода информации в окна и на виртуальные экраны подвергается оптимизации на каждом этапе. Поэтому, несмотря на возможно значительный объем выводимых данных, в итоге между прикладной программой и терминалом пересылаются довольно небольшие объемы, а фактически – только изменения экрана. Это подтвердила и трассировка обмена программы и терминала. К тому же, везде, где только можно, используются операции буферизации потока команд DSM. В частности, практически все команды от одного обновления экрана до другого пересылаются в одном буфере. Наблюдения показали, что это значительно увеличивает скорость обмена и реакции терминала.



    Появились новые возможности


    Функции управления окнами и их содержимым довольно просты и интуитивно понятны. По своему смыслу и синтаксису они близки к соответствующим функциям библиотеки CURSES в UNIX, за исключением функций ввода данных. Вот некоторые из функций работы с экраном:

    1. Создание окна определенного размера с заданными координатами: _Win_T(…)
    2. Получение координат курсора в окне: getcury, getcurx
    3. Получение координат и размеров окна: getbegy, getbegx, getmaxy, getmaxx
    4. Обновление окна: wrefresh, wnoutrefresh, prefresh, pnoutrefresh, doupdate
    5. Очистка окна или его части: wclrtobot, wclrtoeol, werase, wclear
    6. Прокрутка окна, удаление и вставка строк: wsetscrreg, wscrl, winsdelln
    7. Перемещение курсора: wmove
    8. Получение символов и строк из окна: winch, mvwinch, winnstr, mvwinnstr
    9. Вставка и удаление символов и строк: wdelch, mvwdelch, winsch, mvwinsch, winsnstr, mvwinsnstr
    10. Вывод символов и строк в окно: waddch, wechochar, mvwaddch, waddnstr, mvwaddnstr, wprintw, mvwprintw
    11. Копирование окон: copywin, overlay, overwrite
    12. Рисование бордюра, вертикальной и горизонтальной линии: wborder, wvline, mvwvline, whline, mvwhline
    13. Перемещение и изменение размеров окон: mvwin, wresize

    Разработанных базовых функций вполне достаточно для осуществления ввода информации с терминала и вывода информации на экран. Для удобства работы на их основе были реализованы более сложные конструкции, такие как окна вывода сообщений, разнообразные меню, формы ввода данных, табличный просмотр результатов выполнения SQL-запросов, подключена ли мышь.

    Теперь посмотрим, что же можно сделать с практической точки зрения. Будет также интересно сравнить «как было» и «как стало». Надеюсь, что следующий раздел будет интересен не только пытливому и цепкому взгляду опытного и погруженного в тему человеку.

    Примеры использования ASDU


    Теория закончилась. Давайте посмотрим на примеры реализации. Посмотрим, стало ли веселее и на правильном ли мы пути. Приведу несколько примеров использования библиотеки работы с экраном.

    Вот так выглядит программа, выводящая на стандартный экран строки разного цвета, и результат ее работы:



    Вместо «перфокарт»


    Под спойлером приведена программа, написанная на С++ с использованием ASDU, функционально аналогичная приведенной выше на языке RPG с использованием DDS.



    Программа
    int main(int argc, char **argv)
     {
        char *msg = "Ошибка вызова";
        // Описание рамки окна
        _Box_T box = { TRUE,  '.', '.', '.', ':', ':', '.', ':', ':', ':', '.', '+' };
    
        if(argc > 1) {
            if(*argv[1] == 'A') {
                msg = "Внештатная ситуация №1";
            } else if(*argv[1] == 'B') {
                msg = "Внештатная ситуация №2";
            }
        }
        _Screen_T       screen('3');                // Инициализация экрана. Режим 24x80
        // Вывод сообщения на стандартный экран
        STDSCR->mvwcenter(0, "%cПример программы, использующей%cASDU", QSN_SA_WHT, QSN_SA_RED);
    
        _FrameDesc_T    desc(&box);                 // Создание описания фрейма по умолчанию
    
        desc.set_leading_attr(QSN_SA_WHT);          // Установить лидирующий атрибут окна
        desc.set_cur_border_attr(QSN_SA_BLU);       // Установить цвет рамки текущего окна
    
        _Frame_T        frame(6, 9, 9, 63, &desc);  // Создать окно
        _Win_T         *subwin = frame.sub();       // Получить указатель на область вывода
    
        frame.set_color(0, QSN_SA_BLU);             // Установить цвет строки 0
        subwin->mvwprintw(0, 0, "WINDEMO 100");     // Вывести наименование программы
    
        subwin->mvwprintw(0, subwin->getmaxx()-12, "%c18 ЯНВ 2019", QSN_SA_NORM);
    
        subwin->mvwcenter(2, "%s", msg);            // Вывести сообщение по центру строки 2
    
        frame.set_color(subwin->getmaxy()-2, QSN_SA_BLU);       // Установить цвет строки
        subwin->mvwprintw(subwin->getmaxy()-2, 0, "F3=Выход");  // Вывести сообщение
    
        for(;;) {
            subwin->wmove(0, 0);        // Установить курсор в координаты (0, 0) области вывода окна
            frame.refresh();            // Обновить экран при необходимости
    
            switch(subwin->wgetch()) {  // Получить код нажатой клавиши
    
                case QSN_F3:            // F3 - выход
                    break;
    
                case QSN_ENTER:         // ENTER - стереть сообщение об ошибке в последней строке
                    subwin->wmove(subwin->getmaxy()-1, 0);
                    subwin->wclrtoeol();
                    continue;
    
                default:                // Вывести сообщение об ошибке в последней строке
                    subwin->mvwprintw(subwin->getmaxy()-1, 0, "Функциональная клавиша недопустима.");
                    continue;
            }
            break;
        }
        // Завершение программы
        return 0;
     }
    


    Если сравнить со статическим позиционным монстром, листинг которого я приводил в начале статьи, то здесь уже что-то управляемое и «живое». Конечно же, это все требует дальнейшей обертки. Важно отметить, что обертка здесь уже имеет право на существование, чего в статике не сделаешь. Таким образом, ASDU-собрат неплохо начинает себя показывать.

    Массив строк


    Реализацию этой и следующей задачи для статики можно записать в «unreal». Наверное, если пойти на принцип, то можно исхитриться, однако, стандарт явно не для таких задач.
    Просмотр массива строк с возможностью поиска и выделения цветом найденных фрагментов.



    Область отображения и вертикальной прокрутки может быть меньше размеров окна, что позволяет выводить дополнительную информацию. На слайде это текст TITLE и FOOTER. Возможна горизонтальная прокрутка, если ширина строк превышает ширину окна.

    Массив строк с прокруткой


    Просмотр массива строк с выделением текущей строки, вертикальной, горизонтальной прокруткой и возможностью организации меню.



    SQL-процессор?


    Если предыдущие два примера простейшие и вряд ли из-за них, как говорится, стоило огород городить, то теперь мы с вами заденем конкретику, которой не было в стандартном подходе в принципе. С ASDU в «зеленом экране», например, появляется возможность вывода результата произвольного SQL-запроса на экран. А если можем вывести и подсветить отдельные строки, то можно прикрутить и редактирование, удаление, маркировку, удобную фильтрацию и прочее.

    Напомню, ранее это было принципиально невозможно. Сейчас же на базе ASDU логично сделать SQL-процессор, которого нет по умолчанию. Мои коллеги сделали такой SQL-процессор и, возможно, это будет темой для одной из статей.

    Давайте посмотрим на экраны и описания функциональности в том виде, как у меня получилось передать словами и скриншотами.

    Произвольный SQL-запрос


    Реализация просмотра результатов выполнения произвольного SQL-запроса:

    1. Окно просмотра содержит горизонтальные секции, каждая из которых имеет свой источник данных. На скриншоте показано 5 секций. Секция заголовков, горизонтальных разделителей, данных, еще одна секция разделителей и секция сносок.
    2. Для каждой секции указывается количество строк экрана для отображения одной записи и количество отображаемых записей. Одна секция может быть расширяемой, то есть занимать все доступное от остальных секций пространство окна.
    3. Источники данных должны удовлетворять определенным требованиям. Должна быть обеспечена возможность получения количества полей, их размеров и содержимого, позиционирования на нужную запись.
    4. Все секции обеспечивают одинаковую и независимую друг от друга функциональность, то есть. фиксацию столбцов, скроллинг, фильтрацию, поиск, перемещение по записям и прочее. Команды управления секциями можно подавать в произвольном порядке.
    5. Все секции равноправны и могут иметь разную ширину столбцов и разное количество полей отображения, а также разное количество строк. Фактически каждая секция – это самостоятельная реализация просмотра, связанная с определенным источником данных.
    6. Данные в ячейках могут быть преобразованы при необходимости. Есть возможность использования callback-функций для любых полей, что позволяет применять нестандартные механизмы фильтрации данных и преобразовывать содержимое полей для отображения.
    7. Есть возможность выделять определенным цветом строки и столбцы, а также отдельные ячейки в зависимости от произвольных условий.
    8. Есть возможность фильтрации записей и их поиска с помощью указания метасимволов или по точному совпадению. Информация в ячейках может выравниваться в различных направлениях по горизонтали и вертикали.
    9. Рамка и символы-разделители между столбцами могут отсутствовать.
    10. Ширина всех отображаемых полей может превышать горизонтальные размеры экрана. В этом случае будет использована горизонтальная прокрутка. Левые поля таблицы просмотра могут быть зафиксированы и, таким образом, исключены из горизонтальной прокрутки.

    Просмотр результатов выполнения SQL-запроса с возможностью редактирования некоторых полей текущей строки


    Каждая запись секции данных занимает 3 строки экрана. Для включения режима редактирования необходимо указание уникальных ключевых полей.

    Редактироваться могут поля текущей строки которые не подвержены горизонтальной прокрутке и полностью помещаются в ячейке. Измененные значения полей сохраняются в памяти до момента их использования. Данные в ячейках могут быть приведены к виду, необходимому для редактирования, с помощью callback-функций и провалидированы. Допустимо и обратное преобразование – от редактирования к просмотру. Для данных, занимающих более одной строки, создаются композитные поля.

    Есть возможность фильтрации записей и их поиска с помощью указания метасимволов или по точному совпадению. При этом фильтрация осуществляется по первоначальной информации, а поиск – по вновь введенной.



    Возможно и редактирование информации в нескольких секциях одновременно.



    Просмотр SQL-запроса с возможностью редактирования некоторых полей


    Этот режим аналогичен предыдущему, за исключением того, что возможно редактирование выбранных полей всех строк экрана. Возможно, в некоторых простых ситуациях такое табличное редактирование полей может быть уместно.



    Да-да, эти примеры работают. Повторюсь, что они не придут на смену современным фреймворкам, например, по созданию web-приложений. Более того, кто-то из читателей моего труда по-прежнему останется при мнении о «потерянном зря времени» и предложит простые понятные (и, возможно, не совсем верные =)) пути решения подобного рода задач. Буду рад и благодарен прочесть аргументированные конструктивные комментарии.

    При этом стоит отметить, что эти примеры активно и успешно заменяют ранее принятые в банке подходы к реализации приложений на «зеленом экране», войдя в число наших стандартов и в состав программного обеспечения (наряду с тем, про что писал мой коллега в прошлом году aka AS/400), получившего Роспатент. Также мне приятно осознавать, что результаты муторных исследований и кропотливого труда используются не только в Альфа-Банке.

    Идем дальше. Впереди осталось положенное подведение итогов, литература и прочие стандартные атрибуты повествования.

    Планы


    В планах более полное использование возможностей потока данных 5250:

    1. Попытаться вернуться к использованию windows services и session services.
    2. Расширенные атрибуты (Write Extended Attribute Order). Возможность использовать одну позицию экрана для вывода символа и атрибута.
    3. Всплывающие меню (pop-up menus)
    4. Графические элементы оформления
    5. Поля выбора (selection fields)
    6. Поля прокрутки (scrollbar fields)
    7. Возможности выравнивания и форматирования полей ввода

    Выводы


    У прочитавшего статью все еще может возникнуть справедливый вопрос «И что?». Очень хочется понимать практический эффект от такого рода исследований.

    Во-первых, возможность использования приведенных здесь наработок нашла живой отклик в сердцах бизнес-пользователей. Конечно, не будем преувеличивать и ожидать, что пользователи смогли оценить именно инженерную составляющую. Они оценили удобство работы, которое было предложено взамен стандартных возможностей «от производителя», а также скорость вносимых изменений. А Time-2-Market это наше, если не все, то многое.

    Во-вторых, мы уже не первый год видим пользу от системного подхода к работе. В этом контексте это про работу коллектива разработчиков. Коллектив занимается не только кодированием, но и вкладывается в подробное фокусное изучение смежных областей. Это дает свои плоды иногда даже там, где изначально не ожидали. Однако, не зря говорят, что «везет тому, кто везет». Например, проделанная работа предоставила расширенные возможности по использованию роботов в автотестировании приложений, а это уже не только инженерная история, но и прямая и заметная экономия на затратах на тестирование приложений. Но это уже тема отдельной статьи.

    И, наконец, повторюсь, что очень важно в современном мире: получилось не просто решить исследовательско-инженерную задачу, но и получить довольных бизнес-пользователей. А это значит, что продолжение следует.

    Спасибо, что дочитали до конца.

    Всем интересных задач и успехов в их разрешении.

    P.S. В декабре 2019 года состоялась очередная Конференция разработчиков IBMi, где в том числе был сделан доклад на тему этой статьи.

    Конференция разработчиков IBMi – это первая и единственная в России площадка для общения разработчиков на одноименной платформе. Здесь можно расширить круг своего профессионального общения, принести на всеобщее внимание свой кейс и пообщаться с коллегами. В этом году Конференция состоится 2-4 декабря. Читайте наши статьи, оставляйте комментарии.

    Используемая документация


    1. Dynamic screen manager APIs (sc41-5606-00)
    2. IBM 5250 Information Display System Functions Reference Manual (sa21-9247-00)
    3. 5494 Remote Control Unit Functions Reference (sc30-3533-00)
    4. Application Display Programming (sc41-5715-00)
    5. DDS Reference (sc41-5712-00)
    6. Programming DDS for Display files
    7. Programming DDS Concepts
    8. IBM System i (aka AS/400) — Как мы делали автотесты приложений зеленого экрана
    Альфа-Банк
    Компания

    Комментарии 28

      +1
      По-моему, на предыдущем, митапе 18-го года обсуждал с кем-то из ваших АСОД.

      На мой взгляд — натягивание совы на глобус.

      1. Нотация АСОД ничуть не понятнее DDS.
      2. Работа с АСОД подразумевает разработку на C++, в том время как >95% кода написано на RPG. И более половины задач (работающих с интерфейсом) — доработка уже существующего кода, а не разработка нового.
      3. Для работы с дисплейными и принтерными файлами в RDi если визуальный редактор, где можно сразу видеть как все это будет выглядеть на экране (и располагать/двигать поля на экране мышкой, а не высчитывая в уме позиции). И простейшие интерфейсы там делаются вообще без вникания в тонкости DDS. Для АСОД такого инструмента, насколько я знаю, нет.
      4. Возможности DDS достаточно широки. От простейших форм до управления цветом, видимостью, возможностью ввода в поля. Всплывающие окна, списки прокрутки, менюшки, выбор радиокнопками — все это есть в DDS. Там можно много чего делать — я делал автоматичекую подгрузку некоторых дополнительных значений с отображением из на экране по факту ввода данных в нужное поле без нажатия Enter (например — вводите ПИН клиента и сразу (без нажатия Enter) автоматически заполняются поля с его именем/названием и т.п
      5. Разработка с использованием DDS проще — на RPG не требуется писать никакого дополнительного кода для вывода на экран помимо READ/WRITE. Только логика работы с данными. В АСОД же код загромождает восприятие


      В общем, к идее АСОД лично я отношусь весьма скептически. При том, что С/С++ для меня «родной» язык (пишу на нем с конца 80-х, а на RPG начал писать только в банке в 17-м), но сама концепция DDS как единого средства описания данных (PF, LF, DSPF, PRTF) мне видится вполне разумной и достаточной для выполнения текущих задач. Но в эту концепцию надо вникнуть, разобраться с ней, а не убоявшись непонятных буков кидаться изобретать свой велосипед.

      Ну и пример программы можно было бы подобрать более удачный. На Fixed сейчас уже давно не пишем. Все новые скелетоны написаны на free и выглядят не столь устрашающе. :-)

      Про использование SQL отдельная тема. Не так давно була у меня задача на оптимизацию, где пришлось заменять SQL запросы (которые не удавалось параметризировать и которые тормозили тем, что перестраивались при каждом вызове) на «нативный RPG»

      Из PEX статистики работы XXXXXXXXX видно, что 33% времени и 36% ресурсов CPU тратится на выполнение QSQRPARS в программе YYYYYYY, т.е. парсинг статических выражений при подготовке SQL запроса,


      В результате отказа от SQL и перехода на «чистый RPG» время выполнения конкретного участка кода сократилось в три раза и нагрузка была довольна

      Рессурсовзатратность QSQRPARS уменьшилась до незначительных показателей.


      В «нефункциональных требованиях» этот вопрос обсуждался.
        +2
        Не соглашусь с Вами.

        Во-первых, АСОД это «собирательное понятие» и оно намного больше чем интерфейс. UI — лишь небольшая его часть. Не стоит обобщать.

        Во-вторых, почему наличие большого объема кода на RPG должно останавливать от создания кода на плюсах. Особенно под ILE, где можно вызывать функции из модулей на разных языках без особых проблем. К тому же Вы сами знаете, что RPG — процедурный язык со всеми вытекающими «процедурными» проблемами и отсутствием ООП. В добавок, иногда IBM полна сюрпризов. К примеру, недавно вышел для 7.3 PTF SI73189 для поддержки %Timestamp с микросекундами. Теперь, если собрать программу на машине с этим PTF и развернуть на машине, где его еще не поставили обновление — получите MCH4437 Program import not found. Лично я начинаю переживать за стабильность софта RPG под вендорским runtime-ом.

        В-третьих, в статье продемонстрирована только низкоуровневая работа с UI-подсистемой. Никто не пишет экраны на чистых плюсах. Для этого есть язык DPL, который позволяет декларативно описать и нарисовать форму. Тут не нужна IDE на старом Eclipse чтобы пододвинуть поле, достаточно простого текстового редактора (я использую Sublime Text 3 + подсветка). Все «некрасивые» конструкции спрятаны внутри, никакого кода кроме прочитай вон ту форму и .Do() писать не надо. И в дополнение, можно указать бизнес-смысл поля, например, счет или клиент. Все валидации работают «из коробки».

        В-четвертых, возможности DDS конечно впечатляют, не просто так мануал составляет более 1000 листов. Но DDS больше не развивается. За последние 10 лет в нем не было никаких изменений. Он так и останется позиционным, хотя это дело привычки. Кроме того, его конструкции для использования продвинутых элементов управления не такие уж и простые, и уж точно немаленькие по размеру. В DDS ярко выражена идея MVC, они же примерно ровесники, и мне тоже нравится идея выделения отдельной структуры record format-а для передачи данных между компонентами. Но в реализации для DDS она статична и требует пересборки всего связанного при изменении. Любое изменение — перекомпилируй программу, перекомпилируй DDS. И еще, динамическая работа с полями — это практически невыносимое занятие. Дикое ограничение в 2020-м году.

        В описанном решении таких ограничений нет. Библиотеки были созданы для динамики. Динамические формы, динамические record-форматы…

        К тому же, пример с SQL немного не в тему. Воспринимается как рекомендация, что SQL — это плохо и использовать его не стоит.
        Повышенный CPU с QSQRPARS означает, что постоянно проверяется синтаксис SQL-запроса. Видимо это динамический запрос, который постоянно менялся. Зациклите API QSQCHKS и будет то же самое. Возможно есть баг у IBM, вы не задавали вопрос о проблеме на midrange?

        Сомневаюсь, что такие запросы появляются часто. Переезд в 2020-м году с SQL на ручное управление путями доступа к данным — это возвращение в прошлый век. Хотелось бы разбираться в причинах такого поведения. Не факт, что при следующем аудите производительности IBM не скажет на разработанный RPG-кусок: выбросите прямой доступ и перейдите на SQL, все будет работать быстрее.

        Если говорить про пример в статье, то для UI-подсистемы SQL — это просто адаптер над данными. Реализуя специальный интерфейс, можно написать запрос и на прямом доступе, если попали в такую ситуацию, что другого решения не видно.
          0
          Ну, начнем с того, что ООП не самоцель и уж точно не панацея. Сейчас оно уже не так модно как в конце 90-х.

          Так что упирать на то, что АСОД хорошо потому что ООП я бы точно не стал (при всем моем уважении к ООП в целом С++ в частности и более 25-ти лет опыта писании на оном).

          И, как практикующий (команда ядровых функций, сейчас в группе комплаенса) разработчик (кстати, ради интереса попробовал АСОД и какую-то несложную опцию на нем таки сделал) я могу уверенно сказать, что для наших конкретных задач он не дает никаких ощутимых преимуществ. А отсутствие визуального редактора форм — это вообще жирный минус когда приходится делать что-то сложное (ну, скажем, то же «структурированное место рождения» — 9 битком набитых экранов).

          Что касается необходимости перекомпиляции при изменении экранки — это особенности наших скелетонов. Никак на связано с дисплейниками. Там проблема в том, что для обмена информацией между модулями опции (MR-VR-UR-RR) используются автогенерируемые экранные структуры. У меня есть опции, где этого нет — обмен идет GZ структурами (так получилось, что сначала там делался внешний ввод, а потом уже к нему дописывался интерактив). И там можно сколько угодно менять дисплейник, пересобрать придется только MR модуль. Что не является проблемой от слова совсем.

          Уж если хочется изобресть, то скорее интереснее вот это:

          image
          www.jbcs.nl/products/j42aa.shtml

          Ну и все равно все упирается в конечный вопрос — кто у нас будет разрабатывать опции на АСОД? Я вот работаю в команде ядровых функций (т.е. самый что ни на есть backend). 99.99% приходящего на доработку кода — RPG. Разработчиков, способных писать на С++ очень немного (есть, но даже не половина). Т.е. для разработки и поддержки все равно будет использоваться RPG. С/С++ используется для низкоуровневых сервисов там, где его применение оправдано удобством и скоростью разработки.

          Если разрабатывать некоторую систему с нуля — наверное есть шансы. Заменить все наработанное — зачем?
            0
            По поводу SQL отдельно.

            Там проблема была в том, что запросы, содержашие IN (...) не параметризуются (для них нельзя вынести в *INZSR Prepare/Declare. Т.е. строка запроса строится на лету и каждый раз перед исполнением строится план заново. Что приводит к повышенной нагрузке.

            Прямой доступ 100% предсказуем и управляем. Для сложных запросов — да, муторно. Но там, где он вызывается десятки и сотни раз в секунду (а функции, скажем, проверки клиента по спискам террористов-экстремистов дергаются ох как часто и очень много откуда) требования к эффективности очень высокие. И у нас таких функций очень много. Репликаторы JMON, обработчики HMQ… Тут приходится сильно думать за эффективность кода и о том как он будет работать. И многие наши разработки идут на бой только через нагрузочное тестирование.
          +2

          А что заставляет банки в РФ использовать подобное legacy? Я понимаю, что в США это обусловлено тем, что автоматизация там началась 50 лет назад. А у нас это только 90-е годы (собственно когда и появились коммерческие банки).

            0
            А что в этом плохого? Оно работает. Хорошая производительность, высокая надежность. Реальное время (все операции совершаются круглосуточно, а не «с 4-х утра до полуночи»).

            На самом деле, все это спрятано внутри. Внешний (пользовательский) интерфейс может быть каким угодно — через WS можно подключить любую морду.

            Терминал — это для разработчиков и поддержки по большей части. Ну кто-то из бизнеса работает в нем, но далеко не все.

            Могу уверенно сказать, что на уровне ядра АСОД не используется. Пробовали ради интереса, но плюсов для себя не нашли. Таких, чтобы тратить время на перестройку рабочего процесса и стандартов разработки.
              0

              Это у банка-то высокая производительность? А почему рублевый перевод из Альфы в Сбер идет сутки? И валютный (внутри!) Альфы тоже быстрее суток не проходит? Я конечно понимаю, что тут скорее всего человеческий фактор, но зачем тогда говорить про требование высокой производительности для такой системы? С точки зрения пользователя от замены клерков на компьютеры скорость работы банка не поменялась.


              Я принимал участие во многих highload проектах и что-то мэйнфреймов там не наблюдал.

                0
                А почему проблема именно в Альфе?

                Мой опыт переводов (все рублевые)

                С2С Сбер — Альфа. Практически сразу
                С2С СКБ — Альфа. Практически сразу
                С2С Альфа — Сбер — в течении суток

                Между клиентами по номеру телефона или счета
                Альфа — практически сразу вне зависимости от того, в одном городе клиенты или в разных
                Сбер — практически сразу в пределах города и в течении суток если между городами (Екб-СПб, например).

                Со счета в ВТБ на счет в Сбер перевод шел вообще дня три…

                А вот еще ситуация, с которой я сталкивался в одном банке. Есть счет и привязанная к нему карта. Остаток по карте и остаток по счету технически разные вещи. Так вот в том банке было так — если к счету привязаны две карты и на счете лежит, допустим, 10тр, то можно сначала по одной карте потратить 7тр, а потом по другой еще 5тр. Потому что остатки на счете и карте выравнивались только на следующий день. А то и через день. В такой ситуации в момент синхронизации остатков получался технический овердрафт на -2тр.

                В Альфе такого быть в принципе не может — там сихнронизация проходит максимум в течении минуты, а реально за несколько секунд.

                Еще в рекламе одного из банков было «все операции проводятся с 4-х утра до полуночи». Потому что с полуночи до 4-х утра издет переход на следующий банковский день (End-Of-Day — EOD) в это время все операции кешируются и не выполняются, они проведутся уже следующим днем.

                В Альфе этого нет. Там все операции идут и во время EOD в режиме реального времени. Это достаочно геморройно для разработчиков (юнит ночного ввода, накат из ночи в новый день и т.п.) Но это работает.

                Я не знаю что такое hiload. Видимо, что-то из разряда realtime. Некое качественное понятие, характеризующее внутреннее устройство системы. Те, кто релаьно работает с реалтаймом, оперируют количественными понятиями — гарантированное время отклика системы. Думаю с hiload что-то подобное.

                Так вот. Только таблица клиентов в Альфе — несколько десятков миллионов записей. А каждая запись в таблице клиентов тянет за собой еще кучу клиентских данных (карточки клиентов, счета, карты и еще много чего...) Итого нагрузка на систему по оценкам составляет (в обычном режиме) порядка 3млрд изменений БД в сутки. Это только изменений. Обращений к БД на чтение там как минимум на порядок больше. С таким hiload работали?

                  0

                  Highload это например Google, Yandex, Skype, WhatsApp.
                  Я около 8 лет назад делал часть backend'а Skype и там пользователей было больше миллиарда. Кластер из обычных серверов с postgresql вполне справлялся. Не знаю, сколько информации нужно на одного клиента (допустим 1кб), то на 1e7 клиентов это 10ГБ. Можно в памяти прокешировать. 3e9 изменений ~ 300 транзакций в среднем на клиента в сутки? Ну я так часто в магазин не хожу :-)


                  А по поводу Альфа-банка — быстро работают только рублевые платежи у физлиц. Валютный перевод (любой) или конвертация у юрлица — только по рабочим дням и медленно.

                    0
                    Там зависит какие операции. Если только отдавать контент, у вас хорошо все горизонтально масштабируется, актуальность не критична — то проблем нет.
                    В банках же идет суровый OLTP и деньги. Там так просто на кластер не переведешь.
                    Конечно, это возможно все перевести на PG и т.п. и большинство шопов или уже перевели, или в процессе или задумываются. Но процесс не быстрый и дорогой.
                    Почему Альфа упорно держится за i… Была хорошая статья по теме, не могу сейчас найти. Там смысл в психологии менеджмента. Менеджерам спокойнее продолжать платить IBM ежегодно предсказуемую сумму (стоимость владения i относительно невелика), чем рисковать затевать миграцию где сразу нужны большие затраты и успех не гарантирован. В больших инертных организациях менеджмент крайне консервативен в данном вопросе. Пока какой-то внешний фактор явно не припрет (типа санкции), никто ответственность на себя брать не будет.
                    С точки зрения технической, конечно, открытые технологии и стандарты дают гораздо более высокий уровень гибкости и являются предпочтительными.
                      0
                      Тут ключевой вопрос — надежность и стабильность. Сама по себе гибкость никуда не уперлась ибо есть огромное количество уже работающего кода и весь он написан по определенному стандарту и весь последующий код будет писаться по этому же стандарту просто с точки зрения просто ты его дальнейшей поддержки и доработки.

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

                      Вполне, кстати, реальная ситуация — в конце прошлого года попала такая задачка. Но там полный п. был. ТЗ толком нет — обрывочные «записки на манжетах», разработчик был человек сильно творческий и уволился. Аналитик тоже уволился. В общем, консультант направления мне просто на пальцах объяснял как это должно работать, а я пытался соотнести все это с кодом и привести все в порядок.

                      Потому я и возражаю против описанного в статье АСОД. Не потому что плохая идея. Идея хорошая. Если все писать с нуля, я бы пошел примерно тем же путем почти наверняка.
                      И дисплейные сессии вещь хорошая и полезная. Когда все на них сделано.

                      Но сейчас в банке есть определенные стандарты и есть команда, которая с этими стандартами работает.
                      Вот уволится команда, разрабатывающая АСОД — кто будет поддерживать все ими созданное?
                        0
                        Надежность и стабильность современных систем c IBM i во многом является коммерческой рекламой IBM, а не реальным состоянием дел.
                        Железо Power Systems сейчас абсолютно одинаковое для i, AIX и Linux. И я бы не сказал, что оно надежнее серверов Fujitsu или HP, например.
                        Безопасность системы, которая раньше гарантировалась закрытостью системы и возможностью запускать исключительно скомпилированный для i код, исключительно компиляторами IBM, порушена появлением PASE и возможностью запускать код скомпилированный где угодно и чем угодно. Более того, IBM перетащил еще и кучу опенсоурсного софта, типа ssh, ssl. Так что теперь эти системы не менее уязвимы, чем линукс системы, где этот софт используется. А чаще еще и более уязвимы, так как патчи доходят медленнее.
                        Более того, скажу страшное… Как известно, безопасность всей системы основывается на том факте, что предполагается возможность генерировать исполняемый код исключительно через доверенный компилятор — память то плоская, и защиты памяти на уровне ISA CPU нету. Т.е. любой процесс может обратиться по любому адресу и чего нибудь туда попытаться записать. Если в старых моделях AS400 использовалась специальная «тагетированная» память, то сейчас это обычные планки. Компилятор этот не лишен ошибок. И кто надо тот знает, как его запутать и получить желанный таг. Но я не буду здесь вдаваться глубоко в эту тему ;-). Вот так вкратце обстоят дела с надежностью и безопасностью.
                        А что касается наличия легаси кода который дорого переписывать, а переносить на другие платформы невозможно — так кто же с этим спорит. Гибкость же предполагает возможность запускать программы на других платформах.
                          0
                          Безопасность системы, которая раньше гарантировалась закрытостью системы и возможностью запускать исключительно скомпилированный для i код, исключительно компиляторами IBM, порушена появлением PASE и возможностью запускать код скомпилированный где угодно и чем угодно.


                          Чтобы пользоваться PASE, его надо сначала установить :-) Это не неотъемлемая часть системы, а дополнительно устанавливаемое ПО.

                          Т.е. любой процесс может обратиться по любому адресу и чего нибудь туда попытаться записать.


                          И получить MCH0601 или MCH3601. Он может что-то попробовать записать только в рамках выделенной под задачу памяти.

                          Что касается защищенности… Ну если Вы так хорошо в курсе — попробуйте похулигатить на PUB400 — он на 50-м уровне защиты работает :-)

                          И, опять же, ниже MI так просто не пробраться. В отличие от того же лунуха, где можно копаться в самом ядре при некоторых навыках.

                          Но в целом я не готов спорить на эту тему предметно — знаний пока нехватает именно на уровне таких глубоких потрохов.
                            +1
                            А вы не в курсе про решение Infinitie i? С этого года работает в облаках Amazon и Azure. Говорят могут любую нагрузку IBM i транслировать на x64 платформу без потери скорости.
                  0

                  Недостатки вроде очевидны: вендор-лок, сложно искать и удерживать специалистов и подозреваю, что есть и другие сложности.
                  А что хорошего взамен? Должны быть какие-то существенные преимущества перед более распространёнными технологиями, чтобы использование этой технологии было обосновано, т.к. сложность поиска специалистов обычно чуть ли не основной аргумент за или против применения той или иной технологии. Однако ни в статье, ни в вашем ответе я таких существенных причин не нашёл. Хотя возможно пропустил по невнимательности.

                    0
                    Особой сложности тут нет. При приеме нового разработчика есть три месяца на обучение. Обычно человек через полтора-два уже выходит на уровень выполнения несложных боевых задач.

                    Тут больше времени уходит на вникание в предметную область, а она от технологии не зависит.

                    Ну а выбор платформы зависит от того, какую АБС выбрал банк изначально. По нее уже и платформа будет конфигурироваться.

                    А АБС выбирается по функционалу. Альфа, Райф и Росбанк в свое время выбрали MiSys Equation под платформу IBM i. Ничего страшного в этом нет. Сложности с поиском специалистов нет, берут и обучают под себя. Удерживать специалистов тут в целом получается просто нормальным к ним отношением.

                    Но все это исключительно на уровне глубокого бэка. НА фронтах там все попсово и современно. Фронт с беком через WS общается.
                0

                В 80х годах RSX-11M была уже намного более удобнее этого, с WYSIWYG редакторами, нормальными файлами итд

                  0
                  А кто сказал что привычные файлы «нормальны»?

                  AS/400 — объектно-ориентированная система. Основной принцип «все есть объект». Над каждым системным объектом допустимы только те действия, которые предписаны его системными свойствами.

                  Например, там нельзя открыть программный объект HEX редактором и поправить в нем пару байтиков. Просто потому что такая операция недопустима для данного типа объекта на уровне системы.
                    0
                    Например, там нельзя открыть программный объект HEX редактором и поправить в нем пару байтиков. Просто потому что такая операция недопустима для данного типа объекта на уровне системы.

                    наверное отлаживать такую систему еще то веселье...

                      0
                      Она просто объектная. Не объектно-ориентированная. Между объектами, к примеру, нет свойства наследования.
                        0
                        Насколько я понимаю, наследование в ООП используется при создании нового типа объекта на основе старого. Просто взять два существующих типа объектов и «установить между ними наследование» невозможно.

                        В AS/400 не предусмотрено создание новых типов объектов. Соответственно, негде и наследование применить.

                        Возможно, что все типы объектов AS/400 унаследованы от одного общего предка (можно так предположить судя по однотипности работы MI с объектами).

                        Не исключено, что объекты, создаваемые из DDS исходников (PF-DTA, LF, DSPF, PRTF), имеют общего предка — у них много общих свойств, общая структура (команды CL DSPFD, DSPFFD, системные API, возвращающие структуру таких объектов, работают со всеми ними одинаково).

                        Также есть наследование определенных свойств (права доступа, Job Description...) при создании объектов некоторых типов.
                          0
                          Прошу не подменять смысл сказанного.
                          Разговор об объектах AS/400. Объекты машинного интерфейса MI и объекты AS/400 — две абсолютно разные группы сущностей, которые практически никак не пересекаются (ну разве кроме того, что MI контекст == AS/400 библиотека, как так вышло — отдельная забавная история).
                          Когда говорят про объекты IBM i всегда имеют в виду объекты AS/400. Они состоят из одного и более MI объекта, здесь речь о вложении а не о наследовании.
                          Да, все объекты имеют стандартную для всех часть и специальную часть (как пишет Солтис). Но это не делает структуры объектно-ориентированными.

                          Ваш пример с объектами, создаваемыми из DDS исходников (PF-DTA, LF, DSPF, PRTF) в принципе здесь не уместен, потому что у всех них тип объекта — один *FILE. DSPF, PRTF, LF и др — это атрибуты объекта. Внимательно посмотрите в WRKOBJ прежде чем вводить людей в заблуждение.

                          А наследование определенных свойств здесь как может решить вопрос объектной ориентированности? Job description — это вообще отдельная структура, которая подготавливается ОС при старте задачи и указатель на нее записывается в PCO job-а, сущность исключительно runtime-а.
                            0
                            Ну хорошо. Пусть она не будет объектно-ориентированной, пусть будет просто объектной :-) Как Вам будет угодно.

                            Я давно уже отучился упираться в концепцию ради концепции.

                            Кстати, из того с чем сталкивался — *USRQ Системный объект, он же объект MI. Уверен, что есть и другие.

                            И вложенность объектов никак не противоречит ООП. А вот строгая типизация объектов и наличие у каждого типа определенного набора свойств и допустимых операций — это вполне себе признаки объектно-ориентированного подхода при разработке системы (представления ее как набора взаимодействующих между собой объектов).
                              0
                              Не могу согласиться. Потому что тогда бы все команды OS для всех объектов *FILE можно было бы применять друг к другу, а это не так. Создаются эти объекты разными командами, специфичными для конкретного класса. Например, для создания логического файла используется команда CRTLF, а для дисплейного — CRTDSPF. Если бы было по вашему, то существовала бы единая команда типа CRTFILE, которыой бы создавались все варианты объектов данного класса, и логические файл и физические и дисплейные.
                              При этом, объекты наследуют ряд свойств от базового класса и есть команды применимые ко всем объектам наследующим от *FILE.
                              Файлы же в свою очередь наследуют от общего класса, и потому WRKOBJ работает не только с файлами но и другими объектами.
                                0
                                Не обязательно в моем случае должна быть одна команда типа CRTFILE. Структура данных, описывающая файл, может вкладывать в себя поля от всех типов атрибутов файла, прямо или по указателю.
                                Только очень сложно и неудобно работать с одной CRTFILE с очень большим количеством параметров, удобнее иметь несколько разных функций инициализации. Таким образом получаются разные CRTxxx. При этом наследование дало бы практически такой же эффект.

                                Френк Солтис (архитектор AS/400 по чьей диссертации можно сказать мы работаем) пишет в Fortress Rochester (2001 года книга, не та которая обрубленная «Основы AS/400» от 96го) о том, что все объекты имеют в себе общую часть, — системный заголовок, и специальную часть.

                                Объекты AS400 вкладывают в себя 1 или более MI-объектов, потому как эти части писались разными командами в разных странах. Могу ошибиться в цифрах, но в книге приводилась информация, что V4R? содержал более 7000 С++ классов, и внутри безусловно используется ООП.

                                Но в рамках объектов AS400 для нас, пользователей, эти объекты закрыты.

                                А WRKOBJ работает с объектом MI контекста (или библиотеки AS/400), один из простейших объектов, просто именованный список системных указателей в Single Level Storage с доп инфо.

                                Системный указатель (любопытное отличие этой системы от других, здесь 7 или 8 различных типов указателей на уровне виртуальной машины ILE) отличается от других как раз тем, что он спозиционирован на адрес SLS на системный заголовок. И когда выполняется resolve system pointer, в зависимости от параметров будет выполнен поиск по контексту и возвращен системный указатель на объект. Инструкция вообще там много всего умеет, в том числе сразу же ограничивать права доступа к объекту по указателю (в системном указателе права доступа «кэшируются» в нем же либо системой в зависимости от объекта авторизации job-а, либо можно самому подкорректировать их усиление, создавая свою модель безопасности).
                                Тема огромная, все это в книге Солтиса описано. К сожалению книгу очень сложно достать, полной онлайн версии не нашел, только отрывки в виде страниц некоторых глав.
                                  0
                                  Ну, я уже как-то приводил здесь ссылку на книжку. Если есть интерес, то вот еще раз. Обращаю внимание, что книга во многом устарела, но об этом ниже.
                                  Теперь к сути вопроса. Я думаю, вы путаете модель с внутренней реализацией. Мне ваши рассуждения напомнили следующую аналогию. Взять какой нибудь OOП язык (типа С++) для которого существует транслятор в процедурный (типа C). Вы смотрите в полученный C код и говорите: ага, да там же все плоские структуры, никакого наследования! Ну все, С++ никакой не объектно ориентированный.
                                  Да, с точки зрения MI структура плоская. Вернее, там все сложнее, но не важно. Важно что MI — это внутренняя реализация. Более того, то что вы называете MI — сегодня не более чем анахронизм и рудимент. Он давно заменен на NMI аka w-code, который глубоко закрыт, никогда не публиковался и существует сегодня только лишь в виде транслятора MI -> NMI для легаси кода в OPM.
                                  CRTLF и CRTDSPF — это никакие не «удобные функции». Это конструкторы объектов конкретных классов. И эти классы разные, хотя и наследуют от общего предка. Короче говоря, система IBM i именно объектно ориентированная с точки зрения клиента. А уж какая там внутренняя реализация — это дело десятое.
                                    0
                                    Да, книжка эта очень устарела и там уровень детализации низкий, в Fortress Rochester более глубоко написано. Ссылка. Это неплохое расширение первой. И про W-Code там тоже есть пара слов, сейчас Cube-3 кажется называется.
                                    Видимо мы друг друга не поняли про MI, я когда говорил про него, имел в виду машинный интерфейс, доступный разработчику. Конкретно вот этот.
                                    И он совсем не рудимент, документированный низкоуровневый интерфейс, когда хочется выжать максимум.
                                    Про аналогию с транслятором C++ в Си я понял идею. Согласен, меня занесло в сторону. Но это не суть важно.
                      0
                      Я думаю, надо принципиально решать насчет продолжения использования 5250, а не пытаться искать заместители DDS. DDS отлично делает свое дело. Пример с результатами SQL запроса притянут искусственно. Пользователям никто не даст запускать непредсказуемые запросы. А тех-персоналу все эти «украшательства» не нужны.
                      Из PRG уже давно можно и в HTTP и во что угодно. Не хочется самим делать — есть куча готовых решений на рынке. Самое известное — profoundlogic.
                      Хотя сама идея поиграться с возможностью напрямую писать в 5250 поток, конечно, интересная.

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                      Самое читаемое