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.
All the code shown in this chapter uses the Micro Focus alternatives to the ISO 2002 syntax.
Exception handling gives you a flexible mechanism for handling errors in OO COBOL programs. When an object traps an error, it raises an exception. Each different kind of error is represented by a different exception number.
Objects in the supplied class libraries react to error conditions by raising exceptions. The Class Library has a set of exception numbers, and a file of error messages. You can define your own exception conditions for objects you create, associating each set of exception conditions with its own error messages file.
An object raises an exception by sending itself the "raiseException" message, passing an exception number as a parameter. The Base class implements the "raiseException" method, so it is inherited by all objects. Exception handlers trap errors raised by objects through the "raiseException" mechanism; they do not trap run-time system errors.
The ExceptionManager class in the Base Class Library provides most of the logic for actually handling exceptions, including a system exception handler. The system exception handler displays an error message and shuts down the application when an object raises an exception, but an application can define its own exception handlers and attach them to individual classes or objects to redefine their behavior.
You can replace the system exception handler with a system exception handler of your own.
Create a file with the extension .err, using the Editor. It should start 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 "error-message-text"
where:
nnnnn is the exception number
"error-message-text" is the text of the error message you wish to output for this exception number.
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. Here is an example:
$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 $ ************************************************************
Net Express :
Next, add the .err file to the
project for your application. The IDE compiles this to a .lng file.
Right-click on the .lng file, and package it as a Micro Focus library (.lbr) file. Name the library file filenamedf.lbr. For example, an error message file you refer to in your source code as myerrors has the filename myerrorsdf.lbr.
Server Express:
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
Note: Earlier versions of OO COBOL only supported a single user error 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 error message files should use exception numbers starting from 1, and should be registered explicitly with the ExceptionManager as described in this chapter.
Before an object can raise any exceptions, an error message file must have been registered with the ExceptionManager. When you register a message file with the ExceptionManager, it returns an error file offset. This is an integer number which uniquely identifies the file.
Any number of classes or objects can share the same error 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 error file offset value into your classes; always query the ExceptionManager for the value.
To register an error file:
invoke ExceptionManager "registerMessageFile" using library errfile returning anOffset
where:
library |
Name of the library containing the error file |
errfile |
The name of the file containing your error messges. |
anOffset |
PIC X(4) COMP-5. The error file offset value. |
Server Express:
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 a "queryMessageFile" message
to the ExceptionManager referring to the same file. Although the first
parameter is not strictly needed on Server Express, including it as part of the
method interface keeps source code compatibility between Server Express and Net
Express.
The example below is a method that registers an error 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 error message file.
Before raising the exception, you add the error 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 no exception handler is registered for the object, the system exception handler displays the exception number and error 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:
To raise an exception:
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.
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. To create an exception handler, you need to:
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 a differnt exception handler agianst a particular instance.
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
An exception method enables you to handle an error raised by a 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 reraise the exception. The exception can then be trapped either 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 exception 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".
where:
anObject | is the object which originally raised the error. |
anExceptionId | is the number representing the error raised. |
aDataItem | is an object returned by your exception method. This enables you to return a default parameter from a method which has raised an exception, provided the method is coded to pass back the parameter it receives from the "raiseException" method. |
To register an exception handler against an object:, you invoke the "register"method of the ExceptionManager class:
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 your exception method. For more information about Callbacks see the chapter Callback Frameworks.
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 deregister, and aBool is a PIC X COMP-5. It contains the value 1 if the deregistration is successful.
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 behaviour is to display the exception number with an error 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:
newHandler | is the object handle to the Callback for your exception method. |
oldHandler | is the object handle to the Callback for the system exception method you have replaced. |
Copyright © 2004 Micro Focus International Limited. All rights reserved.