]> Some of my projects - localmylist.git/commitdiff
Add Service and ServiceManager.
authorAPTX <marek321@gmail.com>
Sun, 22 Jun 2014 09:36:59 +0000 (11:36 +0200)
committerAPTX <marek321@gmail.com>
Sun, 22 Jun 2014 09:36:59 +0000 (11:36 +0200)
LML has 3 "services": RequestHandler, RenameHandler and DirectoryWatcher.
Now they have a common base class and a manager.

16 files changed:
anioni/anioni.cpp
localmylist/directorywatcher.cpp
localmylist/directorywatcher.h
localmylist/include/LocalMyList/Service [new file with mode: 0644]
localmylist/include/LocalMyList/ServiceManager [new file with mode: 0644]
localmylist/localmylist.pro
localmylist/mylist.cpp
localmylist/mylist.h
localmylist/renamehandler.cpp
localmylist/renamehandler.h
localmylist/requesthandler.cpp
localmylist/requesthandler.h
localmylist/service.cpp [new file with mode: 0644]
localmylist/service.h [new file with mode: 0644]
localmylist/servicemanager.cpp [new file with mode: 0644]
localmylist/servicemanager.h [new file with mode: 0644]

index 8e403bfbcdcfc48f341aec66ac4858d34f6dead2..48f345f65fef7735a44e3651850506e9e9f157cc 100644 (file)
@@ -2,6 +2,8 @@
 
 #include <LocalMyList/MyList>
 #include <LocalMyList/Settings>
+#include <LocalMyList/ServiceManager>
+#include <LocalMyList/Service>
 #include <LocalMyList/DirectoryWatcher>
 #ifndef LOCALMYLIST_NO_ANIDBUDPCLIENT
 #      include <LocalMyList/RequestHandler>
@@ -112,8 +114,7 @@ void AniOni::start()
                connect(AniDBUdpClient::Client::instance(), SIGNAL(connectionError()), this, SLOT(handleUdpClientError()));
 
                LocalMyList::instance()->setupRequestHandler();
-               LocalMyList::instance()->requestHandler()->handleRequests();
-               LocalMyList::instance()->requestHandler()->handleMyListUpdates();
+               LocalMyList::instance()->serviceManager()->processRequests("RequestHandler");
 #else
                log(QString("AniOni was configured to run the UDP client, but LocalMyList is not compiled with the UDP client."
                                        " Recompile LocalMyList with AniDBUdpClient"), QtServiceBase::Error);
@@ -130,12 +131,12 @@ void AniOni::start()
        if (watchDirectories)
        {
                LocalMyList::instance()->setupDirectoryWatcher();
-               LocalMyList::instance()->directoryWatcher()->checkWatchedDirectories();
+               LocalMyList::instance()->serviceManager()->processRequests("DirectoryWatcher");
        }
 
        if (!(runUdpClient || runRenameHandler || watchDirectories))
        {
-               log(QString("AniOni was configured to do nothing. Check settings"), QtServiceBase::Error);
+               log(QString("AniOni was configured to do nothing. Check settings."), QtServiceBase::Error);
                application()->exit(1);
                return;
        }
index 3418effe7e91849f123e89b690707a8dd500bd88..ff07ac79e3b906ad175deaedbae7425264d4615b 100644 (file)
 namespace LocalMyList {
 
 DirectoryWatcher::DirectoryWatcher(Database *db, Settings *settings, QObject *parent) :
-       QObject(parent)
+       Service("DirectoryWatcher", parent)
 {
        this->db = db;
        this->settings = settings;
-
-       watcher = new QFileSystemWatcher();
-       connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(watchedDirectoryChanged(QString)), Qt::QueuedConnection);
-
-       setWatchedDirectories();
+       watcher = 0;
 }
 
 DirectoryWatcher::~DirectoryWatcher()
@@ -87,4 +83,33 @@ void DirectoryWatcher::checkWatchedDirectories()
                watchedDirectoryChanged(dir);
 }
 
+void DirectoryWatcher::doInit()
+{
+       watcher = new QFileSystemWatcher();
+}
+
+void DirectoryWatcher::doDeInit()
+{
+       delete watcher;
+       watcher = 0;
+}
+
+bool DirectoryWatcher::doStart()
+{
+       connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(watchedDirectoryChanged(QString)), Qt::QueuedConnection);
+
+       setWatchedDirectories();
+       return true;
+}
+
+void LocalMyList::DirectoryWatcher::doStop()
+{
+       disconnect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(watchedDirectoryChanged(QString)));
+}
+
+void DirectoryWatcher::doProcessRequests()
+{
+       checkWatchedDirectories();
+}
+
 } // namespace LocalMyList
