Interactor
Описание
Механизм позволяющий описать сущности, такие как процесс или контрагент в виде интерфейса, работая с ним как с обычным объектом. Такой подход позволяет избавиться от boilerplate-кода и сконцентрироваться на бизнес-логике.
Примеры задач:
-
Получение, обновление и валидация значений параметров
-
Получение и обновление свойств процесса: статус, описание и т.д
-
Работа с привязками (получение, добавление, удаление, распаковка)
-
Работа с конфигурациями
Quick Start
1. Заведение интерфейса
Идеология в следующем - одному типу процесса должно соответствовать не более одного интерфейса, в большем количестве нет смысла, так как они будут описывать абсолютно одну и ту же сущность. Поэтому начинаем всегда с проверки не был ли заведен соответствующий интерфейс ранее.
@ProcessInteractorReference(typeIds = 11011)
public interface DhcpCameraInstallationProcess extends ProcessInteractor {
}
В случае с процессами рекомендуется наследовать интерфейсы от ru.bgcrm.util.interactor.utils.ProcessInteractor , в нем содержится базовый набор методов для работы с процессами. Бонусом идет упрощение поиска существующих интерфейсов, если знать что они являются его наследниками. См. Аспекты
|
2. Описание методов
У сущности, будь то контрагент или процесс, есть состояние (параметры, статусы, привязки и т.п) наша задача описать в интерфейсе методы для работы с ним. Каждый метод, исходя из решаемой им задачи, должен быть отмечен специальной аннотацией и иметь одну из поддерживаемых этой аннотацией сигнатур.
2.1 Выбор обработчика
см. [_Обработчики]
Предположим, что у нас есть процесс и мы хотим работать с его параметром "Адрес". Для работы с параметрами этого типа у нас уже есть аннотация @BindAddressParam
.
@BindAddressParam(90)
ParameterAddressValue getAddress();
@BindAddressParam(90)
void setAddress(ParameterAddressValue address);
2.2 Валидация
см. Валидация данных
Распространенным явлением является валидация данных, которые мы получаем из процесса. Здесь это возможно посредством аннотаций.
@BindAddressParam(90)
@NotNull(message = "Не указан адрес!")
ParameterAddressValue getAddress();
2.3 Кеширование
По умолчанию при каждом вызове метода вызывается и закрепленная за ним логика, чаще всего это подразумевает обращение к БД. Чтобы избежать лишних обращений предусмотрен механизм ленивого кеширования возвращаемых данных, по-умолчанию он отключен.
@EnableCache - вешается на весь интерфейс или конкретный метод, активирует кеширование для соответствующих не void-методов.
@DropCache - помечаем методы при вызове которых сбрасывается весь имеющийся в объекте кеш (актуально для методов изменяющих состояние).
@BindAddressParam(90)
@EnableCache
ParameterAddressValue getAddress();
@BindAddressParam(90)
@DropCache
void setAddress(ParameterAddressValue address);
3. Получение интерактора
Для того чтобы получить объект для работы с сущностью необходимо указать её ID и соответствующий интерфейс.
CameraInstallationProcess process = Interactor.create(processId, CameraInstallationProcess.class);
Далее работа с процессом ведется как с обычным классом.
Contract contract = process.getCctvContract();
String camera = process.getCameraNumber();
try {
int accountId = billingService.registerCamera(contract, camera);
process.setAccountId(accountId);
process.addDescription("Аккаунт камеры зарегистрирован");
process.markSuccess();
} catch (Exception e) {
process.addDescription("Ошибка регистрации камеры: " + e.getMessage());
process.markFailed();
}
Сущности
В рамках каждой сущности имеется собственный набор допустимых обработчиков.
Обработчики регистрируются в фабрике конкретной сущности (см. ru.bgcrm.util.interactor.factory.InteractionDispatcherFactory
).
Для работы с конкретными сущностями рекомендуется создать интерфейс-наследник и использовать конкретные обработчики в нем, оставив в исходном интерфейсы только универсальные обработчики или можно использовать [_Аспекты]
Поддерживаемые в данный момент сущности:
-
Процессы (
ru.bgcrm.util.interactor.utils.process.ProcessInteractor
) -
Контрагенты (
ru.bgcrm.util.interactor.utils.customer.CustomerInteractor
) -
Единые договора (
ru.bgcrm.util.interactor.utils.commonContract.CommonContractInteractor
) -
Пользователи (
ru.bgcrm.util.interactor.utils.user.UserInteractor
) -
Группы пользователей (
ru.bgcrm.util.interactor.utils.group.GroupInteractor
)
Сущности адресного справочника:
-
Город (
ru.bgcrm.util.interactor.utils.address.CityInteractor
) -
Улица (
ru.bgcrm.util.interactor.utils.address.StreetInteractor
) -
Дом (
ru.bgcrm.util.interactor.utils.address.HouseInteractor
)
Обработчики
Подразумевается, что есть некий набор аннотаций, каждая из которых соответствует определенному обработчику вызовов. Вешая аннотацию на свой метод вы должны убедиться, что он имеет подходящую сигнатуру.
См. классы-наследники от ru.bgcrm.util.interactor.InteractionHandler
и javadoc к соответствующим аннотациям.
Регистрация нового обработчика производится для конкретных сущностей, в которых обработчик поддерживается.
Для этого необходимо создать наследника от ru.bgcrm.util.interactor.InteractionHandler
и зарегистрировать его через InteractionDispatcher#registerHandler
Текущие обработчики
@BindConfig
Получение данных из конфигурации
Параметры
Name | Type | Required | Default | Description |
---|---|---|---|---|
key |
String |
false |
"" |
Ключ значения |
defaultValue |
String |
false |
"" |
Значение по-умолчанию |
useGlobalConfig |
Boolean |
false |
false |
Использование глобальной конфигурации |
Поддерживаемые сигнатуры
T getValue(); //Ключ должен быть указан в аннотации
T getValue(@Key String key); //Ключ должен быть указан в аннотации
T getValue(@Default String defaultValue);
T getValue(@Key String key, @Default String defaultValue);
/*Где T это тип данных к которому будет приведено полученное по ключу значение, поддерживаются:
- String
- Boolean
- Int
- Long
- BigDecimal
- enum class [имя_класса]
- List<String>
- List<Integer>
- Set<String>
- Set<Integer>
- ru.bgcrm.util.configuration.Configurable //Получение конфигурации через функционал ru.bgcrm.util.configuration.ConfigMapper*/
При этом в конфигурации имя enum-параметра может быть указано невзирая на регистр. Например: doctype.PDF или doctype.pdf замапятся в enum class DocType {PDF, DOCX} как DocType.PDF
@BindTextParamAsNumber
Получение и обновление параметров с типом text
и blob
хранящих числовые значения.
При отсутствии корректного значения в параметре (null, пустая строка, текст) для примитивных типов возвращается 0, для объектов null.
Поддерживаемые сигнатуры
//Получение значений:
int getValue();
@Nullable Integer getValue();
long getValue();
@Nullable Long getValue();
@Nullable BigDecimal getValue();
//Запись значений
void setValue(int value);
void setValue(@Nullable Integer value);
void setValue(long value);
void setValue(@Nullable Long value);
void setValue(@Nullable BigDecimal value);
//Очистка значения параметра (осуществляется за счет префикса 'clear' в названии метода)
void clearValue();
@BindTextParamAsCollection
Получение и обновление параметров с типом text
и blob
, хранящих списки из значений разделенных спец.символом.
При отсутствии корректного значения в параметре будет возвращаться пустая коллекция.
Параметры
Name | Type | Required | Default | Description |
---|---|---|---|---|
value |
Int |
true |
ID параметра |
|
delimiters |
Array<String> |
false |
[","] |
Разделители элементов коллекции |
Поддерживаемые сигнатуры
//Получение значений
@NotNull List<String> getValues();
@NotNull Set<String> getValues();
@NotNull List<Integer> getValues();
@NotNull Set<Integer> getValues();
//Запись значений
void setValues(@NotNull Collection<Integer> values);
void setValues(@NotNull Collection<String> values);
//Очистка значения параметра (осуществляется за счет префикса 'clear' в названии метода)
void clearValues();
@BindTextParamAsJson
Получение и обновление параметров с типом text
и blob
, хранящимися в json-представлении в качестве значения текстового параметра, под капотом используется Jackson.
При отсутствии значения в параметре будет возвращаться null.
Таблица param_number
Name | Type | Nullable | Default | Description |
---|---|---|---|---|
id |
Int |
false |
Порядок записи |
|
param_id |
Int |
false |
Идентификатор параметра |
|
value |
decimal(20,5) |
true |
Значение параметра |
|
last_update |
timestamp |
false |
current_timestamp |
Время добавления значения |
Таблица param_number_log
Name | Type | Nullable | Description |
---|---|---|---|
id |
Int |
false |
Порядок записи |
param_id |
Int |
false |
Идентификатор параметра |
value |
decimal(20,5) |
true |
Значение параметра |
change_time |
timestamp |
false |
Время добавления значения |
user_id |
Int |
false |
Идентификатор пользователя (ктр добавил значение) |
Поддерживаемые сигнатуры
== **Получение значения**
* @Nullable BigDecimal getValue();
* @Nullable Integer getValue();
* @Nullable Long getValue();
* @Nullable Double getValue();
* @Nullable Float getValue();
* @Nullable Short getValue();
* @Nullable Byte getValue();
== **Обновление значения**
* void setValue(@Nullable BigDecimal value);
* void setValue(@Nullable Integer value);
* void setValue(@Nullable Long value);
* void setValue(@Nullable Double value);
* void setValue(@Nullable Float value);
* void setValue(@Nullable Short value);
* void setValue(@Nullable Byte value);
== **Очистка значения параметра**
(осуществляется за счет префикса 'clear' в названии метода)
* void clearValue();
@BindDateParam
Получение и обновление параметров с типом date
Параметры
Name | Type | Required | Default | Description |
---|---|---|---|---|
value |
Int |
true |
ID параметра |
|
format |
String |
false |
"yyyy-MM-dd" |
Паттерн форматирования даты (для работы с типом String) |
Поддерживаемые сигнатуры
//Получение значений
@Nullable LocalDate getValue();
@Nullable Date getValue();
@Nullable String getValue();
//Запись значений
void setValue(@Nullable LocalDate value);
void setValue(@Nullable Date value);
void setValue(@Nullable String value);
//Очистка значения параметра (осуществляется за счет префикса 'clear' в названии метода)
void clearValue();
@BindDateTimeParam
Получение и обновление параметров с типом datetime
Параметры
Name | Type | Required | Default | Description |
---|---|---|---|---|
value |
Int |
true |
ID параметра |
|
format |
String |
false |
"yyyy-MM-dd HH:mm:ss" |
Паттерн форматирования даты (для работы с типом String) |
Поддерживаемые сигнатуры
//Получение значений
@Nullable LocalDateTime getValue();
@Nullable Date getValue();
@Nullable String getValue();
//Запись значений
void setValue(@Nullable LocalDateTime value);
void setValue(@Nullable Date value);
void setValue(@Nullable String value);
//Очистка значения параметра (осуществляется за счет префикса 'clear' в названии метода)
void clearValue();
@BindListParam
Получение и обновление параметров с типом list
Поддерживаемые сигнатуры
//Получение значений
@Nullable Integer getValue();
@Nullable IdTitleComment getValues();
@Nullable IdTitle getValues();
List<Integer> getValues();
Set<Integer> getValues();
List<IdTitleComment> getValues();
List<IdTitle> getValues();
Set<IdTitleComment> getValues();
Set<IdTitle> getValues();
//Добавление значений (за счет префикса 'add', 'plus' в названии метода)
void addValue(int id);
void addValue(IdTitle value);
void addValue(IdTitleComment value);
void addValues(Collection<Integer> ids);
void addValues(Collection<IdTitle> values);
void addValues(Collection<IdTitleComment> values);
//Обновление значений
void setValues(Collection<Integer> values);
void setValues(Collection<IdTitle> values);
void setValues(Collection<IdTitleComment> values);
void setValue(int value);
void setValue(IdTitle value);
void setValue(IdTitleComment value);
//Удаление значений (за счет префикса 'remove', 'delete' в названии метода)
void removeValue(int value)
void removeValue(IdTitle value)
void removeValue(IdTitleComment value)
void removeValues(Collection<Integer> values)
void removeValues(Collection<IdTitle> values)
void removeValues(Collection<IdTitleComment> values)
//Очистка значения параметра (осуществляется за счет префикса 'clear' в названии метода)
void clearValues();
@BindListCountParam
Получение и обновление параметров с типом listCount
Поддерживаемые сигнатуры
//Получение значений
@Nullable ParameterListCountValue getValue();
List<ParameterListCountValue> getValues();
Set<ParameterListCountValue> getValues();
//Добавление значений (за счет префикса 'add', 'plus' в названии метода)
void addValue(ParameterListCountValue listCount);
void addValues(Collection<ParameterListCountValue> listCounts);
//Обновление значений
void setValues(Collection<ParameterListCountValue> values);
void setValue(ParameterListCountValue value);
//Удаление значений (за счет префикса 'remove', 'delete' в названии метода)
void removeValue(ParameterListCountValue value)
void removeValues(Collection<ParameterListCountValue> values)
//Очистка значения параметра (осуществляется за счет префикса 'clear' в названии метода)
void clearValues();
@BindTreeParam
Получение и обновление параметров с типом tree
Поддерживаемые сигнатуры
//Получение значений
@Nullable String getValue();
@Nullable TreeTitle getValues();
List<String> getValues();
Set<String> getValues();
List<TreeTitle> getValues();
Set<TreeTitle> getValues();
//Добавление значений (за счет префикса 'add', 'plus' в названии метода)
void addValue(String id);
void addValue(TreeTitle value);
void addValues(Collection<String> ids);
void addValues(Collection<TreeTitle> values);
//Обновление значений
void setValues(Collection<String> values);
void setValues(Collection<TreeTitle> values);
void setValue(String value);
void setValue(TreeTitle value);
//Удаление значений (за счет префикса 'remove', 'delete' в названии метода)
void removeValue(String value)
void removeValue(TreeTitle value)
void removeValues(Collection<String> values)
void removeValues(Collection<TreeTitle> values)
//Очистка значения параметра (осуществляется за счет префикса 'clear' в названии метода)
void clearValues();
@BindAddressParam
Получение и обновление параметров с типом address
Параметры
Name | Type | Required | Default | Description |
---|---|---|---|---|
value |
Int |
true |
ID параметра |
|
loadDetails |
Boolean |
false |
false |
Загрузка дополнительной информации по адресу |
Поддерживаемые сигнатуры
//Получение значений
@Nullable ParameterAddressValue getValue();
@Nullable HouseInteractor getValue();
@Nullable StreetInteractor getValue(); // Необходимо включить флаг loadDetails
@Nullable CityInteractor getValue(); // Необходимо включить флаг loadDetails
List<ParameterAddressValue> getValues();
List<HouseInteractor> getValues();
List<StreetInteractor> getValues(); // Необходимо включить флаг loadDetails
List<CityInteractor> getValues(); // Необходимо включить флаг loadDetails
Set<ParameterAddressValue> getValues();
Set<HouseInteractor> getValues();
Set<StreetInteractor> getValues(); // Необходимо включить флаг loadDetails
Set<CityInteractor> getValues(); // Необходимо включить флаг loadDetails
//Обновление значений
void setValue(@Nullable ParameterAddressValue value);
void setValues(Collection<ParameterAddressValue> values);
//Добавление значений (за счет префиксов "add" и "plus")
void addValue(ParameterAddressValue value);
void addValues(Collection<ParameterAddressValue> values);
//Удаление значений (за счет префиксов "remove" и "delete")
void removeValue(ParameterAddressValue value);
void removeValues(Collection<ParameterAddressValue> values);
//Очистка значения параметра (осуществляется за счет префикса 'clear' в названии метода)
void clearValue();
@BindPhoneParam
Получение и обновление параметров с типом phone
Параметры
Name | Type | Required | Default | Description |
---|---|---|---|---|
value |
Int |
true |
ID параметра |
|
format |
String |
false |
"10" |
Формат номера телефона (CRM) |
unformatted |
Boolean |
false |
true |
Возвращать номер телефона без форматирования |
Поддерживаемые сигнатуры
//Получение значений
@Nullable String getValue();
List<String> getValues();
Set<String> getValues();
//Обновление значений
void setValue(@Nullable String value);
void setValues(Collection<String> values);
void addValue(String value);
void addValues(Collection<String> values);
void removeValue(String value);
void removeValues(Collection<String> values);
@BindEmailParam
Получение и обновление параметров с типом email
Поддерживаемые сигнатуры
//Получение значений
@Nullable ParameterEmailValue getValue();
List<ParameterEmailValue> getValues();
Set<ParameterEmailValue> getValues();
//Добавление значений (за счет префикса 'add', 'plus' в названии метода)
void addValue(ParameterEmailValue listCount);
void addValues(Collection<ParameterEmailValue> listCounts);
//Обновление значений
void setValues(Collection<ParameterEmailValue> values);
void setValue(ParameterEmailValue value);
//Удаление значений (за счет префикса 'remove', 'delete' в названии метода)
void removeValue(ParameterEmailValue value)
void removeValues(Collection<ParameterEmailValue> values)
//Очистка значения параметра (осуществляется за счет префикса 'clear' в названии метода)
void clearValue();
@BindProcessLinkedObjects
Получение и обновление списка привязанных объектов процесса
Параметры
Name | Type | Required | Default | Description |
---|---|---|---|---|
titlePattern |
String |
false |
".*" |
Фильтр по заголовку привязанного объекта |
typePattern |
String |
false |
".*" |
Фильтр по типу привязанного объекта |
Поддерживаемые сигнатуры
//Получение значений
@Nullable CommonObjectLink getLink(); // имеется поддержка аннотации @Size
List<CommonObjectLink> getLinks();
Set<CommonObjectLink> getLinks();
//Обновление значений
void setLinks(Collection<CommonObjectLink> links);
//Добавление значений (достигается за счет префиксов 'add', 'plus' в названии метода)
void addLink(CommonObjectLink link); // префикс НЕ обязателен
void addLinks(Collection<CommonObjectLink> links); // префикс обязателен
//Удаление значений (достигается за счет префиксов 'remove', 'delete' в названии метода)
void removeLink(CommonObjectLink link);
void removeLinks(CommonObjectLink links); // префикс обязателен
@BindProcessLinkedCustomers
Получение и обновление списка привязанных к процессу контрагентов
Поддерживаемые сигнатуры
//Получение значений
@Nullable Customer getLink(); // имеется поддержка аннотации @Size
@Nullable CustomerInteractor getLink(); // имеется поддержка аннотации @Size
List<Customer> getLinks();
List<CustomerInteractor> getLinks();
Set<Customer> getLinks();
Set<CustomerInteractor> getLinks();
//Обновление значений
void setLinks(Collection<Customer> links);
void setLinks(Collection<CustomerInteractor> links);
//Добавление значений (достигается за счет префиксов 'add', 'plus' в названии метода)
void addLink(Customer link); // префикс НЕ обязателен
void addLink(CustomerInteractor link); // префикс НЕ обязателен
void addLinks(Collection<Customer> links); // префикс обязателен
void addLinks(Collection<CustomerInteractor> links); // префикс обязателен
//Удаление значений (достигается за счет префиксов 'remove', 'delete' в названии метода)
void removeLink(Customer link);
void removeLink(CustomerInteractor link);
void removeLinks(Collection<Customer> links);
void removeLinks(Collection<CustomerInteractor> links);
@BindLinkedCommonContracts
Получение и обновление списка привязанных к процессу единых договоров
Параметры
Name | Type | Required | Default | Description |
---|---|---|---|---|
titlePattern |
String |
false |
".*" |
Фильтр по номеру единого договора |
Поддерживаемые сигнатуры
//Получение значений
@Nullable CommonContract getLink(); // имеется поддержка аннотации @Size
@Nullable CommonContractInteractor getLink(); // имеется поддержка аннотации @Size
List<CommonContract> getLinks();
List<CommonContractInteractor> getLinks();
Set<CommonContract> getLinks();
Set<CommonContractInteractor> getLinks();
//Обновление значений
void setLinks(Collection<CommonContract> links);
void setLinks(Collection<CommonContractInteractor> links);
//Добавление значений (достигается за счет префиксов 'add', 'plus' в названии метода)
void addLink(CommonContract link); // префикс НЕ обязателен
void addLink(CommonContractInteractor link); // префикс НЕ обязателен
void addLink(int commonContractId); // префикс НЕ обязателен
void addLinks(Collection<CommonContract> links); // префикс обязателен
void addLinks(Collection<CommonContractInteractor> links); // префикс обязателен
//Удаление значений (достигается за счет префиксов 'remove', 'delete' в названии метода)
void removeLink(CommonContract link);
void removeLink(CommonContractInteractor link);
void removeLink(int commonContractId);
@BindProcessLinkedContracts
Получение и обновление списка привязанных к процессу договоров
Параметры
Name | Type | Required | Default | Description |
---|---|---|---|---|
billings |
Array<String> |
false |
[] |
Фильтр по биллингам (если биллинг не задан, то будет производиться поиск по всем биллингам) |
titlePattern |
String |
false |
".*" |
Фильтр по номеру единого договора |
typeFilter |
Array<BindProcessLinkedContracts.Type> |
false |
[] |
Фильтр по типу договора, если не заполнено, то фильтрация не производится |
Поддерживаемые сигнатуры
//Получение значений
@Nullable CommonContract getLink(); // имеется поддержка аннотации @Size
@Nullable CommonContractInteractor getLink(); // имеется поддержка аннотации @Size
List<CommonContract> getLinks();
List<CommonContractInteractor> getLinks();
Set<CommonContract> getLinks();
Set<CommonContractInteractor> getLinks();
//Обновление значений
void setLinks(Collection<Contract> links);
//Добавление значений (достигается за счет префиксов 'add', 'plus' в названии метода)
void addLink(Contract link); // префикс НЕ обязателен
void addLinks(Collection<Contract> links); // префикс обязателен
//Удаление значений (достигается за счет префиксов 'remove', 'delete' в названии метода)
void removeLink(Contract link);
void removeLinks(Collection<Contract> links); // префикс обязателен
@BindLinkedProcesses
Получение и обновление списка привязанных к процессу процессов
Параметры
Name | Type | Required | Default | Description |
---|---|---|---|---|
mode |
Mode |
false |
Mode.LINKED |
Режим привязки (только для получения процессов). LINKED - искомый процесс привязан к текущему процессу LINKING - текущий процесс привязан к искомому процессу |
linkTypes |
Array<String> |
false |
[LINK_TYPE_LINK,LINK_TYPE_MADE,LINK_TYPE_DEPEND] |
Фильтр по типу привязки |
processTypes |
Array<Integer> |
false |
[] |
Фильтр по типу процесса (если не указан, то ищутся процессы любого типа) |
statuses |
Array<Integer> |
false |
[] |
Фильтр по статусу процесса (только для получения процессов). |
statusMode |
StatusMode |
false |
[ANY] |
Режим фильтра по статусам (только для получения процессов). ANY - процесс в любом из указанных статусов NONE - процесс стоящий ни в одном из указанных статусов |
Поддерживаемые сигнатуры
//Получение значений
@Nullable Process getProcess(); // имеется поддержка аннотации @Size
@Nullable Integer getProcess(); // имеется поддержка аннотации @Size
@Nullable ProcessInteractor getProcess(); // имеется поддержка аннотации @Size
List<Process> getProcesses();
List<Integer> getProcesses();
List<ProcessInteractor> getProcesses();
Set<Process> getProcesses();
Set<Integer> getProcesses();
Set<ProcessInteractor> getProcesses();
//Добавление значений
void addProcess(Process process);
void addProcess(ProcessInteractor process);
void addProcess(int processId);
void addProcesses(Collection<Process> processes);
void addProcesses(Collection<ProcessInteractor> processes);
//Удаление значений (достигается за счет префиксов 'remove', 'delete' в названии метода)
void removeProcess(Process process);
void removeProcess(ProcessInteractor process);
void removeProcess(int processId);
@BindCreateTime
Получение даты создания процесса
@BindCloseTime
Получение даты закрытия процесса
@BindProcessDescription
Получение и добавление описания процесса
@BindProcessStatus
Получение и установка статуса процесса
Поддерживаемые сигнатуры
//Получение значения
int getStatus();
@NotNull StatusChange getStatus();
@NotNull IdTitle getStatus();
//Проверка закрывающего статуса (достигается за счет префикса 'isClosed' в названии метода)**
boolean isClosed();
//Установка значения
void setStatus(int statusId)
void setStatus(int statusId, @Nullable String comment)
@BindProcessStatusCheck
Проверка процесса на соответствие заданным условиям статусов
@BindProcessStatusSwitch
Перевод процесса в определенный статус, с возможностью проверки доступности нужного статуса в матрице статусов типа процесса
@BindProcessGroups
Получение и обновление списка групп процесса
Поддерживаемые сигнатуры
//Получение значений
@Nullable ProcessGroup getGroup(); // имеется поддержка аннотации @Size
int getGroup();
List<ProcessGroup> getGroups();
Set<ProcessGroup> getGroups();
List<Integer> getGroups();
Set<Integer> getGroups();
//Обновление значений
void setGroups(Collection<ProcessGroup> groups);
//Добавление значений (достигается за счет префиксов 'add', 'plus' в названии метода)
void addGroup(ProcessGroup link); // префикс НЕ обязателен
void addGroups(Collection<ProcessGroup> groups); // префикс обязателен
//Удаление значений (достигается за счет префиксов 'remove', 'delete' в названии метода)
void removeGroup(ProcessGroup group);
void removeGroups(Collection<ProcessGroup> groups);
@BindProcessExecutors
Получение и обновление списка исполнителей процесса
Параметры
Name | Type | Required | Default | Description |
---|---|---|---|---|
roleId |
Int |
false |
0 |
ID роли |
firstSuitableGroup |
Boolean |
false |
false |
Возможность установки первой подходящей группы (работает при использовании типа User). Если указано значение false, то при наличии нескольких подходящий групп будет ошибка |
Поддерживаемые сигнатуры
//Получение значений
@Nullable ProcessExecutor getExecutor(); // имеется поддержка аннотации @Size
User getExecutor();
UserInteractor getExecutor();
int getExecutor();
List<ProcessExecutor> getExecutors();
Set<ProcessExecutor> getExecutors();
List<User> getExecutors();
List<UserInteractor> getExecutors();
List<Integer> getExecutors();
Set<User> getExecutors();
Set<UserInteractor> getExecutors();
Set<Integer> getExecutors();
//Обновление значений
void setExecutors(Collection<ProcessExecutor> executors);
void setExecutors(Collection<User> executors);
void setExecutors(Collection<UserInteractor> executors);
//Добавление значений (достигается за счет префиксов 'add', 'plus' в названии метода)
void addExecutor(ProcessExecutor executor); // префикс НЕ обязателен
void addExecutor(User user); // префикс НЕ обязателен
void addExecutor(UserInteractor user); // префикс НЕ обязателен
void addExecutors(Collection<ProcessExecutor> executors); // префикс обязателен
void addExecutors(Collection<User> executors); // префикс обязателен
void addExecutors(Collection<UserInteractor> executors); // префикс обязателен
//Удаление значений (достигается за счет префиксов 'remove', 'delete' в названии метода)
void removeExecutor(ProcessExecutor executor);
void removeExecutor(User executor);
void removeExecutor(UserInteractor executor);
void removeExecutors(Collection<ProcessExecutor> executors);
void removeExecutors(Collection<User> executors);
void removeExecutors(Collection<UserInteractor> executors);
Поддержка обработчиков в сущностях
Сущность | Интерфейс сущности | Обработчики |
---|---|---|
Процесс |
|
|
Контрагент |
|
|
Единый договор |
|
|
Группы пользователей |
|
|
Пользователи |
|
|
Город |
|
|
Улица |
|
|
Дом |
|
|
Валидация данных
Предусмотрена возможность валидации входных и выходных данных.
В случае если при вызове метода аргументы или его возвращаемое значение не проходит проверку - кидается BGMessageException
с текстом указанным в аннотации, либо стандартным, если он не задан (имеется возможность указания id объекта в сообщении через #objectId
).
TODO: изменяемый тип исключения
@NotEmpty
javax.validation.constraints.NotEmpty
String - Проверка наличия символов в строке
Collection - Проверка наличия элементов в коллекции
javax.validation.constraints.Email
String - Проверка строки с email-адресом на соответствие regex-паттерну и указанным флагам
(Паттерн и флаги, если не указаны в аннотации, берутся из конфигурации: email.regexp и email.flags)
@Size
javax.validation.constraints.Size
String - Проверка количества символов в строке
Collection - Проверка количества элемента в коллекции
@Future
javax.validation.constraints.Future
Date, LocalDate, LocalDateTime - Проверка является ли дата будущей с точностью до секунды
@FutureOrPresent
javax.validation.constraints.FutureOrPresent
Date, LocalDate, LocalDateTime - Проверка является ли дата будущей или текущей с точностью до секунды
@Past
javax.validation.constraints.Past
Date, LocalDate, LocalDateTime - Проверка является ли дата прошедшей с точностью до секунды
@PastOrPresent
javax.validation.constraints.PastOrPresent
Date, LocalDate, LocalDateTime - Проверка является ли дата прошедшей или текущей с точностью до секунды
@PositiveOrZero
javax.validation.constraints.PositiveOrZero
Number - Проверка является ли число положительным или равным нулю
@NegativeOrZero
javax.validation.constraints.NegativeOrZero
Number - Проверка является ли число отрицательным или равным нулю
@AssertTrue
javax.validation.constraints.AssertTrue
Boolean - Проверка является ли логический тип true
@AssertFalse
javax.validation.constraints.AssertFalse
Boolean - Проверка является ли логический тип false
Валидаторы с поддержкой точности проверки
@Future
ru.bgcrm.util.interactor.annotation.Future
Date, LocalDate, LocalDateTime - Проверка является ли дата будущей с указанием точности
@FutureOrPresent
ru.bgcrm.util.interactor.annotation.FutureOrPresent
Date, LocalDate, LocalDateTime - Проверка является ли дата будущей или текущей с указанием точности
@Past
ru.bgcrm.util.interactor.annotation.Past
Date, LocalDate, LocalDateTime - Проверка является ли дата прошедшей с указанием точности
@PastOrPresent
ru.bgcrm.util.interactor.annotation.PastOrPresent
Date, LocalDate, LocalDateTime - Проверка является ли дата прошедшей или текущей с указанием точности
Contribution Guide
Принцип работы
Вся магия базируется на рефлексии и в частности динамическом проксировании (см. java.lang.reflect.Proxy
).
При вызове Interactor#create
формируется прокси-объект состоящий из набора вложенных друг в друга InvocationHandler
, каждый из которых выполняет какую-то определенную роль в обработке запроса и / или принимает решение о делегировании запроса следующему за ним обработчику.
Конечный прокси можно поделить на слои (соответственно вызов идет от верхнего к нижнему):
-
Валидация (ValidationProxyHandler)
-
Кеширование (CacheProxyHandler)
-
Маршрутизация (InteractionDispatcher + InteractionDispatcherFactory)
-
Обработка (InteractionHandler)
На этапе маршрутизации исходя из используемого интерфейса определяется нужная фабрика обработчиков, на основе аннотаций вызываемого метода определяется какому именно обработчику следует делегировать вызов, далее уже вызывается сам обработчик в котором и содержится логика по работе с сущностью.
Добавление сущностей
-
Завести класс-фабрику, наследующийся от
ru.bgcrm.util.interactor.factory.InteractionDispatcherFactory
-
Зарегистрировать в фабрике маппинг аннотаций и их обработчиков
-
Зарегистрировать фабрику в
ru.bgcrm.util.interactor.InteractionDispatcher
-
Написать тесты
-
Написать документацию
Добавление обработчиков
-
Определиться с пакетом, по принципу универсальный это функционал или он подходит только для процессов / контрагентов (см.
ru.bgcrm.util.interactor.handler
) -
Завести аннотацию
-
Завести класс-обработчик, наследующийся от
BaseInteractionHandler
-
Зарегистрировать маппинг в требуемой(ых) сущности(ях) (в наследниках
ru.bgcrm.util.interactor.factory.InteractionDispatcherFactory
) -
Написать тесты (см.
ru.bgcrm.util.interactor.BaseInteractorTest
) -
Написать документацию (javadoc на аннотации + adoc)
Best Practices
Аспекты
Имеет смысл выделять часто встречающиеся наборы свойств и параметров в отдельные небольшие интерфейсы, каждый из которых бы описывал какой-то определенный аспект содержания или поведения процесса.
Яркий пример аспекта - ru.bgcrm.util.interactor.utils.ProcessInteractor
, он описывает методы характерные для работы с любыми процессами.
Соглашение об именовании
-
With*
- аспекты описывающие привязанные сущности, напримерWithSingleCctvContract
,WithSingleCustomer
-
Has*
- аспекты описывающие параметры, напримерHasSingleAddress
-
CanBe*
- аспекты описывающие статусы процессов, например (CanBeClosed
)
Доп.пример №1
Во многих процессах используется параметр "Адрес", в большинстве случаев речь идет о каком-то одном адресе и для этого часто используется параметр #90. Это значит, что мы можем завести интерфейс HasSingleAddress
, описать в нем методы для работы с этим параметром и в дальнейшем уже наследоваться от него.
interface HasSingleAddress : ProcessInteractor {
@BindAddressParam(PROCESS_PARAMETER_ADDRESS_ID)
@NotNull(message = "В процессе не указан адрес!")
fun getAddress(): ParameterAddressValue
@BindAddressParam(PROCESS_PARAMETER_ADDRESS_ID)
fun getAddressOrNull(): ParameterAddressValue?
@BindAddressParam(PROCESS_PARAMETER_ADDRESS_ID)
fun setAddress(value: ParameterAddressValue?)
}
Доп.пример №2
Предположим, что есть некий набор типов процессов в автоматизации которых участвуют привязанные к ним субдоговора видеонаблюдения.
interface WithSingleCctvContract : ProcessInteractor {
@BindProcessLinkedContracts([Thesaurus.RB_BILLING_ID], "CCTV")
@MustBeUnique("К процессу должен быть привязан только один субдоговор видеонаблюдения!")
@NotNull(message = "К процессу не привязан субдоговор видеонаблюдения!")
fun getCctvContract(): Contract
@BindProcessLinkedContracts([Thesaurus.RB_BILLING_ID], "CCTV")
@MustBeUnique("К процессу должен быть привязан только один субдоговор видеонаблюдения!")
fun getCctvContractOrNull(): Contract?
}
interface WithMultipleCctvContracts : ProcessInteractor {
@BindProcessLinkedContracts([Thesaurus.RB_BILLING_ID], "CCTV")
fun getCctvContracts(): List<Contract>
}