c++_api/inc/opals/Exception.hpp
1 #ifndef OPALS_EXCEPTION_FILTER_HPP_INCLUDED
2 #define OPALS_EXCEPTION_FILTER_HPP_INCLUDED
3 
4 #pragma once
5 
6 //opals
7 #include "opals/config.hpp"
8 
9 //stl
10 #include <stdexcept>
11 
12 // Exception guidelines for opals programmers:
13 //
14 // Exception classes allow applications to react programmatically on specific error types (without analysing the error message).
15 // The organisation of exception classes into a hierarchy allows applications to react on groups of more specific errors.
16 //
17 // It can be assumed that most errors are caused by incorrect or missing input parameters. So there should be a fine
18 // granulation of classes concerning those errors. All exception classes must be derived from opals::Exceptions::Base,
19 // either directly or indirectly. Exceptions are only throw if the program cannot continue safely. For other "problematic"
20 // situations use a warning log message:
21 // OPALS_LOG(opals::LogLevel::warning) << message
22 //
23 // Opals exception classes provide an error code, which will be the return code of opals executables.
24 // So if you add a new exception class, also add a new opals::ErrorCode::Type enumerator!
25 // To avoid different messages for the same error, offer as few text input as possible. Which means that the exception
26 // itself should set its text in the constructor (see e.g. opals::Exceptions::FileExistence).
27 //
28 // For errors that can only appear if opals module programmers don't use the opals framework correctly, it is
29 // appropriate to simply throw opals::Exception::Internal.
30 // Since the opals framework translates any exceptions to opals exceptions, it
31 // is necessary to add new opals exceptions to the OPALS_EXCEPTIONS preprocessor list in ExceptionProxy.hpp
32 //
33 // Task list when adding a new exception class:
34 // Is there already an exception describing my error? If not, then define a new exception class:
35 // 1) If the new exception describes an existing exception more precisely, then derive from that existing class.
36 // Otherwise, derive from opals::Exceptions::Base
37 // 2) Add a corresponding enumerator to the enumeration opals::ErrorCode::Type
38 // 3) In the constructor, specify a textual description of the error as a prefix to the constructor argument (const char*)
39 // 4) Add the new exception class to the preprocessor list OPALS_EXCEPTIONS in ExceptionProxy.hpp
40 
41 #ifdef _MSC_VER
42 # define _GLIBCXX_USE_NOEXCEPT
43 #endif
44 
45 namespace opals {
46 
47  /// error codes that identify an Exception
48  /** opals executables return these values (instead of exceptions). */
49  namespace ErrorCode {
50  enum Type {
51  ok = 0, ///< no error
52 
53  unknown, ///< unknown error number, which may appear if exceptions are throw inside used library
54  internally, ///< programming error which appears if the opals framework wasn't used correctly;
55 
56  parameter = 1000, ///< a general parameter error (usally comes from boost::program_options)
57  unknownParameter, ///< thrown if an unknown parameter was set as a command line parameter
58  ambiguousParameter, ///< thrown if there are ambiguities amoung several possible parameter names
59  invalidSyntax, ///< thrown if the command line parameters contain an invalid syntax
60  paramQueriedBeforeSet, ///< thrown if a parameter value is queried although the value has not been set (neither internally, nor externally)
61  fileExistence, ///< thrown if the provided filename doesn't exist.
62  fileReadAccess, ///< thrown if the provided file cannot be accessed for reading.
63  fileWriteAccess, ///< thrown if the provided file cannot be accessed for writing.
64  aliasColumnName, ///< thrown if an alias is set for unknown column name (only predefined column name are allowed)
65  aliasAlreadyDefined, ///< thrown if an alias is used multiple times
66  gdalReadAccess, ///< thrown if the provided file cannot be opened as a GDAL raster (GDALOpen returns NULL)
67  unknownStripName, ///< thrown if a strip name was provided that is unknown
68  xmlParsing, ///< thrown if the provided xml file could not be parsed
69  fileFormatDefinition, ///< thrown if an error in the OPALS file format definition was detected.
70  unknownAttribute, ///< thrown a specified attribute doesn't exists in the corresponding odm.
71  odmReadAccess, ///< thrown if the provided file cannot be opened as an ODM
72  differentCRS, ///< thrown if input data set have different coordinate reference systems
73  missingCRS, ///< thrown if a module requires a coordinate reference systems to be set
74 
75  fileCorrupt = 2000, ///< general file corruption error: thrown if a file to be used is not interpretable
76  logFileCorrupt, ///< thrown if an existing log file shall be used, but the correct position to proceed writing cannot be determined
77  paramFileCorrupt, ///< thrown if an existing parameter file shall be appended to, but the correct position to proceed writing cannot be determined, resulting in a probably ill-formed XML-file
78 
79  licence = 3000, ///< general licence error
80 
81  python = 4000, ///< An error occurred during a call to a Python interpreter. Reflects Python's built-in class exceptions.BaseException
82  /*
83  The hierarchy of Python's built-in Exception classes cannot be represented by only 3 digits.
84  Thus, we do not represent the hierarchy in the error codes.
85  To avoid future changes of error codes due to changes of Python's exception hierarchy, we separate the codes by 10.
86  Note: The following hierarchy is the one of Python 2.7. Since then, exception have been both introduced and removed. Most notably, StandardError has been removed.
87  Python exception class | error code
88  -----------------------------------------------------------
89  BaseException | 4000
90  +-- SystemExit | 4010
91  +-- KeyboardInterrupt | 4020
92  +-- GeneratorExit | 4030
93  +-- Exception | 4040
94  +-- StopIteration | 4050
95  +-- StandardError | 4060
96  | +-- BufferError | 4070
97  | +-- ArithmeticError | 4080
98  | | +-- FloatingPointError | 4090
99  | | +-- OverflowError | 4100
100  | | +-- ZeroDivisionError | 4110
101  | +-- AssertionError | 4120
102  | +-- AttributeError | 4130
103  | +-- EnvironmentError | 4140
104  | | +-- IOError | 4150
105  | | +-- OSError | 4160
106  | | +-- WindowsError (Windows) | 4170
107  | | +-- VMSError (VMS) | 4180
108  | +-- EOFError | 4190
109  | +-- ImportError | 4200
110  | +-- LookupError | 4210
111  | | +-- IndexError | 4220
112  | | +-- KeyError | 4230
113  | +-- MemoryError | 4240
114  | +-- NameError | 4250
115  | | +-- UnboundLocalError | 4260
116  | +-- ReferenceError | 4270
117  | +-- RuntimeError | 4280
118  | | +-- NotImplementedError | 4290
119  | +-- SyntaxError | 4300
120  | | +-- IndentationError | 4310
121  | | +-- TabError | 4320
122  | +-- SystemError | 4330
123  | +-- TypeError | 4340
124  | +-- ValueError | 4350
125  | +-- UnicodeError | 4360
126  | +-- UnicodeDecodeError | 4370
127  | +-- UnicodeEncodeError | 4380
128  | +-- UnicodeTranslateError | 4390
129  +-- Warning | 4400
130  +-- DeprecationWarning | 4410
131  +-- PendingDeprecationWarning | 4420
132  +-- RuntimeWarning | 4430
133  +-- SyntaxWarning | 4440
134  +-- UserWarning | 4450
135  +-- FutureWarning | 4460
136  +-- ImportWarning | 4470
137  +-- UnicodeWarning | 4480
138  +-- BytesWarning | 4490
139  */
140  pythonException = 4040, ///< Reflects Python's built-in class exceptions.Exception
141  /**< All of Python's built-in, non-system-exiting exceptions are derived from that class. */
142  pythonArithmeticError = 4080, ///< Reflects Python's built-in class exceptions.ArithmeticError
143  /**< Python's base class for those built-in exceptions that are raised for various arithmetic errors. */
144  pythonNameError = 4250, ///< Reflects Python's built-in class exceptions.NameError
145  /**< Raised by Python when a local or global name is not found. */
146  pythonSyntaxError = 4300, ///< Reflects Python's built-in class exceptions.SyntaxError
147  /**< Raised by Python when the parser encounters a syntax error. */
148  pythonTypeError = 4340, ///< Reflects Python's built-in class exceptions.TypeError
149  /**< Raised by Python when an operation or function is applied to an object of inappropriate type. */
150  pythonValueError = 4350, ///< Reflects Python's built-in class exceptions.ValueError
151  /**< Raised by Python when a built-in operation or function receives an argument that has the right type but an inappropriate value. */
152 
153  userInterrupt = 5000, ///< thrown by user programmer (in C++ or Python) to stop processing
154 
155  riwaveError = 6000 ///< thrown if an error is reported by the RiWave lib
156  };
157  };
158 
159  /// \namespace opals::Exceptions
160  /// \brief The namespace containing all exception types that may be thrown from within namespace opals
161  /** All exceptions derive from Exceptions::Base (except for Base itself, of course). */
162  namespace Exceptions {
163 
164  /// The base class of all exceptions thrown by opals.
165  class OPALS_API Base : public ::std::runtime_error
166  {
167  public:
168  Base();
169  Base(const char *errorMessage, ErrorCode::Type errorCode = ErrorCode::unknown);
170  Base(const Base &ref);
171  virtual ~Base() _GLIBCXX_USE_NOEXCEPT;
172 
173  /// returns the error code
174  ErrorCode::Type errorCode() const;
175  /// returns the actual error message
176  const char* errorMessage() const;
177 
178  /// returns the full error message including the error code: "Error XXXX: Text..."
179  const char* what() const _GLIBCXX_USE_NOEXCEPT;
180 
181  protected:
182  ErrorCode::Type e_Code;
183  unsigned u_MessagePos;
184 
185  friend class ExceptionCloner;
186  };
187 
188  /// \copydoc ErrorCode::unknown
189  class OPALS_API Unknown : public Base {
190  public:
191  Unknown(const char *errorMessage);
192  };
193 
194  /// \copydoc ErrorCode::internally
195  class OPALS_API Internal : public Base {
196  public:
197  Internal(const char *errorMessage);
198  };
199 
200  /// \copydoc ErrorCode::parameter
201  class OPALS_API Parameter : public Base {
202  public:
203  Parameter(const char *errorMessage);
204  protected:
205  Parameter(const char *errorMessage, ErrorCode::Type code); ///< Constructor for child classes
206  };
207 
208  /// \copydoc ErrorCode::unknownParameter
209  class OPALS_API UnknownParameter : public Parameter {
210  public:
211  UnknownParameter(const char *errorMessage);
212  };
213 
214  /// \copydoc ErrorCode::ambiguousParameter
215  class OPALS_API AmbiguousParameter : public Parameter {
216  public:
217  AmbiguousParameter(const char *errorMessage);
218  };
219 
220  /// \copydoc ErrorCode::invalidSyntax
221  class OPALS_API InvalidSyntax : public Parameter {
222  public:
223  InvalidSyntax(const char *errorMessage);
224  };
225 
226  /// \copydoc ErrorCode::paramQueriedBeforeSet
227  class OPALS_API ParamQueriedBeforeSet : public Parameter {
228  public:
229  ParamQueriedBeforeSet(const char *errorMessage);
230  };
231 
232  /// \copydoc ErrorCode::fileExistence
233  class OPALS_API FileExistence : public Parameter {
234  public:
235  FileExistence(const char *filename);
236  };
237 
238  /// \copydoc ErrorCode::fileReadAccess
239  class OPALS_API FileReadAccess : public Parameter {
240  public:
241  FileReadAccess(const char *filename);
242  };
243 
244  /// \copydoc ErrorCode::fileWriteAccess
245  class OPALS_API FileWriteAccess : public Parameter {
246  public:
247  FileWriteAccess(const char *filename);
248  };
249 
250  /// \copydoc ErrorCode::odmReadAccess
251  class OPALS_API ODMReadAccess : public Parameter {
252  public:
253  ODMReadAccess(const char *filename);
254  ODMReadAccess(const char *filename, const char *reason);
255  };
256 
257  /// \copydoc ErrorCode::gdalReadAccess
258  class OPALS_API GDALReadAccess : public Parameter {
259  public:
260  GDALReadAccess(const char *filename);
261  };
262 
263  /// \copydoc ErrorCode::aliasColumnName
264  class OPALS_API AliasColumnName : public Parameter {
265  public:
266  AliasColumnName(const char *colname);
267  };
268 
269  /// \copydoc ErrorCode::aliasAlreadyDefined
270  class OPALS_API AliasAlreadyDefined : public Parameter {
271  public:
272  AliasAlreadyDefined(const char *alias);
273  };
274 
275  /// \copydoc ErrorCode::unknownStripName
276  class OPALS_API UnknownStripName : public Parameter {
277  public:
278  UnknownStripName(const char *stripName);
279  };
280 
281  /// \copydoc ErrorCode::xmlParsing
282  class OPALS_API XMLParsing : public Parameter {
283  public:
284  XMLParsing(const char* xmlParser, const char *message);
285  XMLParsing(const char *message);
286  };
287 
288  /// \copydoc ErrorCode::fileFormatDefinition
289  class OPALS_API OpalsFormatDefinition : public Parameter {
290  public:
291  OpalsFormatDefinition(const char *message);
292  };
293 
294  /// \copydoc ErrorCode::unknownAttribute
295  class OPALS_API UnknownAttribute : public Parameter {
296  public:
297  UnknownAttribute(const char *attribute);
298  UnknownAttribute(unsigned count, const char **attributes);
299  UnknownAttribute(const char *filename, unsigned count, const char **attributes);
300  };
301 
302  /// \copydoc ErrorCode::differentCRS
303  class OPALS_API DifferentCRS : public Parameter {
304  public:
305  DifferentCRS(unsigned count, const char **dataSets);
306  };
307 
308  /// \copydoc ErrorCode::missingCRS
309  class OPALS_API MissingCRS : public Parameter {
310  public:
311  MissingCRS();
312  MissingCRS(const char *errorMessage);
313  };
314 
315  /// \copydoc ErrorCode::fileCorrupt
316  class OPALS_API FileCorrupt : public Base {
317  public:
318  FileCorrupt(const char *errorMessage);
319  protected:
320  FileCorrupt(const char *errorMessage, ErrorCode::Type code); ///< Constructor for child classes
321  };
322 
323  /// \copydoc ErrorCode::logFileCorrupt
324  class OPALS_API LogFileCorrupt : public FileCorrupt {
325  public:
326  LogFileCorrupt(const char *filename);
327  };
328 
329  /// \copydoc ErrorCode::paramFileCorrupt
330  class OPALS_API ParamFileCorrupt : public FileCorrupt {
331  public:
332  ParamFileCorrupt(const char *filename, const char *message = 0 );
333  };
334 
335  /// \copydoc ErrorCode::licence
336  class OPALS_API Licence : public Base {
337  public:
338  Licence(const char *errorMessage);
339  protected:
340  Licence(const char *errorMessage, ErrorCode::Type code); ///< Constructor for child classes
341  };
342 
343  /// \copydoc ErrorCode::python
344  class OPALS_API Python : public Base {
345  public:
346  Python(const char *errorMessage);
347  protected:
348  Python(const char *errorMessage, ErrorCode::Type code); ///< Constructor for child classes
349  };
350 
351  /// \copydoc ErrorCode::pythonException
352  class OPALS_API PythonException : public Python {
353  public:
354  PythonException(const char *errorMessage);
355  protected:
356  PythonException(const char *errorMessage, ErrorCode::Type code);
357  };
358 
359  // Python 3 does not define StandardError, so we derive all Python* exceptions directly from PythonException.
360  /// \copydoc ErrorCode::pythonArithmeticError
361  class OPALS_API PythonArithmeticError : public PythonException {
362  public:
363  PythonArithmeticError(const char *errorMessage);
364  protected:
365  PythonArithmeticError(const char *errorMessage, ErrorCode::Type code);
366  };
367 
368  /// \copydoc ErrorCode::pythonNameError
369  class OPALS_API PythonNameError : public PythonException {
370  public:
371  PythonNameError(const char *errorMessage);
372  protected:
373  PythonNameError(const char *errorMessage, ErrorCode::Type code);
374  };
375 
376  /// \copydoc ErrorCode::pythonSyntaxError
377  class OPALS_API PythonSyntaxError : public PythonException {
378  public:
379  PythonSyntaxError(const char *errorMessage);
380  protected:
381  PythonSyntaxError(const char *errorMessage, ErrorCode::Type code);
382  };
383 
384  /// \copydoc ErrorCode::pythonTypeError
385  class OPALS_API PythonTypeError : public PythonException {
386  public:
387  PythonTypeError(const char *errorMessage);
388  protected:
389  PythonTypeError(const char *errorMessage, ErrorCode::Type code);
390  };
391 
392  /// \copydoc ErrorCode::pythonValueError
393  class OPALS_API PythonValueError : public PythonException {
394  public:
395  PythonValueError(const char *errorMessage);
396  protected:
397  PythonValueError(const char *errorMessage, ErrorCode::Type code);
398  };
399 
400  /// \copydoc ErrorCode::userInterrupt
401  class OPALS_API UserInterrupt : public Base {
402  public:
403  UserInterrupt(const char *errorMessage = 0);
404  protected:
405  UserInterrupt(const char *errorMessage, ErrorCode::Type code); ///< Constructor for child classes
406  };
407 
408  /// \copydoc ErrorCode::riwaveError
409  class OPALS_API RiwaveError : public Base {
410  public:
411  RiwaveError(const char *errorMessage = 0);
412  protected:
413  RiwaveError(const char *errorMessage, ErrorCode::Type code); ///< Constructor for child classes
414  };
415  } // namespace Exceptions
416 
417 
418 }
419 
420 #endif //OPALS_EXCEPTION_FILTER_HPP_INCLUDED