NepomukDaemons
servicemanager.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "servicemanager.h"
00020 #include "servicecontroller.h"
00021
00022 #include <QtCore/QHash>
00023 #include <QtDBus/QtDBus>
00024
00025 #include <KService>
00026 #include <KServiceTypeTrader>
00027 #include <KDebug>
00028
00029
00030
00031
00032 Nepomuk::ServiceManager* Nepomuk::ServiceManager::s_self = 0;
00033
00034 namespace {
00035 class DependencyTree : public QHash<QString, QStringList>
00036 {
00037 public:
00042 void cleanup();
00043
00047 bool dependsOn( const QString& service, const QString& dependency );
00048
00053 void removeService( const QString& service );
00054
00055 QStringList servicesDependingOn( const QString& service );
00056 };
00057
00058 void DependencyTree::cleanup()
00059 {
00060
00061 QHash<QString, QStringList> tmpTree( *this );
00062 for( QHash<QString, QStringList>::const_iterator it = tmpTree.constBegin();
00063 it != tmpTree.constEnd(); ++it ) {
00064 QString service = it.key();
00065 QStringList dependencies = it.value();
00066
00067 foreach( const QString &dep, dependencies ) {
00068
00069 if( !contains( dep ) ) {
00070 kDebug() << "Found invalid dependency:" << service << "depends on non-existing service" << dep;
00071
00072 removeService( service );
00073 break;
00074 }
00075
00076
00077
00078 else if( dependsOn( dep, service ) ) {
00079 kDebug() << "Found dependency loop:" << service << "depends on" << dep << "and vice versa";
00080
00081 removeService( service );
00082 break;
00083 }
00084 }
00085 }
00086 }
00087
00088 bool DependencyTree::dependsOn( const QString& service, const QString& dependency )
00089 {
00090 foreach( const QString &dep, value( service ) ) {
00091 if( dep == dependency ||
00092 dependsOn( dep, dependency ) ) {
00093 return true;
00094 }
00095 }
00096 return false;
00097 }
00098
00099
00100 void DependencyTree::removeService( const QString& service )
00101 {
00102 if( contains( service ) ) {
00103 remove( service );
00104
00105
00106 QHash<QString, QStringList> tmpTree( *this );
00107 for( QHash<QString, QStringList>::const_iterator it = tmpTree.constBegin();
00108 it != tmpTree.constEnd(); ++it ) {
00109 if( it.value().contains( service ) ) {
00110 removeService( it.key() );
00111 }
00112 }
00113 }
00114 }
00115
00116 QStringList DependencyTree::servicesDependingOn( const QString& service )
00117 {
00118 QStringList sl;
00119 for( QHash<QString, QStringList>::const_iterator it = constBegin();
00120 it != constEnd(); ++it ) {
00121 if( it.value().contains( service ) ) {
00122 sl.append( it.key() );
00123 }
00124 }
00125 return sl;
00126 }
00127 }
00128
00129
00130 class Nepomuk::ServiceManager::Private
00131 {
00132 public:
00133 Private( ServiceManager* p )
00134 : m_initialized(false),
00135 q(p) {
00136 }
00137
00138
00139 QHash<QString, ServiceController*> services;
00140
00141
00142 DependencyTree dependencyTree;
00143
00144
00145 QSet<ServiceController*> pendingServices;
00146
00147 ServiceController* findService( const QString& name );
00148 void buildServiceMap();
00149
00154 void startService( ServiceController* );
00155
00159 void stopService( ServiceController* );
00160
00164 void startPendingServices( ServiceController* newService );
00165
00170 void _k_serviceInitialized( ServiceController* );
00171
00172 private:
00173 bool m_initialized;
00174 ServiceManager* q;
00175 };
00176
00177
00178 void Nepomuk::ServiceManager::Private::buildServiceMap()
00179 {
00180 if( !m_initialized ) {
00181 const KService::List modules = KServiceTypeTrader::self()->query( "NepomukService" );
00182 for( KService::List::ConstIterator it = modules.constBegin(); it != modules.constEnd(); ++it ) {
00183 KService::Ptr service = *it;
00184 QStringList deps = service->property( "X-KDE-Nepomuk-dependencies", QVariant::StringList ).toStringList();
00185 if ( deps.isEmpty() ) {
00186 deps.append( "nepomukstorage" );
00187 }
00188 deps.removeAll( service->desktopEntryName() );
00189 dependencyTree.insert( service->desktopEntryName(), deps );
00190 }
00191
00192 dependencyTree.cleanup();
00193
00194 for( KService::List::ConstIterator it = modules.constBegin(); it != modules.constEnd(); ++it ) {
00195 KService::Ptr service = *it;
00196 if( dependencyTree.contains( service->desktopEntryName() ) ) {
00197 ServiceController* sc = new ServiceController( service, q );
00198 connect( sc, SIGNAL(serviceInitialized(ServiceController*)),
00199 q, SLOT(_k_serviceInitialized(ServiceController*)) );
00200 services.insert( sc->name(), sc );
00201 }
00202 }
00203
00204 m_initialized = true;
00205 }
00206 }
00207
00208
00209 Nepomuk::ServiceController* Nepomuk::ServiceManager::Private::findService( const QString& name )
00210 {
00211 QHash<QString, ServiceController*>::iterator it = services.find( name );
00212 if( it != services.end() ) {
00213 return it.value();
00214 }
00215 return 0;
00216 }
00217
00218
00219 void Nepomuk::ServiceManager::Private::startService( ServiceController* sc )
00220 {
00221 kDebug( 300002 ) << sc->name();
00222
00223 if( !sc->isRunning() ) {
00224
00225 bool needToQueue = false;
00226 foreach( const QString &dependency, dependencyTree[sc->name()] ) {
00227 ServiceController* depSc = findService( dependency );
00228 if ( !depSc->isInitialized() ) {
00229 kDebug() << "Queueing" << sc->name() << "due to dependency" << dependency;
00230 pendingServices.insert( sc );
00231 needToQueue = true;
00232 }
00233
00234 if ( !depSc->isRunning() ) {
00235 startService( depSc );
00236 }
00237 }
00238
00239
00240 if ( !needToQueue ) {
00241 sc->start();
00242 }
00243 }
00244 }
00245
00246
00247 void Nepomuk::ServiceManager::Private::stopService( ServiceController* sc )
00248 {
00249 if( sc->isRunning() ) {
00250
00251 foreach( const QString &dep, dependencyTree.servicesDependingOn( sc->name() ) ) {
00252 stopService( services[dep] );
00253 }
00254
00255 sc->stop();
00256 }
00257 }
00258
00259
00260 void Nepomuk::ServiceManager::Private::startPendingServices( ServiceController* newService )
00261 {
00262
00263
00264 QList<ServiceController*> sl = pendingServices.toList();
00265 foreach( ServiceController* service, sl ) {
00266 if ( service->dependencies().contains( newService->name() ) ) {
00267
00268 pendingServices.remove( service );
00269 startService( service );
00270 }
00271 }
00272 }
00273
00274
00275 void Nepomuk::ServiceManager::Private::_k_serviceInitialized( ServiceController* sc )
00276 {
00277 kDebug() << "Service initialized:" << sc->name();
00278 if ( !pendingServices.isEmpty() ) {
00279 startPendingServices( sc );
00280 }
00281 emit q->serviceInitialized( sc->name() );
00282 }
00283
00284
00285
00286 Nepomuk::ServiceManager::ServiceManager( QObject* parent )
00287 : QObject(parent),
00288 d(new Private(this))
00289 {
00290 s_self = this;
00291
00292 }
00293
00294
00295 Nepomuk::ServiceManager::~ServiceManager()
00296 {
00297 stopAllServices();
00298 delete d;
00299 }
00300
00301
00302 void Nepomuk::ServiceManager::startAllServices()
00303 {
00304 d->buildServiceMap();
00305
00306 for( QHash<QString, ServiceController*>::iterator it = d->services.begin();
00307 it != d->services.end(); ++it ) {
00308 ServiceController* serviceControl = it.value();
00309
00310 if( serviceControl->autostart() ) {
00311 d->startService( serviceControl );
00312 }
00313 }
00314 }
00315
00316
00317 void Nepomuk::ServiceManager::stopAllServices()
00318 {
00319 for( QHash<QString, ServiceController*>::iterator it = d->services.begin();
00320 it != d->services.end(); ++it ) {
00321 ServiceController* serviceControl = it.value();
00322 d->stopService( serviceControl );
00323 }
00324 }
00325
00326
00327 bool Nepomuk::ServiceManager::startService( const QString& name )
00328 {
00329 if( ServiceController* sc = d->findService( name ) ) {
00330 if( !sc->isRunning() ) {
00331
00332 foreach( const QString &dependency, d->dependencyTree[name] ) {
00333 if ( ServiceController* depSc = d->findService( dependency ) ) {
00334 if( depSc->autostart() || depSc->startOnDemand() ) {
00335 if ( !startService( dependency ) ) {
00336 kDebug() << "Cannot start dependency" << dependency;
00337 return false;
00338 }
00339 }
00340 else {
00341 kDebug() << "Dependency" << dependency << "can not be started automatically. It is not an autostart or start on demand service";
00342 return false;
00343 }
00344 }
00345 else {
00346 kDebug() << "Invalid dependency:" << dependency;
00347 return false;
00348 }
00349 }
00350
00351 if ( sc->start() ) {
00352 return sc->waitForInitialized();
00353 }
00354 else {
00355
00356 return false;
00357 }
00358 }
00359 else {
00360
00361 return true;
00362 }
00363 }
00364 else {
00365
00366 return false;
00367 }
00368 }
00369
00370
00371 bool Nepomuk::ServiceManager::stopService( const QString& name )
00372 {
00373 if( ServiceController* sc = d->findService( name ) ) {
00374 if( sc->isRunning() ) {
00375 d->stopService( sc );
00376 return true;
00377 }
00378 }
00379
00380 return false;
00381 }
00382
00383
00384 QStringList Nepomuk::ServiceManager::runningServices() const
00385 {
00386 QStringList sl;
00387 for( QHash<QString, ServiceController*>::iterator it = d->services.begin();
00388 it != d->services.end(); ++it ) {
00389 ServiceController* serviceControl = it.value();
00390 if( serviceControl->isRunning() ) {
00391 sl.append( serviceControl->name() );
00392 }
00393 }
00394 return sl;
00395 }
00396
00397
00398 QStringList Nepomuk::ServiceManager::availableServices() const
00399 {
00400 return d->services.keys();
00401 }
00402
00403
00404 bool Nepomuk::ServiceManager::isServiceInitialized( const QString& service ) const
00405 {
00406 if ( ServiceController* sc = d->findService( service ) ) {
00407 return sc->isInitialized();
00408 }
00409 else {
00410 return false;
00411 }
00412 }
00413
00414
00415 bool Nepomuk::ServiceManager::isServiceAutostarted( const QString& name )
00416 {
00417 if ( ServiceController* sc = d->findService( name ) ) {
00418 return sc->autostart();
00419 }
00420 else {
00421 return false;
00422 }
00423 }
00424
00425
00426 void Nepomuk::ServiceManager::setServiceAutostarted( const QString& name, bool autostart )
00427 {
00428 if ( ServiceController* sc = d->findService( name ) ) {
00429 sc->setAutostart( autostart );
00430 }
00431 }
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461 #include "servicemanager.moc"