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
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.