# Проектные расширения
## Точка расширения
Аббревиатуры:
- `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());
```