• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.8.3 API Reference
  • KDE Home
  • Contact Us
 

akonadi

servermanager.cpp
00001 /*
00002     Copyright (c) 2008 Volker Krause <vkrause@kde.org>
00003 
00004     This library is free software; you can redistribute it and/or modify it
00005     under the terms of the GNU Library General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or (at your
00007     option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful, but WITHOUT
00010     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00011     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00012     License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to the
00016     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017     02110-1301, USA.
00018 */
00019 
00020 #include "servermanager.h"
00021 #include "servermanager_p.h"
00022 
00023 #include "agenttype.h"
00024 #include "agentbase.h"
00025 #include "agentmanager.h"
00026 #include "dbusconnectionpool.h"
00027 #ifndef Q_OS_WINCE
00028 #include "selftestdialog_p.h"
00029 #endif
00030 #include "session_p.h"
00031 #include "firstrun_p.h"
00032 
00033 #include <KDebug>
00034 #include <KGlobal>
00035 #include <KLocale>
00036 
00037 #include <QtDBus>
00038 #include <QTimer>
00039 
00040 #include <boost/scoped_ptr.hpp>
00041 
00042 #define AKONADI_CONTROL_SERVICE QLatin1String( "org.freedesktop.Akonadi.Control" )
00043 #define AKONADI_SERVER_SERVICE QLatin1String( "org.freedesktop.Akonadi" )
00044 
00045 using namespace Akonadi;
00046 
00047 class Akonadi::ServerManagerPrivate
00048 {
00049   public:
00050     ServerManagerPrivate() :
00051       instance( new ServerManager( this ) ),
00052       mState( ServerManager::NotRunning ),
00053       mSafetyTimer( new QTimer ),
00054       mFirstRunner( 0 )
00055     {
00056       mState = instance->state();
00057       mSafetyTimer->setSingleShot( true );
00058       mSafetyTimer->setInterval( 30000 );
00059       QObject::connect( mSafetyTimer.get(), SIGNAL(timeout()), instance, SLOT(timeout()) );
00060       KGlobal::locale()->insertCatalog( QString::fromLatin1( "libakonadi" ) );
00061       if ( mState == ServerManager::Running && Internal::clientType() == Internal::User )
00062         mFirstRunner = new Firstrun( instance );
00063     }
00064 
00065     ~ServerManagerPrivate()
00066     {
00067       delete instance;
00068     }
00069 
00070     void serviceOwnerChanged( const QString&, const QString&, const QString& )
00071     {
00072       serverProtocolVersion = -1,
00073       checkStatusChanged();
00074     }
00075 
00076     void checkStatusChanged()
00077     {
00078       setState( instance->state() );
00079     }
00080 
00081     void setState( ServerManager::State state )
00082     {
00083 
00084       if ( mState != state ) {
00085         mState = state;
00086         emit instance->stateChanged( state );
00087         if ( state == ServerManager::Running ) {
00088           emit instance->started();
00089           if ( !mFirstRunner && Internal::clientType() == Internal::User )
00090             mFirstRunner = new Firstrun( instance );
00091         } else if ( state == ServerManager::NotRunning || state == ServerManager::Broken ) {
00092           emit instance->stopped();
00093         }
00094 
00095         if ( state == ServerManager::Starting || state == ServerManager::Stopping )
00096           QMetaObject::invokeMethod( mSafetyTimer.get(), "start", Qt::QueuedConnection ); // in case we are in a different thread
00097         else
00098           QMetaObject::invokeMethod( mSafetyTimer.get(), "stop", Qt::QueuedConnection ); // in case we are in a different thread
00099       }
00100     }
00101 
00102     void timeout()
00103     {
00104       if ( mState == ServerManager::Starting || mState == ServerManager::Stopping )
00105         setState( ServerManager::Broken );
00106     }
00107 
00108     ServerManager *instance;
00109     static int serverProtocolVersion;
00110     ServerManager::State mState;
00111     boost::scoped_ptr<QTimer> mSafetyTimer;
00112     Firstrun *mFirstRunner;
00113     static Internal::ClientType clientType;
00114 };
00115 
00116 int ServerManagerPrivate::serverProtocolVersion = -1;
00117 Internal::ClientType ServerManagerPrivate::clientType = Internal::User;
00118 
00119 K_GLOBAL_STATIC( ServerManagerPrivate, sInstance )
00120 
00121 ServerManager::ServerManager(ServerManagerPrivate * dd ) :
00122     d( dd )
00123 {
00124   qRegisterMetaType<Akonadi::ServerManager::State>();
00125 
00126   QDBusServiceWatcher *watcher = new QDBusServiceWatcher( AKONADI_SERVER_SERVICE,
00127                                                           DBusConnectionPool::threadConnection(),
00128                                                           QDBusServiceWatcher::WatchForOwnerChange, this );
00129   watcher->addWatchedService( AKONADI_CONTROL_SERVICE );
00130 
00131   // this (and also the two connects below) are queued so that they trigger after AgentManager is done loading
00132   // the current agent types and instances
00133   // this ensures the invariant of AgentManager reporting a consistent state if ServerManager::state() == Running
00134   // that's the case with direct connections as well, but only after you enter the event loop once
00135   connect( watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)),
00136            this, SLOT(serviceOwnerChanged(QString,QString,QString)), Qt::QueuedConnection );
00137 
00138   // AgentManager is dangerous to use for agents themselves
00139   if ( Internal::clientType() != Internal::User )
00140     return;
00141   connect( AgentManager::self(), SIGNAL(typeAdded(Akonadi::AgentType)), SLOT(checkStatusChanged()), Qt::QueuedConnection );
00142   connect( AgentManager::self(), SIGNAL(typeRemoved(Akonadi::AgentType)), SLOT(checkStatusChanged()), Qt::QueuedConnection );
00143 }
00144 
00145 ServerManager * Akonadi::ServerManager::self()
00146 {
00147   return sInstance->instance;
00148 }
00149 
00150 bool ServerManager::start()
00151 {
00152   const bool controlRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE );
00153   const bool serverRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_SERVER_SERVICE );
00154   if (  controlRegistered && serverRegistered )
00155     return true;
00156 
00157   // TODO: use AKONADI_CONTROL_SERVICE_LOCK instead once we depend on a recent enough Akonadi server
00158   const bool controlLockRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE + QLatin1String( ".lock" ) );
00159   if ( controlLockRegistered || controlRegistered ) {
00160     kDebug() << "Akonadi server is already starting up";
00161     sInstance->setState( Starting );
00162     return true;
00163   }
00164 
00165   kDebug() << "executing akonadi_control";
00166   const bool ok = QProcess::startDetached( QLatin1String( "akonadi_control" ) );
00167   if ( !ok ) {
00168     kWarning() << "Unable to execute akonadi_control, falling back to D-Bus auto-launch";
00169     QDBusReply<void> reply = DBusConnectionPool::threadConnection().interface()->startService( AKONADI_CONTROL_SERVICE );
00170     if ( !reply.isValid() ) {
00171       kDebug() << "Akonadi server could not be started via D-Bus either: "
00172                << reply.error().message();
00173       return false;
00174     }
00175   }
00176   sInstance->setState( Starting );
00177   return true;
00178 }
00179 
00180 bool ServerManager::stop()
00181 {
00182   QDBusInterface iface( AKONADI_CONTROL_SERVICE,
00183                         QString::fromLatin1( "/ControlManager" ),
00184                         QString::fromLatin1( "org.freedesktop.Akonadi.ControlManager" ) );
00185   if ( !iface.isValid() )
00186     return false;
00187   iface.call( QDBus::NoBlock, QString::fromLatin1( "shutdown" ) );
00188   sInstance->setState( Stopping );
00189   return true;
00190 }
00191 
00192 void ServerManager::showSelfTestDialog( QWidget *parent )
00193 {
00194 #ifndef Q_OS_WINCE
00195   Akonadi::SelfTestDialog dlg( parent );
00196   dlg.hideIntroduction();
00197   dlg.exec();
00198 #endif
00199 }
00200 
00201 bool ServerManager::isRunning()
00202 {
00203   return state() == Running;
00204 }
00205 
00206 ServerManager::State ServerManager::state()
00207 {
00208   ServerManager::State previousState = NotRunning;
00209   if ( sInstance.exists() ) // be careful, this is called from the ServerManager::Private ctor, so using sInstance unprotected can cause infinite recursion
00210     previousState = sInstance->mState;
00211 
00212   const bool controlRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE );
00213   const bool serverRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_SERVER_SERVICE );
00214   if (  controlRegistered && serverRegistered ) {
00215     // check if the server protocol is recent enough
00216     if ( sInstance.exists() ) {
00217       if ( Internal::serverProtocolVersion() >= 0 &&
00218            Internal::serverProtocolVersion() < SessionPrivate::minimumProtocolVersion() )
00219         return Broken;
00220     }
00221 
00222     // AgentManager is dangerous to use for agents themselves
00223     if ( Internal::clientType() == Internal::User ) {
00224       // besides the running server processes we also need at least one resource to be operational
00225       AgentType::List agentTypes = AgentManager::self()->types();
00226       foreach ( const AgentType &type, agentTypes ) {
00227         if ( type.capabilities().contains( QLatin1String( "Resource" ) ) )
00228           return Running;
00229       }
00230       return Broken;
00231     } else {
00232       return Running;
00233     }
00234   }
00235 
00236   // TODO: use AKONADI_CONTROL_SERVICE_LOCK instead once we depend on a recent enough Akonadi server
00237   const bool controlLockRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE + QLatin1String( ".lock" ) );
00238   if ( controlLockRegistered || controlRegistered ) {
00239     kDebug() << "Akonadi server is already starting up";
00240     if ( previousState == Running )
00241       return NotRunning; // we don't know if it's starting or stopping, probably triggered by someone else
00242     return previousState;
00243   }
00244 
00245   if ( serverRegistered ) {
00246     kWarning() << "Akonadi server running without control process!";
00247     return Broken;
00248   }
00249 
00250   if ( previousState == Starting || previousState == Broken ) // valid cases where nothing might be running (yet)
00251     return previousState;
00252   return NotRunning;
00253 }
00254 
00255 int Internal::serverProtocolVersion()
00256 {
00257   return ServerManagerPrivate::serverProtocolVersion;
00258 }
00259 
00260 void Internal::setServerProtocolVersion( int version )
00261 {
00262   ServerManagerPrivate::serverProtocolVersion = version;
00263   if ( sInstance.exists() )
00264     sInstance->checkStatusChanged();
00265 }
00266 
00267 Internal::ClientType Internal::clientType()
00268 {
00269   return ServerManagerPrivate::clientType;
00270 }
00271 
00272 void Internal::setClientType( ClientType type )
00273 {
00274   ServerManagerPrivate::clientType = type;
00275 }
00276 
00277 #include "servermanager.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu May 10 2012 22:18:35 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs-4.8.3 API Reference

Skip menu "kdepimlibs-4.8.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal