|Copyright 2003 Nikolas S. Boyd. All rights reserved.||Nik Boyd|
|Exception Registry||Object Structural|
Convert an elaborate set of legacy system exception codes to an hierarchy of classified exceptions.
Legacy software systems often lack the benefits of object-oriented technologies. One impact of this can be seen in how they surface exceptions through their public interfaces. Legacy system interfaces often include an elaborate, complex set of exception codes. This can complicate the integration of a legacy system with one designed with object-oriented technologies, even when the legacy system is integrated using some wrapper object(s).
Legacy exception indicators are often returned as coded values. Such exception codes do not support convenient organization and handling of the exceptions. The client becomes encumbered with behavior for filtering the returned codes to handle those few in which it has an interest. The exception codes may have evolved in an ad-hoc fashion. At worst, the encoding of exception values is arbitrary, with little or no planning beyond the recognition that problems arise in the server that need to be handled somehow by the client. The set of legacy exception codes can be filtered or summarized in the legacy system wrapper, but the level of detail required by each prospective client will often be unpredictable. Translating the exception codes into thrown exceptions will usually be a better alternative.
Many modern object-oriented programming languages provide syntactic support for exception handling - e.g., C++ and Java. These built-in language mechanisms provide a convenient programming model for distinguishing between normal behavior and exceptional situations. The best exception models allow the design and use of exceptions as classes. This model allows the exceptions to be organized into hierarchies. The client benefits by being able to focus only on those broad or narrow classes of exceptions in which it has an interest. Thus, the server will raise detailed exceptions, while the client can "listen" for specific or general exceptions, or choose to ignore certain kinds of exceptions altogether.
Given a well-defined exception mechanism, it is possible to establish an ExceptionRegistry that contains a set of RegisteredExceptions. Each exception code can be mapped to an exception class. For each unique exceptional condition, a corresponding kind of SpecificException class is defined. The exception classes can then be organized into a classification hierarchy. This usually requires the addition of new classes that generalize some of the exceptions. For a static exception map, each SpecificException class has a single instance registered in the ExceptionRegistry. When an exception code is returned from a legacy function, the wrapper locates the corresponding exception instance in the ExceptionRegistry in order to throw it. The wrapper clients can then choose which kinds of exceptions they will handle based on the organization of the exception hierarchy.
Use the Exception Registry pattern when
- maps each exception code to a RegisteredException.
- serves as a common base class for a set of legacy exception classes.
- registers each derived exception class instance during its construction.
- identifies a specific kind of legacy exception.
- indicates a specific kind of legacy exception occurred when thrown.
- wraps and objectifies the legacy system.
- locates registered exceptions based on their legacy exception codes.
- throws an exception when the legacy system returns an exception code.
- provides a service through a public interface.
- surfaces exceptions using coded return values.
The Exception Registry pattern has the following consequences:
Uniform Exception Handling. The ExceptionRegistry maps all returned exception values to classified exceptions. The LegacySystemWrapper need not concern itself with how exceptions are presented to its Clients. The LegacySystemWrapper simply uses the ExceptionRegistry to identify the appropriate kind of exception and throw it. The LegacySystemWrapper can surface all the exceptions returned by the LegacySystem without concern for whether they will be used by any particular Client.
Simpler Code. Clients no longer need to have elaborate code for detecting the exceptions in which they are interested. They can simply use the standard exception handling mechanism available in the programming language to catch those exceptions they need to handle. Unhandled exceptions will be dealt with by whatever means is standard for the platform.
Uniquely Identifiable Exceptions. Exception codes which adhere to a consistent identification scheme are the easiest to map. Each exception code serves as an unique key used to identify and look up an instance of a SpecificException class. When instantiated during the construction phase, each SpecificException registers itself in the ExceptionRegistry using its unique identifier, i.e. its exception code value.
Multiple Exceptions. Sometimes, a legacy system will return multiple exceptions encoded into a single value or a returned data structure. In this case, the LegacyWrapper can apply one of the following strategies as appropariate:
Exception Prioritization. If the possible exceptions can be prioritized and only one of them needs to be indicated to the caller, the LegacyWrapper can apply the rules for prioritizing the exceptions, look up the most important one using the ExceptionRegistry, and throw it.
Exception Aggregation. If all the exceptions are equally important and need to be available to the caller, the LegacyWrapper can throw an AggregatedException class that contains a collection of all the SpecificExceptions returned by the LegacySystem. Each SpecificException is still identified and looked up using the ExceptionRegistry.
The following systems have elaborate exception codes:
The ISO 7816-41 standard defines an elaborate set of result codes for response APDUs resulting from command APDUs issued against compliant Smart Cards.
The Microsoft Windows APIs2 have an elaborate set of system error codes returned accessed via the GetLastErr() function.