1 /*
2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 #include "kludge_c++11.h"
27 
28 #include <memory>
29 #include "app.h"
30 #include "Log.h"
31 #include "SysInfo.h"
32 #include "ErrorHandling.h"
33 
34 
35 namespace {
36 const std::string* theLastErrorMsg = 0;
37 
38 NopLogAppender nopLogAppender;
39 
40 class StandardLogAppender : public LogAppender {
41 public:
append(const LogEvent & v)42     virtual void append(const LogEvent& v) {
43         std::cerr << "[" << v.logLevel << "] "
44             << v.fileName
45             << ":" << v.lineNum
46             << ": " << v.message
47             << std::endl;
48     }
49 } standardLogAppender;
50 
51 class LastErrorLogAppender : public LogAppender {
52 public:
append(const LogEvent & v)53     virtual void append(const LogEvent& v) {
54         std::cerr << app::lastErrorMsg() << std::endl;
55     }
56 } lastErrorLogAppender;
57 
58 
59 class ResetLastErrorMsgAtEndOfScope {
60 public:
ResetLastErrorMsgAtEndOfScope()61     ResetLastErrorMsgAtEndOfScope() {
62     }
~ResetLastErrorMsgAtEndOfScope()63     ~ResetLastErrorMsgAtEndOfScope() {
64         JP_NO_THROW(theLastErrorMsg = 0);
65     }
66 };
67 
68 class SetLoggerAtEndOfScope {
69 public:
SetLoggerAtEndOfScope(std::unique_ptr<WithExtraLogAppender> & withLogAppender,LogAppender * lastErrorLogAppender)70     SetLoggerAtEndOfScope(
71             std::unique_ptr<WithExtraLogAppender>& withLogAppender,
72             LogAppender* lastErrorLogAppender):
73                 withLogAppender(withLogAppender),
74                 lastErrorLogAppender(lastErrorLogAppender) {
75     }
76 
~SetLoggerAtEndOfScope()77     ~SetLoggerAtEndOfScope() {
78         JP_TRY;
79         std::unique_ptr<WithExtraLogAppender> other(
80                 new WithExtraLogAppender(*lastErrorLogAppender));
81         withLogAppender.swap(other);
82         JP_CATCH_ALL;
83     }
84 
85 private:
86     std::unique_ptr<WithExtraLogAppender>& withLogAppender;
87     LogAppender* lastErrorLogAppender;
88 };
89 
90 } // namespace
91 
92 
93 namespace app {
defaultLastErrorLogAppender()94 LogAppender& defaultLastErrorLogAppender() {
95     return lastErrorLogAppender;
96 }
97 
98 
lastErrorMsg()99 std::string lastErrorMsg() {
100     if (theLastErrorMsg) {
101         return *theLastErrorMsg;
102     }
103     return "";
104 }
105 
106 
isWithLogging()107 bool isWithLogging() {
108     // If JPACKAGE_DEBUG environment variable is set to "true"
109     // logging is enabled.
110     return SysInfo::getEnvVariable(
111             std::nothrow, _T("JPACKAGE_DEBUG")) == _T("true");
112 }
113 
114 
launch(const std::nothrow_t &,LauncherFunc func,LogAppender * lastErrorLogAppender)115 int launch(const std::nothrow_t&,
116         LauncherFunc func, LogAppender* lastErrorLogAppender) {
117     if (isWithLogging()) {
118         Logger::defaultLogger().setAppender(standardLogAppender);
119     } else {
120         Logger::defaultLogger().setAppender(nopLogAppender);
121     }
122 
123     LOG_TRACE_FUNCTION();
124 
125     if (!lastErrorLogAppender) {
126         lastErrorLogAppender = &defaultLastErrorLogAppender();
127     }
128     std::unique_ptr<WithExtraLogAppender> withLogAppender;
129     std::string errorMsg;
130     const ResetLastErrorMsgAtEndOfScope resetLastErrorMsg;
131 
132     JP_TRY;
133 
134     // This will temporary change log appenders of the default logger
135     // to save log messages in the default and additional log appenders.
136     // Log appenders config of the default logger will be restored to
137     // the original state at function exit automatically.
138     const SetLoggerAtEndOfScope setLogger(withLogAppender, lastErrorLogAppender);
139     func();
140     return 0;
141 
142     // The point of all these redefines is to save the last raw error message in
143     // 'theLastErrorMsg' variable.
144     // By default error messages are saved in exception instances with the details
145     // of error origin (source file, function name, line number).
146     // We don't want these details in user error messages. However we still want to
147     // save full information about the last error in the default log appender.
148 #undef JP_HANDLE_ERROR
149 #undef JP_HANDLE_UNKNOWN_ERROR
150 #undef JP_CATCH_EXCEPTIONS
151 #define JP_HANDLE_ERROR(e) \
152     do { \
153         errorMsg = (tstrings::any() << e.what()).str(); \
154         theLastErrorMsg = &errorMsg; \
155         reportError(JP_SOURCE_CODE_POS, e); \
156     } while(0)
157 #define JP_HANDLE_UNKNOWN_ERROR \
158     do { \
159         errorMsg = "Unknown error"; \
160         theLastErrorMsg = &errorMsg; \
161         reportUnknownError(JP_SOURCE_CODE_POS); \
162     } while(0)
163 #define JP_CATCH_EXCEPTIONS \
164     catch (const JpErrorBase& e) { \
165         errorMsg = (tstrings::any() << e.rawMessage()).str(); \
166         theLastErrorMsg = &errorMsg; \
167         try { \
168             throw; \
169         } catch (const std::runtime_error& e) { \
170             reportError(JP_SOURCE_CODE_POS, e); \
171         } \
172     } catch (const std::runtime_error& e) { \
173         errorMsg = lastCRTError(); \
174         theLastErrorMsg = &errorMsg; \
175         reportError(JP_SOURCE_CODE_POS, e); \
176     } \
177     JP_CATCH_UNKNOWN_EXCEPTION
178 
179     JP_CATCH_ALL;
180 
181 #undef JP_HANDLE_ERROR
182 #undef JP_HANDLE_UNKNOWN_ERROR
183 #undef JP_CATCH_EXCEPTIONS
184 #define JP_HANDLE_ERROR(e)      JP_REPORT_ERROR(e)
185 #define JP_HANDLE_UNKNOWN_ERROR JP_REPORT_UNKNOWN_ERROR
186 #define JP_CATCH_EXCEPTIONS     JP_DEFAULT_CATCH_EXCEPTIONS
187 
188     return 1;
189 }
190 } // namespace app
191