add more spacing
[personal-kdebase.git] / runtime / nepomuk / server / servicemanager.cpp
blobc99fed8317a1eac187fe3bf09fe8367300327d4e
1 /* This file is part of the KDE Project
2 Copyright (c) 2008 Sebastian Trueg <trueg@kde.org>
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.
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.
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.
19 #include "servicemanager.h"
20 #include "servicecontroller.h"
22 #include <QtCore/QHash>
23 #include <QtDBus/QtDBus>
25 #include <KService>
26 #include <KServiceTypeTrader>
27 #include <KDebug>
30 //extern QDBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage&));
32 Nepomuk::ServiceManager* Nepomuk::ServiceManager::s_self = 0;
34 namespace {
35 class DependencyTree : public QHash<QString, QStringList>
37 public:
38 /**
39 * Cleanup the tree. Remove all services
40 * that have an invalid dependency branch
42 void cleanup();
44 /**
45 * \return true if service depends on dependency
47 bool dependsOn( const QString& service, const QString& dependency );
49 /**
50 * Remove the service and all those depending on it
51 * from the services list
53 void removeService( const QString& service );
55 QStringList servicesDependingOn( const QString& service );
58 void DependencyTree::cleanup()
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();
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;
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;
88 bool DependencyTree::dependsOn( const QString& service, const QString& dependency )
90 foreach( const QString &dep, value( service ) ) {
91 if( dep == dependency ||
92 dependsOn( dep, dependency ) ) {
93 return true;
96 return false;
100 void DependencyTree::removeService( const QString& service )
102 if( contains( service ) ) {
103 remove( service );
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() );
116 QStringList DependencyTree::servicesDependingOn( const QString& service )
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() );
125 return sl;
130 class Nepomuk::ServiceManager::Private
132 public:
133 Private( ServiceManager* p )
134 : m_initialized(false),
135 q(p) {
138 // map of all services, started and stopped ones
139 QHash<QString, ServiceController*> services;
141 // clean dependency tree
142 DependencyTree dependencyTree;
144 // services that wait for dependencies to initialize
145 QSet<ServiceController*> pendingServices;
147 ServiceController* findService( const QString& name );
148 void buildServiceMap();
151 * Try to start a service including all its
152 * dependecies. Async.
154 void startService( ServiceController* );
157 * Stop a service and all services depending on it.
159 void stopService( ServiceController* );
162 * Start pending services based on the newly initialized service newService
164 void startPendingServices( ServiceController* newService );
167 * Slot connected to all ServiceController::serviceInitialized
168 * signals.
170 void _k_serviceInitialized( ServiceController* );
172 private:
173 bool m_initialized;
174 ServiceManager* q;
178 void Nepomuk::ServiceManager::Private::buildServiceMap()
180 if( !m_initialized ) {
181 const KService::List modules = KServiceTypeTrader::self()->query( "NepomukService" );
182 for( KService::List::ConstIterator it = modules.constBegin(); it != modules.constEnd(); ++it ) {
183 KService::Ptr service = *it;
184 QStringList deps = service->property( "X-KDE-Nepomuk-dependencies", QVariant::StringList ).toStringList();
185 if ( deps.isEmpty() ) {
186 deps.append( "nepomukstorage" );
188 deps.removeAll( service->desktopEntryName() );
189 dependencyTree.insert( service->desktopEntryName(), deps );
192 dependencyTree.cleanup();
194 for( KService::List::ConstIterator it = modules.constBegin(); it != modules.constEnd(); ++it ) {
195 KService::Ptr service = *it;
196 if( dependencyTree.contains( service->desktopEntryName() ) ) {
197 ServiceController* sc = new ServiceController( service, q );
198 connect( sc, SIGNAL(serviceInitialized(ServiceController*)),
199 q, SLOT(_k_serviceInitialized(ServiceController*)) );
200 services.insert( sc->name(), sc );
204 m_initialized = true;
209 Nepomuk::ServiceController* Nepomuk::ServiceManager::Private::findService( const QString& name )
211 QHash<QString, ServiceController*>::iterator it = services.find( name );
212 if( it != services.end() ) {
213 return it.value();
215 return 0;
219 void Nepomuk::ServiceManager::Private::startService( ServiceController* sc )
221 kDebug( 300002 ) << sc->name();
223 if( !sc->isRunning() ) {
224 // start dependencies if possible
225 bool needToQueue = false;
226 foreach( const QString &dependency, dependencyTree[sc->name()] ) {
227 ServiceController* depSc = findService( dependency );
228 if ( !depSc->isInitialized() ) {
229 kDebug() << "Queueing" << sc->name() << "due to dependency" << dependency;
230 pendingServices.insert( sc );
231 needToQueue = true;
234 if ( !depSc->isRunning() ) {
235 startService( depSc );
239 // start service
240 if ( !needToQueue ) {
241 sc->start();
247 void Nepomuk::ServiceManager::Private::stopService( ServiceController* sc )
249 if( sc->isRunning() ) {
250 // shut down any service depending of this one first
251 foreach( const QString &dep, dependencyTree.servicesDependingOn( sc->name() ) ) {
252 stopService( services[dep] );
255 sc->stop();
260 void Nepomuk::ServiceManager::Private::startPendingServices( ServiceController* newService )
262 // check the list of pending services and start as many as possible
263 // (we can start services whose dependencies are initialized)
264 QList<ServiceController*> sl = pendingServices.toList();
265 foreach( ServiceController* service, sl ) {
266 if ( service->dependencies().contains( newService->name() ) ) {
267 // try to start the service again
268 pendingServices.remove( service );
269 startService( service );
275 void Nepomuk::ServiceManager::Private::_k_serviceInitialized( ServiceController* sc )
277 kDebug() << "Service initialized:" << sc->name();
278 if ( !pendingServices.isEmpty() ) {
279 startPendingServices( sc );
281 emit q->serviceInitialized( sc->name() );
286 Nepomuk::ServiceManager::ServiceManager( QObject* parent )
287 : QObject(parent),
288 d(new Private(this))
290 s_self = this;
291 // qDBusAddSpyHook(messageFilter);
295 Nepomuk::ServiceManager::~ServiceManager()
297 stopAllServices();
298 delete d;
302 void Nepomuk::ServiceManager::startAllServices()
304 d->buildServiceMap();
306 for( QHash<QString, ServiceController*>::iterator it = d->services.begin();
307 it != d->services.end(); ++it ) {
308 ServiceController* serviceControl = it.value();
310 if( serviceControl->autostart() ) {
311 d->startService( serviceControl );
317 void Nepomuk::ServiceManager::stopAllServices()
319 for( QHash<QString, ServiceController*>::iterator it = d->services.begin();
320 it != d->services.end(); ++it ) {
321 ServiceController* serviceControl = it.value();
322 d->stopService( serviceControl );
327 bool Nepomuk::ServiceManager::startService( const QString& name )
329 if( ServiceController* sc = d->findService( name ) ) {
330 if( !sc->isRunning() ) {
331 // start dependencies if possible
332 foreach( const QString &dependency, d->dependencyTree[name] ) {
333 if ( ServiceController* depSc = d->findService( dependency ) ) {
334 if( depSc->autostart() || depSc->startOnDemand() ) {
335 if ( !startService( dependency ) ) {
336 kDebug() << "Cannot start dependency" << dependency;
337 return false;
340 else {
341 kDebug() << "Dependency" << dependency << "can not be started automatically. It is not an autostart or start on demand service";
342 return false;
345 else {
346 kDebug() << "Invalid dependency:" << dependency;
347 return false;
351 if ( sc->start() ) {
352 return sc->waitForInitialized();
354 else {
355 // failed to start service
356 return false;
359 else {
360 // service already running
361 return true;
364 else {
365 // could not find service
366 return false;
371 bool Nepomuk::ServiceManager::stopService( const QString& name )
373 if( ServiceController* sc = d->findService( name ) ) {
374 if( sc->isRunning() ) {
375 d->stopService( sc );
376 return true;
380 return false;
384 QStringList Nepomuk::ServiceManager::runningServices() const
386 QStringList sl;
387 for( QHash<QString, ServiceController*>::iterator it = d->services.begin();
388 it != d->services.end(); ++it ) {
389 ServiceController* serviceControl = it.value();
390 if( serviceControl->isRunning() ) {
391 sl.append( serviceControl->name() );
394 return sl;
398 QStringList Nepomuk::ServiceManager::availableServices() const
400 return d->services.keys();
404 bool Nepomuk::ServiceManager::isServiceInitialized( const QString& service ) const
406 if ( ServiceController* sc = d->findService( service ) ) {
407 return sc->isInitialized();
409 else {
410 return false;
415 bool Nepomuk::ServiceManager::isServiceAutostarted( const QString& name )
417 if ( ServiceController* sc = d->findService( name ) ) {
418 return sc->autostart();
420 else {
421 return false;
426 void Nepomuk::ServiceManager::setServiceAutostarted( const QString& name, bool autostart )
428 if ( ServiceController* sc = d->findService( name ) ) {
429 sc->setAutostart( autostart );
434 //#define MODULES_PATH "/modules/"
436 // FIXME: Use our own system and dbus path
437 // on-demand module loading
438 // this function is called by the D-Bus message processing function before
439 // calls are delivered to objects
440 // void Nepomuk::ServiceManager::messageFilter( const QDBusMessage& message )
441 // {
442 // if ( message.type() != QDBusMessage::MethodCallMessage )
443 // return;
445 // QString obj = message.path();
446 // if ( !obj.startsWith( MODULES_PATH ) )
447 // return;
449 // QString name = obj.mid( strlen( MODULES_PATH ) );
450 // if ( name == "ksycoca" )
451 // return; // Ignore this one.
453 // if( ServiceController* sc = self()->d->findService( name ) ) {
454 // if( sc->startOnDemand() ) {
455 // self()->d->startService( sc );
456 // sc->waitForInitialized();
457 // }
458 // }
459 // }
461 #include "servicemanager.moc"