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  /* Generic event notifier for started,
35  stopped, and idle events which are
36  very similarly */
37  class GenericEventNotifier
38  {
39  public:
40  // pointer to virtual function typedef
41  typedef void (IMailDispatcherListener::*GenericNotificationFunc_t)(::rtl::Reference<MailDispatcher>);
42 
43  GenericEventNotifier(
44  GenericNotificationFunc_t notification_function,
45  ::rtl::Reference<MailDispatcher> const & mail_dispatcher) :
46  notification_function_(notification_function),
47  mail_dispatcher_(mail_dispatcher)
48  {}
49 
50  void operator() (::rtl::Reference<IMailDispatcherListener> const & listener) const
51  { (listener.get()->*notification_function_)(mail_dispatcher_); }
52 
53  private:
54  GenericNotificationFunc_t notification_function_;
55  ::rtl::Reference<MailDispatcher> mail_dispatcher_;
56  };
57 
58  class MailDeliveryNotifier
59  {
60  public:
61  MailDeliveryNotifier(::rtl::Reference<MailDispatcher> const & xMailDispatcher, uno::Reference<mail::XMailMessage> const & message) :
62  mail_dispatcher_(xMailDispatcher),
63  message_(message)
64  {}
65 
66  void operator() (::rtl::Reference<IMailDispatcherListener> const & listener) const
67  { listener->mailDelivered(mail_dispatcher_, message_); }
68 
69  private:
70  ::rtl::Reference<MailDispatcher> mail_dispatcher_;
71  uno::Reference<mail::XMailMessage> message_;
72  };
73 
74  class MailDeliveryErrorNotifier
75  {
76  public:
77  MailDeliveryErrorNotifier(
78  ::rtl::Reference<MailDispatcher> const & xMailDispatcher,
79  uno::Reference<mail::XMailMessage> const & message,
80  const OUString& error_message) :
81  mail_dispatcher_(xMailDispatcher),
82  message_(message),
83  error_message_(error_message)
84  {}
85 
86  void operator() (::rtl::Reference<IMailDispatcherListener> const & listener) const
87  { listener->mailDeliveryError(mail_dispatcher_, message_, error_message_); }
88 
89  private:
90  ::rtl::Reference<MailDispatcher> mail_dispatcher_;
91  uno::Reference<mail::XMailMessage> message_;
92  OUString const error_message_;
93  };
94 
95 } // namespace private
96 
97 MailDispatcher::MailDispatcher(uno::Reference<mail::XSmtpService> const & mailserver) :
98  m_xMailserver( mailserver ),
99  m_bActive( false ),
100  m_bShutdownRequested( false )
101 {
102  m_aWakeupCondition.reset();
103  m_aRunCondition.reset();
104 
105  if (!create())
106  throw uno::RuntimeException();
107 
108  // wait until the mail dispatcher thread is really alive
109  // and has acquired a reference to this instance of the
110  // class
111  m_aRunCondition.wait();
112 }
113 
115 {
116 }
117 
118 void MailDispatcher::enqueueMailMessage(uno::Reference<mail::XMailMessage> const & message)
119 {
120  ::osl::MutexGuard thread_status_guard( m_aThreadStatusMutex );
121  ::osl::MutexGuard message_container_guard( m_aMessageContainerMutex );
122 
123  OSL_PRECOND( !m_bShutdownRequested, "MailDispatcher thread is shutting down already" );
124 
125  m_aXMessageList.push_back( message );
126  if ( m_bActive )
127  m_aWakeupCondition.set();
128 }
129 
130 uno::Reference<mail::XMailMessage> MailDispatcher::dequeueMailMessage()
131 {
132  ::osl::MutexGuard guard( m_aMessageContainerMutex );
133  uno::Reference<mail::XMailMessage> message;
134  if ( !m_aXMessageList.empty() )
135  {
136  message = m_aXMessageList.front();
137  m_aXMessageList.pop_front();
138  }
139  return message;
140 }
141 
143 {
144  OSL_PRECOND(!isStarted(), "MailDispatcher is already started!");
145 
146  ::osl::ClearableMutexGuard thread_status_guard( m_aThreadStatusMutex );
147 
148  OSL_PRECOND(!m_bShutdownRequested, "MailDispatcher thread is shutting down already");
149 
150  if ( !m_bShutdownRequested )
151  {
152  m_bActive = true;
153  m_aWakeupCondition.set();
154  thread_status_guard.clear();
155 
156  MailDispatcherListenerContainer_t aClonedListenerVector(cloneListener());
157  std::for_each( aClonedListenerVector.begin(), aClonedListenerVector.end(),
158  GenericEventNotifier(&IMailDispatcherListener::started, this) );
159  }
160 }
161 
163 {
164  OSL_PRECOND(isStarted(), "MailDispatcher not started!");
165 
166  ::osl::ClearableMutexGuard thread_status_guard( m_aThreadStatusMutex );
167 
168  OSL_PRECOND(!m_bShutdownRequested, "MailDispatcher thread is shutting down already");
169 
171  {
172  m_bActive = false;
173  m_aWakeupCondition.reset();
174  thread_status_guard.clear();
175 
176  MailDispatcherListenerContainer_t aClonedListenerVector(cloneListener());
177  std::for_each( aClonedListenerVector.begin(), aClonedListenerVector.end(),
178  GenericEventNotifier(&IMailDispatcherListener::stopped, this) );
179  }
180 }
181 
183 {
184  ::osl::MutexGuard thread_status_guard( m_aThreadStatusMutex );
185 
186  OSL_PRECOND(!m_bShutdownRequested, "MailDispatcher thread is shutting down already");
187 
188  m_bShutdownRequested = true;
189  m_aWakeupCondition.set();
190 }
191 
192 
194 {
195  OSL_PRECOND(!m_bShutdownRequested, "MailDispatcher thread is shutting down already");
196 
197  ::osl::MutexGuard guard( m_aListenerContainerMutex );
198  m_aListenerVector.push_back( listener );
199 }
200 
201 std::vector< ::rtl::Reference<IMailDispatcherListener> > MailDispatcher::cloneListener()
202 {
203  ::osl::MutexGuard guard( m_aListenerContainerMutex );
204  return m_aListenerVector;
205 }
206 
207 void MailDispatcher::sendMailMessageNotifyListener(uno::Reference<mail::XMailMessage> const & message)
208 {
209  try
210  {
211  m_xMailserver->sendMailMessage( message );
212  MailDispatcherListenerContainer_t aClonedListenerVector(cloneListener());
213  std::for_each( aClonedListenerVector.begin(), aClonedListenerVector.end(),
214  MailDeliveryNotifier(this, message) );
215  }
216  catch (const mail::MailException& ex)
217  {
218  MailDispatcherListenerContainer_t aClonedListenerVector(cloneListener());
219  std::for_each( aClonedListenerVector.begin(), aClonedListenerVector.end(),
220  MailDeliveryErrorNotifier(this, message, ex.Message) );
221  }
222  catch (const uno::RuntimeException& ex)
223  {
224  MailDispatcherListenerContainer_t aClonedListenerVector(cloneListener());
225  std::for_each( aClonedListenerVector.begin(), aClonedListenerVector.end(),
226  MailDeliveryErrorNotifier(this, message, ex.Message) );
227  }
228 }
229 
231 {
232  osl_setThreadName("MailDispatcher");
233 
234  // acquire a self reference in order to avoid race
235  // conditions. The last client of this class must
236  // call shutdown before releasing his last reference
237  // to this class in order to shutdown this thread
238  // which will release his (the very last reference
239  // to the class and so force their destruction
240  m_xSelfReference = this;
241 
242  // signal that the mail dispatcher thread is now alive
243  m_aRunCondition.set();
244 
245  for(;;)
246  {
247  m_aWakeupCondition.wait();
248 
249  ::osl::ClearableMutexGuard thread_status_guard( m_aThreadStatusMutex );
250  if ( m_bShutdownRequested )
251  break;
252 
253  ::osl::ClearableMutexGuard message_container_guard( m_aMessageContainerMutex );
254 
255  if ( !m_aXMessageList.empty() )
256  {
257  thread_status_guard.clear();
258  uno::Reference<mail::XMailMessage> message = m_aXMessageList.front();
259  m_aXMessageList.pop_front();
260  message_container_guard.clear();
262  }
263  else // idle - put ourself to sleep
264  {
265  m_aWakeupCondition.reset();
266  message_container_guard.clear();
267  thread_status_guard.clear();
268  MailDispatcherListenerContainer_t aListenerListcloned( cloneListener() );
269  std::for_each( aListenerListcloned.begin(), aListenerListcloned.end(),
270  GenericEventNotifier(&IMailDispatcherListener::idle, this) );
271  }
272  }
273 }
274 
276 {
277  //keep the reference until the end of onTerminated() because of the call order in the
278  //_threadFunc() from osl/thread.hxx
279  m_xSelfReference = nullptr;
280 }
281 
282 /* 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 stopped(::rtl::Reference< MailDispatcher > xMailDispatcher)=0
Called when the MailDispatcher is stopped.
MailDispatcher listener interface.
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.
virtual void started(::rtl::Reference< MailDispatcher > xMailDispatcher)=0
Called when the MailDispatcher is started.
css::uno::Reference< css::mail::XMailMessage > dequeueMailMessage()
Dequeues a mail message.
::osl::Mutex m_aThreadStatusMutex
virtual void idle(::rtl::Reference< MailDispatcher > xMailDispatcher)=0
Called when there are no more mail messages to deliver.
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.
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo