PreviousCallback Frameworks Component FrameworksNext

Chapter 20: Exception Handling Frameworks

Exception handling is the mechanism by which objects raise and trap errors. This chapter shows you how you can use this mechanism in the objects you write.

20.1 Overview

Exception handling gives you a flexible mechanism for handling errors in Object COBOL programs. When an object traps an error, it raises an exception. Each different kind of error is represented by a different exception number. If the exception is not trapped by an exception handler, the Object COBOL run-time displays the exception number and an error message on the console.

Objects in the supplied Class Library react to error conditions by raising exceptions. The Class Library has a set of exception numbers, and a file of exception messages. You can define your own exception conditions for objects you create, associating each set of exception conditions with its own error messages file.

You don't have to create exception handlers for the objects in your application; any exception not trapped closes down your application. Exception handlers only trap errors raised by objects through the "raiseException" mechanism; they do not trap run-time system errors.

20.2 Using Exception Handling

Exception handling consists of two separate activities:

You don't have to create exception handlers for the objects in your application; any exception not trapped closes down your application. Exception handlers only trap errors raised by objects through the "raiseException" mechanism; they do not trap run-time system errors.

20.2.1 Registering an Exception Message File

Before an object can raise any exceptions, there must be an exception message file registered with the ExceptionManager. When you register a message file with the ExceptionManager, it returns an exception file offset. This is an integer number which uniquely identifies the file.

Any number of classes or objects can share the same exception message file, and it doesn't matter if the file is registered more than once; the ExceptionManager will always return the same offset value during a particular run of an application.

The offset value returned depends on how many other message files have been previously registered during the application run. Never hard-code an exception file offset value into your classes; always query the ExceptionManager for the value.

To register an exception file:

invoke ExceptionManager "registerMessageFile"
                         using library errfile
                     returning anOffset

where the parameters are:

library Library name.
errfile The name of the file containing your error messages.
anOffset PIC X(4) COMP-5.

The exception file offset value.

The library name is ignored by the mechanisms which find the message file. It is still used by the ExceptionManager as part of the registration of the message file. You must use the same value for both parameters when you send when you send a "queryMessageFile" message to the ExceptionManager referring to the same file. Although the first parameter is not strictly needed on UNIX, including it as part of the method interface keeps source code compatibility between UNIX and Windows and OS/2 platforms.

The example below is a method which registers an exception message file with the ExceptionManager.

 method-id. "registerFile". 
 local-storage section. 
 01 errorFile            pic x(8)
 01 libraryFile          pic x(6)
 01 anOffset             pic x(4) comp-5. 
 procedure division. 
     move spaces to libraryFile, errorFile
     move "mylibf" to libraryFile
     move "err-file" to errorFile
     invoke ExceptionManager "registerMessageFile"
                                using libraryFile errorFile
                            returning anOffset
     exit method.
 end method "registerFile". 

20.2.2 Raising an Exception

Whenever a method detects an error (for example, a value out of range) it should raise an exception. Each different exception has an exception number relating it to a message in an exception message file.

Before raising the exception, you add the exception file offset to the exception number to get a unique exception ID. The object raising the exception may not be the object which registered the error message file, so it can query the ExceptionManager to get the offset for its associated error file. It then raises the exception by sending itself the "raiseException" message.

The "raiseException" method is implemented in the Base class and is inherited by all subclasses. If there is no exception handler registered for the object, the system exception handler displays the error number and message, then terminates the application.

If you have registered an exception handler for the object, execution returns to the statement following the "raiseException" after your exception handler has been invoked.

In order of descending priority, the ExceptionHandler will try to call exception handlers registered with:

  1. The object instance.

  2. The class of the object.

  3. The system exception handler.

To raise an exception :

  1. Get the exception message file offset for this type of object, by sending the "queryMessageFile" to the ExceptionManager.

  2. Calculate the exception ID by adding the exception offset to the exception number.

  3. Send the "raiseException" message to self using the exception ID as a parameter.

The basic "raiseException" message doesn't allow you to supply any information about an error apart from the exception number. The following variations on "raiseException" enable you to send text with the exception number to provide extra information:

"raiseExceptionWithText" Enables you to pass up to six CharacterArrays as parameters with the exception number.
"raiseExceptionWithTextZ" Enables you to pass up to six null-terminated strings as parameters with the exception number.
"raiseExceptionWithTextCollection" Enables you to pass an OrderedCollection of CharacterArrays with the exception number.

The code fragment below is an example of how to raise an exception:

*    Get the error offset. 

     invoke ExceptionManager "queryMessageFile" using "mylibf"
                                            returning errorOffset
*    Calculate the exception ID
     add errorOffset to errorNumber giving exceptionId
*    Raise the exception
     invoke self "raiseException" using exceptionId
                           returning anObject

ErrorOffset, ErrorNumber and ExceptionId are all declared as PIC X(4) COMP-5.

20.2.3 Registering an Object with the Exception Handler

You can use the ExceptionManager to register an exception handler against any class or instance object. An exception handler is a CallBack to a method which knows how to deal with the exception. When the object raises an exception your exception handling method is invoked.

