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

Текущие обработчики

@BindId

Получение ID сущности

Поддерживаемые сигнатуры

int getId()

@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

@BindTextParam

Получение и обновление параметров с типами text и blob

Параметры

Name Type Required Default Description

value

Int

true

ID параметра

Поддерживаемые сигнатуры

//Получение значений
@Nullable String getValue();

//Запись значений
void setValue(@Nullable String value);

//Очистка значения параметра (осуществляется за счет префикса 'clear' в названии метода)
void clearValue();

@BindTextParamAsNumber

Получение и обновление параметров с типом text и blob хранящих числовые значения.

При отсутствии корректного значения в параметре (null, пустая строка, текст) для примитивных типов возвращается 0, для объектов null.

Параметры

Name Type Required Default Description

value

Int

true

ID параметра

Поддерживаемые сигнатуры

//Получение значений:
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.

Параметры

Name Type Required Default Description

value

Int

true

ID параметра

Поддерживаемые сигнатуры

//Получение значений
@Nullable T getValue();
T getValue(@Default T defaultValue);

//Запись значений
void setValue(@Nullable T value);

//Очистка значения параметра (осуществляется за счет префикса 'clear' в названии метода)
void clearValue();

@BindBooleanParam

Получение и обновление параметров с типом boolean

Параметры

Name Type Required Default Description

value

Int

true

ID параметра

Поддерживаемые сигнатуры

//Получение значений
boolean getValue();

//Запись значений
setValue(boolean value);

//Очистка значения параметра (осуществляется за счет префикса 'clear' в названии метода)
//Очистка является альтернативой методу setValue(false)
void clearValue();

@BindNumberParam

Получение и обновление параметров с типом number

Таблица 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

Время добавления значения

primary key:

id + param_id

indexes:

param_id
value
last_update

Таблица 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

Параметры

Name Type Required Default Description

value

Int

true

ID параметра

Поддерживаемые сигнатуры

//Получение значений
@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

Параметры

Name Type Required Default Description

value

Int

true

ID параметра

Поддерживаемые сигнатуры

//Получение значений
@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

Параметры

Name Type Required Default Description

value

Int

true

ID параметра

Поддерживаемые сигнатуры

//Получение значений
@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);

Поддерживаемые сигнатуры

//Получение и обновление параметров с типом phone
@Nullable String getValue();
void setValue(@Nullable String value);
//Очистка значения параметра (осуществляется за счет префикса 'clear' в названии метода)
void clearValue();

@BindEmailParam

Получение и обновление параметров с типом email

Параметры

Name Type Required Default Description

value

Int

true

ID параметра

Поддерживаемые сигнатуры

//Получение значений
@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);

@BindProcessType

Получение типа процесса

Поддерживаемые сигнатуры

int getTypeId();
@NotNull IdTitle getType();
@NotNull ProcessType getType();

@BindCreateTime

Получение даты создания процесса

Параметры

Name Type Required Default Description

format

String

false

"yyyy-MM-dd HH:mm:ss"

Паттерн формата даты (только для работы с типом String)

Поддерживаемые сигнатуры

@NotNull LocalDateTime getCreateTime();
@NotNull Date getCreateTime();
@Nullable String getCreateTime(); //null возможен в случае, если указан несовместимый формат

@BindCloseTime

Получение даты закрытия процесса

Параметры

Name Type Required Default Description

format

String

false

"yyyy-MM-dd HH:mm:ss"

Паттерн формата даты (только для работы с типом String)

Поддерживаемые сигнатуры

@Nullable LocalDateTime getCreateTime();
@Nullable Date getCreateTime();
@Nullable String getCreateTime(); //null также возможен в случае, если указан несовместимый формат

@BindProcessDescription

Получение и добавление описания процесса

Параметры

Name Type Required Default Description

pattern

String

false

""

Паттерн добавления к описанию процесса

Поддерживаемые сигнатуры

//Получение значения
@Nullable String getValue();

//Добавление значения (достигается за счет префикса add в названии метода)
void addValue(String value);

//Обновление значения
void setValue(@Nullable String value);

@BindProcessStatus

Получение и установка статуса процесса

Поддерживаемые сигнатуры

