1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 #include "maildispatcher.hxx"
27 #include "imaildsplistener.hxx"
28
29 #include <algorithm>
30
31 using namespace ::com::sun::star;
32 using ::rtl::OUString;
33
34 typedef std::list< uno::Reference<mail::XMailMessage> > MailMessageContainer_t;
35 typedef std::list< ::rtl::Reference<IMailDispatcherListener> > MailDispatcherListenerContainer_t;
36
37 namespace /* private */
38 {
39 /* Generic event notifier for started,
40 stopped, and idle events which are
41 very similary */
42 class GenericEventNotifier
43 {
44 public:
45 // pointer to virtual function typedef
46 typedef void (IMailDispatcherListener::*GenericNotificationFunc_t)(::rtl::Reference<MailDispatcher>);
47
GenericEventNotifier(GenericNotificationFunc_t notification_function,::rtl::Reference<MailDispatcher> mail_dispatcher)48 GenericEventNotifier(
49 GenericNotificationFunc_t notification_function,
50 ::rtl::Reference<MailDispatcher> mail_dispatcher) :
51 notification_function_(notification_function),
52 mail_dispatcher_(mail_dispatcher)
53 {}
54
operator ()(::rtl::Reference<IMailDispatcherListener> listener) const55 void operator() (::rtl::Reference<IMailDispatcherListener> listener) const
56 { (listener.get()->*notification_function_)(mail_dispatcher_); }
57
58 private:
59 GenericNotificationFunc_t notification_function_;
60 ::rtl::Reference<MailDispatcher> mail_dispatcher_;
61 };
62
63 class MailDeliveryNotifier
64 {
65 public:
MailDeliveryNotifier(::rtl::Reference<MailDispatcher> xMailDispatcher,uno::Reference<mail::XMailMessage> message)66 MailDeliveryNotifier(::rtl::Reference<MailDispatcher> xMailDispatcher, uno::Reference<mail::XMailMessage> message) :
67 mail_dispatcher_(xMailDispatcher),
68 message_(message)
69 {}
70
operator ()(::rtl::Reference<IMailDispatcherListener> listener) const71 void operator() (::rtl::Reference<IMailDispatcherListener> listener) const
72 { listener->mailDelivered(mail_dispatcher_, message_); }
73
74 private:
75 ::rtl::Reference<MailDispatcher> mail_dispatcher_;
76 uno::Reference<mail::XMailMessage> message_;
77 };
78
79 class MailDeliveryErrorNotifier
80 {
81 public:
MailDeliveryErrorNotifier(::rtl::Reference<MailDispatcher> xMailDispatcher,uno::Reference<mail::XMailMessage> message,const::rtl::OUString & error_message)82 MailDeliveryErrorNotifier(
83 ::rtl::Reference<MailDispatcher> xMailDispatcher,
84 uno::Reference<mail::XMailMessage> message,
85 const ::rtl::OUString& error_message) :
86 mail_dispatcher_(xMailDispatcher),
87 message_(message),
88 error_message_(error_message)
89 {}
90
operator ()(::rtl::Reference<IMailDispatcherListener> listener) const91 void operator() (::rtl::Reference<IMailDispatcherListener> listener) const
92 { listener->mailDeliveryError(mail_dispatcher_, message_, error_message_); }
93
94 private:
95 ::rtl::Reference<MailDispatcher> mail_dispatcher_;
96 uno::Reference<mail::XMailMessage> message_;
97 ::rtl::OUString error_message_;
98 };
99
100 } // namespace private
101
102
MailDispatcher(uno::Reference<mail::XSmtpService> mailserver)103 MailDispatcher::MailDispatcher(uno::Reference<mail::XSmtpService> mailserver) :
104 mailserver_ (mailserver),
105 run_(false),
106 shutdown_requested_(false)
107 {
108 wakening_call_.reset();
109 mail_dispatcher_active_.reset();
110
111 if (!create())
112 throw uno::RuntimeException();
113
114 // wait until the mail dispatcher thread is really alive
115 // and has aquired a reference to this instance of the
116 // class
117 mail_dispatcher_active_.wait();
118 }
119
~MailDispatcher()120 MailDispatcher::~MailDispatcher()
121 {
122 }
123
enqueueMailMessage(uno::Reference<mail::XMailMessage> message)124 void MailDispatcher::enqueueMailMessage(uno::Reference<mail::XMailMessage> message)
125 {
126 ::osl::MutexGuard thread_status_guard(thread_status_mutex_);
127 ::osl::MutexGuard message_container_guard(message_container_mutex_);
128
129 OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
130
131 messages_.push_back(message);
132 if (run_)
133 wakening_call_.set();
134 }
135
dequeueMailMessage()136 uno::Reference<mail::XMailMessage> MailDispatcher::dequeueMailMessage()
137 {
138 ::osl::MutexGuard guard(message_container_mutex_);
139 uno::Reference<mail::XMailMessage> message;
140 if(!messages_.empty())
141 {
142 message = messages_.front();
143 messages_.pop_front();
144 }
145 return message;
146 }
147
start()148 void MailDispatcher::start()
149 {
150 OSL_PRECOND(!isStarted(), "MailDispatcher is already started!");
151
152 ::osl::ClearableMutexGuard thread_status_guard(thread_status_mutex_);
153
154 OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
155
156 if (!shutdown_requested_)
157 {
158 run_ = true;
159 wakening_call_.set();
160 thread_status_guard.clear();
161
162 MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
163 std::for_each(listeners_cloned.begin(), listeners_cloned.end(), GenericEventNotifier(&IMailDispatcherListener::started, this));
164 }
165 }
166
stop()167 void MailDispatcher::stop()
168 {
169 OSL_PRECOND(isStarted(), "MailDispatcher not started!");
170
171 ::osl::ClearableMutexGuard thread_status_guard(thread_status_mutex_);
172
173 OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
174
175 if (!shutdown_requested_)
176 {
177 run_ = false;
178 wakening_call_.reset();
179 thread_status_guard.clear();
180
181 MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
182 std::for_each(listeners_cloned.begin(), listeners_cloned.end(), GenericEventNotifier(&IMailDispatcherListener::stopped, this));
183 }
184 }
185
shutdown()186 void MailDispatcher::shutdown()
187 {
188 ::osl::MutexGuard thread_status_guard(thread_status_mutex_);
189
190 OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
191
192 shutdown_requested_ = true;
193 wakening_call_.set();
194 }
195
isStarted() const196 bool MailDispatcher::isStarted() const
197 {
198 return run_;
199 }
200
addListener(::rtl::Reference<IMailDispatcherListener> listener)201 void MailDispatcher::addListener(::rtl::Reference<IMailDispatcherListener> listener)
202 {
203 OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
204
205 ::osl::MutexGuard guard(listener_container_mutex_);
206 listeners_.push_back(listener);
207 }
208
removeListener(::rtl::Reference<IMailDispatcherListener> listener)209 void MailDispatcher::removeListener(::rtl::Reference<IMailDispatcherListener> listener)
210 {
211 OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
212
213 ::osl::MutexGuard guard(listener_container_mutex_);
214 listeners_.remove(listener);
215 }
216
cloneListener()217 std::list< ::rtl::Reference<IMailDispatcherListener> > MailDispatcher::cloneListener()
218 {
219 ::osl::MutexGuard guard(listener_container_mutex_);
220 return listeners_;
221 }
222
sendMailMessageNotifyListener(uno::Reference<mail::XMailMessage> message)223 void MailDispatcher::sendMailMessageNotifyListener(uno::Reference<mail::XMailMessage> message)
224 {
225 try
226 {
227 mailserver_->sendMailMessage(message);
228 MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
229 std::for_each(listeners_cloned.begin(), listeners_cloned.end(), MailDeliveryNotifier(this, message));
230 }
231 catch (mail::MailException& ex)
232 {
233 MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
234 std::for_each(listeners_cloned.begin(), listeners_cloned.end(), MailDeliveryErrorNotifier(this, message, ex.Message));
235 }
236 catch (uno::RuntimeException& ex)
237 {
238 MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
239 std::for_each(listeners_cloned.begin(), listeners_cloned.end(), MailDeliveryErrorNotifier(this, message, ex.Message));
240 }
241 }
242
run()243 void MailDispatcher::run()
244 {
245 // aquire a self reference in order to avoid race
246 // conditions. The last client of this class must
247 // call shutdown before releasing his last reference
248 // to this class in order to shutdown this thread
249 // which will release his (the very last reference
250 // to the class and so force their destruction
251 m_xSelfReference = this;
252
253 // signal that the mail dispatcher thread is now alive
254 mail_dispatcher_active_.set();
255
256 for(;;)
257 {
258 wakening_call_.wait();
259
260 ::osl::ClearableMutexGuard thread_status_guard(thread_status_mutex_);
261 if (shutdown_requested_)
262 break;
263
264 ::osl::ClearableMutexGuard message_container_guard(message_container_mutex_);
265
266 if (messages_.size())
267 {
268 thread_status_guard.clear();
269 uno::Reference<mail::XMailMessage> message = messages_.front();
270 messages_.pop_front();
271 message_container_guard.clear();
272 sendMailMessageNotifyListener(message);
273 }
274 else // idle - put ourself to sleep
275 {
276 wakening_call_.reset();
277 message_container_guard.clear();
278 thread_status_guard.clear();
279 MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
280 std::for_each(listeners_cloned.begin(), listeners_cloned.end(), GenericEventNotifier(&IMailDispatcherListener::idle, this));
281 }
282 } // end for SSH ALI
283 }
284 /*-- 27.08.2004 12:04:46---------------------------------------------------
285
286 -----------------------------------------------------------------------*/
onTerminated()287 void MailDispatcher::onTerminated()
288 {
289 //keep the reference until the end of onTerminated() because of the call order in the
290 //_threadFunc() from osl/thread.hxx
291 m_xSelfReference = 0;
292 }
293