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>
33 QString
dbusServiceName( const QString
& serviceName
) {
34 return QString("org.kde.nepomuk.services.%1").arg(serviceName
);
39 class Nepomuk::ServiceController::Private
43 : processControl( 0 ),
44 serviceControlInterface( 0 ),
47 failedToInitialize( false ) {
50 KService::Ptr service
;
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)
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
)
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 );
89 Nepomuk::ServiceController::ServiceController( KService::Ptr service
, QObject
* parent
)
97 Nepomuk::ServiceController::~ServiceController()
104 KService::Ptr
Nepomuk::ServiceController::service() const
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() );
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
140 bool Nepomuk::ServiceController::startOnDemand() const
142 return d
->startOnDemand
;
146 bool Nepomuk::ServiceController::runOnce() const
152 bool Nepomuk::ServiceController::start()
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();
166 createServiceControlInterface();
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
& ) ),
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()
193 kDebug(300002) << "Stopping" << name();
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
213 foreach( QEventLoop
* loop
, d
->loops
) {
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
)
238 if( !d
->initialized
&& !d
->failedToInitialize
) {
240 d
->loops
.append( &loop
);
242 QTimer::singleShot( timeout
, &loop
, SLOT(quit()) );
244 QPointer
<ServiceController
> guard
= this;
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;
259 disconnect( QDBusConnection::sessionBus().interface() );
260 delete d
->serviceControlInterface
;
261 d
->serviceControlInterface
= 0;
262 foreach( QEventLoop
* loop
, d
->loops
) {
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
279 else if( d
->attached
&&
280 oldOwner
== dbusServiceName( name() ) ) {
281 kDebug() << "Attached service" << name() << "went down. Restarting ourselves.";
288 void Nepomuk::ServiceController::createServiceControlInterface()
290 delete d
->serviceControlInterface
;
292 d
->serviceControlInterface
= new OrgKdeNepomukServiceControlInterface( dbusServiceName( name() ),
294 QDBusConnection::sessionBus(),
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
) {
309 kDebug() << "Service" << name() << "initialized";
310 d
->initialized
= true;
311 emit
serviceInitialized( this );
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 );
320 d
->failedToInitialize
= true;
321 kDebug() << "Failed to initialize service" << name();
326 foreach( QEventLoop
* loop
, d
->loops
) {