If you register an exception handler against a class object, then all instances of the class are also automatically registered against the same exception handler. You can override the registration by registering an exception handler against a particular instance.

 invoke ExceptionHandler "register" using anObject

where anObject is the object reference to the object you want to register, and anExceptionMethod is a Callback to the exception method. See the chapter Callback Frameworks for more information about Callbacks.

20.2.4 Canceling an Exception Registration

You can cancel an exception handler that has been registered against an object at any time. Once you do this, any exceptions raised by the object will be dealt with by the system exception handler. To cancel registration of an exception handler object , send the Exceptionmanager the "cancel" message.

To cancel the registration of an object with the ExceptionHandler, send it the "cancel" message:

 invoke ExceptionHandler "cancel" using anObject returning aBool

where anObject is the object to de-register, and aBool is a PIC X COMP-5. It contains the value 1 if the deregistration is successful.

20.2.5 Writing Exception Handler Methods

An exception method enables you to handle an error raised by an Object COBOL object in the way that best suits the application. By registering your exception method against a class or instance object, you ensure that it gets invoked whenever those objects raise exceptions.

An exception method is passed the handle to the object that raised the exception, and the exception ID. The exception method needs to calculate the exception number from the exception ID. To do this, the exception method does the following:

  1. Queries the ExceptionManager for the exception offset for the exception message file. The exception method either needs to know the name of the exception message file, or the object raising the exception must implement a method to return it.

  2. Subtracts the exception file offset from the exception ID to get the exception number.

Once the exception method has the exception number, it should test it to see if it has a value it expects. If it doesn't recognize the error, it should raise the exception again. The exception can then either be trapped by an exception handler that knows what to do with it, or by the system exception handler, which terminates your application.

The code below is an example of an exception handling method:

  method-id. "exceptionMethod".
 local-storage section. 

 01  errorNumber             pic x(4) comp-5. 
 01  lsOffset                pic x(4) comp-5. 

 linkage section
 01  anObject                object reference.
 01  anExceptionId           pic x(4) comp-5. 
 01  aDataItem               object reference.
 01  aTextCollection         object reference.

 procedure division using anObject anExceptionId aTextCollection
                returning aDataItem. 
*    Calculate the error number
     invoke ExceptionManager "queryMessageFile"
                                 using "err-lib" "err-file"
                             returning lsOffset
     subtract lsOffset from exceptionId giving errorNumber
*    process the error 
     evaluate errorNumber
         when knownError1 
*    Handle the error
         when knownError2
*    Handle the error
         when other
*    Unknown error, so reraise the exception. 
         invoke self "raiseExceptionWithTextCollection" 
                             using anExceptionId aTextCollection
                         returning aDataItem

     exit method.
 end method "exceptionMethod". 

20.2.6 System Exception Method

The system exception method is an exception method registered for the whole system. It is invoked whenever an object not explicitly registered with the exception handler raises an exception. The default behavior is to display the exception number with an exception message, then end the program.

You can replace the system exception method with your own. Create a Callback for an exception method. Then send the "setSystemHandler" message to the ExceptionManager.

The "setSystemHandler" method returns you a handle to a CallBack for the existing system exception handler. If your replacement system exception method gets an exception it does not know how to handle, reraise the exception, and the default SystemHandler will actually still get invoked.

The example below shows you how to replace the system exception method:

invoke ExceptionManager "setSystemHandler" using newHandler
                                       returning oldHandler

where the parameters are:

newHandler Object handle to the Callback for your exception method.
oldHandler Object handle to the Callback for the system exception method you have replaced.

20.2.7 User Exception Messages

Write your exception messages into a file, using an ASCII editor such as the Micro Focus Editor, and save the file as filename.err (see the section Error File Format below). Then run the shell script, mfmsg to create a .lng file and copy it into the message directory structure under $COBDIR/lang/. You need to be logged in as the superuser to run this script successfully. To run the shell script:

mfmsg output.lng input.err Error File Format

When you write the .err file, start it with the statements:

$quote x

$set 1

where x is the character you wish to use as a quote character. Then, write each error message in the format:

nnnnn  "your error message here" 

where the double-quote character (") is assumed to be the quote character set in the $quote statement above. You can change quote statements at any point during the .err file; each change applies to all the messages which follow it up until the next $quote statement. You can also enter comments, by starting a line with a $ followed by a space.

$quote "

$set 1
1 "Invalid key type"
2 "Failed to open file for dictionary"
3 "Using a key of different size"
4 "Record exceeds maximum allowed length"
5 "Error reading control record"
6 "Indexed file has wrong key structure"
7 "Key not found in file"
8 "Attempt to write a record which has been deleted"
$ ************************************************************
$ Last modified on 95/08/01
$ **************************************************************

Note: Earlier versions of Object COBOL only supported a single user exception file, user.err, with exception numbers starting at 10,000. The ExceptionManager did not require you to register this file. This mechanism still works for backwards compatibility; any exception numbers in the range 10,000 to 65535 are assumed to refer to messages in user.err. All new exception message files should use exception numbers starting from 1, and should be registered explicitly with the ExceptionManager as described in this chapter.

Copyright © 1999 MERANT International Limited. All rights reserved.
This document and the proprietary marks and names used herein are protected by international law.

PreviousCallback Frameworks Component FrameworksNext