• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

Nepomuk-Core

  • sources
  • kde-4.12
  • kdelibs
  • nepomuk-core
  • server
servicemanager.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE Project
2  Copyright (c) 2008 Sebastian Trueg <trueg@kde.org>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License version 2 as published by the Free Software Foundation.
7 
8  This library is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  Library General Public License for more details.
12 
13  You should have received a copy of the GNU Library General Public License
14  along with this library; see the file COPYING.LIB. If not, write to
15  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  Boston, MA 02110-1301, USA.
17 */
18 
19 #include "servicemanager.h"
20 #include "servicecontroller.h"
21 
22 #include <QtCore/QHash>
23 #include <QtDBus/QtDBus>
24 
25 #include <KService>
26 #include <KServiceTypeTrader>
27 #include <KDebug>
28 
29 
30 //extern QDBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage&));
31 
32 Nepomuk2::ServiceManager* Nepomuk2::ServiceManager::s_self = 0;
33 
34 namespace {
35  class DependencyTree : public QHash<QString, QStringList>
36  {
37  public:
42  void cleanup();
43 
47  bool dependsOn( const QString& service, const QString& dependency );
48 
53  void removeService( const QString& service );
54 
55  QStringList servicesDependingOn( const QString& service );
56  };
57 
58  void DependencyTree::cleanup()
59  {
60  // cleanup dependency tree
61  QHash<QString, QStringList> tmpTree( *this );
62  for( QHash<QString, QStringList>::const_iterator it = tmpTree.constBegin();
63  it != tmpTree.constEnd(); ++it ) {
64  QString service = it.key();
65  QStringList dependencies = it.value();
66 
67  foreach( const QString &dep, dependencies ) {
68  // check if the service depends on a non-existing service
69  if( !contains( dep ) ) {
70  kDebug() << "Found invalid dependency:" << service << "depends on non-existing service" << dep;
71  // ignore the service and all those depending on it
72  removeService( service );
73  break;
74  }
75 
76  // check if the service itself is a dependency of any of its
77  // dependencies
78  else if( dependsOn( dep, service ) ) {
79  kDebug() << "Found dependency loop:" << service << "depends on" << dep << "and vice versa";
80  // ignore the service and all those depending on it
81  removeService( service );
82  break;
83  }
84  }
85  }
86  }
87 
88  bool DependencyTree::dependsOn( const QString& service, const QString& dependency )
89  {
90  foreach( const QString &dep, value( service ) ) {
91  if( dep == dependency ||
92  dependsOn( dep, dependency ) ) {
93  return true;
94  }
95  }
96  return false;
97  }
98 
99 
100  void DependencyTree::removeService( const QString& service )
101  {
102  if( contains( service ) ) {
103  remove( service );
104 
105  // remove any service depending on the removed one
106  QHash<QString, QStringList> tmpTree( *this );
107  for( QHash<QString, QStringList>::const_iterator it = tmpTree.constBegin();
108  it != tmpTree.constEnd(); ++it ) {
109  if( it.value().contains( service ) ) {
110  removeService( it.key() );
111  }
112  }
113  }
114  }
115 
116  QStringList DependencyTree::servicesDependingOn( const QString& service )
117  {
118  QStringList sl;
119  for( QHash<QString, QStringList>::const_iterator it = constBegin();
120  it != constEnd(); ++it ) {
121  if( it.value().contains( service ) ) {
122  sl.append( it.key() );
123  }
124  }
125  return sl;
126  }
127 }
128 
129 
130 class Nepomuk2::ServiceManager::Private
131 {
132 public:
133  Private( ServiceManager* p )
134  : m_initialized(false),
135  q(p) {
136  }
137 
138  // map of all services, started and stopped ones
139  QHash<QString, ServiceController*> services;
140 
141  // clean dependency tree
142  DependencyTree dependencyTree;
143 
144  // services that wait for dependencies to initialize
145  QSet<ServiceController*> pendingServices;
146 
147  // services that were stopped and are waiting for services to stop that depend on them
148  QSet<ServiceController*> stoppedServices;
149 
150  ServiceController* findService( const QString& name );
151  void buildServiceMap();
152 
157  void startService( ServiceController* );
158 
162  void stopService( ServiceController* );
163 
168  void _k_serviceInitialized( ServiceController* );
169 
174  void _k_serviceStopped( ServiceController* );
175 
176 private:
177  bool m_initialized;
178  ServiceManager* q;
179 };
180 
181 
182 void Nepomuk2::ServiceManager::Private::buildServiceMap()
183 {
184  if( !m_initialized ) {
185  KService::List modules = KServiceTypeTrader::self()->query( "NepomukService" );
186  for( KService::List::ConstIterator it = modules.constBegin(); it != modules.constEnd(); ++it ) {
187  KService::Ptr service = *it;
188  QStringList deps = service->property( "X-KDE-Nepomuk-dependencies", QVariant::StringList ).toStringList();
189  if ( deps.isEmpty() ) {
190  deps.append( "nepomukstorage" );
191  }
192  deps.removeAll( service->desktopEntryName() );
193  dependencyTree.insert( service->desktopEntryName(), deps );
194  }
195 
196  //
197  // Services2
198  //
199  const KService::List newModules = KServiceTypeTrader::self()->query( "NepomukService2" );
200  for( KService::List::ConstIterator it = newModules.constBegin(); it != newModules.constEnd(); ++it ) {
201  KService::Ptr service = *it;
202  QStringList deps = service->property( "X-KDE-Nepomuk-dependencies", QVariant::StringList ).toStringList();
203  if ( deps.isEmpty() ) {
204  deps.append( "nepomukstorage" );
205  }
206  deps.removeAll( service->desktopEntryName() );
207  dependencyTree.insert( service->desktopEntryName(), deps );
208  }
209 
210  dependencyTree.cleanup();
211  modules.append( newModules );
212 
213  for( KService::List::ConstIterator it = modules.constBegin(); it != modules.constEnd(); ++it ) {
214  KService::Ptr service = *it;
215  if( dependencyTree.contains( service->desktopEntryName() ) ) {
216  ServiceController* sc = new ServiceController( service, q );
217  connect( sc, SIGNAL(serviceInitialized(ServiceController*)),
218  q, SLOT(_k_serviceInitialized(ServiceController*)) );
219  connect( sc, SIGNAL(serviceStopped(ServiceController*)),
220  q, SLOT(_k_serviceStopped(ServiceController*)) );
221  services.insert( sc->name(), sc );
222  }
223  }
224 
225  m_initialized = true;
226  }
227 }
228 
229 
230 Nepomuk2::ServiceController* Nepomuk2::ServiceManager::Private::findService( const QString& name )
231 {
232  QHash<QString, ServiceController*>::iterator it = services.find( name );
233  if( it != services.end() ) {
234  return it.value();
235  }
236  return 0;
237 }
238 
239 
240 void Nepomuk2::ServiceManager::Private::startService( ServiceController* sc )
241 {
242  kDebug() << sc->name();
243 
244  stoppedServices.remove(sc);
245 
246  if( !sc->isRunning() ) {
247  // start dependencies if possible
248  bool needToQueue = false;
249  foreach( const QString &dependency, dependencyTree[sc->name()] ) {
250  ServiceController* depSc = findService( dependency );
251  if ( !needToQueue && !depSc->isInitialized() ) {
252  kDebug() << "Queueing" << sc->name() << "due to dependency" << dependency;
253  pendingServices.insert( sc );
254  needToQueue = true;
255  }
256 
257  if ( !depSc->isRunning() ) {
258  startService( depSc );
259  }
260  }
261 
262  // start service
263  if ( !needToQueue ) {
264  sc->start();
265  }
266  }
267 }
268 
269 
270 void Nepomuk2::ServiceManager::Private::stopService( ServiceController* service )
271 {
272  pendingServices.remove(service);
273 
274  if( service->isRunning() ) {
275  // shut down any service depending of this one first
276  bool haveRunningRevDeps = false;
277  foreach(const QString& dep, dependencyTree.servicesDependingOn( service->name() )) {
278  ServiceController* sc = services[dep];
279  if( sc->isRunning() ) {
280  kDebug() << "Revdep still running:" << sc->name() << "Queuing to be stopped:" << service->name();
281  stoppedServices.insert( service );
282  haveRunningRevDeps = true;
283 
284  stopService( sc );
285  pendingServices.insert( sc );
286  }
287  }
288 
289  // if we did not queue it to be stopped we can do it now
290  if(!haveRunningRevDeps) {
291  stoppedServices.remove(service);
292  service->stop();
293  }
294  }
295 }
296 
297 
298 void Nepomuk2::ServiceManager::Private::_k_serviceInitialized( ServiceController* sc )
299 {
300  kDebug() << "Service initialized:" << sc->name();
301 
302  // check the list of pending services and start as many as possible
303  // (we can start services whose dependencies are initialized)
304  QList<ServiceController*> sl = pendingServices.toList();
305  foreach( ServiceController* service, sl ) {
306  if ( service->dependencies().contains( sc->name() ) ) {
307  // try to start the service again
308  pendingServices.remove( service );
309  startService( service );
310  }
311  }
312 
313  emit q->serviceInitialized( sc->name() );
314 }
315 
316 
317 void Nepomuk2::ServiceManager::Private::_k_serviceStopped( ServiceController* sc )
318 {
319  kDebug() << "Service stopped:" << sc->name();
320 
321  emit q->serviceStopped( sc->name() );
322 
323  // 1. The standard case: we stopped a service and waited for the rev deps to go down
324  //
325  // try to stop all stopped services that are still waiting for reverse deps to shut down
326  QSet<ServiceController*> ss = stoppedServices;
327  foreach(ServiceController* sc, ss) {
328  stoppedServices.remove(sc);
329  stopService(sc);
330  }
331 
332 
333  // 2. The other case where a service was stopped from the outside and we have to shut down its
334  // reverse deps
335  //
336  // stop and queue all services depending on the stopped one
337  // this will re-trigger this method until all reverse-deps are stopped
338  foreach( const QString &dep, dependencyTree.servicesDependingOn( sc->name() ) ) {
339  ServiceController* depsc = services[dep];
340  if( depsc->isRunning() ) {
341  kDebug() << "Stopping and queuing rev-dep" << depsc->name();
342  stopService(depsc);
343  pendingServices.insert( depsc );
344  }
345  }
346 }
347 
348 
349 Nepomuk2::ServiceManager::ServiceManager( QObject* parent )
350  : QObject(parent),
351  d(new Private(this))
352 {
353  s_self = this;
354 // qDBusAddSpyHook(messageFilter);
355 }
356 
357 
358 Nepomuk2::ServiceManager::~ServiceManager()
359 {
360  qDeleteAll(d->services);
361  delete d;
362 }
363 
364 
365 void Nepomuk2::ServiceManager::startAllServices()
366 {
367  d->buildServiceMap();
368 
369  for( QHash<QString, ServiceController*>::iterator it = d->services.begin();
370  it != d->services.end(); ++it ) {
371  ServiceController* serviceControl = it.value();
372 
373  if( serviceControl->autostart() ) {
374  d->startService( serviceControl );
375  }
376  }
377 }
378 
379 
380 void Nepomuk2::ServiceManager::stopAllServices()
381 {
382  d->pendingServices.clear();
383  for( QHash<QString, ServiceController*>::iterator it = d->services.begin();
384  it != d->services.end(); ++it ) {
385  ServiceController* serviceControl = it.value();
386  d->stopService( serviceControl );
387  }
388 }
389 
390 
391 bool Nepomuk2::ServiceManager::startService( const QString& name )
392 {
393  if( ServiceController* sc = d->findService( name ) ) {
394  d->startService( sc );
395  return true;
396  }
397  else {
398  // could not find service
399  return false;
400  }
401 }
402 
403 
404 bool Nepomuk2::ServiceManager::stopService( const QString& name )
405 {
406  if( ServiceController* sc = d->findService( name ) ) {
407  d->stopService( sc );
408  return true;
409  }
410  return false;
411 }
412 
413 
414 QStringList Nepomuk2::ServiceManager::runningServices() const
415 {
416  QStringList sl;
417  for( QHash<QString, ServiceController*>::iterator it = d->services.begin();
418  it != d->services.end(); ++it ) {
419  ServiceController* serviceControl = it.value();
420  if( serviceControl->isRunning() ) {
421  sl.append( serviceControl->name() );
422  }
423  }
424  return sl;
425 }
426 
427 
428 QStringList Nepomuk2::ServiceManager::pendingServices() const
429 {
430  QStringList sl;
431  foreach(ServiceController* sc, d->pendingServices) {
432  sl.append(sc->name());
433  }
434  return sl;
435 }
436 
437 QStringList Nepomuk2::ServiceManager::availableServices() const
438 {
439  return d->services.keys();
440 }
441 
442 
443 bool Nepomuk2::ServiceManager::isServiceInitialized( const QString& service ) const
444 {
445  if ( ServiceController* sc = d->findService( service ) ) {
446  return sc->isInitialized();
447  }
448  else {
449  return false;
450  }
451 }
452 
453 
454 bool Nepomuk2::ServiceManager::isServiceRunning( const QString& service ) const
455 {
456  if ( ServiceController* sc = d->findService( service ) ) {
457  return sc->isRunning();
458  }
459  else {
460  return false;
461  }
462 }
463 
464 
465 bool Nepomuk2::ServiceManager::isServiceAutostarted( const QString& name )
466 {
467  if ( ServiceController* sc = d->findService( name ) ) {
468  return sc->autostart();
469  }
470  else {
471  return false;
472  }
473 }
474 
475 
476 void Nepomuk2::ServiceManager::setServiceAutostarted( const QString& name, bool autostart )
477 {
478  if ( ServiceController* sc = d->findService( name ) ) {
479  sc->setAutostart( autostart );
480  }
481 }
482 
483 
484 //#define MODULES_PATH "/modules/"
485 
486 // FIXME: Use our own system and dbus path
487 // on-demand module loading
488 // this function is called by the D-Bus message processing function before
489 // calls are delivered to objects
490 // void Nepomuk2::ServiceManager::messageFilter( const QDBusMessage& message )
491 // {
492 // if ( message.type() != QDBusMessage::MethodCallMessage )
493 // return;
494 
495 // QString obj = message.path();
496 // if ( !obj.startsWith( MODULES_PATH ) )
497 // return;
498 
499 // QString name = obj.mid( strlen( MODULES_PATH ) );
500 // if ( name == "ksycoca" )
501 // return; // Ignore this one.
502 
503 // if( ServiceController* sc = self()->d->findService( name ) ) {
504 // if( sc->startOnDemand() ) {
505 // self()->d->startService( sc );
506 // sc->waitForInitialized();
507 // }
508 // }
509 // }
510 
511 #include "servicemanager.moc"
Nepomuk2::ServiceManager::availableServices
QStringList availableServices() const
All services that are available in the system.
Definition: servicemanager.cpp:437
Nepomuk2::ServiceManager::isServiceRunning
bool isServiceRunning(const QString &servicename) const
Definition: servicemanager.cpp:454
Nepomuk2::ServiceController
Definition: servicecontroller.h:28
QHash
QObject
Nepomuk2::ServiceManager::startAllServices
void startAllServices()
Starts all autoload services.
Definition: servicemanager.cpp:365
servicecontroller.h
Nepomuk2::ServiceManager::stopService
bool stopService(const QString &name)
Stop a specific service.
Definition: servicemanager.cpp:404
stopService
void stopService(const KService::Ptr &ptr)
Definition: tools/nepomukctl/main.cpp:229
startService
void startService(const KService::Ptr &ptr)
Definition: tools/nepomukctl/main.cpp:197
servicemanager.h
Nepomuk2::ServiceManager::ServiceManager
ServiceManager(QObject *parent=0)
Definition: servicemanager.cpp:349
Nepomuk2::ServiceManager::setServiceAutostarted
void setServiceAutostarted(const QString &name, bool autostart)
Set the service indicated by name to be autostarted.
Definition: servicemanager.cpp:476
Nepomuk2::ServiceManager::stopAllServices
void stopAllServices()
Stops all services.
Definition: servicemanager.cpp:380
Nepomuk2::ServiceManager
Manages all Nepomuk services.
Definition: servicemanager.h:34
Nepomuk2::ServiceManager::pendingServices
QStringList pendingServices() const
The services that are scheduled to be started but are waiting for dependancies to get initialized...
Definition: servicemanager.cpp:428
Nepomuk2::ServiceManager::runningServices
QStringList runningServices() const
Even uninitialized services are running.
Definition: servicemanager.cpp:414
Nepomuk2::ServiceController::isRunning
bool isRunning() const
Definition: servicecontroller.cpp:250
Nepomuk2::ServiceController::name
QString name() const
The name of the service.
Definition: servicecontroller.cpp:139
Nepomuk2::ServiceManager::~ServiceManager
~ServiceManager()
Definition: servicemanager.cpp:358
Nepomuk2::ServiceManager::isServiceAutostarted
bool isServiceAutostarted(const QString &name)
Definition: servicemanager.cpp:465
Nepomuk2::ServiceController::autostart
bool autostart() const
Definition: servicecontroller.cpp:163
Nepomuk2::ServiceManager::startService
bool startService(const QString &name)
Start a specific service.
Definition: servicemanager.cpp:391
Nepomuk2::ServiceManager::isServiceInitialized
bool isServiceInitialized(const QString &servicename) const
Definition: servicemanager.cpp:443
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:48:09 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Nepomuk-Core

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

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



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