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 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 55 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: 66 MailDeliveryNotifier(::rtl::Reference<MailDispatcher> xMailDispatcher, uno::Reference<mail::XMailMessage> message) : 67 mail_dispatcher_(xMailDispatcher), 68 message_(message) 69 {} 70 71 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: 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 91 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 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 120 MailDispatcher::~MailDispatcher() 121 { 122 } 123 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 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 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 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 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 196 bool MailDispatcher::isStarted() const 197 { 198 return run_; 199 } 200 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 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 217 std::list< ::rtl::Reference<IMailDispatcherListener> > MailDispatcher::cloneListener() 218 { 219 ::osl::MutexGuard guard(listener_container_mutex_); 220 return listeners_; 221 } 222 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 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 -----------------------------------------------------------------------*/ 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