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