NepomukDaemons
servicecontroller.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 "servicecontroller.h"
00020 #include "processcontrol.h"
00021 #include "servicecontrolinterface.h"
00022 #include "nepomukserver.h"
00023
00024 #include <QtCore/QEventLoop>
00025 #include <QtCore/QTimer>
00026
00027 #include <KStandardDirs>
00028 #include <KConfigGroup>
00029 #include <KDebug>
00030
00031
00032 namespace {
00033 QString dbusServiceName( const QString& serviceName ) {
00034 return QString("org.kde.nepomuk.services.%1").arg(serviceName);
00035 }
00036 }
00037
00038
00039 class Nepomuk::ServiceController::Private
00040 {
00041 public:
00042 Private()
00043 : processControl( 0 ),
00044 serviceControlInterface( 0 ),
00045 attached( false ),
00046 initialized( false ),
00047 failedToInitialize( false ) {
00048 }
00049
00050 KService::Ptr service;
00051 bool autostart;
00052 bool startOnDemand;
00053 bool runOnce;
00054
00055 ProcessControl* processControl;
00056 OrgKdeNepomukServiceControlInterface* serviceControlInterface;
00057
00058
00059
00060 bool attached;
00061
00062 bool initialized;
00063 bool failedToInitialize;
00064
00065
00066 QList<QEventLoop*> loops;
00067
00068 void init( KService::Ptr service );
00069 };
00070
00071
00072 void Nepomuk::ServiceController::Private::init( KService::Ptr s )
00073 {
00074 service = s;
00075 autostart = service->property( "X-KDE-Nepomuk-autostart", QVariant::Bool ).toBool();
00076 KConfigGroup cg( Server::self()->config(), QString("Service-%1").arg(service->desktopEntryName()) );
00077 autostart = cg.readEntry( "autostart", autostart );
00078
00079 QVariant p = service->property( "X-KDE-Nepomuk-start-on-demand", QVariant::Bool );
00080 startOnDemand = ( p.isValid() ? p.toBool() : false );
00081
00082 p = service->property( "X-KDE-Nepomuk-run-once", QVariant::Bool );
00083 runOnce = ( p.isValid() ? p.toBool() : false );
00084
00085 initialized = false;
00086 }
00087
00088
00089 Nepomuk::ServiceController::ServiceController( KService::Ptr service, QObject* parent )
00090 : QObject( parent ),
00091 d(new Private())
00092 {
00093 d->init( service );
00094 }
00095
00096
00097 Nepomuk::ServiceController::~ServiceController()
00098 {
00099 stop();
00100 delete d;
00101 }
00102
00103
00104 KService::Ptr Nepomuk::ServiceController::service() const
00105 {
00106 return d->service;
00107 }
00108
00109
00110 QString Nepomuk::ServiceController::name() const
00111 {
00112 return d->service->desktopEntryName();
00113 }
00114
00115
00116 QStringList Nepomuk::ServiceController::dependencies() const
00117 {
00118 QStringList deps = d->service->property( "X-KDE-Nepomuk-dependencies", QVariant::StringList ).toStringList();
00119 if ( deps.isEmpty() ) {
00120 deps.append( "nepomukstorage" );
00121 }
00122 deps.removeAll( name() );
00123 return deps;
00124 }
00125
00126
00127 void Nepomuk::ServiceController::setAutostart( bool enable )
00128 {
00129 KConfigGroup cg( Server::self()->config(), QString("Service-%1").arg(name()) );
00130 cg.writeEntry( "autostart", enable );
00131 }
00132
00133
00134 bool Nepomuk::ServiceController::autostart() const
00135 {
00136 return d->autostart;
00137 }
00138
00139
00140 bool Nepomuk::ServiceController::startOnDemand() const
00141 {
00142 return d->startOnDemand;
00143 }
00144
00145
00146 bool Nepomuk::ServiceController::runOnce() const
00147 {
00148 return d->runOnce;
00149 }
00150
00151
00152 bool Nepomuk::ServiceController::start()
00153 {
00154 if( isRunning() ) {
00155 return true;
00156 }
00157
00158 d->initialized = false;
00159 d->failedToInitialize = false;
00160
00161
00162
00163 if( QDBusConnection::sessionBus().interface()->isServiceRegistered( dbusServiceName( name() ) ) ) {
00164 kDebug() << "Attaching to already running service" << name();
00165 d->attached = true;
00166 createServiceControlInterface();
00167 return true;
00168 }
00169 else {
00170 kDebug(300002) << "Starting" << name();
00171
00172 if( !d->processControl ) {
00173 d->processControl = new ProcessControl( this );
00174 connect( d->processControl, SIGNAL( finished( bool ) ),
00175 this, SLOT( slotProcessFinished( bool ) ) );
00176 }
00177
00178 connect( QDBusConnection::sessionBus().interface(),
00179 SIGNAL( serviceOwnerChanged( const QString&, const QString&, const QString& ) ),
00180 this,
00181 SLOT( slotServiceOwnerChanged( const QString&, const QString&, const QString& ) ) );
00182
00183 d->processControl->setCrashPolicy( ProcessControl::RestartOnCrash );
00184 return d->processControl->start( KGlobal::dirs()->locate( "exe", "nepomukservicestub" ),
00185 QStringList() << name() );
00186 }
00187 }
00188
00189
00190 void Nepomuk::ServiceController::stop()
00191 {
00192 if( isRunning() ) {
00193 kDebug(300002) << "Stopping" << name();
00194
00195 d->attached = false;
00196
00197 if( d->processControl ) {
00198 d->processControl->setCrashPolicy( ProcessControl::StopOnCrash );
00199 }
00200
00201 if ( d->serviceControlInterface ||
00202 ( !QCoreApplication::closingDown() &&
00203 waitForInitialized( 2000 ) ) ) {
00204 d->serviceControlInterface->shutdown();
00205 }
00206
00207 if( d->processControl ) {
00208 d->processControl->stop();
00209 }
00210
00211
00212
00213 foreach( QEventLoop* loop, d->loops ) {
00214 loop->exit();
00215 }
00216 }
00217 }
00218
00219
00220 bool Nepomuk::ServiceController::isRunning() const
00221 {
00222 return( d->attached || ( d->processControl ? d->processControl->isRunning() : false ) );
00223 }
00224
00225
00226 bool Nepomuk::ServiceController::isInitialized() const
00227 {
00228 return d->initialized;
00229 }
00230
00231
00232 bool Nepomuk::ServiceController::waitForInitialized( int timeout )
00233 {
00234 if( !isRunning() ) {
00235 return false;
00236 }
00237
00238 if( !d->initialized && !d->failedToInitialize ) {
00239 QEventLoop loop;
00240 d->loops.append( &loop );
00241 if ( timeout > 0 ) {
00242 QTimer::singleShot( timeout, &loop, SLOT(quit()) );
00243 }
00244 QPointer<ServiceController> guard = this;
00245 loop.exec();
00246 if ( !guard.isNull() )
00247 d->loops.removeAll( &loop );
00248 }
00249
00250 return d->initialized;
00251 }
00252
00253
00254 void Nepomuk::ServiceController::slotProcessFinished( bool )
00255 {
00256 kDebug() << "Service" << name() << "went down";
00257 d->initialized = false;
00258 d->attached = false;
00259 disconnect( QDBusConnection::sessionBus().interface() );
00260 delete d->serviceControlInterface;
00261 d->serviceControlInterface = 0;
00262 foreach( QEventLoop* loop, d->loops ) {
00263 loop->exit();
00264 }
00265 }
00266
00267
00268 void Nepomuk::ServiceController::slotServiceOwnerChanged( const QString& serviceName,
00269 const QString& oldOwner,
00270 const QString& newOwner )
00271 {
00272 if( !newOwner.isEmpty() && serviceName == dbusServiceName( name() ) ) {
00273 createServiceControlInterface();
00274 }
00275
00276
00277
00278
00279 else if( d->attached &&
00280 oldOwner == dbusServiceName( name() ) ) {
00281 kDebug() << "Attached service" << name() << "went down. Restarting ourselves.";
00282 d->attached = false;
00283 start();
00284 }
00285 }
00286
00287
00288 void Nepomuk::ServiceController::createServiceControlInterface()
00289 {
00290 delete d->serviceControlInterface;
00291
00292 d->serviceControlInterface = new OrgKdeNepomukServiceControlInterface( dbusServiceName( name() ),
00293 "/servicecontrol",
00294 QDBusConnection::sessionBus(),
00295 this );
00296 connect( d->serviceControlInterface, SIGNAL( serviceInitialized( bool ) ),
00297 this, SLOT( slotServiceInitialized( bool ) ) );
00298
00299 if ( d->serviceControlInterface->isInitialized() ) {
00300 slotServiceInitialized( true );
00301 }
00302 }
00303
00304
00305 void Nepomuk::ServiceController::slotServiceInitialized( bool success )
00306 {
00307 if ( !d->initialized ) {
00308 if ( success ) {
00309 kDebug() << "Service" << name() << "initialized";
00310 d->initialized = true;
00311 emit serviceInitialized( this );
00312
00313 if ( runOnce() ) {
00314
00315 KConfigGroup cg( Server::self()->config(), QString("Service-%1").arg(name()) );
00316 cg.writeEntry( "autostart", false );
00317 }
00318 }
00319 else {
00320 d->failedToInitialize = true;
00321 kDebug() << "Failed to initialize service" << name();
00322 stop();
00323 }
00324 }
00325
00326 foreach( QEventLoop* loop, d->loops ) {
00327 loop->exit();
00328 }
00329 }