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

NepomukDaemons

servicecontroller.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 "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     // true if we attached to an already running instance instead of
00059     // starting our own (in that case processControl will be 0)
00060     bool attached;
00061 
00062     bool initialized;
00063     bool failedToInitialize;
00064 
00065     // list of loops waiting for the service to become initialized
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     // check if the service is already running, ie. has been started by someone else or by a crashed instance of the server
00162     // we cannot rely on the auto-restart feature of ProcessControl here. So we handle that completely in slotServiceOwnerChanged
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         // make sure all loops waiting for the service to initialize
00212         // are terminated.
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 /*clean*/ )
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     // an attached service was not started through ProcessControl. Thus, we cannot rely
00277     // on its restart-on-crash feature and have to do it manually. Afterwards it is back
00278     // to normals
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                 // we have been run once. Do not autostart next time
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 }

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.7
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