a2e3dcff5f9c794891b7e925d299122527e01829
[platform/framework/web/wrt-commons.git] / modules / core / include / dpl / exception.h
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file    exception.h
18  * @author  Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version 1.0
20  * @brief   Header file for base exception
21  */
22 #ifndef DPL_EXCEPTION_H
23 #define DPL_EXCEPTION_H
24
25 #include <string>
26 #include <cstring>
27 #include <cstdio>
28 #include <exception>
29 #include <cstdlib>
30 #include <sstream>
31
32 namespace DPL
33 {
34 void LogUnhandledException(const std::string &str);
35 void LogUnhandledException(const std::string &str, const char *filename, int line, const char *function);
36 }
37
38 namespace DPL
39 {
40 class Exception
41 {
42 private:
43     static unsigned int m_exceptionCount;
44     static Exception* m_lastException;
45     static void (*m_terminateHandler)();
46
47     static void AddRef(Exception* exception)
48     {
49         if (!m_exceptionCount)
50             m_terminateHandler  = std::set_terminate(&TerminateHandler);
51
52         ++m_exceptionCount;
53         m_lastException = exception;
54     }
55
56     static void UnRef(Exception* e)
57     {
58         if (m_lastException == e)
59             m_lastException = NULL;
60
61         --m_exceptionCount;
62
63         if (!m_exceptionCount)
64         {
65             std::set_terminate(m_terminateHandler);
66             m_terminateHandler = NULL;
67         }
68     }
69
70     static void TerminateHandler()
71     {
72         if (m_lastException != NULL)
73         {
74             DisplayKnownException(*m_lastException);
75             abort();
76         }
77         else
78         {
79             DisplayUnknownException();
80             abort();
81         }
82     }
83
84     Exception *m_reason;
85     std::string m_path;
86     std::string m_function;
87     int m_line;
88
89 protected:
90     std::string m_message;
91     std::string m_className;
92
93 public:
94     static std::string KnownExceptionToString(const Exception &e)
95     {
96         std::ostringstream message;
97         message << "\033[1;5;31m\n=== Unhandled DPL exception occurred ===\033[m\n\n";
98         message << "\033[1;33mException trace:\033[m\n\n";
99         message << e.DumpToString();
100         message << "\033[1;31m\n=== Will now abort ===\033[m\n";
101
102         return message.str();
103     }
104
105     static std::string UnknownExceptionToString()
106     {
107         std::ostringstream message;
108         message << "\033[1;5;31m\n=== Unhandled non-DPL exception occurred ===\033[m\n\n";
109         message <<  "\033[1;31m\n=== Will now abort ===\033[m\n";
110
111         return message.str();
112     }
113
114     static void DisplayKnownException(const Exception& e)
115     {
116         LogUnhandledException(KnownExceptionToString(e).c_str());
117     }
118
119     static void DisplayUnknownException()
120     {
121         LogUnhandledException(UnknownExceptionToString().c_str());
122     }
123
124     Exception(const Exception &other)
125     {
126         // Deep copy
127         if (other.m_reason != NULL)
128             m_reason = new Exception(*other.m_reason);
129         else
130             m_reason = NULL;
131
132         m_message = other.m_message;
133         m_path = other.m_path;
134         m_function = other.m_function;
135         m_line = other.m_line;
136
137         m_className = other.m_className;
138
139         AddRef(this);
140     }
141
142     const Exception &operator =(const Exception &other)
143     {
144         if (this == &other)
145             return *this;
146
147         // Deep copy
148         if (other.m_reason != NULL)
149             m_reason = new Exception(*other.m_reason);
150         else
151             m_reason = NULL;
152
153         m_message = other.m_message;
154         m_path = other.m_path;
155         m_function = other.m_function;
156         m_line = other.m_line;
157
158         m_className = other.m_className;
159
160         AddRef(this);
161
162         return *this;
163     }
164
165     Exception(const char *path, const char *function, int line, const std::string &message)
166         : m_reason(NULL),
167           m_path(path),
168           m_function(function),
169           m_line(line),
170           m_message(message)
171     {
172         AddRef(this);
173     }
174
175     Exception(const char *path, const char *function, int line, const Exception &reason, const std::string &message)
176         : m_reason(new Exception(reason)),
177           m_path(path),
178           m_function(function),
179           m_line(line),
180           m_message(message)
181     {
182         AddRef(this);
183     }
184
185     virtual ~Exception() throw()
186     {
187         if (m_reason != NULL)
188         {
189             delete m_reason;
190             m_reason = NULL;
191         }
192
193         UnRef(this);
194     }
195
196     void Dump() const
197     {
198         // Show reason first
199         if (m_reason != NULL)
200             m_reason->Dump();
201
202         // Afterward, dump exception
203         const char *file = strchr(m_path.c_str(), '/');
204
205         if (file == NULL)
206             file = m_path.c_str();
207         else
208             ++file;
209
210         printf("\033[0;36m[%s:%i]\033[m %s() \033[4;35m%s\033[m: %s\033[m\n",
211                file, m_line,
212                m_function.c_str(),
213                m_className.c_str(),
214                m_message.empty() ? "<EMPTY>" : m_message.c_str());
215     }
216
217     std::string DumpToString() const
218     {
219         std::string ret;
220         if (m_reason != NULL)
221             ret = m_reason->DumpToString();
222
223         const char *file = strchr(m_path.c_str(), '/');
224
225         if (file == NULL)
226             file = m_path.c_str();
227         else
228             ++file;
229
230         char buf[1024];
231         snprintf(buf, sizeof(buf), "\033[0;36m[%s:%i]\033[m %s() \033[4;35m%s\033[m: %s\033[m\n",
232                file, m_line,
233                m_function.c_str(),
234                m_className.c_str(),
235                m_message.empty() ? "<EMPTY>" : m_message.c_str());
236
237         buf[sizeof(buf)-1] = '\n';
238         ret += buf;
239
240         return ret;
241     }
242
243     Exception *GetReason() const
244     {
245         return m_reason;
246     }
247
248     std::string GetPath() const
249     {
250         return m_path;
251     }
252
253     std::string GetFunction() const
254     {
255         return m_function;
256     }
257
258     int GetLine() const
259     {
260         return m_line;
261     }
262
263     std::string GetMessage() const
264     {
265         return m_message;
266     }
267
268     std::string GetClassName() const
269     {
270         return m_className;
271     }
272 };
273 } // namespace DPL
274
275 #define Try try
276
277 #define Throw(ClassName) \
278     throw ClassName(__FILE__, __FUNCTION__, __LINE__)
279
280 #define ThrowMsg(ClassName, Message)                                                 \
281     do                                                                               \
282     {                                                                                \
283         std::ostringstream dplLoggingStream;                                         \
284         dplLoggingStream << Message;                                                 \
285         throw ClassName(__FILE__, __FUNCTION__, __LINE__, dplLoggingStream.str());   \
286     }while(0)
287
288 #define ReThrow(ClassName) \
289     throw ClassName(__FILE__, __FUNCTION__, __LINE__, _rethrown_exception)
290
291 #define ReThrowMsg(ClassName, Message) \
292     throw ClassName(__FILE__, __FUNCTION__, __LINE__, _rethrown_exception, Message)
293
294 #define Catch(ClassName) \
295     catch (const ClassName &_rethrown_exception)
296
297 #define DECLARE_EXCEPTION_TYPE(BaseClass, Class)                                                                                          \
298     class Class                                                                                                                           \
299         : public BaseClass                                                                                                                \
300     {                                                                                                                                     \
301     public:                                                                                                                               \
302         Class(const char *path, const char *function, int line, const std::string &message = std::string())                               \
303             : BaseClass(path, function, line, message)                                                                                    \
304         {                                                                                                                                 \
305             BaseClass::m_className = #Class;                                                                                              \
306         }                                                                                                                                 \
307                                                                                                                                           \
308         Class(const char *path, const char *function, int line, const DPL::Exception &reason, const std::string &message = std::string()) \
309             : BaseClass(path, function, line, reason, message)                                                                            \
310         {                                                                                                                                 \
311             BaseClass::m_className = #Class;                                                                                              \
312         }                                                                                                                                 \
313     };
314
315 #define UNHANDLED_EXCEPTION_HANDLER_BEGIN try
316
317 #define UNHANDLED_EXCEPTION_HANDLER_END                                                                   \
318     catch (const DPL::Exception &exception)                                                               \
319     {                                                                                                     \
320         std::ostringstream msg;                                                                           \
321         msg << DPL::Exception::KnownExceptionToString(exception);                                         \
322         DPL::LogUnhandledException(msg.str(), __FILE__, __LINE__, __FUNCTION__);                          \
323         abort();                                                                                          \
324     }                                                                                                     \
325     catch (std::exception& e)                                                                             \
326     {                                                                                                     \
327         std::ostringstream msg;                                                                           \
328         msg << e.what();                                                                                  \
329         msg << "\n";                                                                                      \
330         msg << DPL::Exception::UnknownExceptionToString();                                                \
331         DPL::LogUnhandledException(msg.str(), __FILE__, __LINE__, __FUNCTION__);                          \
332         abort();                                                                                          \
333     }                                                                                                     \
334     catch (...)                                                                                           \
335     {                                                                                                     \
336         std::ostringstream msg;                                                                           \
337         msg << DPL::Exception::UnknownExceptionToString();                                                \
338         DPL::LogUnhandledException(msg.str(), __FILE__, __LINE__, __FUNCTION__);                          \
339         abort();                                                                                          \
340     }
341
342 namespace DPL
343 {
344 namespace CommonException
345 {
346 /**
347  * Internal exception definitions
348  *
349  * These should normally not happen.
350  * Usually, exception trace with internal error includes
351  * important messages.
352  */
353 DECLARE_EXCEPTION_TYPE(Exception, InternalError) ///< Unexpected error from underlying libraries or kernel
354 }
355 }
356
357 #endif // DPL_EXCEPTION_H