7. Exception Handling

Previous chapter

Next chapter

This chapter discusses exceptions: how to handle them and how to recover from them, and how to define your own GemStone errors.

GemStone Errors and Exception Classes
describes how GbsErrors and Exceptions are created and used.

Handling Exceptions
explains how to handle exceptions, and how to define and signal your own errors.

Interrupting GemStone Execution
explains how to interrupt GemStone Execution.

7.1  GemStone Errors and Exception Classes

When an error occurs in the GemStone server and is not handled by server Smalltalk execution, an instance of GbsError is created on the client that contains detailed information about the error, and an exception is signaled in GemBuilder. You may set up exception handlers to catch the exception, and perform the desired client Smalltalk exception handling. If no exception handler is set up for the particular exception that occurred, the default handler opens a notifier, from which you can open a debugger.

GBS and GemStone server exceptions are signaled in client Smalltalk as instances of exception classes.

In GemStone/S 64 Bit 3.0 or later, you can replicate exception instances to the client, along with their instance variables. (See the discussion that begins here.) This behavior may be desirable if you wish to more fully bring information about the server exception to the client. To replicate exception instances to the client, you must set the configuration parameter replicateExceptions to true. By default, replicateExceptions is false and the following behavior applies.

With the GemStone/S 64 Bit 2.x and GemStone/S 32-bit server products, and GemStone/S 64 Bit 3.0 (when replicateExceptions is false), exception classes can be found in the application/package GbsExceptions. In VisualWorks, these exception classes are defined in the namespace GemStone.Gbs.

On the GemStone server, there is a dictionary of error names, called ErrorSymbols. This dictionary lists all the errors that can occur when communicating with a GemStone session. For each of these errors, there is a corresponding client exception class. The name of that class is derived by making the first character of the error symbol uppercase, and prepending “Gbs”. So, for instance, the server error #rtErrBadArgKind corresponds to the client exception class GbsRtErrBadArgKind.

The GemBuilder exception classes fit into the VisualWorks exception hierarchy as shown below:

GenericException
	ControlInterrupt
		GbxAbstractControlInterrupt
			<various specific error classes related to pauses, breaks, or breakpoints>
	Exception
		Error
			GbxAbstractException
				GbsGemStoneError
					GbsAbortingError
						<various specific error classes that cause aborts>
					GbsCompilerError
						<various specific compile-related error classes>
					GbsEventError
						<various specific signal related error classes>
					GbsFatalError
						<various specific fatal error classes>
					GbsInterpreterError
						<various specific other error classes>
				GbsInterfaceError
					GbsAssertionError
					GbsBlockReplicationError
					GbsClassGenerationError
					GbsConnectorError
					GbsDeprecatedError
					GbsLinkedLoginError
					GbsMethodRemovedError
					GbsNotCachedError
					GbsPrintTimeoutError
					GbsUnsupportedFloatError
					GbsWSAEventSelect

The subclasses of GbxAbstractControlInterrupt are exceptions raised by the GemStone server that are normally used to invoke a debugger. Applications do not typically define handlers for these exceptions.

The subclasses of GbsGemStoneError are exceptions that are raised by the GemStone server.

The subclasses of GbsInterfaceError represent client side only GBS errors, that is, errors that are detected by the GBS client.

GemStone/S 64 Bit 3.0 or later (replicateExceptions=true)

For each server exception class, there is a corresponding client exception class. With GemStone/S 64 Bit 3.0 and later, when replicateExceptions is true, these client exception classes have the same name as the corresponding server classes, and are defined in the namespace GemStone.Gbs.Exceptions.

Before being signaled on the client, the actual exception instance on the server is replicated to the client, along with its instance variables.

7.2  Handling Exceptions

You can use the on:do: method to install error handlers to anticipate specific GemStone errors. For example, this shows how to use the exception classes to handle a GemStone server error:

Example 7.1 

[ GBSM currentSession evaluate: '5 / 0' ]
	on: GbsNumErrIntDivisionByZero
	do: [ :ex | ex proceedWith: 'oops' ]
 

To handle an entire set of errors, rather than an individual error, set up the handler for the common superclass of the errors you want to handle. For example, to handle all GemStone fatal errors, set up a handler for GbsFatalError, something like this:

[ … ]
	on: GbsFatalError
	do: [ :ex | … ]

Each exception detected by the GemStone server also has an associated instance of the class GbsError. This is primarily for internal use by GemBuilder, but you can examine the GbsError by sending #originator to the exception instance. For example:

Example 7.2 

