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 <osl/diagnose.h>
27 
28 using namespace ::com::sun::star;
29 
30 typedef std::vector< ::rtl::Reference<IMailDispatcherListener> > MailDispatcherListenerContainer_t;
31 
32 namespace /* private */
33 {
34  class MailDeliveryNotifier
35  {
36  public:
37  MailDeliveryNotifier(uno::Reference<mail::XMailMessage> const & message) :
38  message_(message)
39  {}
40 
41  void operator() (::rtl::Reference<IMailDispatcherListener> const & listener) const
42  { listener->mailDelivered(message_); }
43 
44  private:
45  uno::Reference<mail::XMailMessage> message_;
46  };
47 
48  class MailDeliveryErrorNotifier
49  {
50  public:
51  MailDeliveryErrorNotifier(
52  ::rtl::Reference<MailDispatcher> const & xMailDispatcher,
53  uno::Reference<mail::XMailMessage> const & message,
54  const OUString& error_message) :
55  mail_dispatcher_(xMailDispatcher),
56  message_(message),
57  error_message_(error_message)
58  {}
59 
60  void operator() (::rtl::Reference<IMailDispatcherListener> const & listener) const
61  { listener->mailDeliveryError(mail_dispatcher_, message_, error_message_); }
62 
63  private:
64  ::rtl::Reference<MailDispatcher> mail_dispatcher_;
65  uno::Reference<mail::XMailMessage> message_;
66  OUString error_message_;
67  };
68 
69 } // namespace private
70 
71 MailDispatcher::MailDispatcher(uno::Reference<mail::XSmtpService> const & mailserver) :
72  m_xMailserver( mailserver ),
73  m_bActive( false ),
74  m_bShutdownRequested( false )
75 {
76  m_aWakeupCondition.reset();
77  m_aRunCondition.reset();
78 
79  if (!create())
80  throw uno::RuntimeException();
81 
82  // wait until the mail dispatcher thread is really alive
83  // and has acquired a reference to this instance of the
84  // class
85  m_aRunCondition.wait();
86 }
87 
89 {
90 }
91 
92 void MailDispatcher::enqueueMailMessage(uno::Reference<mail::XMailMessage> const & message)
93 {
94  ::osl::MutexGuard thread_status_guard( m_aThreadStatusMutex );
95  ::osl::MutexGuard message_container_guard( m_aMessageContainerMutex );
96 
97  OSL_PRECOND( !m_bShutdownRequested, "MailDispatcher thread is shutting down already" );
98 
99  m_aXMessageList.push_back( message );
100  if ( m_bActive )
101  m_aWakeupCondition.set();
102 }
103 
104 uno::Reference<mail::XMailMessage> MailDispatcher::dequeueMailMessage()
105 {
106  ::osl::MutexGuard guard( m_aMessageContainerMutex );
107  uno::Reference<mail::XMailMessage> message;
108  if ( !m_aXMessageList.empty() )
109  {
110  message = m_aXMessageList.front();
111  m_aXMessageList.pop_front();
112  }
113  return message;
114 }
115 
117 {
118  OSL_PRECOND(!isStarted(), "MailDispatcher is already started!");
119 
120  ::osl::ClearableMutexGuard thread_status_guard( m_aThreadStatusMutex );
121 
122  OSL_PRECOND(!m_bShutdownRequested, "MailDispatcher thread is shutting down already");
123 
124  if ( !m_bShutdownRequested )
125  {
126  m_bActive = true;
127  m_aWakeupCondition.set();
128  thread_status_guard.clear();
129  }
130 }
131 
133 {
134  OSL_PRECOND(isStarted(), "MailDispatcher not started!");
135 
136  ::osl::ClearableMutexGuard thread_status_guard( m_aThreadStatusMutex );
137 
138  OSL_PRECOND(!m_bShutdownRequested, "MailDispatcher thread is shutting down already");
139 
141  {
142  m_bActive = false;
143  m_aWakeupCondition.reset();
144  thread_status_guard.clear();
145  }
146 }
147 
149 {
150  ::osl::MutexGuard thread_status_guard( m_aThreadStatusMutex );
151 
152  OSL_PRECOND(!m_bShutdownRequested, "MailDispatcher thread is shutting down already");
153 
154  m_bShutdownRequested = true;
155  m_aWakeupCondition.set();
156 }
157 
158 
160 {
161  OSL_PRECOND(!m_bShutdownRequested, "MailDispatcher thread is shutting down already");
162 
163  ::osl::MutexGuard guard( m_aListenerContainerMutex );
164  m_aListenerVector.push_back( listener );
165 }
166 
167 std::vector< ::rtl::Reference<IMailDispatcherListener> > MailDispatcher::cloneListener()
168 {
169  ::osl::MutexGuard guard( m_aListenerContainerMutex );
170  return m_aListenerVector;
171 }
172 
173 void MailDispatcher::sendMailMessageNotifyListener(uno::Reference<mail::XMailMessage> const & message)
174 {
175  try
176  {
177  m_xMailserver->sendMailMessage( message );
178  MailDispatcherListenerContainer_t aClonedListenerVector(cloneListener());
179  std::for_each( aClonedListenerVector.begin(), aClonedListenerVector.end(),
180  MailDeliveryNotifier(message) );
181  }
182  catch (const mail::MailException& ex)
183  {
184  MailDispatcherListenerContainer_t aClonedListenerVector(cloneListener());
185  std::for_each( aClonedListenerVector.begin(), aClonedListenerVector.end(),
186  MailDeliveryErrorNotifier(this, message, ex.Message) );
187  }
188  catch (const uno::RuntimeException& ex)
189  {
190  MailDispatcherListenerContainer_t aClonedListenerVector(cloneListener());
191  std::for_each( aClonedListenerVector.begin(), aClonedListenerVector.end(),
192  MailDeliveryErrorNotifier(this, message, ex.Message) );
193  }
194 }
195 
197 {
198  osl_setThreadName("MailDispatcher");
199 
200  // acquire a self reference in order to avoid race
201  // conditions. The last client of this class must
202  // call shutdown before releasing his last reference
203  // to this class in order to shutdown this thread
204  // which will release his (the very last reference
205  // to the class and so force their destruction
206  m_xSelfReference = this;
207 
208  // signal that the mail dispatcher thread is now alive
209  m_aRunCondition.set();
210 
211  for(;;)
212  {
213  m_aWakeupCondition.wait();
214 
215  ::osl::ClearableMutexGuard thread_status_guard( m_aThreadStatusMutex );
216  if ( m_bShutdownRequested )
217  break;
218 
219  ::osl::ClearableMutexGuard message_container_guard( m_aMessageContainerMutex );
220 
221  if ( !m_aXMessageList.empty() )
222  {
223  thread_status_guard.clear();
224  uno::Reference<mail::XMailMessage> message = m_aXMessageList.front();
225  m_aXMessageList.pop_front();
226  message_container_guard.clear();
228  }
229  else // idle - put ourself to sleep
230  {
231  m_aWakeupCondition.reset();
232  message_container_guard.clear();
233  thread_status_guard.clear();
234  MailDispatcherListenerContainer_t aListenerListcloned( cloneListener() );
235  for( const auto & l : aListenerListcloned)
236  l->idle();
237  }
238  }
239 }
240 
242 {
243  //keep the reference until the end of onTerminated() because of the call order in the
244  //_threadFunc() from osl/thread.hxx
245  m_xSelfReference = nullptr;
246 }
247 
248 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::vector< ::rtl::Reference< IMailDispatcherListener > > MailDispatcherListenerContainer_t
::osl::Mutex m_aListenerContainerMutex
std::vector< ::rtl::Reference< IMailDispatcherListener > > m_aListenerVector
virtual void SAL_CALL onTerminated() override
MailDispatcher(css::uno::Reference< css::mail::XSmtpService > const &xMailService)
virtual void SAL_CALL run() override
::osl::Condition m_aWakeupCondition
std::list< css::uno::Reference< css::mail::XMailMessage > > m_aXMessageList
Reference< deployment::XPackageRegistry > create(Reference< deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, Reference< XComponentContext > const &xComponentContext)
virtual ~MailDispatcher() override
Shutdown the mail dispatcher.
void shutdown()
Request shutdown of the mail dispatcher thread.
css::uno::Reference< css::mail::XMailMessage > dequeueMailMessage()
Dequeues a mail message.
::osl::Mutex m_aThreadStatusMutex
void sendMailMessageNotifyListener(css::uno::Reference< css::mail::XMailMessage > const &message)
::osl::Condition m_aRunCondition
::osl::Mutex m_aMessageContainerMutex
bool isStarted() const
Check whether the mail dispatcher is started or not.
std::vector< ::rtl::Reference< IMailDispatcherListener > > cloneListener()
::rtl::Reference< MailDispatcher > m_xSelfReference
void start()
Start sending mail messages asynchronously.
void stop()
Stop sending mail messages.
css::uno::Reference< css::mail::XSmtpService > m_xMailserver
void addListener(::rtl::Reference< IMailDispatcherListener > const &listener)
Register a listener for mail dispatcher events.
void enqueueMailMessage(css::uno::Reference< css::mail::XMailMessage > const &xMailMessage)
Enqueue a mail message for delivery.