• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.9.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 <KLocale>
36 
37 #include <QtDBus>
38 #include <QTimer>
39 
40 #include <boost/scoped_ptr.hpp>
41 
42 #define AKONADI_CONTROL_SERVICE QLatin1String( "org.freedesktop.Akonadi.Control" )
43 #define AKONADI_SERVER_SERVICE QLatin1String( "org.freedesktop.Akonadi" )
44 
45 using namespace Akonadi;
46 
47 class Akonadi::ServerManagerPrivate
48 {
49  public:
50  ServerManagerPrivate() :
51  instance( new ServerManager( this ) ),
52  mState( ServerManager::NotRunning ),
53  mSafetyTimer( new QTimer ),
54  mFirstRunner( 0 )
55  {
56  mState = instance->state();
57  mSafetyTimer->setSingleShot( true );
58  mSafetyTimer->setInterval( 30000 );
59  QObject::connect( mSafetyTimer.get(), SIGNAL(timeout()), instance, SLOT(timeout()) );
60  KGlobal::locale()->insertCatalog( QString::fromLatin1( "libakonadi" ) );
61  if ( mState == ServerManager::Running && Internal::clientType() == Internal::User )
62  mFirstRunner = new Firstrun( instance );
63  }
64 
65  ~ServerManagerPrivate()
66  {
67  delete instance;
68  }
69 
70  void serviceOwnerChanged( const QString&, const QString&, const QString& )
71  {
72  serverProtocolVersion = -1,
73  checkStatusChanged();
74  }
75 
76  void checkStatusChanged()
77  {
78  setState( instance->state() );
79  }
80 
81  void setState( ServerManager::State state )
82  {
83 
84  if ( mState != state ) {
85  mState = state;
86  emit instance->stateChanged( state );
87  if ( state == ServerManager::Running ) {
88  emit instance->started();
89  if ( !mFirstRunner && Internal::clientType() == Internal::User )
90  mFirstRunner = new Firstrun( instance );
91  } else if ( state == ServerManager::NotRunning || state == ServerManager::Broken ) {
92  emit instance->stopped();
93  }
94 
95  if ( state == ServerManager::Starting || state == ServerManager::Stopping )
96  QMetaObject::invokeMethod( mSafetyTimer.get(), "start", Qt::QueuedConnection ); // in case we are in a different thread
97  else
98  QMetaObject::invokeMethod( mSafetyTimer.get(), "stop", Qt::QueuedConnection ); // in case we are in a different thread
99  }
100  }
101 
102  void timeout()
103  {
104  if ( mState == ServerManager::Starting || mState == ServerManager::Stopping )
105  setState( ServerManager::Broken );
106  }
107 
108  ServerManager *instance;
109  static int serverProtocolVersion;
110  ServerManager::State mState;
111  boost::scoped_ptr<QTimer> mSafetyTimer;
112  Firstrun *mFirstRunner;
113  static Internal::ClientType clientType;
114 };
115 
116 int ServerManagerPrivate::serverProtocolVersion = -1;
117 Internal::ClientType ServerManagerPrivate::clientType = Internal::User;
118 
119 K_GLOBAL_STATIC( ServerManagerPrivate, sInstance )
120 
121 ServerManager::ServerManager(ServerManagerPrivate * dd ) :
122  d( dd )
123 {
124  qRegisterMetaType<Akonadi::ServerManager::State>();
125 
126  QDBusServiceWatcher *watcher = new QDBusServiceWatcher( AKONADI_SERVER_SERVICE,
127  DBusConnectionPool::threadConnection(),
128  QDBusServiceWatcher::WatchForOwnerChange, this );
129  watcher->addWatchedService( AKONADI_CONTROL_SERVICE );
130 
131  // this (and also the two connects below) are queued so that they trigger after AgentManager is done loading
132  // the current agent types and instances
133  // this ensures the invariant of AgentManager reporting a consistent state if ServerManager::state() == Running
134  // that's the case with direct connections as well, but only after you enter the event loop once
135  connect( watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)),
136  this, SLOT(serviceOwnerChanged(QString,QString,QString)), Qt::QueuedConnection );
137 
138  // AgentManager is dangerous to use for agents themselves
139  if ( Internal::clientType() != Internal::User )
140  return;
141  connect( AgentManager::self(), SIGNAL(typeAdded(Akonadi::AgentType)), SLOT(checkStatusChanged()), Qt::QueuedConnection );
142  connect( AgentManager::self(), SIGNAL(typeRemoved(Akonadi::AgentType)), SLOT(checkStatusChanged()), Qt::QueuedConnection );
143 }
144 
145 ServerManager * Akonadi::ServerManager::self()
146 {
147  return sInstance->instance;
148 }
149 
150 bool ServerManager::start()
151 {
152  const bool controlRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE );
153  const bool serverRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_SERVER_SERVICE );
154  if ( controlRegistered && serverRegistered )
155  return true;
156 
157  // TODO: use AKONADI_CONTROL_SERVICE_LOCK instead once we depend on a recent enough Akonadi server
158  const bool controlLockRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE + QLatin1String( ".lock" ) );
159  if ( controlLockRegistered || controlRegistered ) {
160  kDebug() << "Akonadi server is already starting up";
161  sInstance->setState( Starting );
162  return true;
163  }
164 
165  kDebug() << "executing akonadi_control";
166  const bool ok = QProcess::startDetached( QLatin1String( "akonadi_control" ) );
167  if ( !ok ) {
168  kWarning() << "Unable to execute akonadi_control, falling back to D-Bus auto-launch";
169  QDBusReply<void> reply = DBusConnectionPool::threadConnection().interface()->startService( AKONADI_CONTROL_SERVICE );
170  if ( !reply.isValid() ) {
171  kDebug() << "Akonadi server could not be started via D-Bus either: "
172  << reply.error().message();
173  return false;
174  }
175  }
176  sInstance->setState( Starting );
177  return true;
178 }
179 
180 bool ServerManager::stop()
181 {
182  QDBusInterface iface( AKONADI_CONTROL_SERVICE,
183  QString::fromLatin1( "/ControlManager" ),
184  QString::fromLatin1( "org.freedesktop.Akonadi.ControlManager" ) );
185  if ( !iface.isValid() )
186  return false;
187  iface.call( QDBus::NoBlock, QString::fromLatin1( "shutdown" ) );
188  sInstance->setState( Stopping );
189  return true;
190 }
191 
192 void ServerManager::showSelfTestDialog( QWidget *parent )
193 {
194 #ifndef Q_OS_WINCE
195  Akonadi::SelfTestDialog dlg( parent );
196  dlg.hideIntroduction();
197  dlg.exec();
198 #endif
199 }
200 
201 bool ServerManager::isRunning()
202 {
203  return state() == Running;
204 }
205 
206 ServerManager::State ServerManager::state()
207 {
208  ServerManager::State previousState = NotRunning;
209  if ( sInstance.exists() ) // be careful, this is called from the ServerManager::Private ctor, so using sInstance unprotected can cause infinite recursion
210  previousState = sInstance->mState;
211 
212  const bool controlRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE );
213  const bool serverRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_SERVER_SERVICE );
214  if ( controlRegistered && serverRegistered ) {
215  // check if the server protocol is recent enough
216  if ( sInstance.exists() ) {
217  if ( Internal::serverProtocolVersion() >= 0 &&
218  Internal::serverProtocolVersion() < SessionPrivate::minimumProtocolVersion() )
219  return Broken;
220  }
221 
222  // AgentManager is dangerous to use for agents themselves
223  if ( Internal::clientType() == Internal::User ) {
224  // besides the running server processes we also need at least one resource to be operational
225  AgentType::List agentTypes = AgentManager::self()->types();
226  foreach ( const AgentType &type, agentTypes ) {
227  if ( type.capabilities().contains( QLatin1String( "Resource" ) ) )
228  return Running;
229  }
230  return Broken;
231  } else {
232  return Running;
233  }
234  }
235 
236  // TODO: use AKONADI_CONTROL_SERVICE_LOCK instead once we depend on a recent enough Akonadi server
237  const bool controlLockRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE + QLatin1String( ".lock" ) );
238  if ( controlLockRegistered || controlRegistered ) {
239  kDebug() << "Akonadi server is already starting up";
240  if ( previousState == Running )
241  return NotRunning; // we don't know if it's starting or stopping, probably triggered by someone else
242  return previousState;
243  }
244 
245  if ( serverRegistered ) {
246  kWarning() << "Akonadi server running without control process!";
247  return Broken;
248  }
249 
250  if ( previousState == Starting || previousState == Broken ) // valid cases where nothing might be running (yet)
251  return previousState;
252  return NotRunning;
253 }
254 
255 int Internal::serverProtocolVersion()
256 {
257  return ServerManagerPrivate::serverProtocolVersion;
258 }
259 
260 void Internal::setServerProtocolVersion( int version )
261 {
262  ServerManagerPrivate::serverProtocolVersion = version;
263  if ( sInstance.exists() )
264  sInstance->checkStatusChanged();
265 }
266 
267 Internal::ClientType Internal::clientType()
268 {
269  return ServerManagerPrivate::clientType;
270 }
271 
272 void Internal::setClientType( ClientType type )
273 {
274  ServerManagerPrivate::clientType = type;
275 }
276 
277 #include "servermanager.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Wed Nov 28 2012 21:51:40 by doxygen 1.8.1.2 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.9.3 API Reference

Skip menu "kdepimlibs-4.9.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