LibreOffice Module sw (master) 1
maildispatcher.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <maildispatcher.hxx>
21#include <imaildsplistener.hxx>
22
23#include <algorithm>
24
25#include <com/sun/star/mail/MailException.hpp>
26#include <utility>
27#include <osl/diagnose.h>
28
29using namespace ::com::sun::star;
30
31typedef std::vector< ::rtl::Reference<IMailDispatcherListener> > MailDispatcherListenerContainer_t;
32
33namespace /* private */
34{
35 class MailDeliveryNotifier
36 {
37 public:
38 MailDeliveryNotifier(uno::Reference<mail::XMailMessage> message) :
39 message_(std::move(message))
40 {}
41
42 void operator() (::rtl::Reference<IMailDispatcherListener> const & listener) const
43 { listener->mailDelivered(message_); }
44
45 private:
46 uno::Reference<mail::XMailMessage> message_;
47 };
48
49 class MailDeliveryErrorNotifier
50 {
51 public:
52 MailDeliveryErrorNotifier(
54 uno::Reference<mail::XMailMessage> message,
55 OUString error_message) :
56 m_mail_dispatcher(std::move(xMailDispatcher)),
57 m_message(std::move(message)),
58 m_error_message(std::move(error_message))
59 {}
60
61 void operator() (::rtl::Reference<IMailDispatcherListener> const & listener) const
62 { listener->mailDeliveryError(m_mail_dispatcher, m_message, m_error_message); }
63
64 private:
65 ::rtl::Reference<MailDispatcher> m_mail_dispatcher;
66 uno::Reference<mail::XMailMessage> m_message;
67 OUString m_error_message;
68 };
69
70} // namespace private
71
72MailDispatcher::MailDispatcher(uno::Reference<mail::XSmtpService> mailserver) :
73 m_xMailserver(std::move( mailserver )),
74 m_bActive( false ),
75 m_bShutdownRequested( false )
76{
77 m_aWakeupCondition.reset();
78 m_aRunCondition.reset();
79
80 if (!create())
81 throw uno::RuntimeException();
82
83 // wait until the mail dispatcher thread is really alive
84 // and has acquired a reference to this instance of the
85 // class
86 m_aRunCondition.wait();
87}
88
90{
91}
92
93void MailDispatcher::enqueueMailMessage(uno::Reference<mail::XMailMessage> const & message)
94{
95 ::osl::MutexGuard thread_status_guard( m_aThreadStatusMutex );
96 ::osl::MutexGuard message_container_guard( m_aMessageContainerMutex );
97
98 OSL_PRECOND( !m_bShutdownRequested, "MailDispatcher thread is shutting down already" );
99
100 m_aXMessageList.push_back( message );
101 if ( m_bActive )
102 m_aWakeupCondition.set();
103}
104
105uno::Reference<mail::XMailMessage> MailDispatcher::dequeueMailMessage()
106{
107 ::osl::MutexGuard guard( m_aMessageContainerMutex );
108 uno::Reference<mail::XMailMessage> message;
109 if ( !m_aXMessageList.empty() )
110 {
111 message = m_aXMessageList.front();
112 m_aXMessageList.pop_front();
113 }
114 return message;
115}
116
118{
119 OSL_PRECOND(!isStarted(), "MailDispatcher is already started!");
120
121 ::osl::ClearableMutexGuard thread_status_guard( m_aThreadStatusMutex );
122
123 OSL_PRECOND(!m_bShutdownRequested, "MailDispatcher thread is shutting down already");
124
126 {
127 m_bActive = true;
128 m_aWakeupCondition.set();
129 thread_status_guard.clear();
130 }
131}
132
134{
135 OSL_PRECOND(isStarted(), "MailDispatcher not started!");
136
137 ::osl::ClearableMutexGuard thread_status_guard( m_aThreadStatusMutex );
138
139 OSL_PRECOND(!m_bShutdownRequested, "MailDispatcher thread is shutting down already");
140
142 {
143 m_bActive = false;
144 m_aWakeupCondition.reset();
145 thread_status_guard.clear();
146 }
147}
148
150{
151 ::osl::MutexGuard thread_status_guard( m_aThreadStatusMutex );
152
153 OSL_PRECOND(!m_bShutdownRequested, "MailDispatcher thread is shutting down already");
154
156 m_aWakeupCondition.set();
157}
158
159
161{
162 OSL_PRECOND(!m_bShutdownRequested, "MailDispatcher thread is shutting down already");
163
164 ::osl::MutexGuard guard( m_aListenerContainerMutex );
165 m_aListenerVector.push_back( listener );
166}
167
168std::vector< ::rtl::Reference<IMailDispatcherListener> > MailDispatcher::cloneListener()
169{
170 ::osl::MutexGuard guard( m_aListenerContainerMutex );
171 return m_aListenerVector;
172}
173
174void MailDispatcher::sendMailMessageNotifyListener(uno::Reference<mail::XMailMessage> const & message)
175{
176 try
177 {
178 m_xMailserver->sendMailMessage( message );
179 MailDispatcherListenerContainer_t aClonedListenerVector(cloneListener());
180 std::for_each( aClonedListenerVector.begin(), aClonedListenerVector.end(),
181 MailDeliveryNotifier(message) );
182 }
183 catch (const mail::MailException& ex)
184 {
185 MailDispatcherListenerContainer_t aClonedListenerVector(cloneListener());
186 std::for_each( aClonedListenerVector.begin(), aClonedListenerVector.end(),
187 MailDeliveryErrorNotifier(this, message, ex.Message) );
188 }
189 catch (const uno::RuntimeException& ex)
190 {
191 MailDispatcherListenerContainer_t aClonedListenerVector(cloneListener());
192 std::for_each( aClonedListenerVector.begin(), aClonedListenerVector.end(),
193 MailDeliveryErrorNotifier(this, message, ex.Message) );
194 }
195}
196
198{
199 osl_setThreadName("MailDispatcher");
200
201 // acquire a self reference in order to avoid race
202 // conditions. The last client of this class must
203 // call shutdown before releasing his last reference
204 // to this class in order to shutdown this thread
205 // which will release his (the very last reference
206 // to the class and so force their destruction
207 m_xSelfReference = this;
208
209 // signal that the mail dispatcher thread is now alive
210 m_aRunCondition.set();
211
212 for(;;)
213 {
214 m_aWakeupCondition.wait();
215
216 ::osl::ClearableMutexGuard thread_status_guard( m_aThreadStatusMutex );
218 break;
219
220 ::osl::ClearableMutexGuard message_container_guard( m_aMessageContainerMutex );
221
222 if ( !m_aXMessageList.empty() )
223 {
224 thread_status_guard.clear();
225 uno::Reference<mail::XMailMessage> message = m_aXMessageList.front();
226 m_aXMessageList.pop_front();
227 message_container_guard.clear();
229 }
230 else // idle - put ourself to sleep
231 {
232 m_aWakeupCondition.reset();
233 message_container_guard.clear();
234 thread_status_guard.clear();
235 MailDispatcherListenerContainer_t aListenerListcloned( cloneListener() );
236 for( const auto & l : aListenerListcloned)
237 l->idle();
238 }
239 }
240}
241
243{
244 //keep the reference until the end of onTerminated() because of the call order in the
245 //_threadFunc() from osl/thread.hxx
246 m_xSelfReference = nullptr;
247}
248
249/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::vector<::rtl::Reference< IMailDispatcherListener > > m_aListenerVector
css::uno::Reference< css::mail::XSmtpService > m_xMailserver
::osl::Mutex m_aThreadStatusMutex
MailDispatcher(css::uno::Reference< css::mail::XSmtpService > xMailService)
void sendMailMessageNotifyListener(css::uno::Reference< css::mail::XMailMessage > const &message)
void enqueueMailMessage(css::uno::Reference< css::mail::XMailMessage > const &xMailMessage)
Enqueue a mail message for delivery.
void start()
Start sending mail messages asynchronously.
::osl::Condition m_aRunCondition
::osl::Condition m_aWakeupCondition
void stop()
Stop sending mail messages.
std::list< css::uno::Reference< css::mail::XMailMessage > > m_aXMessageList
css::uno::Reference< css::mail::XMailMessage > dequeueMailMessage()
Dequeues a mail message.
std::vector<::rtl::Reference< IMailDispatcherListener > > cloneListener()
virtual void SAL_CALL run() override
virtual ~MailDispatcher() override
Shutdown the mail dispatcher.
bool isStarted() const
Check whether the mail dispatcher is started or not.
::osl::Mutex m_aListenerContainerMutex
::osl::Mutex m_aMessageContainerMutex
::rtl::Reference< MailDispatcher > m_xSelfReference
void addListener(::rtl::Reference< IMailDispatcherListener > const &listener)
Register a listener for mail dispatcher events.
void shutdown()
Request shutdown of the mail dispatcher thread.
virtual void SAL_CALL onTerminated() override
std::vector< ::rtl::Reference< IMailDispatcherListener > > MailDispatcherListenerContainer_t
css::uno::Reference< css::deployment::XPackageRegistry > create(css::uno::Reference< css::deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, css::uno::Reference< css::uno::XComponentContext > const &xComponentContext)