Введение в обработку ошибок
Обработка ошибок (error handling, condition handling, exception handling) – это действия, выполняющиеся при возникновении некоторых событий, при которых нормальное выполнение приложения прерывается. В OpenEdge ABL для прерываний используется термин condition, который можно перевести как условие или состояние. В ABL имеется четыре типа прерываний:
- Состояние ERROR
- Состояние ENDKEY
- Состояние STOP
- Состояние QUIT
Состояние ERROR устанавливается, когда AVM (ABL Virtual Machine) не может продолжить нормальное выполнение кода из-за системной ошибки или ошибки приложения.
- Когда AVM не в состоянии выполнить ABL код, обычно на уровне операторов. Например, когда оператор FIND не находит соответствующей записи, то возникает ошибка. Эти ошибки известны под названием системные ошибки. Такие ошибки идентифицируется числовым номером и описательным сообщением.
- Когда приложение исполняет оператор RETURN ERROR. Ошибки, сгенерированные таким образом, называются программными ошибками (application error).
- Когда пользователь приложения наживает клавишу, связанную с кодом (keycode) ERROR.
Состояние ENDKEY устанавливается в случаях:
- При вводе данных, пользователь нажимает клавишу, связанную с кодом (keycode) ENDKEY.
- Приложение достигло окончания входного потока.
Практически, основное назначение этого состояния – обработка завершения чтения данных из внешнего файла.
Состояние STOP возникает при возникновении невосстановимой (unrecoverable) ошибки, требующей прекращения сессии, например, AVM обнаружил потерю связи с базой данных, или не смог найти процедуру или программу, запущенную оператором RUN. Программно состояние может быть установлено из приложения с помощью оператора STOP. Пользователь также может установить это состояние, нажав клавишу, связанную с кодом STOP.
Состояние QUIT устанавливается только программно, когда приложение выполняет оператор QUIT.
Для каждого состояния в ABL определены некоторые действия по умолчанию (default error handling). Это обеспечивает защиту данных в базе и метод восстановления работы приложения. В большинстве случаев обработка по умолчанию может быть подавлена и заменена собственным обработчиком ошибок.
Традиционная обработка ошибок.
Стандартно обработчик ошибок определяется на уровне блока ABL и является свойством (property) блока. Стандартная обработка ошибок зависит от типа блока и от того, является ли данный блок транзакционным. Простой пример (Программа 22):
Программа 22. Обработка ошибок – Пример 1
FIND FIRST Customer WHERE CustNum = 1000. DISPLAY Customer.Name.
База данных Sports2000 не содержит в таблице Customer записи с таким номером, поэтому при выполнении оператора FIND произойдет ошибка и будет установлено состояние ERROR. При этом ABL выполнит следующие действия:
- Остановит выполнение блока с ошибочным оператором;
- Отобразит на экран системное сообщение, описывающее возникшую ошибку
- Проверит блок, который содержит ошибочный оператор, на предмет отмены обработки по умолчанию. Если в блоке задана собственная обработка ошибки, будет выполнена она. В нашем случае будет выполнена обработка по умолчанию.
- Выполнит откат блока (UNDO). Если блок транзакционный, будет выполнен откат транзакции. Также будет выполнен откат локальных переменных и временных таблиц, описанных без опции NO-UNDO.
- После отката блока будет выполнено одно из действий «перехода» по умолчанию (RETRY, LEAVE или NEXT – смотри ниже). В нашем случае, для процедуры, будет выполнен LEAVE, что приведет к завершению работы процедуры.
Стандартная обработка ошибок для блока может быть изменена с помощью фразы ON ERROR в заголовке блока.
Большинство операторов ABL поддерживают опцию NO-ERROR. Эта опция подавляет возникновение состояния ERROR при ошибке. Соответственно, никакая стандартная обработка не выполняется. Если ошибка происходит, информация о ней сохраняется в системном объекте ERROR-STATUS. Это позволяет приложению обрабатывать ошибки самостоятельно и выдавать собственные (а не системные) сообщения.
Оператор RETURN ERROR позволяет приложению устанавливать состояние ERROR программно, обработка такого состояния может быть выполнена как стандартным обработчиком, так и приложением (Программа 23).
Программа 23. Обработка ошибок – Пример 2
PROCEDURE Customer1000: FIND FIRST Customer WHERE CustNum = 1000 NO-ERROR. IF ERROR-STATUS:ERROR = TRUE THEN RETURN ERROR "Customer 1000 does not exist.". END PROCEDURE. RUN Customer1000 NO-ERROR. IF ERROR-STATUS:ERROR = TRUE THEN DISPLAY RETURN-VALUE FORMAT "x(60)". ELSE DISPLAY "Success!" FORMAT "x(60)".
Структурная обработка ошибок.
Структурная обработка ошибок представляет собой расширение обычной обработки ошибок ABL (далее называемой традиционной), и доступна в OpenEdge, начиная с версии 10.1C. Новые элементы языка предоставляют более продвинутую модель обработки ошибок, в то же время они сосуществуют и взаимодействуют с традиционными возможностями. При структурной обработке ошибки представляются в виде объектов на основе классов, они могут быть перехвачены обработчиком ошибок и легко переданы из вызываемого контекста в вызывающий для обработки. Структурная обработка ошибок известна как try-catch и является распространенной функцией в объектно-ориентированных языках.
Основные особенности структурной обработки ошибок:
- Все ошибки представляются как объекты (реализации класса)
- Можно определять собственные типы ошибок (классы)
- Можно установить состояние ошибки явно (throw)
- Можно перехватывать и обрабатывать конкретные типы ошибок в конкретном контексте (ABL блоке) (catch)
- Можно передавать ошибки из текущего контекста (внутренний блок) в ближайший внешний контекст (внешний блок) для обработки (re-throw)
- Можно указать код для выполнения в конце взаимосвязанного блока кода, независимо от успешности его завершения (блок FINALLY)
Пример псевдокода структурной обработки ошибок приведен на Рис. 13.
TRY /* to execute this code */ { WRITE FILE myAddresses. } CATCH errorFileLocked /* and if the errorFileLocked error is thrown (raised), let the error handling behavior here catch (handle) the error instead of the system’s default behavior. */ { SEND MESSAGE “File currently unavailable.” } CATCH errorNoWritePermission /* or if the errorNoWritePermission error is thrown, use this behavior.*/ { SEND MESSAGE “You do not have permission to write files.”
Рис. 13. Структурная обработка ошибок – псевдокод
Оператор TRY позволяет определить блок кода, с которым связывается обработка ошибок. Операторы CATCH позволяют определить обработчики ошибок и связать их с определенным типом ошибки. Когда система обнаруживает ошибку в блоке TRY, она исполняет код в соответствующем блоке CATCH. Если соответствующий блок CATCH не найден, поведение системы зависит от конкретной реализации, в большинстве случаев просматривается стек вызовов, пока система не найдет соответствующий CATCH-блок.
Таким образом, структурная обработка ошибок рассматривает ошибку, как именованный объект, и предоставляет блочную структуру обработчиков. Такой синтаксис существенно облегчает чтение и понимание кода.
Хотя базовые принципы являются общими, другие возможности и поведение по умолчанию зависят от реализации конкретного языка.
Так как ABL является блок-структурированным языком, и блоки ABL сами по себе представляют нечто большее, чем простой блок TRY, в нем не требуется оператор TRY. Для всех блоков ABL, кроме простого DO-блока, неявно определена некоторая обработка ошибок (неявная фраза ON ERROR). Явная обработка ошибок для блока может быть задана с помощью явного указания фразы ON ERROR в заголовке блока. В общем, неявные и явные фразы ON ERROR и представляют собой традиционную обработку ошибок в ABL.
Для структурной обработки ABL добавляет встроенные классы для представления ошибок как объектов, и оператор CATCH. Эти расширения предоставляют базовый механизм структурной обработки ошибок в ABL. Рассмотрим простой пример (Программа 24):
Программа 24. Обработка ошибок – Пример 3
DO ON ERROR UNDO, RETURN: FIND FIRST Customer WHERE CustNum = 1000. CATCH eSystemError AS Progress.Lang.SysError: MESSAGE "Not a valid customer number.". UNDO, THROW eSystemError. END CATCH. END. /* DO */
Явная фраза ON ERROR определяет обработку ошибок в блоке DO. При традиционной обработке ошибок действие UNDO, RETURN выполнится при возникновении любой ошибки в блоке. При структурной обработке действие UNDO, RETURN выполнится для любой ошибки, которая не обрабатывается явно в блоке CATCH. Так как оператор FIND устанавливает системную ошибку, выполняется CATCH-блок и оператор MESSAGE выдает пользовательское сообщение об ошибке. Однако блок CATCH заканчивается оператором UNDO, THROW, который перенаправляет обработку объекта eSystemError в блок, содержащий блок DO. В данном случае – в процедуру, которая выполняет традиционную обработку ошибок по умолчанию. Так что системное сообщение об ошибке тоже будет показано. Здесь мы также видим взаимодействие традиционного и структурного методов обработки ошибок.