add more spacing
[personal-kdebase.git] / runtime / nepomuk / server / servicecontroller.cpp
blobea81c6935b9fcf4525e833fb8fac5742d0c51db7
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 "servicecontroller.h"
20 #include "processcontrol.h"
21 #include "servicecontrolinterface.h"
22 #include "nepomukserver.h"
24 #include <QtCore/QEventLoop>
25 #include <QtCore/QTimer>
27 #include <KStandardDirs>
28 #include <KConfigGroup>
29 #include <KDebug>
32 namespace {
33 QString dbusServiceName( const QString& serviceName ) {
34 return QString("org.kde.nepomuk.services.%1").arg(serviceName);
39 class Nepomuk::ServiceController::Private
41 public:
42 Private()
43 : processControl( 0 ),
44 serviceControlInterface( 0 ),
45 attached( false ),
46 initialized( false ),
47 failedToInitialize( false ) {
50 KService::Ptr service;
51 bool autostart;
52 bool startOnDemand;
53 bool runOnce;
55 ProcessControl* processControl;
56 OrgKdeNepomukServiceControlInterface* serviceControlInterface;
58 // true if we attached to an already running instance instead of
59 // starting our own (in that case processControl will be 0)
60 bool attached;
62 bool initialized;
63 bool failedToInitialize;
65 // list of loops waiting for the service to become initialized
66 QList<QEventLoop*> loops;
68 void init( KService::Ptr service );
72 void Nepomuk::ServiceController::Private::init( KService::Ptr s )
74 service = s;
75 autostart = service->property( "X-KDE-Nepomuk-autostart", QVariant::Bool ).toBool();
76 KConfigGroup cg( Server::self()->config(), QString("Service-%1").arg(service->desktopEntryName()) );
77 autostart = cg.readEntry( "autostart", autostart );
79 QVariant p = service->property( "X-KDE-Nepomuk-start-on-demand", QVariant::Bool );
80 startOnDemand = ( p.isValid() ? p.toBool() : false );
82 p = service->property( "X-KDE-Nepomuk-run-once", QVariant::Bool );
83 runOnce = ( p.isValid() ? p.toBool() : false );
85 initialized = false;
89 Nepomuk::ServiceController::ServiceController( KService::Ptr service, QObject* parent )
90 : QObject( parent ),
91 d(new Private())
93 d->init( service );
97 Nepomuk::ServiceController::~ServiceController()
99 stop();
100 delete d;
104 KService::Ptr Nepomuk::ServiceController::service() const
106 return d->service;
110 QString Nepomuk::ServiceController::name() const
112 return d->service->desktopEntryName();
116 QStringList Nepomuk::ServiceController::dependencies() const
118 QStringList deps = d->service->property( "X-KDE-Nepomuk-dependencies", QVariant::StringList ).toStringList();
119 if ( deps.isEmpty() ) {
120 deps.append( "nepomukstorage" );
122 deps.removeAll( name() );
123 return deps;
127 void Nepomuk::ServiceController::setAutostart( bool enable )
129 KConfigGroup cg( Server::self()->config(), QString("Service-%1").arg(name()) );
130 cg.writeEntry( "autostart", enable );
134 bool Nepomuk::ServiceController::autostart() const
136 return d->autostart;
140 bool Nepomuk::ServiceController::startOnDemand() const
142 return d->startOnDemand;
146 bool Nepomuk::ServiceController::runOnce() const
148 return d->runOnce;
152 bool Nepomuk::ServiceController::start()
154 if( isRunning() ) {
155 return true;
158 d->initialized = false;
159 d->failedToInitialize = false;
161 // check if the service is already running, ie. has been started by someone else or by a crashed instance of the server
162 // we cannot rely on the auto-restart feature of ProcessControl here. So we handle that completely in slotServiceOwnerChanged
163 if( QDBusConnection::sessionBus().interface()->isServiceRegistered( dbusServiceName( name() ) ) ) {
164 kDebug() << "Attaching to already running service" << name();
165 d->attached = true;
166 createServiceControlInterface();
167 return true;
169 else {
170 kDebug(300002) << "Starting" << name();
172 if( !d->processControl ) {
173 d->processControl = new ProcessControl( this );
174 connect( d->processControl, SIGNAL( finished( bool ) ),
175 this, SLOT( slotProcessFinished( bool ) ) );
178 connect( QDBusConnection::sessionBus().interface(),
179 SIGNAL( serviceOwnerChanged( const QString&, const QString&, const QString& ) ),
180 this,
181 SLOT( slotServiceOwnerChanged( const QString&, const QString&, const QString& ) ) );
183 d->processControl->setCrashPolicy( ProcessControl::RestartOnCrash );
184 return d->processControl->start( KGlobal::dirs()->locate( "exe", "nepomukservicestub" ),
185 QStringList() << name() );
190 void Nepomuk::ServiceController::stop()
192 if( isRunning() ) {
193 kDebug(300002) << "Stopping" << name();
195 d->attached = false;
197 if( d->processControl ) {
198 d->processControl->setCrashPolicy( ProcessControl::StopOnCrash );
201 if ( d->serviceControlInterface ||
202 ( !QCoreApplication::closingDown() &&
203 waitForInitialized( 2000 ) ) ) {
204 d->serviceControlInterface->shutdown();
207 if( d->processControl ) {
208 d->processControl->stop();
211 // make sure all loops waiting for the service to initialize
212 // are terminated.
213 foreach( QEventLoop* loop, d->loops ) {
214 loop->exit();
220 bool Nepomuk::ServiceController::isRunning() const
222 return( d->attached || ( d->processControl ? d->processControl->isRunning() : false ) );
226 bool Nepomuk::ServiceController::isInitialized() const
228 return d->initialized;
232 bool Nepomuk::ServiceController::waitForInitialized( int timeout )
234 if( !isRunning() ) {
235 return false;
238 if( !d->initialized && !d->failedToInitialize ) {
239 QEventLoop loop;
240 d->loops.append( &loop );
241 if ( timeout > 0 ) {
242 QTimer::singleShot( timeout, &loop, SLOT(quit()) );
244 QPointer<ServiceController> guard = this;
245 loop.exec();
246 if ( !guard.isNull() )
247 d->loops.removeAll( &loop );
250 return d->initialized;
254 void Nepomuk::ServiceController::slotProcessFinished( bool /*clean*/ )
256 kDebug() << "Service" << name() << "went down";
257 d->initialized = false;
258 d->attached = false;
259 disconnect( QDBusConnection::sessionBus().interface() );
260 delete d->serviceControlInterface;
261 d->serviceControlInterface = 0;
262 foreach( QEventLoop* loop, d->loops ) {
263 loop->exit();
268 void Nepomuk::ServiceController::slotServiceOwnerChanged( const QString& serviceName,
269 const QString& oldOwner,
270 const QString& newOwner )
272 if( !newOwner.isEmpty() && serviceName == dbusServiceName( name() ) ) {
273 createServiceControlInterface();
276 // an attached service was not started through ProcessControl. Thus, we cannot rely
277 // on its restart-on-crash feature and have to do it manually. Afterwards it is back
278 // to normals
279 else if( d->attached &&
280 oldOwner == dbusServiceName( name() ) ) {
281 kDebug() << "Attached service" << name() << "went down. Restarting ourselves.";
282 d->attached = false;
283 start();
288 void Nepomuk::ServiceController::createServiceControlInterface()
290 delete d->serviceControlInterface;
292 d->serviceControlInterface = new OrgKdeNepomukServiceControlInterface( dbusServiceName( name() ),
293 "/servicecontrol",
294 QDBusConnection::sessionBus(),
295 this );
296 connect( d->serviceControlInterface, SIGNAL( serviceInitialized( bool ) ),
297 this, SLOT( slotServiceInitialized( bool ) ) );
299 if ( d->serviceControlInterface->isInitialized() ) {
300 slotServiceInitialized( true );
305 void Nepomuk::ServiceController::slotServiceInitialized( bool success )
307 if ( !d->initialized ) {
308 if ( success ) {
309 kDebug() << "Service" << name() << "initialized";
310 d->initialized = true;
311 emit serviceInitialized( this );
313 if ( runOnce() ) {
314 // we have been run once. Do not autostart next time
315 KConfigGroup cg( Server::self()->config(), QString("Service-%1").arg(name()) );
316 cg.writeEntry( "autostart", false );
319 else {
320 d->failedToInitialize = true;
321 kDebug() << "Failed to initialize service" << name();
322 stop();
326 foreach( QEventLoop* loop, d->loops ) {
327 loop->exit();