1 /* $Id: ncbi_message.cpp 578880 2019-01-28 16:27:18Z grichenk $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Authors: Aleksey Grichenko
27 *
28 * File Description: IMessage/IMessageListener implementation
29 *
30 */
31
32 #include <ncbi_pch.hpp>
33 #include <corelib/ncbi_message.hpp>
34 #include <corelib/ncbithr.hpp>
35 #include <corelib/error_codes.hpp>
36 #include <stdlib.h>
37 #include <list>
38
39 #define NCBI_USE_ERRCODE_X Corelib_Message
40
41 BEGIN_NCBI_SCOPE
42
43
CMessageListener_Stack(void)44 CMessageListener_Stack::CMessageListener_Stack(void)
45 {
46 }
47
48
PushListener(IMessageListener & listener,IMessageListener::EListenFlag flag)49 size_t CMessageListener_Stack::PushListener(IMessageListener& listener,
50 IMessageListener::EListenFlag flag)
51 {
52 m_Stack.push_front(SListenerNode(listener, flag));
53 return m_Stack.size();
54 }
55
56
PopListener(size_t depth)57 void CMessageListener_Stack::PopListener(size_t depth)
58 {
59 size_t sz = m_Stack.size();
60 if (depth == 0) depth = sz;
61 if (m_Stack.empty() || sz < depth) {
62 // Nothing to pop.
63 ERR_POST_X_ONCE(1, Warning <<
64 "Unbalanced PushListener/PopListener calls: "
65 "listener index " << depth << " has been already removed");
66 return;
67 }
68 if (sz > depth) {
69 // Report lost listeners.
70 ERR_POST_X_ONCE(2, Warning <<
71 "Unbalanced PushListener/PopListener calls: "
72 "removing " << sz - depth << " lost listeners");
73 }
74 while (m_Stack.size() >= depth) {
75 m_Stack.pop_front();
76 }
77 }
78
79
HaveListeners(void)80 bool CMessageListener_Stack::HaveListeners(void)
81 {
82 return !m_Stack.empty();
83 }
84
85
86 IMessageListener::EPostResult
Post(const IMessage & message)87 CMessageListener_Stack::Post(const IMessage& message)
88 {
89 IMessageListener::EPostResult ret = IMessageListener::eUnhandled;
90 NON_CONST_ITERATE(TListenerStack, it, m_Stack) {
91 if (ret == IMessageListener::eHandled &&
92 it->m_Flag == IMessageListener::eListen_Unhandled) continue;
93 if (it->m_Listener->PostMessage(message) == IMessageListener::eHandled) {
94 ret = IMessageListener::eHandled;
95 }
96 }
97 return ret;
98 }
99
100
101 IMessageListener::EPostResult
Post(const IProgressMessage & progress)102 CMessageListener_Stack::Post(const IProgressMessage& progress)
103 {
104 IMessageListener::EPostResult ret = IMessageListener::eUnhandled;
105 NON_CONST_ITERATE(TListenerStack, it, m_Stack) {
106 if (ret == IMessageListener::eHandled &&
107 it->m_Flag == IMessageListener::eListen_Unhandled) continue;
108 if (it->m_Listener->PostProgress(progress) == IMessageListener::eHandled) {
109 ret = IMessageListener::eHandled;
110 }
111 }
112 return ret;
113 }
114
115
116 static CStaticTls<CMessageListener_Stack> s_Listeners;
117
118
s_GetListenerStack(void)119 CMessageListener_Stack& s_GetListenerStack(void)
120 {
121 CMessageListener_Stack* ls = s_Listeners.GetValue();
122 if ( !ls ) {
123 ls = new CMessageListener_Stack;
124 s_Listeners.SetValue(ls, CTlsBase::DefaultCleanup<CMessageListener_Stack>);
125 }
126 _ASSERT(ls);
127 return *ls;
128 }
129
PushListener(IMessageListener & listener,EListenFlag flag)130 size_t IMessageListener::PushListener(IMessageListener& listener,
131 EListenFlag flag)
132 {
133 CMessageListener_Stack& ls = s_GetListenerStack();
134 return ls.PushListener(listener, flag);
135 }
136
137
PopListener(size_t depth)138 void IMessageListener::PopListener(size_t depth)
139 {
140 CMessageListener_Stack& ls = s_GetListenerStack();
141 return ls.PopListener(depth);
142 }
143
144
HaveListeners(void)145 bool IMessageListener::HaveListeners(void)
146 {
147 return s_GetListenerStack().HaveListeners();
148 }
149
150
151 IMessageListener::EPostResult
Post(const IMessage & message)152 IMessageListener::Post(const IMessage& message)
153 {
154 return s_GetListenerStack().Post(message);
155 }
156
157
158 IMessageListener::EPostResult
Post(const IProgressMessage & progress)159 IMessageListener::Post(const IProgressMessage& progress)
160 {
161 return s_GetListenerStack().Post(progress);
162 }
163
164
CMessage_Basic(const string & txt,EDiagSev sev,int err_code,int sub_code)165 CMessage_Basic::CMessage_Basic(const string& txt,
166 EDiagSev sev,
167 int err_code,
168 int sub_code)
169 : m_Text(txt),
170 m_Severity(sev),
171 m_ErrCode(err_code),
172 m_SubCode(sub_code)
173 {
174 }
175
176
GetText(void) const177 string CMessage_Basic::GetText(void) const
178 {
179 return m_Text;
180 }
181
182
GetSeverity(void) const183 EDiagSev CMessage_Basic::GetSeverity(void) const
184 {
185 return m_Severity;
186 }
187
188
GetCode(void) const189 int CMessage_Basic::GetCode(void) const
190 {
191 return m_ErrCode;
192 }
193
194
GetSubCode(void) const195 int CMessage_Basic::GetSubCode(void) const
196 {
197 return m_SubCode;
198 }
199
200
Clone(void) const201 IMessage* CMessage_Basic::Clone(void) const
202 {
203 return new CMessage_Basic(*this);
204 }
205
206
Write(CNcbiOstream & out) const207 void CMessage_Basic::Write(CNcbiOstream& out) const
208 {
209 out << CNcbiDiag::SeverityName(GetSeverity()) << ": " << GetText() << endl;
210 }
211
212
Compose(void) const213 string CMessage_Basic::Compose(void) const
214 {
215 CNcbiOstrstream out;
216 Write(out);
217 return CNcbiOstrstreamToString(out);
218 }
219
220
CProgressMessage_Basic(const string & txt,Uint8 current,Uint8 total)221 CProgressMessage_Basic::CProgressMessage_Basic(const string& txt,
222 Uint8 current,
223 Uint8 total)
224 : m_Text(txt),
225 m_Current(current),
226 m_Total(total)
227 {
228 }
229
230
GetText(void) const231 string CProgressMessage_Basic::GetText(void) const
232 {
233 return m_Text;
234 }
235
236
GetCurrent(void) const237 Uint8 CProgressMessage_Basic::GetCurrent(void) const
238 {
239 return m_Current;
240 }
241
242
GetTotal(void) const243 Uint8 CProgressMessage_Basic::GetTotal(void) const
244 {
245 return m_Total;
246 }
247
248
Clone(void) const249 CProgressMessage_Basic* CProgressMessage_Basic::Clone(void) const
250 {
251 return new CProgressMessage_Basic(*this);
252 }
253
254
Write(CNcbiOstream & out) const255 void CProgressMessage_Basic::Write(CNcbiOstream& out) const
256 {
257 out << GetText() << " [" << m_Current << "/" << m_Total << "]" << endl;
258 }
259
260
Compose(void) const261 string CProgressMessage_Basic::Compose(void) const
262 {
263 CNcbiOstrstream out;
264 Write(out);
265 return CNcbiOstrstreamToString(out);
266 }
267
268
269 IMessageListener::EPostResult
PostMessage(const IMessage & message)270 CMessageListener_Basic::PostMessage(const IMessage& message)
271 {
272 m_Messages.push_back(AutoPtr<IMessage>(message.Clone()));
273 return eHandled;
274 }
275
276
277 IMessageListener::EPostResult
PostProgress(const IProgressMessage & progress)278 CMessageListener_Basic::PostProgress(const IProgressMessage& progress)
279 {
280 ERR_POST(Note << progress);
281 return eHandled;
282 }
283
284
GetMessage(size_t index) const285 const IMessage& CMessageListener_Basic::GetMessage(size_t index) const
286 {
287 return *m_Messages[index].get();
288 }
289
290
Count(void) const291 size_t CMessageListener_Basic::Count(void) const
292 {
293 return m_Messages.size();
294 }
295
296
Clear(void)297 void CMessageListener_Basic::Clear(void)
298 {
299 m_Messages.clear();
300 }
301
302
303 END_NCBI_SCOPE
304