Контекст вызова

1. Создание и жизненный цикл контекста вызова

Для того, чтобы можно было реализовать требования распределения прав доступа и логирования действий, любая операция над данными в Celesta производится от имени некоторого пользователя, «анонимных» операций быть не может. Поэтому любой Celesta-код выполняется в некотором контексте вызова, определяемом экземпляром класса (CallContext).

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

Создание контекста вызова производится на уровне контроллера, где предполагается известным (по переданному в запрос токену, цифровой подписи или каким-либо ещё способом) имя пользователя, выполняющего операции.

Контекст создаётся с помощью конструктора

CallContext(String userId)

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

Любой созданный таким образом контекст далее проходит следующий жизненный цикл:

  1. Активация. Вызов метода activate(..), в который передаётся ссылка на объект Celesta и имя выполняемой процедуры. В этот момент открывается неявная транзакция в базе данных и начинается отсчёт времени выполнения вызова.

  2. Вызов сервисного метода. Контекст передаётся в качестве параметра в сервисный метод и используется для создания курсоров.

  3. Закрытие. Вызов метода close(), фиксирующего транзакцию и закрывающего все незакрытые курсоры с высвобождением всех ресурсов JDBC.

Разработчику обычно не требуется выполнять активацию и закрытие контекста самостоятельно, т. к. они выполняются автоматически фреймворком Celesta.

  • При использовании Celesta Spring Boot starter активация и закрытие курсора выполняются при вызове методов сервисов, помеченных аннотацией @CelestaTransaction. Таким образом на этапе разработки достаточно передавать в них неактивированный контекст. Прокси-объект, создаваемый фреймворком Spring вокруг экземпляра сервисного класса, будет выполнять активацию, закрытие контекста и откат транзакции базы данных в случае необработанного исключения.

  • При использовании CelestaUnit в параметры тестов, имеющих тип CallContext, будет передан уже активированный системный контекст на базе Celesta, запущенной с базой данных H2 в in-memory режиме. Закрытие контекста, а также фиксация/откат изменений также обеспечиваются в CelestaUnit прозрачно для разработчика.

2. Использование контекста вызова

Каждый из методов сервисного слоя, использующих Celesta, принимает в качестве аргумента объект ru.curs.celesta.CallContext. Этот объект предназначен, в первую очередь, чтобы быть аргументом конструкторов курсоров. Однако и сам по себе контекст вызова имеет публично доступные методы и свойства, которые могут быть использованы внутри сервисного метода:

commit()

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

rollback()

откатывает текущую транзакцию.

getCelesta()

вызывает текущий экземпляр объекта Celesta. Необходимо, например, для получения информации о метаданных.

getUserId()

возвращает имя пользователя, от лица которого производятся действия.

getStartTime()

возвращает время создания контекста вызова (время начала работы Celesta-процедуры, полученное с помощью System.currentTimeMillis()).

getDurationNs()

возвращает время жизни контекста вызова в наносекундах, измеренное как разница между значениями, возвращаемыми вызовами System.nanoTime().

getProcName()

возвращает имя процедуры, которая была изначально вызвана из контроллера (используется для нужд отладки).

getDBPid()

возвращает PID (process identifier) текущего соединения с базой данных (используется для нужд отладки).