index fd2f3503c9ff27c60e6856871a237a4a23ee6795..d81f6296fde3169eb1e9944f06f702160d8b7304 100644 (file)
@@ -2,7 +2,7 @@
 #define DIRECTORYWATCHER_H
 
 #include "localmylist_global.h"
-#include <QObject>
+#include "service.h"
 #include <QMap>
 #include <QSet>
 
@@ -13,7 +13,7 @@ namespace LocalMyList {
 class Database;
 class Settings;
 
-class LOCALMYLISTSHARED_EXPORT DirectoryWatcher : public QObject
+class LOCALMYLISTSHARED_EXPORT DirectoryWatcher : public Service
 {
        Q_OBJECT
 public:
@@ -29,6 +29,13 @@ public slots:
 
        void checkWatchedDirectories();
 
+protected:
+       void doInit();
+       void doDeInit();
+       bool doStart();
+       void doStop();
+       void doProcessRequests();
+
 private:
        Database *db;
        Settings *settings;
diff --git a/localmylist/include/LocalMyList/Service b/localmylist/include/LocalMyList/Service
new file mode 100644 (file)
index 0000000..c1bedfb
--- /dev/null
@@ -0,0 +1,2 @@
+#include "../../service.h"
+
diff --git a/localmylist/include/LocalMyList/ServiceManager b/localmylist/include/LocalMyList/ServiceManager
new file mode 100644 (file)
index 0000000..54f91e5
--- /dev/null
@@ -0,0 +1,2 @@
+#include "../../servicemanager.h"
+
index 98e4063e141cef784c36c50fb83b3d6f5cb8b6d7..0d670827fd4d52aea172355b976ffe2656e0d5c9 100644 (file)
@@ -34,13 +34,15 @@ SOURCES += \
        filelocationchecktask.cpp \
        messagehandler.cpp \
        asyncquerytask.cpp \
+       service.cpp \
+       servicemanager.cpp \
        dynamicmodel/data.cpp \
        dynamicmodel/node.cpp \
        dynamicmodel/model.cpp \
        dynamicmodel/datatype.cpp \
        dynamicmodel/types.cpp \
        dynamicmodel/datamodel.cpp \
-    dynamicmodel/typerelation.cpp
+       dynamicmodel/typerelation.cpp
 
 HEADERS += \
        localmylist_global.h \
@@ -68,6 +70,8 @@ HEADERS += \
        asyncquerytask.h \
        filelocationchecktask.h \
        sqlresultiteratorinterface.h \
+       service.h \
+       servicemanager.h \
        dynamicmodel/data.h \
        dynamicmodel/node.h \
        dynamicmodel/model.h \
@@ -75,7 +79,7 @@ HEADERS += \
        dynamicmodel/dynamicmodel_global.h \
        dynamicmodel/types.h \
        dynamicmodel/datamodel.h \
-    dynamicmodel/typerelation.h
+       dynamicmodel/typerelation.h
 
 CONV_HEADERS += \
        include/LocalMyList/AbstractTask \
@@ -89,6 +93,8 @@ CONV_HEADERS += \
        include/LocalMyList/MyListExportParseTask \
        include/LocalMyList/MyListModel \
        include/LocalMyList/MyListNode \
+       include/LocalMyList/Service \
+       include/LocalMyList/ServiceManager \
        include/LocalMyList/Settings \
        include/LocalMyList/UnknownFileLookupTask \
        include/LocalMyList/UnknownFileLookupTask \
index 39cfc705053e3b0b9997e51dcd75e7a20b018c62..216314fdb42e399a9fe9458194ff5c0c42977258 100644 (file)
@@ -13,6 +13,8 @@
 #include "asyncquerytask.h"
 #include "workthread.h"
 #include "messagehandler.h"
+#include "servicemanager.h"
+#include "service.h"
 #ifndef LOCALMYLIST_NO_ANIDBUDPCLIENT
 #      include "requesthandler.h"
 #      include "renamehandler.h"
@@ -27,14 +29,12 @@ MyList::MyList()
 {
        init();
 
-       m_requestHandler = 0;
-       m_renameHandler = 0;
-       m_directoryWatcher = 0;
        workThread = 0;
        m_defaultLocalQSettings = new QSettings(QSettings::IniFormat, QSettings::UserScope, organizationName, libraryName, this);
        db = new Database();
        connect(db, SIGNAL(connected()), this, SLOT(setupHostInfo()));
        m_settings = new Settings(db, this);
+       m_serviceManager = new ServiceManager(this);
 
        m_udpClientId = 0;
 }
@@ -98,14 +98,9 @@ Settings *MyList::settings() const
        return m_settings;
 }
 
-RequestHandler *MyList::requestHandler() const
+ServiceManager *MyList::serviceManager() const
 {
-       return m_requestHandler;
-}
-
-DirectoryWatcher *MyList::directoryWatcher() const
-{
-       return m_directoryWatcher;
+       return m_serviceManager;
 }
 
 // -------
@@ -204,34 +199,38 @@ void MyList::setupUdpClient()
 void MyList::setupRequestHandler()
 {
 #ifndef LOCALMYLIST_NO_ANIDBUDPCLIENT
-       if (m_requestHandler || !db->isConnected() || !udpClientId())
+       if (m_serviceManager->hasService("RequestHandler") || !db->isConnected() || !udpClientId())
                return;
 
-       m_requestHandler = new RequestHandler(db, this);
-       connect(db, SIGNAL(newPendingRequest()), m_requestHandler, SLOT(handleRequests()));
-       connect(db, SIGNAL(newPendingMyListUpdate()), m_requestHandler, SLOT(handleMyListUpdates()));
+       Service *service = new RequestHandler(db, this);
+       m_serviceManager->addService(service);
+       service->start();
 #endif
 }
 
 void MyList::setupRenameHandler()
 {
 #ifndef LOCALMYLIST_NO_ANIDBUDPCLIENT
-       if (m_renameHandler || !db->isConnected())
+       if (m_serviceManager->hasService("RenameHandler") || !db->isConnected())
                return;
 
        setupWorkThread();
 
-       m_renameHandler = new RenameHandler(workThread->database(), workThread->settings());
-       m_renameHandler->moveToThread(workThread);
+       Service *service = new RenameHandler(workThread->database(), workThread->settings());
+       service->moveToThread(workThread);
+       m_serviceManager->addService(service);
+       service->start();
 #endif
 }
 
 void MyList::setupDirectoryWatcher()
 {
-       if (m_directoryWatcher || !db->isConnected())
+       if (m_serviceManager->hasService("DirectoryWatcher") || !db->isConnected())
                return;
 
-       m_directoryWatcher = new DirectoryWatcher(db, m_settings);
+       Service *service = new DirectoryWatcher(db, m_settings);
+       m_serviceManager->addService(service);
+       service->start();
 }
 
 void MyList::setupWorkThread()
index b744341c809677563b409eb5cb3d16c0458de83b..b53fe6fffb7916a4b0e7d6e162062ba9d631e7b1 100644 (file)
@@ -16,6 +16,7 @@ namespace LocalMyList {
 class Settings;
 class AbstractTask;
 class WorkThread;
+class ServiceManager;
 class RequestHandler;
 class RenameHandler;
 class DirectoryWatcher;
@@ -25,7 +26,7 @@ class LOCALMYLISTSHARED_EXPORT MyList : public QObject
        Q_OBJECT
        Q_PROPERTY(LocalMyList::Database *database READ database)
        Q_PROPERTY(LocalMyList::Settings *settings READ settings)
-       Q_PROPERTY(LocalMyList::RequestHandler *requestHandler READ requestHandler)
+       Q_PROPERTY(LocalMyList::ServiceManager *serviceManager READ serviceManager)
        Q_PROPERTY(QString hostName READ hostName WRITE setHostName)
        Q_PROPERTY(int hostId READ hostId)
        Q_PROPERTY(bool isUdpHost READ isUdpHost)
@@ -38,8 +39,7 @@ public:
 
        LocalMyList::Database *database() const;
        LocalMyList::Settings *settings() const;
-       LocalMyList::RequestHandler *requestHandler() const;
-       LocalMyList::DirectoryWatcher *directoryWatcher() const;
+       LocalMyList::ServiceManager *serviceManager() const;
 
        QString hostName() const;
        void setHostName(QString name);
@@ -95,9 +95,7 @@ private:
        DatabaseConnectionSettings dbs;
        Database *db;
        WorkThread *workThread;
-       RequestHandler *m_requestHandler;
-       RenameHandler *m_renameHandler;
-       DirectoryWatcher *m_directoryWatcher;
+       ServiceManager *m_serviceManager;
        Settings *m_settings;
 
        HostInfo hostInfo;
index f7bd721f17e5666575ca832a4d395aff5bd124fc..7cca5353af07a34c58c04565badb946617f21901 100644 (file)
 namespace LocalMyList {
 
 RenameHandler::RenameHandler(Database *db, Settings *settings, QObject *parent) :
-       QObject(parent), renameEngine(0), validScript(false)
+       Service("RenameHandler", parent), renameEngine(0), validScript(false)
 {
        this->db = db;
        this->settings = settings;
-       connect(db, SIGNAL(renameDataChanged()), this, SLOT(handleRename()), Qt::QueuedConnection);
-       connect(this, SIGNAL(renameBatchFinished()), this, SLOT(handleRename()), Qt::QueuedConnection);
-       connect(settings, SIGNAL(settingsChanged()), this, SLOT(clearSetup()));
-       connect(db, SIGNAL(reconnected()), this, SLOT(handleRename()), Qt::QueuedConnection);
        m_setup = false;
 }
 
@@ -33,12 +29,13 @@ void RenameHandler::handleRename()
 {
        RaiiTransaction t(db);
 
-       QSqlQuery &q = db->prepare(
-       "SELECT * "
-       "FROM rename_data "
-       "WHERE host_id = :host_id "
-       "AND renamed IS NULL AND failed_rename = false "
-       "LIMIT :limit");
+       QSqlQuery &q = db->prepare(R"(
+       SELECT *
+       FROM rename_data
+       WHERE host_id = :host_id
+       AND renamed IS NULL AND failed_rename = false
+       LIMIT :limit
+       )");
        q.bindValue(":host_id", MyList::instance()->hostId());
        q.bindValue(":limit", 1);
 
@@ -271,4 +268,26 @@ void RenameHandler::setupRenameEngine()
        m_setup = true;
 }
 
+bool RenameHandler::doStart()
+{
+       connect(db, SIGNAL(renameDataChanged()), this, SLOT(handleRename()), Qt::QueuedConnection);
+       connect(this, SIGNAL(renameBatchFinished()), this, SLOT(handleRename()), Qt::QueuedConnection);
+       connect(settings, SIGNAL(settingsChanged()), this, SLOT(clearSetup()));
+       connect(db, SIGNAL(reconnected()), this, SLOT(handleRename()), Qt::QueuedConnection);
+       return true;
+}
+
+void RenameHandler::doStop()
+{
+       disconnect(db, SIGNAL(renameDataChanged()), this, SLOT(handleRename()));
+       disconnect(this, SIGNAL(renameBatchFinished()), this, SLOT(handleRename()));
+       disconnect(settings, SIGNAL(settingsChanged()), this, SLOT(clearSetup()));
+       disconnect(db, SIGNAL(reconnected()), this, SLOT(handleRename()));
+}
+
+void RenameHandler::doProcessRequests()
+{
+       handleRename();
+}
+
 } // namespace LocalMyList
index c2411dd6aa324b50f191a7bf519c05a939499082..35d8769e6f5bf821d598bc5073dafec0daaab91e 100644 (file)
@@ -2,7 +2,7 @@
 #define RENAMEHANDLER_H
 
 #include "localmylist_global.h"
-#include <QObject>
+#include "service.h"
 
 namespace RenameParser {
        class RenameEngine;
@@ -13,12 +13,12 @@ namespace LocalMyList {
 class Database;
 class Settings;
 
-class RenameHandler : public QObject
+class RenameHandler : public Service
 {
        Q_OBJECT
 public:
        explicit RenameHandler(Database *db, Settings *settings, QObject *parent = 0);
-       
+
        bool isSetup();
 
 signals:
@@ -30,6 +30,11 @@ public slots:
        void clearSetup();
        void setupRenameEngine();
 
+protected:
+       bool doStart();
+       void doStop();
+       void doProcessRequests();
+
 private:
        Database *db;
        Settings *settings;
index 132768224f1aa98c6e142c9c32960efec1736b97..f5d8392cb950f2814abdbd2b321a976e1755b818 100644 (file)
 namespace LocalMyList {
 
 RequestHandler::RequestHandler(Database *db, QObject *parent) :
-       QObject(parent)
+       Service("RequestHandler", parent)
 {
        this->db = db;
-       connect(this, SIGNAL(batchFinished()), this, SLOT(handleRequests()), Qt::QueuedConnection);
-       connect(this, SIGNAL(myListUpdateBatchFinished()), this, SLOT(handleMyListUpdates()), Qt::QueuedConnection);
-       connect(db, SIGNAL(reconnected()), this, SLOT(handleRequests()), Qt::QueuedConnection);
-       connect(db, SIGNAL(reconnected()), this, SLOT(handleMyListUpdates()), Qt::QueuedConnection);
-
-       db->failPendingRequestsFromOldClients();
 }
 
 void RequestHandler::handleRequests()
@@ -213,6 +207,38 @@ void RequestHandler::handleMyListUpdates()
        emit myListUpdateBatchFinished();
 }
 
+bool RequestHandler::doStart()
+{
+       connect(this, SIGNAL(batchFinished()), this, SLOT(handleRequests()), Qt::QueuedConnection);
+       connect(this, SIGNAL(myListUpdateBatchFinished()), this, SLOT(handleMyListUpdates()), Qt::QueuedConnection);
+       connect(db, SIGNAL(reconnected()), this, SLOT(handleRequests()), Qt::QueuedConnection);
+       connect(db, SIGNAL(reconnected()), this, SLOT(handleMyListUpdates()), Qt::QueuedConnection);
+
+
+       connect(db, SIGNAL(newPendingRequest()), this, SLOT(handleRequests()));
+       connect(db, SIGNAL(newPendingMyListUpdate()), this, SLOT(handleMyListUpdates()));
+
+       db->failPendingRequestsFromOldClients();
+       return true;
+}
+
+void RequestHandler::doStop()
+{
+       disconnect(this, SIGNAL(batchFinished()), this, SLOT(handleRequests()));
+       disconnect(this, SIGNAL(myListUpdateBatchFinished()), this, SLOT(handleMyListUpdates()));
+       disconnect(db, SIGNAL(reconnected()), this, SLOT(handleRequests()));
+       disconnect(db, SIGNAL(reconnected()), this, SLOT(handleMyListUpdates()));
+
+       disconnect(db, SIGNAL(newPendingRequest()), this, SLOT(handleRequests()));
+       disconnect(db, SIGNAL(newPendingMyListUpdate()), this, SLOT(handleMyListUpdates()));
+}
+
+void RequestHandler::doProcessRequests()
+{
+       handleRequests();
+       handleMyListUpdates();
+}
+
 void RequestHandler::animeRequestComplete(bool success)
 {
        using namespace ::AniDBUdpClient;
index adb2e207c806f70921714c3dcc1a301545088795..dce243c998e20810960b2d4f1b4dc06bfab0d673 100644 (file)
@@ -2,6 +2,7 @@
 #define REQUESTHANDLER_H
 
 #include "localmylist_global.h"
+#include "service.h"
 #include <QObject>
 #include <QMetaType>
 #include <QMap>
@@ -19,7 +20,7 @@ namespace LocalMyList {
 
 class Database;
 
-class LOCALMYLISTSHARED_EXPORT RequestHandler : public QObject
+class LOCALMYLISTSHARED_EXPORT RequestHandler : public Service
 {
        Q_OBJECT
 public:
@@ -33,6 +34,11 @@ public slots:
        void handleRequests();
        void handleMyListUpdates();
 
+protected:
+       bool doStart();
+       void doStop();
+       void doProcessRequests();
+
 private slots:
        void animeRequestComplete(bool success);
        void episodeRequestComplete(bool success);
@@ -41,6 +47,7 @@ private slots:
        void myListAddReplyComplete(bool success);
        void myListEditReplyComplete(bool success);
        void myListUpdateVoteReplyComplete(bool success);
+
 private:
        Database *db;
 
diff --git a/localmylist/service.cpp b/localmylist/service.cpp
new file mode 100644 (file)
index 0000000..9934cc4
--- /dev/null
@@ -0,0 +1,98 @@
+#include "service.h"
+
+#include <QDebug>
+#include "mylist.h"
+
+namespace LocalMyList {
+
+Service::Service(const QString &name, QObject *parent) :
+       QObject{parent}, m_state{Stopped}, m_name{name}
+{
+}
+
+Service::~Service()
+{
+       stop();
+       deinitialize();
+}
+
+Service::ServiceState Service::state() const
+{
+       return m_state;
+}
+
+
+QString Service::name() const
+{
+       return m_name;
+}
+
+void Service::start()
+{
+       if (m_state == Running)
+               return;
+       if (m_state == Uninitialized)
+       {
+               initAndStart();
+               return;
+       }
+       if (m_state != Stopped || m_state != Error)
+               return;
+       tryStart();
+}
+
+void Service::stop()
+{
+       if (m_state != Running)
+               return;
+
+       qDebug() << "Stopping service" << name();
+       doStop();
+       setState(Stopped);
+}
+
+void Service::deinitialize()
+{
+       if (m_state != Stopped || m_state != Error)
+               return;
+       doDeInit();
+       setState(Uninitialized);
+}
+
+void Service::processRequests()
+{
+       if (m_state != Running)
+               return;
+
+       doProcessRequests();
+}
+
+void Service::setState(Service::ServiceState state)
+{
+       if (m_state == state)
+               return;
+       m_state = state;
+       emit stateChanged(state);
+}
+
+void Service::initAndStart()
+{
+       doInit();
+       setState(Stopped);
+       tryStart();
+}
+
+void Service::tryStart()
+{
+       qDebug() << "Starting service" << name();
+       if (doStart())
+       {
+               setState(Running);
+               return;
+       }
+       MyList::instance()->database()->log(QString("Service %1 failed to start!").arg(name()));
+       setState(Error);
+}
+
+
+} // namespace LocalMyList
diff --git a/localmylist/service.h b/localmylist/service.h
new file mode 100644 (file)
index 0000000..094968f
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef SERVICE_H
+#define SERVICE_H
+
+#include "localmylist_global.h"
+#include <QObject>
+
+namespace LocalMyList {
+
+class LOCALMYLISTSHARED_EXPORT Service : public QObject
+{
+       Q_OBJECT
+       Q_ENUMS(ServiceState)
+       Q_PROPERTY(ServiceState state READ state NOTIFY stateChanged)
+       Q_PROPERTY(QString name READ name)
+
+public:
+       ~Service();
+
+       enum ServiceState
+       {
+               Uninitialized, //<! Uninitialized
+               Stopped,       //<! Initialized
+               Running,       //<! Service is running
+               Error,         //<! Service failed to start
+               Invalid = -1,  //<! This value represents the state of an invalid/nonexistant service. A service can't be in this state.
+       };
+
+       ServiceState state() const;
+       QString name() const;
+
+public slots:
+       /*!
+        * \brief start Starts the service if it isn't started.
+        *
+        * Initializes if necessary.
+        * To check if the service started correctly connect to the stateChanged signal
+        */
+       void start();
+
+       //! Stops the service if it is running
+       void stop();
+
+       //! Stops the service if it is stopped
+       void deinitialize();
+
+       //! Forces the service to check for and process any requests.
+       void processRequests();
+
+signals:
+       void stateChanged(ServiceState state);
+
+protected:
+       Service(const QString &name, QObject *parent = 0);
+
+       /*!
+        * \brief initialize any resourcesneeded by the service
+        * Called only when needed. Do not call yourself.
+        */
+       virtual void doInit() {}
+       /*!
+        * \brief doDeInit cleanup any resources
+        * Called only when needed. Do not call yourself.
+        */
+       virtual void doDeInit() {}
+       virtual bool doStart() = 0;
+       virtual void doStop() = 0;
+
+       /*!
+        * \brief Check and process any pending requests
+        *  Called only when service is running.
+        */
+       virtual void doProcessRequests() {}
+
+private slots:
+       void initAndStart();
+
+private:
+       void setState(ServiceState state);
+       void tryStart();
+
+       ServiceState m_state;
+       QString m_name;
+};
+
+} // namespace LocalMyList
+
+#endif // SERVICE_H
diff --git a/localmylist/servicemanager.cpp b/localmylist/servicemanager.cpp
new file mode 100644 (file)
index 0000000..fa1a4df
--- /dev/null
@@ -0,0 +1,103 @@
+#include "servicemanager.h"
+
+#include "service.h"
+
+namespace LocalMyList {
+
+ServiceManager::ServiceManager(QObject *parent) :
+       QObject(parent)
+{
+       //      qRegisterMetaType
+}
+
+ServiceManager::~ServiceManager()
+{
+       for (Service *s : m_registeredServices)
+               callServiceSlot(s, SLOT(deleteLater()));
+}
+
+bool ServiceManager::addService(Service *service)
+{
+       if (m_registeredServices.contains(service->name()))
+               return false;
+
+       m_registeredServices.insert(service->name(), service);
+       connect(service, SIGNAL(stateChanged(Service::ServiceState)), this, SLOT(serviceStateChanged(Service::ServiceState)));
+       return true;
+}
+
+bool ServiceManager::hasService(const QString &serviceName) const
+{
+       return m_registeredServices.contains(serviceName);
+}
+
+void ServiceManager::start(const QString &serviceName)
+{
+       auto it = m_registeredServices.find(serviceName);
+       if (it == m_registeredServices.end())
+               return;
+
+       callServiceSlot(it.value(), "start");
+}
+
+void ServiceManager::startAll()
+{
+       for (Service *s : m_registeredServices)
+               callServiceSlot(s, "start");
+}
+
+void ServiceManager::stop(const QString &serviceName)
+{
+       auto it = m_registeredServices.find(serviceName);
+       if (it == m_registeredServices.end())
+               return;
+
+       callServiceSlot(it.value(), "stop");
+}
+
+void ServiceManager::stopAll()
+{
+       for (Service *s : m_registeredServices)
+               callServiceSlot(s, "stop");
+}
+
+void ServiceManager::processRequests(const QString &serviceName)
+{
+       auto it = m_registeredServices.find(serviceName);
+       if (it == m_registeredServices.end())
+               return;
+
+       callServiceSlot(it.value(), "processRequests");
+}
+
+void ServiceManager::processRequestsAll()
+{
+       for (Service *s : m_registeredServices)
+               callServiceSlot(s, "processRequests");
+}
+
+Service::ServiceState ServiceManager::state(const QString &serviceName)
+{
+       auto it = m_registeredServices.find(serviceName);
+       if (it == m_registeredServices.end())
+               return Service::Invalid;
+       return it.value()->state();
+}
+
+QList<QString> ServiceManager::registeredServices() const
+{
+       return m_registeredServices.keys();
+}
+
+void ServiceManager::serviceStateChanged(Service::ServiceState state)
+{
+       Q_ASSERT(qobject_cast<Service *>(sender()));
+       emit stateChanged(static_cast<Service *>(sender())->name(), state);
+}
+
+void ServiceManager::callServiceSlot(Service *s, const char *slot) const
+{
+       QMetaObject::invokeMethod(s, slot, Qt::AutoConnection);
+}
+
+} // namespace LocalMyList
diff --git a/localmylist/servicemanager.h b/localmylist/servicemanager.h
new file mode 100644 (file)
index 0000000..baafcce
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef SERVICEMANAGER_H
+#define SERVICEMANAGER_H
+
+#include "localmylist_global.h"
+#include <QObject>
+#include <QString>
+#include <QMap>
+
+#include "service.h"
+
+namespace LocalMyList {
+
+class LOCALMYLISTSHARED_EXPORT ServiceManager : public QObject
+{
+       Q_OBJECT
+
+public:
+       explicit ServiceManager(QObject *parent = 0);
+       ~ServiceManager();
+
+       /*!
+        * \brief addService Adds service to be managed by the ServiceMAnager.
+        * Takes ownershit of the passed service.
+        *
+        * \param service The service to add
+        * \return Returns true on success.
+        */
+       bool addService(Service *service);
+
+signals:
+       void stateChanged(const QString &serviceName, Service::ServiceState state);
+
+public slots:
+       void start(const QString &serviceName);
+       void startAll();
+       void stop(const QString &serviceName);
+       void stopAll();
+       void processRequests(const QString &serviceName);
+       void processRequestsAll();
+
+       Service::ServiceState state(const QString &serviceName);
+
+       bool hasService(const QString &serviceName) const;
+
+       /*!
+        * \brief registeredServices return the names of registered services.
+        * \return list of names of registered services.
+        */
+       QList<QString> registeredServices() const;
+
+private slots:
+       void serviceStateChanged(Service::ServiceState state);
+
+private:
+       void callServiceSlot(Service *s, const char *slot) const;
+       QMap<QString, Service*> m_registeredServices;
+};
+
+} // namespace LocalMyList
+
+#endif // SERVICEMANAGER_H