//Получение значения
int getStatus();
@NotNull StatusChange getStatus();
@NotNull IdTitle getStatus();

//Проверка закрывающего статуса (достигается за счет префикса 'isClosed' в названии метода)**
boolean isClosed();

//Установка значения
void setStatus(int statusId)
void setStatus(int statusId, @Nullable String comment)

@BindProcessStatusCheck

Проверка процесса на соответствие заданным условиям статусов

Параметры

Name Type Required Default Description

statuses

Array<Int>

true

ID статусов

mode

Mode

false

Mode.ANY

Режим проверки:

ANY - вхождение

NONE - исключение

Поддерживаемые сигнатуры

boolean check();
boolean check(int statusId);
boolean check(Set<Integer> statusIds);

@BindProcessStatusSwitch

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

Параметры

Name Type Required Default Description

status

Int

true

ID статуса

Поддерживаемые сигнатуры

void switchStatus();
void switchStatus(@Nullable String comment);
//Проверка возможности перехода в статус (достигается за счет префикса can в названии метода)
boolean canStatus();

@BindProcessGroups

Получение и обновление списка групп процесса

Параметры

Name Type Required Default Description

roleId

Int

false

0

ID роли

Поддерживаемые сигнатуры

//Получение значений
@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);

Поддержка обработчиков в сущностях

Сущность Интерфейс сущности Обработчики

Процесс

ru.bgcrm.util.interactor.utils.process.ProcessInteractor

  • BindId

  • BindConfig

  • BindCreateTime

  • BindCloseTime

  • BindProcessType

  • BindProcessGroups

  • BindProcessExecutors

  • BindProcessDescription

  • BindProcessStatus

  • BindProcessStatusCheck

  • BindProcessStatusSwitch

  • BindProcessLinkedObjects

  • BindProcessLinkedCustomers

  • BindProcessLinkedCommonContracts

  • BindProcessLinkedContracts

  • BindLinkedProcesses

  • BindTextParam

  • BindTextParamAsNumber

  • BindTextParamAsCollection

  • BindTextParamAsJson

  • BindAddressParam

  • BindPhoneParam

  • BindEmailParam

  • BindListParam

  • BindListCountParam

  • BindTreeParam

  • BindDateParam

  • BindDateTimeParam

Контрагент

ru.bgcrm.util.interactor.utils.customer.CustomerInteractor

  • BindId

  • BindTextParam

  • BindTextParamAsNumber

  • BindTextParamAsCollection

  • BindTextParamAsJson

  • BindAddressParam

  • BindPhoneParam

  • BindEmailParam

  • BindListParam

  • BindListCountParam

  • BindTreeParam

  • BindDateParam

  • BindDateTimeParam

Единый договор

ru.bgcrm.util.interactor.utils.commonContract.CommonContractInteractor

  • BindId

  • BindTextParam

  • BindTextParamAsNumber

  • BindTextParamAsCollection

  • BindTextParamAsJson

  • BindAddressParam

  • BindPhoneParam

  • BindEmailParam

  • BindListParam

  • BindListCountParam

  • BindTreeParam

  • BindDateParam

  • BindDateTimeParam

Группы пользователей

ru.bgcrm.util.interactor.utils.group.GroupInteractor

  • BindId

  • BindConfig

  • BindTextParam

  • BindTextParamAsNumber

  • BindTextParamAsCollection

  • BindTextParamAsJson

  • BindAddressParam

  • BindPhoneParam

  • BindEmailParam

  • BindListParam

  • BindListCountParam

  • BindTreeParam

  • BindDateParam

  • BindDateTimeParam

Пользователи

ru.bgcrm.util.interactor.utils.user.UserInteractor

  • BindId

  • BindConfig

  • BindTextParam

  • BindTextParamAsNumber

  • BindTextParamAsCollection

  • BindTextParamAsJson

  • BindAddressParam

  • BindPhoneParam

  • BindEmailParam

  • BindListParam

  • BindListCountParam

  • BindTreeParam

  • BindDateParam

  • BindDateTimeParam

Город

