# Проектные расширения ## Точка расширения Аббревиатуры: - `Ept` - Точка расширения - `Ext` - Расширения *Точка расширения (ExtensionPoint)* – специфический пакет, методы которого объявлены таким образом, что к ним можно подключить дополнительный исполняемый код из других пакетов (расширений/Extension). Код расширений будет выполнен при вызове метода точки расширения. ```scala class Btk_ExampleEpt extends ExtensionPoint { val doSomeThing = declFunc("doSomeThing") { (sf: SuperFunc[Int], a: Int, b: Int) => val superVal = sf().getOrElse(0) a + b + superVal } } object Btk_ExampleEpt extends PkgFactory[Btk_ExampleEpt] ``` Пример представляет объявление "Точки расширения" с методом `doSomeThing` Правила наименования для точек расширения, которые используются для дополнения функционала сеттеров, вставки. удаления – `Xxx_Ept`, где `Xxx` – имя модуля, для которого точка расширения создается (например `Bs_Ept`, `Btk_Ept`). *Расширение (Extension)* – специфический пакет, методы которого подключаются к методам точки расширения, и выполняются при вызове соответствующего метода точки расширения. К методу точки расширения может быть подключено произвольное число методов расширений. При первом обращении к классу точки расширения, производится поиск и сканирование файлов `META-INF/extensions.xml`. Расширения, у которых свойство `targetEpt` совпадает с именем точки расширения, подключаются к точке расширения. ```scala class Gs3_Btk_ExampleExt extends Extension { subFunc("doSomeThing") { (sf: SuperFunc[Int], a: Int, b: Int) => val superVal = sf(a - 2, b).getOrElse(0) superVal + 2 } } ``` Пример представляет объявление метода расширения. На вход метод получает ссылку на метод расширения, находящийся ниже в очереди вызовов. ```{attention} Если не вызвать `sf()`, методы расширений, находящиеся ниже в очереди не будут вызваны. ``` Правила наименования для расширений, которые используются для дополнения функционала других модулей для сеттеров, вставки. удаления – `Xxx_YyyExt`, где `Xxx` – имя модуля расширения, `Yyy` – имя модуля, в котором находится точка расширения (например `Mct_BsExt` ). ### Конфигурирование расширений Конфигурация расширений находится в файле `META-INF/extensions.xml`. Структура фала: ```xml ``` ### Порядок вызовов По умолчанию, метод точки расширения получает порядковый номер "0", а все методы расширений – номер "10". В результате, в первую очередь буду вызваны все методы расширений, в произвольном порядке, в конце будет вызван код точки расширения. Для изменения порядка вызовов необходимо задать порядковые номера методам расширений. ```scala subFunc("doSomeThing", 1) { (sf: SuperFunc[Int], a: Int, b: Int) => } ``` ## Проектное перекрытие кода Api, Avi, Lib, Pkg Для перекрытия кода Api, Avi, Lib, Pkg необходимо: 1. Создать свой класс-наследник от перекрываемого класса. 2. Зарегистрировать перекрытие класса в файле `META-INF/overrides.xml` ### Пример перекрытия Avi-класса #### Код исходного Avi-класса `Gs3_RootTestAvi.scala` ```scala object Gs3_RootTestAvi extends Gs3_RootTestAvi @AvmFile(name = "Gs3_RootTest.avm.xml") class Gs3_RootTestAvi extends Gs3_RootTestDvi { override def list(): List = { new List { override def meta = this } } } ``` #### Код перекрытия Avi-класса `Gs3_RootTestOverrideAvi.scala` ```scala object Gs3_RootTestOverrideAvi extends Gs3_RootTestOverrideAvi @AvmFile(name = "Gs3_RootTestOverride.avm.xml") class Gs3_RootTestOverrideAvi extends Gs3_RootTestAvi { override def list(): List = { new List { override def meta = this } } trait List extends super.List { } } ``` Аннотация `@AvmFile` может быть не указана, в этом случае будет использоваться аннотация из класса-предка. #### Текст `META-INF/overrides.xml` ```xml ``` ### Пример перекрытия Api #### Код перекрытия ```scala class Gs3_RootTestOverrideApi extends Gs3_RootTestApi { } object Gs3_RootTestOverrideApi extends ApiFactory[ java.lang.Long, Gs3_RootTestAro, Gs3_RootTestOverrideApi ] ``` #### Текст `META-INF/overrides.xml` ```xml ``` ### Пример перекрытия Pkg #### Код перекрытия ```scala class Btk_OverridePkg extends Btk_Pkg { } object Btk_OverridePkg extends PkgFactory[Btk_OverridePkg] ``` #### Текст `META-INF/overrides.xml` ```xml ``` ### Пример перекрытия Lib #### Код перекрытия ```scala class Btk_OverrideLib extends Btk_Lib { } object Btk_OverrideLib extends AviLibFactory[Btk_Lib] ``` #### Текст `META-INF/overrides.xml` ```xml ``` ### Запрет перекрытия Для запрета проектного перекрытия кода Avi-класса, необходимо отметить класс аннотацией @Final. ```scala @Final class Gs3_RootTestAvi extends Gs3_RootTestDvi {} ``` Для запрета проектного перекрытия кода Api,Lib,Pkg классов, необходимо отметить класс аннотацией `@Final` или ключевым словом `final`. ```scala @Final class Gs3_RootTestApi extends Gs3_RootTestDpi[ Gs3_RootTestAro, Gs3_RootTestApi, Gs3_RootTestAta ] {} ``` или ```scala final class Gs3_RootTestApi extends Gs3_RootTestDpi[ Gs3_RootTestAro, Gs3_RootTestApi, Gs3_RootTestAta ] {} ``` ## Jexl расширения методов С помощью расширений методов имеется возможность доработки и модификации стандартных серверных методов и операций пользовательских интерфейсов из приложения `Настройки системы`. Расширение представляет из себя jexl-скрипт, вызываемый перед или после выполнения стандартного метода/операции. ### Расширения Api-методов Добавление точек расширения в `Api` предусмотрено только в следующие методы: - `Сеттеры атрибутов` – `Dpi-`сеттеры всех атрибутов выбранного класса; - `AfterEdit` – `Dpi-`метод, вызываемый на окончание редактирования объекта класса, например при редактировании строки и перемещении курсора на другую строку; - `BeforeEdit` – `Dpi-`метод, вызываемый в начале редактирования объекта класса; - `FlushObject` – метод записи (сохранения) объекта в базу данных; - `Delete` – `Dpi-`метод удаления объекта класса из базы данных; - `Insert` – `Dpi-`метод создания нового объекта класса. ```{note} Все расширения вызываются из 'Dpi'. Т.е. срабатывание перед сеттером - это срабатывание перед вызовом `Dpi-`сеттера. ``` ```{note} Для методов "FlushObject" и "BeforeEdit" можно добавлять только точки расширения «До». ``` Выполнение этих точек будет производиться в контексте сессии, без использования интерактивной бизнес логики (т.е. нельзя использовать методы открытия всплывающих окон и диалогов, открытия каких либо интерфейсов системы). Для подключения точек расширения Api-методов перейдите: `Настройки системы` - `Обозреватель проекта`. Выбрав Api нужного класса, перейдите на закладку `Точки расширения`. На закладке `Расширения до` или `Расширения после` создайти запись нового расширения и пропишите ему исполняемый скрипт. Пример скрипта с использованием вызова процедур из Bts: ```text Bts_ProcedureApi.execByMnemoCode("ProcedureCode", {"argName1": value1, "argName2": value2, ...}) ``` Пример выброса ошибки, если у объекта не заполнен атрибут `sDescription`: ```text var aro = rop.copyAro(); if (aro.sDescription() == null){ raise("Не заполнено описание!") } ``` ### Расширения Avi-методов Добавление точек расширения в `Avi` предусмотрено в сеттеры выборки, в ее операции или на события выборки, такие как beforeEdit, afterEdit и т.д. Выполнение этих точек будет производиться в контексте выборки. Для подключения точек расширения Avi-методов перейдите: `Настройки системы` - `Обозреватель проекта`. Выбрав нужную выборку, перейдите на закладку `Редактор операций`. На закладке `Расширения до` или `Расширения после` создайте запись нового расширения и пропишите ему исполняемый скрипт. ### Пользовательские события Реализована возможность для `Api` добавлять собственные события, а так же для существующих стандартных событий добавлять новые типы срабатывания. #### Добавление нового события Новое событие будет отображено в списке событий `Api`. Оно создается без типов срабатываний, типы срабатывание привязываются к событию отдельным методом. Пример добавления нового события: ```scala Btk_MethodExtensionApi().registerClassEvent( idvClass, "SomeUserEventName", "Новое пользовательское событие" ) ``` Пример удаления пользовательского события: ```scala Btk_MethodExtensionApi().unregisterClassEvent( idvClass, "SomeUserEventName" ) ``` #### Добавление типа срабатывания к событию Стандартные события (сеттеры, вставка и тд.) имеют по умолчанию 2 типа срабатывания: `До` и `После`, а пользовательские события создаются без типа срабатывания. Реализована возможность добавления нового типа срабатывания к событию. Каждый тип срабатывания будет отображаться отдельной закладкой у события. Создание нового типа срабатывания: ```scala Btk_MethodExtensionTypeApi().register("SomeUserEventType", "На пересчет денормализации") ``` Создание связи между событием и типом срабатывания: ```scala Btk_MethodExtensionApi().registerEventTypeToClassEvent( idvClass, "SomeUserEventName", Btk_MethodExtensionTypeApi().findByMnemoCode("SomeUserEventType") ) ``` Удаление связи между событием и типом срабатывания: ```scala Btk_MethodExtensionApi().unregisterEventTypeFromClassEvent( idvClass, "SomeUserEventName", Btk_MethodExtensionTypeApi().findByMnemoCode("SomeUserEventType") ) ``` #### Вызов пользовательского события или пользовательского типа срабатывания из кода приложения Разработчик в коде сам размещает вызов срабатывания события в нужном месте. Пример вызова: ```scala Btk_MethodExtensionApi().runMethodExtensionByClass(idvClass, "SomeUserEventType", "SomeUserEventName", "valueStr" -> "abc", "valueNum" -> 1.nn) ``` Переданные в метод значения параметров будут доступны в `Jexl-скриптах` этого события. Пример обращения к переменной из `Jexl-скрипта`: ``` println("Значение переменной valueStr: " + valueStr + " Значение переменной valueNum: " + valueNum.toString()); ```