xref: /trunk/main/sw/source/ui/dbui/maildispatcher.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 #include "maildispatcher.hxx"
31 #include "imaildsplistener.hxx"
32 
33 #include <algorithm>
34 
35 using namespace ::com::sun::star;
36 using ::rtl::OUString;
37 
38 typedef std::list< uno::Reference<mail::XMailMessage> > MailMessageContainer_t;
39 typedef std::list< ::rtl::Reference<IMailDispatcherListener> > MailDispatcherListenerContainer_t;
40 
41 namespace /* private */
42 {
43     /* Generic event notifier for started,
44        stopped, and idle events which are
45        very similary */
46     class GenericEventNotifier
47     {
48     public:
49         // pointer to virtual function typedef
50         typedef void (IMailDispatcherListener::*GenericNotificationFunc_t)(::rtl::Reference<MailDispatcher>);
51 
52         GenericEventNotifier(
53             GenericNotificationFunc_t notification_function,
54             ::rtl::Reference<MailDispatcher> mail_dispatcher) :
55             notification_function_(notification_function),
56             mail_dispatcher_(mail_dispatcher)
57         {}
58 
59         void operator() (::rtl::Reference<IMailDispatcherListener> listener) const
60         { (listener.get()->*notification_function_)(mail_dispatcher_); }
61 
62     private:
63         GenericNotificationFunc_t notification_function_;
64         ::rtl::Reference<MailDispatcher> mail_dispatcher_;
65     };
66 
67     class MailDeliveryNotifier
68     {
69     public:
70         MailDeliveryNotifier(::rtl::Reference<MailDispatcher> xMailDispatcher, uno::Reference<mail::XMailMessage> message) :
71             mail_dispatcher_(xMailDispatcher),
72             message_(message)
73         {}
74 
75         void operator() (::rtl::Reference<IMailDispatcherListener> listener) const
76         { listener->mailDelivered(mail_dispatcher_, message_); }
77 
78     private:
79         ::rtl::Reference<MailDispatcher> mail_dispatcher_;
80         uno::Reference<mail::XMailMessage> message_;
81     };
82 
83     class MailDeliveryErrorNotifier
84     {
85     public:
86         MailDeliveryErrorNotifier(
87             ::rtl::Reference<MailDispatcher> xMailDispatcher,
88             uno::Reference<mail::XMailMessage> message,
89             const ::rtl::OUString& error_message) :
90             mail_dispatcher_(xMailDispatcher),
91             message_(message),
92             error_message_(error_message)
93         {}
94 
95         void operator() (::rtl::Reference<IMailDispatcherListener> listener) const
96         { listener->mailDeliveryError(mail_dispatcher_, message_, error_message_); }
97 
98     private:
99         ::rtl::Reference<MailDispatcher> mail_dispatcher_;
100         uno::Reference<mail::XMailMessage> message_;
101         ::rtl::OUString error_message_;
102     };
103 
104 } // namespace private
105 
106 
107 MailDispatcher::MailDispatcher(uno::Reference<mail::XSmtpService> mailserver) :
108     mailserver_ (mailserver),
109     run_(false),
110     shutdown_requested_(false)
111 {
112     wakening_call_.reset();
113     mail_dispatcher_active_.reset();
114 
115     if (!create())
116         throw uno::RuntimeException();
117 
118     // wait until the mail dispatcher thread is really alive
119     // and has aquired a reference to this instance of the
120     // class
121     mail_dispatcher_active_.wait();
122 }
123 
124 MailDispatcher::~MailDispatcher()
125 {
126 }
127 
128 void MailDispatcher::enqueueMailMessage(uno::Reference<mail::XMailMessage> message)
129 {
130     ::osl::MutexGuard thread_status_guard(thread_status_mutex_);
131     ::osl::MutexGuard message_container_guard(message_container_mutex_);
132 
133     OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
134 
135     messages_.push_back(message);
136     if (run_)
137         wakening_call_.set();
138 }
139 
140 uno::Reference<mail::XMailMessage> MailDispatcher::dequeueMailMessage()
141 {
142     ::osl::MutexGuard guard(message_container_mutex_);
143     uno::Reference<mail::XMailMessage> message;
144     if(!messages_.empty())
145     {
146         message = messages_.front();
147         messages_.pop_front();
148     }
149     return message;
150 }
151 
152 void MailDispatcher::start()
153 {
154     OSL_PRECOND(!isStarted(), "MailDispatcher is already started!");
155 
156     ::osl::ClearableMutexGuard thread_status_guard(thread_status_mutex_);
157 
158     OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
159 
160     if (!shutdown_requested_)
161     {
162         run_ = true;
163         wakening_call_.set();
164         thread_status_guard.clear();
165 
166         MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
167         std::for_each(listeners_cloned.begin(), listeners_cloned.end(), GenericEventNotifier(&IMailDispatcherListener::started, this));
168     }
169 }
170 
171 void MailDispatcher::stop()
172 {
173     OSL_PRECOND(isStarted(), "MailDispatcher not started!");
174 
175     ::osl::ClearableMutexGuard thread_status_guard(thread_status_mutex_);
176 
177     OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
178 
179     if (!shutdown_requested_)
180     {
181         run_ = false;
182         wakening_call_.reset();
183         thread_status_guard.clear();
184 
185         MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
186         std::for_each(listeners_cloned.begin(), listeners_cloned.end(), GenericEventNotifier(&IMailDispatcherListener::stopped, this));
187     }
188 }
189 
190 void MailDispatcher::shutdown()
191 {
192     ::osl::MutexGuard thread_status_guard(thread_status_mutex_);
193 
194     OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
195 
196     shutdown_requested_ = true;
197     wakening_call_.set();
198 }
199 
200 bool MailDispatcher::isStarted() const
201 {
202     return run_;
203 }
204 
205 void MailDispatcher::addListener(::rtl::Reference<IMailDispatcherListener> listener)
206 {
207     OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
208 
209     ::osl::MutexGuard guard(listener_container_mutex_);
210     listeners_.push_back(listener);
211 }
212 
213 void MailDispatcher::removeListener(::rtl::Reference<IMailDispatcherListener> listener)
214 {
215     OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
216 
217     ::osl::MutexGuard guard(listener_container_mutex_);
218     listeners_.remove(listener);
219 }
220 
221 std::list< ::rtl::Reference<IMailDispatcherListener> > MailDispatcher::cloneListener()
222 {
223     ::osl::MutexGuard guard(listener_container_mutex_);
224     return listeners_;
225 }
226 
227 void MailDispatcher::sendMailMessageNotifyListener(uno::Reference<mail::XMailMessage> message)
228 {
229     try
230     {
231         mailserver_->sendMailMessage(message);
232         MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
233         std::for_each(listeners_cloned.begin(), listeners_cloned.end(), MailDeliveryNotifier(this, message));
234     }
235     catch (mail::MailException& ex)
236     {
237         MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
238         std::for_each(listeners_cloned.begin(), listeners_cloned.end(), MailDeliveryErrorNotifier(this, message, ex.Message));
239     }
240     catch (uno::RuntimeException& ex)
241     {
242         MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
243         std::for_each(listeners_cloned.begin(), listeners_cloned.end(), MailDeliveryErrorNotifier(this, message, ex.Message));
244     }
245 }
246 
247 void MailDispatcher::run()
248 {
249     // aquire a self reference in order to avoid race
250     // conditions. The last client of this class must
251     // call shutdown before releasing his last reference
252     // to this class in order to shutdown this thread
253     // which will release his (the very last reference
254     // to the class and so force their destruction
255     m_xSelfReference = this;
256 
257     // signal that the mail dispatcher thread is now alive
258     mail_dispatcher_active_.set();
259 
260     for(;;)
261     {
262         wakening_call_.wait();
263 
264         ::osl::ClearableMutexGuard thread_status_guard(thread_status_mutex_);
265         if (shutdown_requested_)
266            break;
267 
268         ::osl::ClearableMutexGuard message_container_guard(message_container_mutex_);
269 
270         if (messages_.size())
271         {
272             thread_status_guard.clear();
273             uno::Reference<mail::XMailMessage> message = messages_.front();
274             messages_.pop_front();
275             message_container_guard.clear();
276             sendMailMessageNotifyListener(message);
277         }
278         else // idle - put ourself to sleep
279         {
280             wakening_call_.reset();
281             message_container_guard.clear();
282             thread_status_guard.clear();
283             MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
284             std::for_each(listeners_cloned.begin(), listeners_cloned.end(), GenericEventNotifier(&IMailDispatcherListener::idle, this));
285         }
286     } // end for        SSH ALI
287 }
288 /*-- 27.08.2004 12:04:46---------------------------------------------------
289 
290   -----------------------------------------------------------------------*/
291 void MailDispatcher::onTerminated()
292 {
293     //keep the reference until the end of onTerminated() because of the call order in the
294     //_threadFunc() from osl/thread.hxx
295     m_xSelfReference = 0;
296 }
297