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