/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sw.hxx" #include "maildispatcher.hxx" #include "imaildsplistener.hxx" #include using namespace ::com::sun::star; using ::rtl::OUString; typedef std::list< uno::Reference > MailMessageContainer_t; typedef std::list< ::rtl::Reference > MailDispatcherListenerContainer_t; namespace /* private */ { /* Generic event notifier for started, stopped, and idle events which are very similary */ class GenericEventNotifier { public: // pointer to virtual function typedef typedef void (IMailDispatcherListener::*GenericNotificationFunc_t)(::rtl::Reference); GenericEventNotifier( GenericNotificationFunc_t notification_function, ::rtl::Reference mail_dispatcher) : notification_function_(notification_function), mail_dispatcher_(mail_dispatcher) {} void operator() (::rtl::Reference listener) const { (listener.get()->*notification_function_)(mail_dispatcher_); } private: GenericNotificationFunc_t notification_function_; ::rtl::Reference mail_dispatcher_; }; class MailDeliveryNotifier { public: MailDeliveryNotifier(::rtl::Reference xMailDispatcher, uno::Reference message) : mail_dispatcher_(xMailDispatcher), message_(message) {} void operator() (::rtl::Reference listener) const { listener->mailDelivered(mail_dispatcher_, message_); } private: ::rtl::Reference mail_dispatcher_; uno::Reference message_; }; class MailDeliveryErrorNotifier { public: MailDeliveryErrorNotifier( ::rtl::Reference xMailDispatcher, uno::Reference message, const ::rtl::OUString& error_message) : mail_dispatcher_(xMailDispatcher), message_(message), error_message_(error_message) {} void operator() (::rtl::Reference listener) const { listener->mailDeliveryError(mail_dispatcher_, message_, error_message_); } private: ::rtl::Reference mail_dispatcher_; uno::Reference message_; ::rtl::OUString error_message_; }; } // namespace private MailDispatcher::MailDispatcher(uno::Reference mailserver) : mailserver_ (mailserver), run_(false), shutdown_requested_(false) { wakening_call_.reset(); mail_dispatcher_active_.reset(); if (!create()) throw uno::RuntimeException(); // wait until the mail dispatcher thread is really alive // and has aquired a reference to this instance of the // class mail_dispatcher_active_.wait(); } MailDispatcher::~MailDispatcher() { } void MailDispatcher::enqueueMailMessage(uno::Reference message) { ::osl::MutexGuard thread_status_guard(thread_status_mutex_); ::osl::MutexGuard message_container_guard(message_container_mutex_); OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already"); messages_.push_back(message); if (run_) wakening_call_.set(); } uno::Reference MailDispatcher::dequeueMailMessage() { ::osl::MutexGuard guard(message_container_mutex_); uno::Reference message; if(!messages_.empty()) { message = messages_.front(); messages_.pop_front(); } return message; } void MailDispatcher::start() { OSL_PRECOND(!isStarted(), "MailDispatcher is already started!"); ::osl::ClearableMutexGuard thread_status_guard(thread_status_mutex_); OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already"); if (!shutdown_requested_) { run_ = true; wakening_call_.set(); thread_status_guard.clear(); MailDispatcherListenerContainer_t listeners_cloned(cloneListener()); std::for_each(listeners_cloned.begin(), listeners_cloned.end(), GenericEventNotifier(&IMailDispatcherListener::started, this)); } } void MailDispatcher::stop() { OSL_PRECOND(isStarted(), "MailDispatcher not started!"); ::osl::ClearableMutexGuard thread_status_guard(thread_status_mutex_); OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already"); if (!shutdown_requested_) { run_ = false; wakening_call_.reset(); thread_status_guard.clear(); MailDispatcherListenerContainer_t listeners_cloned(cloneListener()); std::for_each(listeners_cloned.begin(), listeners_cloned.end(), GenericEventNotifier(&IMailDispatcherListener::stopped, this)); } } void MailDispatcher::shutdown() { ::osl::MutexGuard thread_status_guard(thread_status_mutex_); OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already"); shutdown_requested_ = true; wakening_call_.set(); } bool MailDispatcher::isStarted() const { return run_; } void MailDispatcher::addListener(::rtl::Reference listener) { OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already"); ::osl::MutexGuard guard(listener_container_mutex_); listeners_.push_back(listener); } void MailDispatcher::removeListener(::rtl::Reference listener) { OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already"); ::osl::MutexGuard guard(listener_container_mutex_); listeners_.remove(listener); } std::list< ::rtl::Reference > MailDispatcher::cloneListener() { ::osl::MutexGuard guard(listener_container_mutex_); return listeners_; } void MailDispatcher::sendMailMessageNotifyListener(uno::Reference message) { try { mailserver_->sendMailMessage(message); MailDispatcherListenerContainer_t listeners_cloned(cloneListener()); std::for_each(listeners_cloned.begin(), listeners_cloned.end(), MailDeliveryNotifier(this, message)); } catch (mail::MailException& ex) { MailDispatcherListenerContainer_t listeners_cloned(cloneListener()); std::for_each(listeners_cloned.begin(), listeners_cloned.end(), MailDeliveryErrorNotifier(this, message, ex.Message)); } catch (uno::RuntimeException& ex) { MailDispatcherListenerContainer_t listeners_cloned(cloneListener()); std::for_each(listeners_cloned.begin(), listeners_cloned.end(), MailDeliveryErrorNotifier(this, message, ex.Message)); } } void MailDispatcher::run() { // aquire a self reference in order to avoid race // conditions. The last client of this class must // call shutdown before releasing his last reference // to this class in order to shutdown this thread // which will release his (the very last reference // to the class and so force their destruction m_xSelfReference = this; // signal that the mail dispatcher thread is now alive mail_dispatcher_active_.set(); for(;;) { wakening_call_.wait(); ::osl::ClearableMutexGuard thread_status_guard(thread_status_mutex_); if (shutdown_requested_) break; ::osl::ClearableMutexGuard message_container_guard(message_container_mutex_); if (messages_.size()) { thread_status_guard.clear(); uno::Reference message = messages_.front(); messages_.pop_front(); message_container_guard.clear(); sendMailMessageNotifyListener(message); } else // idle - put ourself to sleep { wakening_call_.reset(); message_container_guard.clear(); thread_status_guard.clear(); MailDispatcherListenerContainer_t listeners_cloned(cloneListener()); std::for_each(listeners_cloned.begin(), listeners_cloned.end(), GenericEventNotifier(&IMailDispatcherListener::idle, this)); } } // end for SSH ALI } /*-- 27.08.2004 12:04:46--------------------------------------------------- -----------------------------------------------------------------------*/ void MailDispatcher::onTerminated() { //keep the reference until the end of onTerminated() because of the call order in the //_threadFunc() from osl/thread.hxx m_xSelfReference = 0; }