Callback Frameworks | Component 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.
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.
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.
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".
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:
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" "err-file" 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.
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 anExceptionMethod
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.
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.
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:
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 end-evaluate exit method. end method "exceptionMethod".
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. |
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
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.
Callback Frameworks | Component Frameworks |