[ GBSM evaluate: '#( 1 2 3 ) at: 4']
	on: GbsObjErrBadOffsetIncomplete
	do: [ :ex | ex originator inspect ]
 

User-Defined Errors

You can define and signal your own errors in GemStone. For more information on how to do this, see the GemStone Programming Guide.

This section describes the behavior when replicateExceptions is false (the default), and for GemStone/S 64 Bit 2.x and GemStone/S 32-bit server products.

  • If you’re using GemStone/S 64 Bit 3.0 or later (with replicateExceptions set to true), see the discussion here.

In a GemBuilder application, if you want to define a client Smalltalk exception handler for a user-defined error, you will first need to associate the GemStone error number with a client Smalltalk exception class. To do this, use the method GbsError class>>defineErrorNumber:class:. This only needs to be done once for each user defined error.

Note that user-defined error numbers must be unique, and the numbers 1000-6999 are reserved for use by GemStone.

For example, suppose you have created a GemStone user-defined error as follows:

Example 7.3 

"In GemStone"
| myErrors |
myErrors := LanguageDictionary new.
UserGlobals at: #MyErrors put: myErrors.
myErrors at: #English put: (Array new: 10).
(myErrors at: #English)
	at: 10
	put: #( 'My new error with argument ' 1 ).
 

The following client Smalltalk code signals your newly created error in GemStone:

GBSM evaluate: 'System signal: 10
	args: #[ 46 ] signalDictionary: MyErrors'

A generic signal-handler for all GemStone errors would trap this signal. This code sets up the exception handler and causes the exception to be signaled:

^[GBSM evaluate: 'System signal: 10
		args: #[ 46 ]
		signalDictionary: MyErrors']
	on: GbsGemStoneError
	do: [ :ex | ex return: #handled ].

To explicitly handle your new error in client Smalltalk, you first need to associate the GemStone error number with a client exception class. Create a new class, which should inherit from GbsGemStoneError. In this example, the class MyNewError has been created, and this code associates this class with the GemStone error number:

GbsError
	defineErrorNumber: 10
	class: MyNewError.

Then to explicitly handle your new error from client Smalltalk:

Example 7.4 

^[ GBSM evaluate: 'System 
	signal: 10 
	args: #[ 46 ]
	signalDictionary: MyErrors' ]
   		on: MyNewError
   		do: [ :ex | ex return: #handled ]
 

You can obtain the exception's error description string by sending it #description. For example:

[GBSM execute: '#a at: 2']
	on: GbsObjErrBadOffsetIncomplete
	do: [ :ex | ex return: ex description ]

You can obtain the array of server exception arguments by sending #serverArguments to the client exception. This array contains client replicates of the server error arguments.

For example:

[GBSM execute: '#a at: 2']
	on: GbsObjErrBadOffsetIncomplete
	do: [ :ex | ex return: ex serverArguments ]

For information on how to create GemStone error dictionaries and how to handle GemStone errors (predefined and user-defined) within the GemStone environment, see the chapter entitled “Handling Errors” in the GemStone Programming Guide. For more information about defining error handlers in the client Smalltalk, refer to your client Smalltalk documentation on exception handling.

GemStone/S 64 Bit 3.0 or later (replicateExceptions=true)

With GemStone/S 64 Bit 3.0 or later, when replicateExceptions is true, you can define and signal your own errors by performing the following steps:

1. Create a subclass of an exception class on the server.

2. Create a subclass of the corresponding exception class on the client.

3. Define a connector to connect these two classes.

Subsequently, any exceptions signaled and not handled on the server will be replicated to the client and signaled there.

7.3  Interrupting GemStone Execution

When executing GemStone server Smalltalk in a non-blocking RPC session, it’s possible to interrupt GemStone execution by sending the session #softBreak. GemStone responds by raising GbsRtErrSoftBreak, which is a continuable exception.

GBS automatically sends #softBreak when a client Smalltalk user interrupt occurs in a Process executing GemStone server code (in a non-blocking RPC session). If VisualWorks can’t determine which Process to interrupt when control-Y is entered, try executing GBSM softBreak, or aGbsSession softBreak (if you have more than one GemStone session).

In addition to being continuable, soft break can also be handled on the server by an exception handler. There is another mechanism called hard break which is not continuable, and cannot be handled on the server. Sending an executing GbsSession the message #hardBreak stops server execution, aborts the current GemStone transaction, and raises GbsRtErrHardBreak on the client.

In GBS, in situations where a client Smalltalk user interrupt sends a soft break, a hard break will be sent after the server has not responded to three soft breaks.

Previous chapter

Next chapter