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

akonadi

  • akonadi
servermanager.cpp
1 /*
2  Copyright (c) 2008 Volker Krause <vkrause@kde.org>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "servermanager.h"
21 #include "servermanager_p.h"
22 
23 #include "agenttype.h"
24 #include "agentbase.h"
25 #include "agentmanager.h"
26 #include "dbusconnectionpool.h"
27 #ifndef Q_OS_WINCE
28 #include "selftestdialog_p.h"
29 #endif
30 #include "session_p.h"
31 #include "firstrun_p.h"
32 
33 #include <KDebug>
34 #include <KGlobal>
35 #include <KLocalizedString>
36 
37 #include <akonadi/private/protocol_p.h>
38 #include <akonadi/private/xdgbasedirs_p.h>
39 
40 #include <QtDBus>
41 #include <QPointer>
42 #include <QTimer>
43 
44 #include <boost/scoped_ptr.hpp>
45 
46 using namespace Akonadi;
47 
48 class Akonadi::ServerManagerPrivate
49 {
50  public:
51  ServerManagerPrivate() :
52  instance( new ServerManager( this ) ),
53  mState( ServerManager::NotRunning ),
54  mSafetyTimer( new QTimer ),
55  mFirstRunner( 0 )
56  {
57  mState = instance->state();
58  mSafetyTimer->setSingleShot( true );
59  mSafetyTimer->setInterval( 30000 );
60  QObject::connect( mSafetyTimer.get(), SIGNAL(timeout()), instance, SLOT(timeout()) );
61  KGlobal::locale()->insertCatalog( QString::fromLatin1( "libakonadi" ) );
62  if ( mState == ServerManager::Running && Internal::clientType() == Internal::User && !ServerManager::hasInstanceIdentifier() ) {
63  mFirstRunner = new Firstrun( instance );
64  }
65  }
66 
67  ~ServerManagerPrivate()
68  {
69  delete instance;
70  }
71 
72  void serviceOwnerChanged( const QString&, const QString&, const QString& )
73  {
74  serverProtocolVersion = -1,
75  checkStatusChanged();
76  }
77 
78  void checkStatusChanged()
79  {
80  setState( instance->state() );
81  }
82 
83  void setState( ServerManager::State state )
84  {
85 
86  if ( mState != state ) {
87  mState = state;
88  emit instance->stateChanged( state );
89  if ( state == ServerManager::Running ) {
90  emit instance->started();
91  if ( !mFirstRunner && Internal::clientType() == Internal::User && !ServerManager::hasInstanceIdentifier() ) {
92  mFirstRunner = new Firstrun( instance );
93  }
94  } else if ( state == ServerManager::NotRunning || state == ServerManager::Broken ) {
95  emit instance->stopped();
96  }
97 
98  if ( state == ServerManager::Starting || state == ServerManager::Stopping ) {
99  QMetaObject::invokeMethod( mSafetyTimer.get(), "start", Qt::QueuedConnection ); // in case we are in a different thread
100  } else {
101  QMetaObject::invokeMethod( mSafetyTimer.get(), "stop", Qt::QueuedConnection ); // in case we are in a different thread
102  }
103  }
104  }
105 
106  void timeout()
107  {
108  if ( mState == ServerManager::Starting || mState == ServerManager::Stopping ) {
109  setState( ServerManager::Broken );
110  }
111  }
112 
113  ServerManager *instance;
114  static int serverProtocolVersion;
115  ServerManager::State mState;
116  boost::scoped_ptr<QTimer> mSafetyTimer;
117  Firstrun *mFirstRunner;
118  static Internal::ClientType clientType;
119 };
120 
121 int ServerManagerPrivate::serverProtocolVersion = -1;
122 Internal::ClientType ServerManagerPrivate::clientType = Internal::User;
123 
124 K_GLOBAL_STATIC( ServerManagerPrivate, sInstance )
125 
126 ServerManager::ServerManager(ServerManagerPrivate * dd ) :
127  d( dd )
128 {
129  qRegisterMetaType<Akonadi::ServerManager::State>();
130 
131  QDBusServiceWatcher *watcher = new QDBusServiceWatcher( ServerManager::serviceName( ServerManager::Server ),
132  DBusConnectionPool::threadConnection(),
133  QDBusServiceWatcher::WatchForOwnerChange, this );
134  watcher->addWatchedService( ServerManager::serviceName( ServerManager::Control ) );
135  watcher->addWatchedService( ServerManager::serviceName( ServerManager::UpgradeIndicator ) );
136 
137  // this (and also the two connects below) are queued so that they trigger after AgentManager is done loading
138  // the current agent types and instances
139  // this ensures the invariant of AgentManager reporting a consistent state if ServerManager::state() == Running
140  // that's the case with direct connections as well, but only after you enter the event loop once
141  connect( watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)),
142  this, SLOT(serviceOwnerChanged(QString,QString,QString)), Qt::QueuedConnection );
143 
144  // AgentManager is dangerous to use for agents themselves
145  if ( Internal::clientType() != Internal::User ) {
146  return;
147  }
148  connect( AgentManager::self(), SIGNAL(typeAdded(Akonadi::AgentType)), SLOT(checkStatusChanged()), Qt::QueuedConnection );
149  connect( AgentManager::self(), SIGNAL(typeRemoved(Akonadi::AgentType)), SLOT(checkStatusChanged()), Qt::QueuedConnection );
150 }
151 
152 ServerManager * Akonadi::ServerManager::self()
153 {
154  return sInstance->instance;
155 }
156 
157 bool ServerManager::start()
158 {
159  const bool controlRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( ServerManager::serviceName( ServerManager::Control ) );
160  const bool serverRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( ServerManager::serviceName( ServerManager::Server ) );
161  if ( controlRegistered && serverRegistered ) {
162  return true;
163  }
164 
165  const bool controlLockRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( ServerManager::serviceName( ServerManager::ControlLock ) );
166  if ( controlLockRegistered || controlRegistered ) {
167  kDebug() << "Akonadi server is already starting up";
168  sInstance->setState( Starting );
169  return true;
170  }
171 
172  kDebug() << "executing akonadi_control";
173  const bool ok = QProcess::startDetached( QLatin1String( "akonadi_control" ) );
174  if ( !ok ) {
175  kWarning() << "Unable to execute akonadi_control, falling back to D-Bus auto-launch";
176  QDBusReply<void> reply = DBusConnectionPool::threadConnection().interface()->startService( ServerManager::serviceName(ServerManager::Control) );
177  if ( !reply.isValid() ) {
178  kDebug() << "Akonadi server could not be started via D-Bus either: "
179  << reply.error().message();
180  return false;
181  }
182  }
183  sInstance->setState( Starting );
184  return true;
185 }
186 
187 bool ServerManager::stop()
188 {
189  QDBusInterface iface( ServerManager::serviceName( ServerManager::Control ),
190  QString::fromLatin1( "/ControlManager" ),
191  QString::fromLatin1( "org.freedesktop.Akonadi.ControlManager" ) );
192  if ( !iface.isValid() ) {
193  return false;
194  }
195  iface.call( QDBus::NoBlock, QString::fromLatin1( "shutdown" ) );
196  sInstance->setState( Stopping );
197  return true;
198 }
199 
200 void ServerManager::showSelfTestDialog( QWidget *parent )
201 {
202 #ifndef Q_OS_WINCE
203  QPointer<Akonadi::SelfTestDialog> dlg( new Akonadi::SelfTestDialog( parent ) );
204  dlg->hideIntroduction();
205  dlg->exec();
206  delete dlg;
207 #endif
208 }
209 
210 bool ServerManager::isRunning()
211 {
212  return state() == Running;
213 }
214 
215 ServerManager::State ServerManager::state()
216 {
217  ServerManager::State previousState = NotRunning;
218  if ( sInstance.exists() ) { // be careful, this is called from the ServerManager::Private ctor, so using sInstance unprotected can cause infinite recursion
219  previousState = sInstance->mState;
220  }
221 
222  const bool serverUpgrading = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( ServerManager::serviceName( ServerManager::UpgradeIndicator ) );
223  if ( serverUpgrading )
224  return Upgrading;
225 
226  const bool controlRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( ServerManager::serviceName( ServerManager::Control ) );
227  const bool serverRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( ServerManager::serviceName( ServerManager::Server ) );
228  if ( controlRegistered && serverRegistered ) {
229  // check if the server protocol is recent enough
230  if ( sInstance.exists() ) {
231  if ( Internal::serverProtocolVersion() >= 0 &&
232  Internal::serverProtocolVersion() < SessionPrivate::minimumProtocolVersion() ) {
233  return Broken;
234  }
235  }
236 
237  // AgentManager is dangerous to use for agents themselves
238  if ( Internal::clientType() == Internal::User ) {
239  // besides the running server processes we also need at least one resource to be operational
240  AgentType::List agentTypes = AgentManager::self()->types();
241  foreach ( const AgentType &type, agentTypes ) {
242  if ( type.capabilities().contains( QLatin1String( "Resource" ) ) ) {
243  return Running;
244  }
245  }
246  return Broken;
247  } else {
248  return Running;
249  }
250  }
251 
252  const bool controlLockRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( ServerManager::serviceName( ServerManager::ControlLock ) );
253  if ( controlLockRegistered || controlRegistered ) {
254  kDebug() << "Akonadi server is already starting up";
255  if ( previousState == Running ) {
256  return NotRunning; // we don't know if it's starting or stopping, probably triggered by someone else
257  }
258  return previousState;
259  }
260 
261  if ( serverRegistered ) {
262  kWarning() << "Akonadi server running without control process!";
263  return Broken;
264  }
265 
266  if ( previousState == Starting || previousState == Broken ) { // valid cases where nothing might be running (yet)
267  return previousState;
268  }
269  return NotRunning;
270 }
271 
272 QString ServerManager::instanceIdentifier()
273 {
274  return QLatin1String( qgetenv( "AKONADI_INSTANCE" ) );
275 }
276 
277 bool ServerManager::hasInstanceIdentifier()
278 {
279  return !instanceIdentifier().isEmpty();
280 }
281 
282 static QString makeServiceName( const char* base, const QString &name = QString() )
283 {
284  if ( ServerManager::instanceIdentifier().isEmpty() ) {
285  return QLatin1String( base ) % name;
286  }
287  return QLatin1String( base ) % name % QLatin1Literal( "." ) % ServerManager::instanceIdentifier();
288 }
289 
290 // remove once we require Akonadi 1.9
291 #ifndef AKONADI_DBUS_SERVER_SERVICE_UPGRADING
292 #define AKONADI_DBUS_SERVER_SERVICE_UPGRADING "org.freedesktop.Akonadi.upgrading"
293 #endif
294 
295 QString ServerManager::serviceName( ServerManager::ServiceType serviceType )
296 {
297  switch ( serviceType ) {
298  case Server: return makeServiceName( AKONADI_DBUS_SERVER_SERVICE );
299  case Control: return makeServiceName( AKONADI_DBUS_CONTROL_SERVICE );
300  case ControlLock: return makeServiceName( AKONADI_DBUS_CONTROL_SERVICE_LOCK );
301  case UpgradeIndicator: return makeServiceName( AKONADI_DBUS_SERVER_SERVICE_UPGRADING );
302  }
303  Q_ASSERT( !"WTF?" );
304  return QString();
305 }
306 
307 QString ServerManager::agentServiceName( ServiceAgentType agentType, const QString &identifier )
308 {
309  switch ( agentType ) {
310  case Agent:
311  return makeServiceName( AKONADI_DBUS_SERVER_SERVICE, QString::fromLatin1( ".Agent.%1" ).arg( identifier ) );
312  case Resource:
313  return makeServiceName( AKONADI_DBUS_SERVER_SERVICE, QString::fromLatin1( ".Resource.%1" ).arg( identifier ) );
314  case Preprocessor:
315  return makeServiceName( AKONADI_DBUS_SERVER_SERVICE, QString::fromLatin1( ".Preprocessor.%1" ).arg( identifier ) );
316  }
317  Q_ASSERT( !"WTF?" );
318  return QString();
319 }
320 
321 QString ServerManager::addNamespace(const QString& string)
322 {
323  if ( ServerManager::hasInstanceIdentifier() ) {
324  return string % QLatin1Char( '_' ) % ServerManager::instanceIdentifier();
325  }
326  return string;
327 }
328 
329 int Internal::serverProtocolVersion()
330 {
331  return ServerManagerPrivate::serverProtocolVersion;
332 }
333 
334 void Internal::setServerProtocolVersion( int version )
335 {
336  ServerManagerPrivate::serverProtocolVersion = version;
337  if ( sInstance.exists() ) {
338  sInstance->checkStatusChanged();
339  }
340 }
341 
342 Internal::ClientType Internal::clientType()
343 {
344  return ServerManagerPrivate::clientType;
345 }
346 
347 void Internal::setClientType( ClientType type )
348 {
349  ServerManagerPrivate::clientType = type;
350 }
351 
352 QString Internal::xdgSaveDir( const char *resource, const QString &relPath )
353 {
354  QString fullRelPath = QLatin1String( "akonadi" );
355  if ( !ServerManager::instanceIdentifier().isEmpty() ) {
356  fullRelPath += QLatin1String( "/instance/" ) + ServerManager::instanceIdentifier();
357  }
358  if ( !relPath.isEmpty() ) {
359  fullRelPath += QLatin1Char( '/' ) + relPath;
360  }
361  return XdgBaseDirs::saveDir( resource, fullRelPath );
362 }
363 
364 #include "moc_servermanager.cpp"
Akonadi::ServerManager::instanceIdentifier
static QString instanceIdentifier()
Returns the identifier of the Akonadi instance we are connected to.
Definition: servermanager.cpp:272
Akonadi::ServerManager::ServiceAgentType
ServiceAgentType
Known agent types.
Definition: servermanager.h:135
Akonadi::ServerManager::self
static ServerManager * self()
Returns the singleton instance of this class, for connecting to its signals.
Definition: servermanager.cpp:152
Akonadi::Control
Provides methods to control the Akonadi server process.
Definition: control.h:63
Akonadi::ServerManager::serviceName
static QString serviceName(ServiceType serviceType)
Returns the namespaced D-Bus service name for serviceType.
Definition: servermanager.cpp:295
Akonadi::ServerManager
Provides methods to control the Akonadi server process.
Definition: servermanager.h:42
Akonadi::AgentType
A representation of an agent type.
Definition: agenttype.h:56
Akonadi::ServerManager::Stopping
Server is shutting down.
Definition: servermanager.h:54
Akonadi::ServerManager::showSelfTestDialog
static void showSelfTestDialog(QWidget *parent)
Shows the Akonadi self test dialog, which tests Akonadi for various problems and reports these to the...
Definition: servermanager.cpp:200
Akonadi::ServerManager::state
static State state()
Returns the state of the server.
Definition: servermanager.cpp:215
Akonadi::AgentType::List
QList< AgentType > List
Describes a list of agent types.
Definition: agenttype.h:65
Akonadi::AgentType::capabilities
QStringList capabilities() const
Returns the list of supported capabilities of the agent type.
Definition: agenttype.cpp:76
Akonadi::ServerManager::Upgrading
Server is performing a database upgrade as part of a new startup.
Definition: servermanager.h:56
Akonadi::ServerManager::NotRunning
Server is not running, could be no one started it yet or it failed to start.
Definition: servermanager.h:51
Akonadi::ServerManager::agentServiceName
static QString agentServiceName(ServiceAgentType agentType, const QString &identifier)
Returns the namespaced D-Bus service name for an agent of type agentType with agent identifier identi...
Definition: servermanager.cpp:307
Akonadi::ServerManager::start
static bool start()
Starts the server.
Definition: servermanager.cpp:157
Akonadi::ServerManager::Starting
Server was started but is not yet running.
Definition: servermanager.h:52
Akonadi::ServerManager::Running
Server is running and operational.
Definition: servermanager.h:53
Akonadi::AgentManager::types
AgentType::List types() const
Returns the list of all available agent types.
Definition: agentmanager.cpp:388
Akonadi::ServerManager::ServiceType
ServiceType
Types of known D-Bus services.
Definition: servermanager.h:115
Akonadi::AgentManager::self
static AgentManager * self()
Returns the global instance of the agent manager.
Definition: agentmanager.cpp:379
Akonadi::ServerManager::State
State
Enum for the various states the server can be in.
Definition: servermanager.h:50
Akonadi::SelfTestDialog
A dialog that checks the current status of the Akonadi system.
Definition: selftestdialog_p.h:44
Akonadi::Firstrun
Takes care of setting up default resource agents when running Akonadi for the first time...
Definition: firstrun_p.h:67
Akonadi::ServerManager::stop
static bool stop()
Stops the server.
Definition: servermanager.cpp:187
Akonadi::ServerManager::addNamespace
static QString addNamespace(const QString &string)
Adds the multi-instance namespace to string if required (with &#39;_&#39; as separator).
Definition: servermanager.cpp:321
Akonadi::ServerManager::isRunning
static bool isRunning()
Checks if the server is available currently.
Definition: servermanager.cpp:210
Akonadi::ServerManager::hasInstanceIdentifier
static bool hasInstanceIdentifier()
Returns true if we are connected to a non-default Akonadi server instance.
Definition: servermanager.cpp:277
Akonadi::ServerManager::Broken
Server is not operational and an error has been detected.
Definition: servermanager.h:55
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Tue Nov 26 2013 09:03:18 by doxygen 1.8.5 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.11.3 API Reference

Skip menu "kdepimlibs-4.11.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • 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