5.2.12.3. Обработчики исключений клиентского уровня

Необработанные исключения в блоках Web Client и Desktop Client, возникшие на клиентском уровне или переданные с Middleware, попадают в специальный механизм обработчиков. Этот механизм реализован в модуле gui и доступен обоим клиентам.

Собственные классы обработчиков можно создавать в корневом пакете модуля gui, web или desktop проекта. Обработчик должен быть управляемым бином, реализовывать интерфейс GenericExceptionHandler, в методе handle() которого производить обработку и возвращать true, либо сразу возвращать false, если данный обработчик не может обработать переданное ему исключение. Такое поведение позволяет организовать "цепочку ответственности" обработчиков.

Рекомендуется наследовать классы своих обработчиков от базового класса AbstractGenericExceptionHandler, который умеет разбирать цепочку исключений (с учетом упакованных внутри RemoteException) и реагировать на конкретные типы исключений. Типы исключений, для которых предназначен данный обработчик, указываются в массиве строк, передаваемом в конструкторе обработчика базовому конструктору. Каждая строка массива должна содержать одно полное имя класса обрабатываемого исключения, например:

@Component("sample_ZeroBalanceExceptionHandler")
public class ZeroBalanceExceptionHandler extends AbstractGenericExceptionHandler {

    public ZeroBalanceExceptionHandler() {
        super(ZeroBalanceException.class.getName());
    }
...

Если класс исключения недоступен на клиенте, следует указывать его имя строковым литералом:

@Component("sample_ForeignKeyViolationExceptionHandler")
public class ForeignKeyViolationExceptionHandler extends AbstractGenericExceptionHandler {

    public ForeignKeyViolationExceptionHandler() {
        super("java.sql.SQLIntegrityConstraintViolationException");
    }
...

В случае использования в качестве базового класса AbstractGenericExceptionHandler логика обработки располагается в методе doHandle(), и может выглядеть следующим образом:

@Override
protected void doHandle(String className, String message, @Nullable Throwable throwable, WindowManager windowManager) {
    String msg = messages.getMainMessage("zeroBalance.message");
    windowManager.showNotification(msg, IFrame.NotificationType.ERROR);
}

Если имени класса исключения недостаточно для того, чтобы принять решение о применимости данного обработчика к исключению, следует определить метод canHandle(), получающий кроме прочего текст исключения. Метод должен вернуть true, если данный обработчик применим для исключения. Например:

@Component("sample_ZeroBalanceExceptionHandler")
public class ZeroBalanceExceptionHandler extends AbstractGenericExceptionHandler {

    public ZeroBalanceExceptionHandler() {
        super(ZeroBalanceException.class.getName());
    }

    @Override
    protected boolean canHandle(String className, String message, @Nullable Throwable throwable) {
        return StringUtils.containsIgnoreCase(message, "Insufficient or zero funds in your account");
    }
...

WindowManager предоставляет метод showExceptionDialog() для отображения диалогового окна с выброшенным исключением и его stacktrace. Метод принимает следующие параметры:

  • throwable - экземпляр Throwable.

  • caption - заголовок диалога. Это необязательный параметр, если он не установлен, используется заголовок по умолчанию.

  • message - сообщение диалога. Это необязательный параметр, если он не установлен, используется сообщение по умолчанию.

Пример вызова диалога в обработчике исключения:

@Override
protected void doHandle(String className, String message, @Nullable Throwable throwable, WindowManager windowManager) {
    if (throwable != null)
        windowManager.showExceptionDialog(throwable, "Exception is thrown", message);
    else
        windowManager.showNotification(message, IFrame.NotificationType.ERROR);
}

Для локализации сообщений об ошибках нужно переопределить ключи для соответствующего обработчика в главном пакете сообщений. Ниже приведён пример ключей для RowLevelSecurityExceptionHandler, обрабатывающего нарушения ограничений прав доступа (row-level security):

  • rowLevelSecurity.caption.User.create - заголовок уведомления о конкретной сущности и операции,

  • rowLevelSecurity.caption.Group - заголовок уведомления о конкретной сущности,

  • rowLevelSecurity.entityAndOperationMessage.User.create - тело сообщения о конкретной сущности и операции,

  • rowLevelSecurity.entityAndOperationMessage.Group - тело сообщения о конкретной сущности.