/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 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; }