ru.bgcrm.util.interactor.utils.address.CityInteractor

  • BindId

  • BindTextParam

  • BindTextParamAsNumber

  • BindTextParamAsCollection

  • BindTextParamAsJson

  • BindAddressParam

  • BindPhoneParam

  • BindEmailParam

  • BindListParam

  • BindListCountParam

  • BindTreeParam

  • BindDateParam

  • BindDateTimeParam

Улица

ru.bgcrm.util.interactor.utils.address.StreetInteractor

  • BindId

  • BindTextParam

  • BindTextParamAsNumber

  • BindTextParamAsCollection

  • BindTextParamAsJson

  • BindAddressParam

  • BindPhoneParam

  • BindEmailParam

  • BindListParam

  • BindListCountParam

  • BindTreeParam

  • BindDateParam

  • BindDateTimeParam

Дом

ru.bgcrm.util.interactor.utils.address.HouseInteractor

  • BindId

  • BindTextParam

  • BindTextParamAsNumber

  • BindTextParamAsCollection

  • BindTextParamAsJson

  • BindAddressParam

  • BindPhoneParam

  • BindEmailParam

  • BindListParam

  • BindListCountParam

  • BindTreeParam

  • BindDateParam

  • BindDateTimeParam

Валидация данных

Предусмотрена возможность валидации входных и выходных данных. В случае если при вызове метода аргументы или его возвращаемое значение не проходит проверку - кидается BGMessageException с текстом указанным в аннотации, либо стандартным, если он не задан (имеется возможность указания id объекта в сообщении через #objectId).

TODO: изменяемый тип исключения

@NotNull

javax.validation.constraints.NotNull

Object - Проверка - возвращаемое значение не null

@Null

javax.validation.constraints.Null

Object - Проверка - возвращаемое значение null

@NotEmpty

javax.validation.constraints.NotEmpty

String - Проверка наличия символов в строке

Collection - Проверка наличия элементов в коллекции

@Pattern

javax.validation.constraints.Pattern

String - Проверка на соответствие regex-паттерну

@Email

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 - Проверка является ли дата прошедшей или текущей с точностью до секунды

@Positive

javax.validation.constraints.Positive

Number - Проверка является ли число положительным

@Negative

javax.validation.constraints.Negative

Number - Проверка является ли число отрицательным

@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, @FutureOrPresent, @Past, @PastOrPresent используются для валидации дат, но с поддержкой точности проверки.

Параметры

Name Type Required Default Description

message

String

true

Сообщение об ошибке

accuracy

ChronoUnit

true

ChronoUnit.MILLIS

Точность проверки

Поддерживаемые значения:

ChronoUnit.MILLIS - точность до миллисекунд

ChronoUnit.SECONDS - точность до секунд

ChronoUnit.MINUTES - точность до минут

ChronoUnit.HOURS - точность до часов

ChronoUnit.HALF_DAYS - точность до полудня

ChronoUnit.DAYS - точность до дня

@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, каждый из которых выполняет какую-то определенную роль в обработке запроса и / или принимает решение о делегировании запроса следующему за ним обработчику. Конечный прокси можно поделить на слои (соответственно вызов идет от верхнего к нижнему):

  1. Валидация (ValidationProxyHandler)

  2. Кеширование (CacheProxyHandler)

  3. Маршрутизация (InteractionDispatcher + InteractionDispatcherFactory)

  4. Обработка (InteractionHandler)

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

Добавление сущностей

  1. Завести класс-фабрику, наследующийся от ru.bgcrm.util.interactor.factory.InteractionDispatcherFactory

  2. Зарегистрировать в фабрике маппинг аннотаций и их обработчиков

  3. Зарегистрировать фабрику в ru.bgcrm.util.interactor.InteractionDispatcher

  4. Написать тесты

  5. Написать документацию

Добавление обработчиков

  1. Определиться с пакетом, по принципу универсальный это функционал или он подходит только для процессов / контрагентов (см. ru.bgcrm.util.interactor.handler)

  2. Завести аннотацию

  3. Завести класс-обработчик, наследующийся от BaseInteractionHandler

  4. Зарегистрировать маппинг в требуемой(ых) сущности(ях) (в наследниках ru.bgcrm.util.interactor.factory.InteractionDispatcherFactory)

  5. Написать тесты (см. ru.bgcrm.util.interactor.BaseInteractorTest)

  6. Написать документацию (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>

}