• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

NepomukDaemons

servicemanager.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE Project
00002    Copyright (c) 2008 Sebastian Trueg <trueg@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016    Boston, MA 02110-1301, USA.
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 //extern QDBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage&));
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         // cleanup dependency tree
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                 // check if the service depends on a non-existing service
00069                 if( !contains( dep ) ) {
00070                     kDebug() << "Found invalid dependency:" << service << "depends on non-existing service" << dep;
00071                     // ignore the service and all those depending on it
00072                     removeService( service );
00073                     break;
00074                 }
00075 
00076                 // check if the service itself is a dependency of any of its
00077                 // dependencies
00078                 else if( dependsOn( dep, service ) ) {
00079                     kDebug() << "Found dependency loop:" << service << "depends on" << dep << "and vice versa";
00080                     // ignore the service and all those depending on it
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             // remove any service depending on the removed one
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     // map of all services, started and stopped ones
00139     QHash<QString, ServiceController*> services;
00140 
00141     // clean dependency tree
00142     DependencyTree dependencyTree;
00143 
00144     // services that wait for dependencies to initialize
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         KService::List modules = KServiceTypeTrader::self()->query( "NepomukService" );
00182         for( KService::List::ConstIterator it = modules.begin(); it != modules.end(); ++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.begin(); it != modules.end(); ++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         // start dependencies if possible
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         // start service
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         // shut down any service depending of this one first
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     // check the list of pending services and start as many as possible
00263     // (we can start services whose dependencies are initialized)
00264     QList<ServiceController*> sl = pendingServices.toList();
00265     foreach( ServiceController* service, sl ) {
00266         if ( service->dependencies().contains( newService->name() ) ) {
00267             // try to start the service again
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 //    qDBusAddSpyHook(messageFilter);
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             // start dependencies if possible
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                 // failed to start service
00356                 return false;
00357             }
00358         }
00359         else {
00360             // service already running
00361             return true;
00362         }
00363     }
00364     else {
00365         // could not find service
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 //#define MODULES_PATH "/modules/"
00435 
00436 // FIXME: Use our own system and dbus path
00437 // on-demand module loading
00438 // this function is called by the D-Bus message processing function before
00439 // calls are delivered to objects
00440 // void Nepomuk::ServiceManager::messageFilter( const QDBusMessage& message )
00441 // {
00442 //     if ( message.type() != QDBusMessage::MethodCallMessage )
00443 //         return;
00444 
00445 //     QString obj = message.path();
00446 //     if ( !obj.startsWith( MODULES_PATH ) )
00447 //         return;
00448 
00449 //     QString name = obj.mid( strlen( MODULES_PATH ) );
00450 //     if ( name == "ksycoca" )
00451 //         return; // Ignore this one.
00452 
00453 //     if( ServiceController* sc = self()->d->findService( name ) ) {
00454 //         if( sc->startOnDemand() ) {
00455 //             self()->d->startService( sc );
00456 //             sc->waitForInitialized();
00457 //         }
00458 //     }
00459 // }
00460 
00461 #include "servicemanager.moc"

NepomukDaemons

Skip menu "NepomukDaemons"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KCMShell
  • KNotify
  • KStyles
  • Nepomuk Daemons
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal