blob: f340113e26d277174789238d49c148bd6f5b2ad8 [file] [log] [blame]
#ifndef UIMA_EXCEPTIONS_HPP
#define UIMA_EXCEPTIONS_HPP
/** \file exceptions.hpp .
******************************************************************************
\brief This file contains the base class for all exceptions used in UIMACPP.
DESCRIPTION:
Declaration of the classes:
ErrorMessage
ExceptionDescription
Exception
AccessError
AssertionFailure
DeviceError
InvalidParameter
InvalidRequest
ResourceExhausted
OutOfMemory
OutOfSystemResource
OutOfWindowResource
This file also contains many of the macros used to implement the
library exception handling mechanism. This includes the UIMA_ASSERT,
UIMA_EXC_THROW, UIMA_EXC_RETHROW, UIMA_EXC_CONTEXT,
UIMA_EXCEPTION_DESCRIPTION, UIMA_EXC_CLASSDECLARE, UIMA_EXC_CLASSIMPLEMENT,
macros.
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
********************************************************************************
This file contains the base class for all exceptions used in UIMACPP
project. The design goal was to allow for an easy way to provide
rich context information with the exception without introducing the
need to write lots of lines of code every time you use an exception.
The way this is accomplished here is by defining a rich exception
class and then providing macros for its everyday use that hide its
complexity and automate a lot of processes.
A UIMACPP exception has an error info object as its main informational
member. Such an error info object containes a text, which is supposed to
be a simple description of the error with out context
(e.g. "Could not open file") an error number and an error severity
(recoverable or unrecoverable). To this basic information a <EM>list</EM> of
error contexts can be added (a context has a text and a location, see class
<TT>ErrorContext</TT> above). A context specifies what the program
was trying to do, when the error occurred (e.g. "Trying to open file
XYZ.ABC for reading") since very often not the whole context a user
might need to understand the error is locally available the exception
can be re-throw after adding a context. At the point where it is
caught more context can be added and again it can be re-thrown until
finally the exception can be taken care of (examined/displayed).
This process of defining/catching, adding context and then
(re)throwing is what is very convenient to do via the macros defined
below.
*/
#include "uima/pragmas.hpp" //must be included first to disable warnings
#include <string>
#include <vector>
#include <stdexcept>
#include <iostream>
#include <sstream>
#include <string>
#include "uima/strtools.hpp"
#include "uima/err_ids.h"
#include "uima/types.h"
#include "unicode/uchar.h"
#include "unicode/unistr.h"
#include "uima/unistrref.hpp"
#define UIMA_MSG_MAX_STR_LEN 4096
#define UIMA_MSG_REPLACE_CHAR '%'
namespace uima {
/** Class ErrorMessage: this is a helper class for main class
<TT>ErrorInfo</TT> and <TT>ErrorContext</TT>. It bundles a message id
and optional a list of string parameters for the message.
*/
class UIMA_LINK_IMPORTSPEC ErrorMessage {
public:
/*------------------------------- Constructors -------------------------------*/
///Constructor with just the message id
ErrorMessage(
TyMessageId utMsgId = 0
);
///Constructor with a single long parameter
ErrorMessage(
TyMessageId utMsgId,
long lParam1
);
///Constructor with a single unsigned long parameter
ErrorMessage(
TyMessageId utMsgId,
unsigned long ulParam1
);
///Constructor with a single int parameter
ErrorMessage(
TyMessageId utMsgId,
int iParam1
);
///Constructor with a single unsigned int parameter
ErrorMessage(
TyMessageId utMsgId,
unsigned int uiParam1
);
///Constructor with a single char * parameter
ErrorMessage(
TyMessageId utMsgId,
const char * cpszParam1
);
///Constructor with a single string parameter
ErrorMessage(
TyMessageId utMsgId,
const std::string & crstrParam1
);
///Constructor with a single UChar * parameter
ErrorMessage(
TyMessageId utMsgId,
const UChar * cpuszParam1
);
///Constructor with a single UnicodeString parameter
ErrorMessage(
TyMessageId utMsgId,
const icu::UnicodeString & crustrParam1
);
///Constructor with a single double parameter
ErrorMessage(
TyMessageId utMsgId,
const double dParam1
);
///Constructor with a full parameter vector
ErrorMessage(
TyMessageId utMsgId,
const std::vector< std::string > & crvecParams
);
/*------------------------- addParams --------------------------------*/
template <class T>
void addParam(T p) {
std::ostringstream message;
message << p;
iv_vecParams.push_back(message.str());
}
/*------------------------- Attributes --------------------------------*/
///accessor for the message id
TyMessageId getMessageID() const {
return(iv_utMsgId);
}
///accessor for the file name
const std::vector< std::string > & getMessageParams() const {
return(iv_vecParams);
}
/*----------------------- Output Support ------------------------------*/
///formatted for error output of the context to string
std::string asString() const;
///Reset method for clearing any error notifications
void reset(void);
private:
/*-------------------------- Private ----------------------------------*/
TyMessageId iv_utMsgId; //The message id
std::vector< std::string > iv_vecParams; //An (optional) list of parameters
}
;// ErrorMessage
/**
<TT>ErrorMessage</TT> output support for streams.
Assuming your message is <TT>"Trying to load function %s"</TT> and
the first argument is <TT>"begindoc"</TT>, your output should look like this:
\code
Trying to load function begindoc.
\endcode
*/
UIMA_LINK_IMPORTSPEC std::ostream &
operator << (
std::ostream & rclOStream,
const ErrorMessage & crclExceptionMessage
);
/** Class ErrorContext: this is a helper class for main class
<TT>Exception</TT>. It stores context information about an information:
What the program tried, when an error occurred, the file where this
occured etc. in short: where, why, how it went wrong.
It should rarely be necessary to use this class directly, since most
of the exceptions are designed to be used via macros, that will
take care of creating context objects for you. */
class UIMA_LINK_IMPORTSPEC ErrorContext {
public:
/*------------------------------- Constructors -------------------------------*/
///Constructor
ErrorContext(
const ErrorMessage & clMsg = ErrorMessage(),
const char* pszFilename = 0,
const char* pszFunction = 0,
unsigned long ulLineNumber = 0
);
/*-------------------------------- Attributes --------------------------------*/
///accessor for the text
const ErrorMessage & getMessage() const;
///accessor for the file name
const char * getFileName() const;
///accessor for the function name
const char * getFunctionName() const;
///accessor for the line number
unsigned long getLineNumber() const;
/*------------------------------ Output Support ------------------------------*/
///formatted for error output of the context to string
std::string asString() const;
private:
/*--------------------------------- Private ----------------------------------*/
ErrorMessage iv_clMessage;
const char * iv_pszFilename;
const char * iv_pszFunction;
unsigned long iv_ulLineNo;
}
; // ErrorContext
/**
<TT>ErrorContext</TT> output support for streams.
This will first stream out the message part of the context and then (indented
by spaces) the file name, function name and line number info (if present).
This means you will typically get a multi-line text!
If <TT>NDEBUG</TT> is defined your output should look like this:
\code
Trying to load function begindoc.
\endcode
In debug mode it will look like:
\code
Trying to load function begindoc.
File : extract.cpp
Function: ExternalAnnotator::tryGetProcAddress(char*)
Line : 87
\endcode
*/
UIMA_LINK_IMPORTSPEC std::ostream &
operator << (
std::ostream & rclOStream,
const ErrorContext & crclExceptionContext
);
/* ----------------------------------------------------------------------- */
/* */
/* ----------------------------------------------------------------------- */
/** Class <TT>ErrorInfo</TT>: This is the base class for all error information
used in UIMACPP.
An error info has a text, that is supposed to be a simple
description of the error with out context (e.g. "Could not open file")
and error number an error code groups and an error severity
(recoverable or unrecoverable). To this basic information a LIST of
error contexts can be added (a context has a text and a location, see class
<TT>ErrorContext</TT> above).
This class is the main informational part in an <TT>Exception</TT>.
But can be also used outside of exceptions in the case where you need
to return detailed error information.
For this second use we need the public setxxx methods for message, errorid and
severity. The setxxx functions should not be used for <TT>ErrorInfo</TT> objects
inside exceptions.
*/
class UIMA_LINK_IMPORTSPEC ErrorInfo {
public:
///enum used to specify severity
enum EnSeverity {
///error is not recoverable
unrecoverable,
///error is recoverable
recoverable
};
/*------------------------------- Constructors -------------------------------*/
/**
Constructor.
@param rclMessage Message id describing <TT>what</TT> went wrong.
@param ulErrorId Error number.
@param enSeverity Recoverability info.
Note that the <TT>clMessage</TT> parameter should just state the plain info what went
wrong (e.g. "Could not open file X").
Use an exception context to add information why, how it went wrong
(e.g. "While trying to open application ini-file").
*/
ErrorInfo(
const ErrorMessage & rclMessage,
TyErrorId ulErrorId,
EnSeverity enSeverity
);
/**
Default Constructor (use outside exceptions only!).
For uses of class ErrorInfo ouside exceptions you will want to
define an empty (neutral, no error) ErrorInfo object which might
get filled with error information by failing functions.
This default constructor will create such a no-error ErrorInfo
object for you.
*/
ErrorInfo( void );
///Destructor
virtual ~ErrorInfo();
/*---------------------------- Exception Message -----------------------------*/
///Accessor for exception message
const ErrorMessage & getMessage(void) const {
return(iv_clErrorMsg);
}
///Accessor for exception message
void setMessage(const ErrorMessage & rclMessage);
/*---------------------------- Exception Severity ----------------------------*/
///Accessor for exception severity: query
virtual bool isRecoverable() const;
///Accessor for exception severity
void setSeverity ( EnSeverity enSeverity );
/*----------------------------- Error Identifier -----------------------------*/
///Accessor for error numbers: query
TyErrorId getErrorId() const;
///Accessor for error numbers
void setErrorId( TyErrorId ulErrorId );
/*---------------------------- Exception Context ----------------------------*/
///Accessor for contexts: add
virtual void addContext( const ErrorContext & crclContext );
///Accessor for contexts: query number
size_t contextCount() const;
///Accessor for contexts: query a specific context
const ErrorContext * contextPtrAtIndex( size_t uiContextIndex ) const;
/*------------------------------ Output Support ------------------------------*/
///formatted for error output of the exception to a string
std::string asString() const;
///Reset method for clearing any error notifications
void reset(void);
/*------------------------------ Static Methods ------------------------------*/
/**@name Static methods.
The following static methods can be called on the <TT>ErrorInfo</TT>
class directly.
*/
//@{
///Static method: set the error info context prefix. Default is" <TT>"\n While: "</TT>
static void setGlobalErrorInfoContextPrefix(const char* cpszContextPrefix);
///Static method: retrieve the error info context prefix.
static const char * getGlobalErrorInfoContextPrefix();
///Static method: set the error info indent. Default is the empty string
static void setGlobalErrorInfoIndent(const char* cpszIndent);
///Static method: retrieve the exception context prefix.
static const char * getGlobalErrorInfoIndent();
//@}
private:
/*--------------------------------- Private ----------------------------------*/
ErrorMessage iv_clErrorMsg;
TyErrorId iv_ulErrorId;
EnSeverity iv_enSeverity;
std::vector< ErrorContext > iv_vecContexts;
/*--------------------------------- Static Private ---------------------------*/
static const char * cv_cpszContextPrefix;
static const char * cv_cpszIndent;
/*--------------------------------- Private functions ------------------------*/
}
; // ErrorInfo
/**
<TT>ErrorInfo</TT> output support for streams.
This will stream out:
<UL>
<LI> Name of the error
<LI> Recoverability info
<LI> Error number
<LI> Error message
<LI> The <TT>ErrorContext</TT> part of the exception
</UL>
This will give you a multi line message!
If <TT>NDEBUG</TT> is defined your output should look like this:
\code
Recoverable : No
Error number : -1
Error : Cannot find function address in DLL/library
While : Trying to load function begindoc
While : Trying to load Annotator IXTalent Test
While : Trying to initialize UIMACPP.
\endcode
In debug mode it will look like:
\code
Error number : -1
Recoverable : No
Error : Cannot find function address in DLL/library
While : Trying to load function begindoc
File : extract.cpp
Function: ExternalAnnotator::tryGetProcAddress(char*)
Line : 87
While : Trying to load Annotator IXTalent Test
File : extracts.cpp
Function: Annotators::init(AnnotatorsConfig&)
Line : 116
While : Trying to initialize UIMACPP.
File : framewrk.cpp
Function: Framework::init(const IString&)
Line : 128
\endcode
*/
UIMA_LINK_IMPORTSPEC std::ostream &
operator << (
std::ostream & rclOStream,
const ErrorInfo & crclErrorInfo
);
/* ----------------------------------------------------------------------- */
/* */
/* ----------------------------------------------------------------------- */
#if defined(OS_STL) // Object Space STL (older compilers)
/** We have to take care of the name of the base class for all exceptions.
ANSI named it simply <TT>exception</TT>, but this conflicts with some existing
objects in older compilers (e.g. in <TT>math.h</TT> on unix).
So for older stuff (Object Space STL based) we don't use the ANSI name
of the base class, but the internal name of the Object Space base class.
*/
#if defined(__xlC__) && (__IBMCPP__ > 310)
/** Define for base class of Exception for old IBM compiler*/
#define EXCEPTION_BASE_CLASS exception
#else
/** Define for base class of Exception for Object Space STL */
#define EXCEPTION_BASE_CLASS os_exception
#endif
#else
/** Define for base class of Exception ANSI compliant STL implementations (newer compilers GNU etc.) */
#define EXCEPTION_BASE_CLASS std::exception
#endif
/**
Class Exception: This is the base class for all exceptions
used in UIMACPP group projects.
An exception can be constructed from atext, that is supposed to be a
simple description of the error with out context (e.g. "Could not open file")
error number and an error severity (recoverable or unrecoverable).
From this basic information a inital error info object is created which
is a publicly avaiable member of the exception class.
To this error info contexts can be added (
a context has a text and a location, see class <TT>ErrorInfo</TT> above).
*/
class UIMA_LINK_IMPORTSPEC Exception :
public EXCEPTION_BASE_CLASS {
public:
/*------------------------------- Constructors -------------------------------*/
/**
Constructor.
@param rclMessage Message id describing <TT>what</TT> went wrong.
@param ulErrorId Error number.
@param enSeverity Recoverability info.
Note that the <TT>clMessage</TT> parameter should just state the plain info what went
wrong (e.g. "Could not open file X").
Use an exception context to add information why, how it went wrong
(e.g. "While trying to open application ini-file").
*/
Exception(
const ErrorMessage & rclMessage,
TyErrorId ulErrorId,
ErrorInfo::EnSeverity enSeverity
);
/**
Constructor from an existing error info object
*/
Exception(const ErrorInfo & crclErrorInfo);
///Destructor
#ifdef OS_STL
virtual ~Exception();
#else
virtual ~Exception() UIMA_THROW0();
#endif
/*------------------------------ Exception Type ------------------------------*/
///name of the exception (automatically set to the name of the class by our macros)
virtual const char * getName() const;
///This is the ANSI standard exceptions way of returning the exception text
virtual const char* what() const UIMA_THROW0() {
return(getName());
}
/*------------------------- Application Termination --------------------------*/
/**
Called to terminate the program instead of actually throwing an exception
if exception support is turned off*/
virtual void terminate();
/*------------------------- Logging Support ----------------------------------*/
/**
Called to write out the exception error message before terminate the program
if exception support is turned off*/
virtual void logExceptionData();
/*------------------------------ Throw Support -------------------------------*/
static void assertParameter(
const char * cpszExceptionText,
ErrorContext clContext
);
/*------------------------------ Output Support ------------------------------*/
///formatted for error output of the exception to a string
std::string asString() const;
/*------------------------------ Access to Error Info -----------------------*/
/// return a reference to the error info member object
ErrorInfo &
getErrorInfo();
/// return a const reference to the error info member object
const ErrorInfo &
getErrorInfo() const ;
/*------------------------------ Static Method -------------------------------*/
/**@name Static methods.
The following static method can be called on the <TT>Exception</TT>
class directly.
*/
//@{
/// Release contents of string container allocated by asString methods
static void release(std::string & msg);
private:
/*----------------------------- Hidden Functions -----------------------------*/
Exception &operator=( const Exception & exc );
/*--------------------------------- Private ----------------------------------*/
ErrorInfo iv_clErrorInfo;
}
; // Exception
/**
<TT>Exception</TT> output support for streams.
This will stream out:
<UL>
<LI> Name of the exception
<LI> Error number
<LI> Recoverability info
<LI> Exception message
<LI> The <TT>ErrorContext</TT> part of the exception
</UL>
This will give you a multi line message!
If <TT>NDEBUG</TT> is defined your output should look like this:
\code
Exception : AnnotatorException
Error number : -1
Recoverable : No
Error : Cannot find function address in DLL/library
While : Trying to load function begindoc
While : Trying to load Annotator IXTalent Test
While : Trying to initialize UIMACPP.
\endcode
In debug mode it will look like:
\code
Exception : AnnotatorException
Error number : -1
Recoverable : No
Error : Cannot find function address in DLL/library
While : Trying to load function begindoc
File : extract.cpp
Function: ExternalAnnotator::tryGetProcAddress(char*)
Line : 87
While : Trying to load Annotator IXTalent Test
File : extracts.cpp
Function: Annotators::init(AnnotatorsConfig&)
Line : 116
While : Trying to initialize UIMACPP.
File : framewrk.cpp
Function: Framework::init(const IString&)
Line : 128
\endcode
*/
UIMA_LINK_IMPORTSPEC std::ostream &
operator << (
std::ostream & rclOStream,
const Exception & crclException
);
/* ----------------------------------------------------------------------- */
/* */
/* ----------------------------------------------------------------------- */
//no function and line information in ship version
#if defined( NDEBUG )
/**
This macro an exception context to be a <TT>ErrorMessage</TT>
with automaticaly added file name, function name and line number information.
The file and line info is optional (not present in <TT>NDEBUG</TT>).
The function name is only used if the compiler supports the <TT>__FUNCTION__</TT> macro
(of course) and can be turned of explicitely by defining
<TT>UIMA_EXC_NO_FUNCTION_NAMES</TT>.
*/
#define UIMA_EXC_CONTEXT(cntxt) \
uima::ErrorContext((uima::ErrorMessage)(cntxt), 0, 0, 0)
#elif defined ( UIMA_EXC_NO_FUNCTION_NAMES )
#define UIMA_EXC_CONTEXT(cntxt) \
uima::ErrorContext((uima::ErrorMessage)(cntxt), __FILE__, 0, __LINE__)
#elif defined ( __FUNCTION__ )
#define UIMA_EXC_CONTEXT(cntxt) \
uima::ErrorContext((uima::ErrorMessage)(cntxt), __FILE__, __FUNCTION__, __LINE__)
#else
#define UIMA_EXC_CONTEXT(cntxt) \
uima::ErrorContext((uima::ErrorMessage)(cntxt), __FILE__, 0, __LINE__)
#endif
/**This macro is intended to be used for adding context to exceptions.
It adds a the contexts <TT>cntxt</TT>
(file name, function name and line number are automatically added
in debug mode = unless <TT>NDEBUG</TT> is defined)
The context can be specified as a single message id or as Message id plus
parameters. In the first case just write down the id. In the second case
write this parameter like this <TT>ErrorMessage(utMsgId, cpszParam1)</TT>.
Note that this macro is not needed if you use the <TT>UIMA_EXC_THROW</TT>,
<TT>UIMA_EXC_RETHROW</TT> or <TT>UIMA_EXC_THROW_NEW</TT> macros. You only need it to add context
without throwing the exception (e.g. just before printing the exception).
@param exc The exception (as defined in catch())
@param cntxt The context string to add (string/char*)*/
#define UIMA_EXC_ADD_CONTEXT(exc, cntxt)\
exc.getErrorInfo().addContext(UIMA_EXC_CONTEXT((ErrorMessage)(cntxt)))
/**This macro is intended to be used for throwing exceptions that are
already defined. It adds a the contexts string <TT>cntxt</TT>
(file name, function name and line number are automatically added
in debug mode = unless <TT>NDEBUG</TT> is defined)
The context can be specified as a single message id or as Message id plus
parameters. In the first case just write down the id. In the second case
write this parameter like this <TT>ErrorMessage(utMsgId, cpszParam1)</TT>.
@param exc The exception (must already be defined)
@param cntxt The context message to add */
#define UIMA_EXC_THROW(exc, cntxt)\
exc.getErrorInfo().addContext(UIMA_EXC_CONTEXT(cntxt)),\
exc.logExceptionData(),\
throw(exc)
/**This macro is intended to be used for re-throwing caught exceptions with
added context. It adds a the contexts string <TT>cntxt</TT>
(file name, function name and line number are automatically added
in debug mode = unless <TT>NDEBUG</TT> is defined)
The context can be specified as a single message id or as Message id plus
parameters. In the first case just write down the id. In the second case
write this parameter like this <TT>ErrorMessage(utMsgId, cpszParam1)</TT>.
@param exc The exception (as defined in catch())
@param cntxt The context message to add */
#define UIMA_EXC_RETHROW(exc, cntxt)\
exc.getErrorInfo().addContext(UIMA_EXC_CONTEXT(cntxt)),\
exc.logExceptionData(),\
throw exc
/**This macro is intended to be used for throwing exceptions that are
not yet defined. It defines an exception of type <TT>extype</TT> with
error number <TT>errorNbr</TT>, error message <TT>errorMsg</TT>, context <TT>exContext</TT>
and severity <TT>recoverable</TT>. (file name, function name and line number
are automatically added to the context in debug mode = unless <TT>NDEBUG</TT>
is defined)
The context can be specified as a single message id or as Message id plus
parameters. In the first case just write down the id. In the second case
write this parameter like this <TT>ErrorMessage(utMsgId, cpszParam1)</TT>.
@param exType The type of the exception (e.g <TT>Exception</TT> or
<TT>FileNotFoundError</TT> see below)
@param errorNbr The error number (long)
@param errorMsg The error message
@param exContext The context message to add
@param recoverable The severity (<TT>Exception::recoverable</TT> or
<TT>Exception::unrecoverable</TT>)
*/
#define UIMA_EXC_THROW_NEW(exType, errorNbr, errorMsg, exContext, recoverable)\
exType exc(errorMsg, errorNbr, recoverable); \
UIMA_EXC_THROW(exc, exContext)
#if defined(DEBUG)
#define UIMA_EXC_ASSERT_EXCEPTION(test)\
if(!(test))\
{\
Exception::assertParameter( \
_TEXT("The following expression must be true, but evaluated to false: ") #test,\
UIMA_EXC_EXCEPTION_CONTEXT());\
}
#else
#define UIMA_EXC_ASSERT_EXCEPTION(test)
#endif
// OS STL does not define exception destructor as exception::~exception() throw();
#ifdef OS_STL
# define CHILD_DESTRUCT_THROW0()
#else
# define CHILD_DESTRUCT_THROW0() UIMA_THROW0()
#endif
/**This macro is intended to derive new exceptions from the base class
(or an already derived exception class).
This will typically be used in .h/.hpp files. For each use of
<TT>UIMA_EXC_CLASSDECLARE</TT> in an .h/.hpp file there must be one use of
<TT>UIMA_EXC_CLASSIMPLEMENT</TT> (see below) in the corresponding .c/.cpp file
@param child The new class name to define
@param parent The class to derive the new one from */
#define UIMA_EXC_CLASSDECLARE(child,parent) \
/*lint -save -e1932 -e1901 -e1931 -e754 -e19 */ \
class UIMA_LINK_IMPORTSPEC child : public parent { \
public: \
child ( \
uima::ErrorMessage clMessage, \
uima::TyErrorId ulErrorId, \
uima::ErrorInfo::EnSeverity enSeverity = uima::ErrorInfo::unrecoverable \
); \
child ( \
uima::ErrorInfo clErrInfo \
); \
virtual const char* getName() const; \
virtual ~child() CHILD_DESTRUCT_THROW0(); \
child (const child &); \
private: \
child &operator = ( const child & ); \
}
/*lint -restore */
/**This macro is intended to derive new exceptions from the base class
(or an already derived exception class).
This will typically be used in .c/.cpp files. For each use of
<TT>UIMA_EXC_CLASSIMPLEMENT</TT> in an .h/.hpp file there must be one use of
<TT>UIMA_EXC_CLASSDECLARE</TT> (see above) in the corresponding .h/.hpp file
@param child The new class name to define
@param parent The class to derive the new one from */
#define UIMA_EXC_CLASSIMPLEMENT(child, parent) \
/*lint -save -e1901 -e1911 -e1746 -e1917 -e1902 */ \
child :: child ( \
uima::ErrorMessage clMessage, \
uima::TyErrorId ulErrorId, \
uima::ErrorInfo::EnSeverity enSeverity \
) \
: parent (clMessage, ulErrorId, enSeverity) \
{;} \
child :: child ( \
uima::ErrorInfo clInfo \
) \
: parent (clInfo) \
{;} \
const char* child :: getName() const { \
return ( # child); \
} \
child :: ~ child () CHILD_DESTRUCT_THROW0() {;} \
child::child (const child & a) : parent (a) {;} \
/*lint -restore */
/**@name Predefined Exceptions (beginning of an error hierarchy).
The following predefined exceptions are supposed to structure the use
of exceptions, help with avoiding multiple definitions of common
exceptions (e.g. file not found) and provide a start for an exception
hierarchy.
*/
//@{
/**
The following classes reimplement the ANSI standard exception hierarchy from
stdexcept.h as exceptions with context and message id support.
This is the reason why they have the "unconventional" names: Uima_<ansi name>
*/
///logic error
UIMA_EXC_CLASSDECLARE(Uima_logic_error, Exception);
///runtime error
UIMA_EXC_CLASSDECLARE(Uima_runtime_error, Exception);
///domain error
UIMA_EXC_CLASSDECLARE(Uima_domain_error, Uima_logic_error);
///invalid argument
UIMA_EXC_CLASSDECLARE(Uima_invalid_argument, Uima_logic_error);
///length error
UIMA_EXC_CLASSDECLARE(Uima_length_error, Uima_logic_error);
///out of range
UIMA_EXC_CLASSDECLARE(Uima_out_of_range, Uima_logic_error);
///range error
UIMA_EXC_CLASSDECLARE(Uima_range_error, Uima_runtime_error);
///overflow error
UIMA_EXC_CLASSDECLARE(Uima_overflow_error, Uima_runtime_error);
///underflow error
UIMA_EXC_CLASSDECLARE(Uima_underflow_error, Uima_runtime_error);
/**
The following exceptions are used by helper test classes that are no longer in the UIMACPP library:
CommandLineDriver DocBuffer ParseHandlers
*/
UIMA_EXC_CLASSDECLARE(ConsoleAbortExc, Exception);
UIMA_EXC_CLASSDECLARE(ExcDocBuffer, Uima_out_of_range);
UIMA_EXC_CLASSDECLARE(ParseHandlerExc, Exception);
/**
The following classes provide a starting point for an exception hierarchy
*/
///Access Error
//? UIMA_EXC_CLASSDECLARE(ExcAccessError, Uima_runtime_error);
///Assertion Failure
//? UIMA_EXC_CLASSDECLARE(ExcAssertionFailure, Exception);
///Ill formed input
UIMA_EXC_CLASSDECLARE(ExcIllFormedInputError, Uima_runtime_error);
///Invalid Parameter
UIMA_EXC_CLASSDECLARE(ExcInvalidParameter, Uima_invalid_argument);
///Index out of Range
UIMA_EXC_CLASSDECLARE(ExcIndexOutOfRange, Uima_out_of_range);
///Device Error
//? UIMA_EXC_CLASSDECLARE(ExcDeviceError, _runtime_error);
///Invalid Request
UIMA_EXC_CLASSDECLARE(ExcInvalidRequest, Uima_runtime_error);
///Resource Exhausted
UIMA_EXC_CLASSDECLARE(ExcResourceExhausted, Uima_runtime_error);
///Out of Memory
UIMA_EXC_CLASSDECLARE(ExcOutOfMemory, ExcResourceExhausted);
///Out of System Resource
//? UIMA_EXC_CLASSDECLARE(ExcOutOfSystemResource, ResourceExhausted);
///Out of Window Resource
//? UIMA_EXC_CLASSDECLARE(ExcOutOfWindowResource, ResourceExhausted);
///File not Found
UIMA_EXC_CLASSDECLARE(ExcFileNotFoundError, Uima_runtime_error);
// Windows specific CException
UIMA_EXC_CLASSDECLARE(ExcWinCException, Uima_runtime_error);
/** Used to report code page conversion errors */
UIMA_EXC_CLASSDECLARE(CodePageConversionException, Exception);
//@}
/**
The following exception is used to report failures from APR functions
*/
UIMA_EXC_CLASSDECLARE(AprFailureException, Exception);
/**
@name Example of using the Exception class/macros
The following example might help to understand how to use the Exception
class/macros:
One of the first things to do during initialization of your program is to set
the message catalog used for exception messages. lets assume <TT>crclMessageCatalog</TT>
is your initialized and valid message catalog object. So in your init code
somewhere you should add:
\code
Exception::setGlobalExceptionMessageCatalog(crclMessageCatalog);
\endcode
This must happen BEFORE THE FIRST EXCEPTION IS THROWN. Otherwise all you will get
is just a "Message catalog not found" instead of your intended error message,
To declare a new exception class, use the <TT>UIMA_EXC_CLASSDECLARE</TT> macro in an .h/.hpp
file:
\code
#include "uima/exceptions.hpp"
UIMA_EXC_CLASSDECLARE(AnnotatorException, InvalidRequest);
\endcode
You can use the <TT>Exception</TT> class as it is, or use one of the predefined
classes for you exceptions. But you can also define your own exceptions.
To define a new exception class use the <TT>UIMA_EXC_CLASSIMPLEMENT</TT> macro in the
corresponding .c/.cpp file:
\code
#include "uima/exceptions.hpp"
UIMA_EXC_CLASSIMPLEMENT(AnnotatorException, InvalidRequest);
\endcode
Later you can use the new exception like this:
\code
if (pFunction == NULL) {
UIMA_EXC_THROW_NEW(AnnotatorException, //exception class defined above
UIMA_Rc_ErrorDLLNotFound, //error number defined somewhere
UIMA_MsgId_ErrorDLLNotFound, //error message msg id (what went wrong)
ErrorMessage(UIMA_MsgId_ContextFunctionLoad, cpszFuncName), //exception context for this error (where, why, how it went wrong)
Exception::unrecoverable); //recoverability info
}
\endcode
This will create a new <TT>AnnotatorException</TT> object, with the error code
<TT>UIMA_Rc_Error</TT>, a text "Cannot find function address in DLL/library", the
context "Trying to load function xxxx" and the severity unrecoverable and
throw this new exception.
Note: Since we have a parameter for the context message we write it as
<TT>ErrorMessage(msgid, param)</TT>
You can catch this function and add to its context in a calling function like
that:
\code
try {
elementAt(cursor)->setConfig(config); //this where UIMA_EXC_THROW_NEW is used
}
catch (Exception &e) {
UIMA_EXC_RETHROW(e, ErrorMessage(UIMA_MsgId_ContextAnnotatorLoad, elementAt(cursor)->getIdString()));
}
\endcode
This will do nothing to correct the error, or inform the user (that might
not be possible or appropriate at this point) but it will add the context
"Trying to load Annotator xxxx" to the exception.
Note: Since we have a parameter for the context message we write it as
<TT>ErrorMessage(msgid, param)</TT>
In a calling function of this code you could finally write:
\code
try {
mExecutionModules.init(mConfig);
}
catch (Exception &e) {
UIMA_EXC_ADD_CONTEXT(e, UIMA_MsgId_ContextUimaInit);
cerr << e << endl;
return e.getErrorId();
}
\endcode
This will add the context "Trying to init UIMACPP" to the exception.
Note: Since we do NOT have a parameter for the context message we can simply
write it as <TT>msgid</TT>
If <TT>NDEBUG</TT> is defined your output should look like this:
...
\code
Exception : AnnotatorException
Recoverable : No
Error number : -1
Error : Cannot find function address in DLL/library
While : Trying to load function begindoc
While : Trying to load Annotator IXTalent Test
While : Trying to initialize UIMACPP.
\endcode
In debug mode it will look like:
\code
Exception : AnnotatorException
Recoverable : No
Error number : -1
Error : Cannot find function address in DLL/library
While : Trying to load function begindoc
File : extract.cpp
Function: ExternalAnnotator::tryGetProcAddress(char*)
Line : 87
While : Trying to load Annotator IXTalent Test
File : extracts.cpp
Function: Annotators::init(AnnotatorsConfig&)
Line : 116
While : Trying to initialize UIMACPP.
File : framewrk.cpp
Function: Framework::init(const IString&)
Line : 128
\endcode
*/
//@{
//@}
/* ----------------------------------------------------------------------- */
/* INLINE Implementation */
/* ----------------------------------------------------------------------- */
inline const ErrorMessage &
ErrorContext::getMessage() const {
return(iv_clMessage);
}
inline const char *
ErrorContext::getFileName() const {
return(iv_pszFilename);
}
inline const char *
ErrorContext::getFunctionName() const {
return(iv_pszFunction);
}
inline unsigned long
ErrorContext::getLineNumber() const {
return(iv_ulLineNo);
}
/* ----------------------------------------------------------------------- */
/* ErrorInfo inline functions */
/* ----------------------------------------------------------------------- */
inline void
ErrorInfo::setGlobalErrorInfoContextPrefix(
const char* cpszContextPrefix
) {
cv_cpszContextPrefix = cpszContextPrefix;
}
inline const char *
ErrorInfo::getGlobalErrorInfoContextPrefix() {
return(cv_cpszContextPrefix);
}
inline void
ErrorInfo::setGlobalErrorInfoIndent(
const char* cpszIndent
) {
cv_cpszIndent = cpszIndent;
}
inline const char *
ErrorInfo::getGlobalErrorInfoIndent() {
return(cv_cpszIndent);
}
inline void ErrorInfo::setMessage( const ErrorMessage & rclMessage ) {
iv_clErrorMsg = rclMessage;
}
inline void ErrorInfo::setSeverity ( EnSeverity enSeverity ) {
iv_enSeverity = enSeverity;
}
inline bool ErrorInfo::isRecoverable() const {
return(iv_enSeverity == ErrorInfo::recoverable);
}
inline void ErrorInfo::setErrorId( TyErrorId ulErrorId ) {
iv_ulErrorId = ulErrorId;
}
inline TyErrorId ErrorInfo::getErrorId() const {
return(iv_ulErrorId);
}
inline size_t ErrorInfo::contextCount() const {
return(iv_vecContexts.size());
}
/* ----------------------------------------------------------------------- */
/* Exception inline functions */
/* ----------------------------------------------------------------------- */
inline ErrorInfo &
Exception::getErrorInfo() {
return iv_clErrorInfo;
}
inline const ErrorInfo &
Exception::getErrorInfo() const {
return iv_clErrorInfo;
}
}
/* ----------------------------------------------------------------------- */
/* */
/* ----------------------------------------------------------------------- */
#endif /* UIMA_EXCEPTIONS_HPP */
/* <EOF> */