Implement JobInfoDatabase and integrate it with JobManager 63/137763/4
authorMu-Woong Lee <muwoong.lee@samsung.com>
Fri, 7 Jul 2017 10:57:56 +0000 (19:57 +0900)
committerMu-Woong Lee <muwoong.lee@samsung.com>
Mon, 10 Jul 2017 11:55:08 +0000 (20:55 +0900)
Change-Id: Ia10fbfb7baaa284f45af65d199b7bd48a7b0b344
Signed-off-by: Mu-Woong Lee <muwoong.lee@samsung.com>
13 files changed:
include/job_scheduler_internal.h
packaging/context-job-scheduler.spec
src/server/CMakeLists.txt
src/server/JobInfoDatabase.cpp [new file with mode: 0644]
src/server/JobInfoDatabase.h [new file with mode: 0644]
src/server/JobManager.cpp
src/server/JobManager.h
src/server/JobRunner.cpp
src/server/JobRunner.h
src/server/JobSchedulerService.cpp
src/server/MethodCallHandler.cpp
src/shared/JobInfo.cpp
src/shared/JobInfo.h

index 5dbba00..f2416b2 100644 (file)
@@ -200,7 +200,7 @@ int ctx_sched_job_destroy(ctx_sched_job_h job);
 
 /**
  * @brief      Adds a trigger context to a job.
- * @remarks    This function consumes the given @c trigger.
+ * @remarks    On success, this function consumes the given @c trigger.
  *                     Using the @c trigger after calling this function leads to undefined behavior.
  * @param[in]  job                     Job handle
  * @param[in]  trigger         Trigger context
@@ -210,7 +210,7 @@ int ctx_sched_job_add_trigger(ctx_sched_job_h job, ctx_sched_job_context_h trigg
 
 /**
  * @brief      Adds a requirement context to a job.
- * @remarks    This function consumes the given @c requirement.
+ * @remarks    On success, this function consumes the given @c requirement.
  *                     Using the @c requirement after calling this function leads to undefined behavior.
  * @param[in]  job                     Job handle
  * @param[in]  requirement     Requirement context
index 0459237..af27a11 100644 (file)
@@ -10,6 +10,7 @@ BuildRequires: cmake
 BuildRequires: pkgconfig(glib-2.0)
 BuildRequires: pkgconfig(gio-2.0)
 BuildRequires: pkgconfig(jsoncpp)
+BuildRequires: pkgconfig(sqlite3)
 BuildRequires: pkgconfig(dlog)
 BuildRequires: pkgconfig(bundle)
 BuildRequires: pkgconfig(capi-base-common)
index 6f94b74..9326172 100644 (file)
@@ -1,6 +1,6 @@
 SET(target "${PROJECT_NAME}-server-genuine")
 
-SET(DEPS "${DEPS} jsoncpp context-common-server")
+SET(DEPS "${DEPS} jsoncpp sqlite3 context-common-server")
 
 FILE(GLOB_RECURSE SRCS *.cpp ../shared/*.cpp)
 MESSAGE("Sources: ${SRCS}")
diff --git a/src/server/JobInfoDatabase.cpp b/src/server/JobInfoDatabase.cpp
new file mode 100644 (file)
index 0000000..c0de028
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sqlite3.h>
+#include <SharedUtil.h>
+#include <PlatformDatabase.h>
+#include "JobInfoDatabase.h"
+
+#define DB_NAME                        "context-job-scheduler"
+#define JOB_INFO_TABLE "PersistentJobInfo"
+#define ST_STARTED             "started"
+
+using namespace ctx;
+
+static Database* __database = NULL;
+static unsigned int __numDBConnection = 0;
+
+static void __initDatabase()
+{
+       const char* createJobInfoTable =
+               "CREATE TABLE IF NOT EXISTS " JOB_INFO_TABLE "(" \
+                       "uid INTEGER NOT NULL," \
+                       "jobId INTEGER NOT NULL," \
+                       "owner TEXT NOT NULL," \
+                       "jobInfo TEXT NOT NULL," \
+                       "state TEXT NOT NULL DEFAULT ''," \
+                       "PRIMARY KEY (uid, jobId)" \
+               ");";
+
+       __database->execute(createJobInfoTable, NULL);
+}
+
+static bool __open()
+{
+       if (__numDBConnection == 0) {
+               __database = new PlatformDatabase(DB_NAME);
+
+               if (!__database->open()) {
+                       delete __database;
+                       __database = NULL;
+                       _E("DB open failed");
+                       return false;
+               }
+
+               __initDatabase();
+       }
+
+       ++__numDBConnection;
+       return true;
+}
+
+static void __close()
+{
+       if (__numDBConnection == 1) {
+               delete __database;
+               __database = NULL;
+       }
+
+       if (__numDBConnection != 0)
+               --__numDBConnection;
+}
+
+JobInfoDatabase::JobInfoDatabase(uid_t uid) :
+       __uid(uid)
+{
+       if (!__open()) {
+               throw std::runtime_error("DB open failed");
+       }
+}
+
+JobInfoDatabase::~JobInfoDatabase()
+{
+       __close();
+}
+
+void JobInfoDatabase::add(JobInfo* jobInfo, const std::string& owner)
+{
+       char* query = sqlite3_mprintf(
+                       "INSERT INTO " JOB_INFO_TABLE " (uid, jobId, owner, jobInfo) VALUES (%d, %d, '%s', '%s')",
+                       static_cast<int>(__uid), jobInfo->getId(), owner.c_str(), jobInfo->serialize().c_str());
+
+       __database->execute(query, NULL);
+
+       sqlite3_free(query);
+}
+
+void JobInfoDatabase::remove(int jobId)
+{
+       char* query = sqlite3_mprintf(
+                       "DELETE FROM " JOB_INFO_TABLE " WHERE uid = %d AND jobId = %d",
+                       static_cast<int>(__uid), jobId);
+
+       __database->execute(query, NULL);
+
+       sqlite3_free(query);
+}
+
+void JobInfoDatabase::setStarted(int jobId, bool started)
+{
+       char* query = sqlite3_mprintf(
+                       "UPDATE " JOB_INFO_TABLE " SET state = '%s' WHERE uid = %d AND jobId = %d",
+                       started ? ST_STARTED : EMPTY_STR, static_cast<int>(__uid), jobId);
+
+       __database->execute(query, NULL);
+
+       sqlite3_free(query);
+}
+
+std::vector<std::pair<std::string, JobInfo*>> JobInfoDatabase::getAll()
+{
+       std::vector<std::pair<std::string, JobInfo*>> jobInfos;
+       std::vector<std::shared_ptr<Tuple>> queryResult;
+
+       std::string query =
+               "SELECT owner, jobInfo, state FROM " JOB_INFO_TABLE " WHERE uid = "
+               + std::to_string(__uid);
+
+       __database->execute(query, &queryResult);
+
+       for (auto& tuple : queryResult) {
+               const char* owner = NULL;
+               const char* jobInfoStr = NULL;
+               const char* state = NULL;
+
+               if (!tuple->getAt(0, &owner)) continue;
+               if (!tuple->getAt(1, &jobInfoStr)) continue;
+               if (!tuple->getAt(2, &state)) continue;
+
+               JobInfo* jobInfo = JobInfo::deserialize(jobInfoStr);
+               if (!jobInfo) continue;
+
+               jobInfo->setStarted(STR_EQ(state, ST_STARTED));
+
+               jobInfos.emplace_back(owner, jobInfo);
+       }
+
+       return jobInfos;
+}
diff --git a/src/server/JobInfoDatabase.h b/src/server/JobInfoDatabase.h
new file mode 100644 (file)
index 0000000..8900c0b
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONTEXT_JOB_SCHEDULER_JOB_INFO_DB_H__
+#define __CONTEXT_JOB_SCHEDULER_JOB_INFO_DB_H__
+
+#include <vector>
+#include <JobInfo.h>
+
+namespace ctx {
+
+       class JobInfoDatabase {
+       public:
+               JobInfoDatabase(uid_t uid);
+               ~JobInfoDatabase();
+
+               void add(JobInfo* jobInfo, const std::string& owner);
+               void remove(int jobId);
+               void setStarted(int jobId, bool started);
+               std::vector<std::pair<std::string, JobInfo*>> getAll();
+
+       private:
+               uid_t __uid;
+       };
+
+}
+
+#endif /* __CONTEXT_JOB_SCHEDULER_JOB_INFO_DB_H__ */
index 3ba3baa..958447b 100644 (file)
 
 using namespace ctx;
 
+static int __lastJobId = 0;
+
 JobManager::JobManager(uid_t uid) :
-       __uid(uid)
+       __uid(uid),
+       __jobInfoDatabase(uid)
 {
+       _I("Initialize JobManager-%u", static_cast<unsigned>(__uid));
+       __restore();
+       __dump();
 }
 
 JobManager::~JobManager()
 {
+       _I("Release JobManager-%u", static_cast<unsigned>(__uid));
+       __release();
 }
 
 bool JobManager::isSupported(JobContext::Type type, const std::string& uri)
 {
-       //TODO
+       //TODO: availability check
        return true;
 }
 
 int JobManager::addJob(JobInfo* jobInfo, IClient* owner)
 {
-       if (jobInfo->getType() == JobInfo::Type::PERIODIC)
-               return __addPeriodicJob(static_cast<PeriodicJobInfo*>(jobInfo), owner);
-       else if (jobInfo->getType() == JobInfo::Type::ON_DEMAND)
-               return __addOnDemandJob(static_cast<OnDemandJobInfo*>(jobInfo), owner);
+       IF_FAIL_RETURN(!owner->getName().empty(), E_ACCESS);
+
+       int jobId = 0;
+
+       //TODO: duplication test
+
+       if (jobInfo->getType() == JobInfo::Type::PERIODIC) {
+               jobId = __addPeriodicJob(static_cast<PeriodicJobInfo*>(jobInfo), owner);
+
+       } else if (jobInfo->getType() == JobInfo::Type::ON_DEMAND) {
+               jobId = __addOnDemandJob(static_cast<OnDemandJobInfo*>(jobInfo), owner);
+
+       } else {
+               return E_PARAM;
+       }
+
+       if (jobInfo->isPersistent())
+               __jobInfoDatabase.add(jobInfo, owner->getName());
 
-       return E_PARAM;
+       return jobId;
 }
 
 int JobManager::__addPeriodicJob(PeriodicJobInfo* jobInfo, IClient* owner)
 {
        __verifyPeriodicJob(jobInfo, owner);
 
-       const std::string& ownerId = owner->getName();
-       IF_FAIL_RETURN(!ownerId.empty(), E_ACCESS);
-
        jobInfo->setId(__generateJobId());
 
-       //TODO: insert to the DB, if it is a persistent job
-
-       JobRunner* runner = new JobRunner(jobInfo);
-       __jobRunners[ownerId].push_back(runner);
+       unsigned int cnt = __addRunner(new JobRunner(owner->getName(), jobInfo));
+       _D("%u jobs have been registered", cnt);
 
        return jobInfo->getId();
 }
@@ -67,79 +84,69 @@ int JobManager::__addOnDemandJob(OnDemandJobInfo* jobInfo, IClient* owner)
 {
        __verifyOnDemandJob(jobInfo, owner);
 
-       const std::string& ownerId = owner->getName();
-       IF_FAIL_RETURN(!ownerId.empty(), E_ACCESS);
-
        jobInfo->setId(__generateJobId());
 
-       //TODO: insert to the DB, if it is a persistent job
-
-       JobRunner* runner = new JobRunner(jobInfo);
-       __jobRunners[ownerId].push_back(runner);
+       unsigned int cnt = __addRunner(new JobRunner(owner->getName(), jobInfo));
+       _D("%u jobs have been registered", cnt);
 
        return jobInfo->getId();
 }
 
 int JobManager::startJob(int jobId, IClient* owner)
 {
-       JobRunner* jobRunner = __findJobRunner(owner->getName(), jobId);
+       JobRunner* jobRunner = __findRunner(owner->getName(), jobId);
        IF_FAIL_RETURN(jobRunner, E_PARAM);
 
-       if (jobRunner->getJobInfo()->isStarted()) {
-               _D("Job-%d of %s has started already", jobId, owner->getName());
+       if (jobRunner->isStarted()) {
+               _D("Job-%d of %s has started already", jobId, owner->getName().c_str());
                return E_RULE_ON;
        }
 
-       jobRunner->getJobInfo()->setStarted(true);
+       jobRunner->start();
 
-       //TODO
+       if (jobRunner->isPersistent())
+               __jobInfoDatabase.setStarted(jobId, true);
 
        return E_NONE;
 }
 
 int JobManager::stopJob(int jobId, IClient* owner)
 {
-       JobRunner* jobRunner = __findJobRunner(owner->getName(), jobId);
+       JobRunner* jobRunner = __findRunner(owner->getName(), jobId);
        IF_FAIL_RETURN(jobRunner, E_PARAM);
 
-       if (!jobRunner->getJobInfo()->isStarted()) {
-               _D("Job-%d of %s has stopped already", jobId, owner->getName());
+       if (!jobRunner->isStarted()) {
+               _D("Job-%d of %s has stopped already", jobId, owner->getName().c_str());
                return E_RULE_OFF;
        }
 
-       jobRunner->getJobInfo()->setStarted(false);
+       jobRunner->stop();
 
-       //TODO
+       if (jobRunner->isPersistent())
+               __jobInfoDatabase.setStarted(jobId, false);
 
        return E_NONE;
 }
 
 int JobManager::removeJob(int jobId, IClient* owner)
 {
-       IF_FAIL_RETURN(stopJob(jobId, owner) != E_PARAM, E_PARAM);
+       JobRunner* runner = __findRunner(owner->getName(), jobId);
+       IF_FAIL_RETURN_TAG(runner, E_PARAM, _W, "Not found");
 
-       auto& runners = __jobRunners[owner->getName()];
+       if (runner->isStarted())
+               runner->stop();
 
-       for (auto iter = runners.begin(); iter != runners.end(); ++iter) {
-               JobRunner* runner = *iter;
+       if (runner->isPersistent())
+               __jobInfoDatabase.remove(jobId);
 
-               if (runner->getJobInfo()->getId() != jobId)
-                       continue;
-
-               //TODO: delete from the DB
-
-               delete runner;
-               runners.erase(iter);
-
-               break;
-       }
+       __removeRunner(runner);
 
        return E_NONE;
 }
 
 JobInfo* JobManager::getJobInfo(int jobId, IClient* owner)
 {
-       JobRunner* jobRunner = __findJobRunner(owner->getName(), jobId);
+       JobRunner* jobRunner = __findRunner(owner->getName(), jobId);
        IF_FAIL_RETURN(jobRunner, NULL);
 
        return jobRunner->getJobInfo();
@@ -149,11 +156,10 @@ std::vector<JobInfo*> JobManager::getAllJobInfo(IClient* owner)
 {
        std::vector<JobInfo*> jobInfos;
 
-       auto runnerMapIterator = __jobRunners.find(owner->getName());
-       IF_FAIL_RETURN(runnerMapIterator != __jobRunners.end(), jobInfos);
-
-       for (auto& runner : runnerMapIterator->second) {
-               jobInfos.push_back(runner->getJobInfo());
+       for (auto& runner : __jobRunners) {
+               if (runner->getOwner() == owner->getName()) {
+                       jobInfos.push_back(runner->getJobInfo());
+               }
        }
 
        return jobInfos;
@@ -161,7 +167,7 @@ std::vector<JobInfo*> JobManager::getAllJobInfo(IClient* owner)
 
 bool JobManager::__isPermitted(IClient* client, const std::string& uri)
 {
-       //TODO
+       //TODO: permission check
        return true;
 }
 
@@ -250,28 +256,72 @@ void JobManager::__verifyAction(JobInfo* jobInfo, IClient* owner)
 
 int JobManager::__generateJobId()
 {
-       static int lastJobId = 0;
+       if (++__lastJobId < 0)
+               __lastJobId = 1;
 
-       if (lastJobId == 0) {
-               //TODO: get the last "persistent" job id
-       }
-
-       if (++lastJobId < 0)
-               lastJobId = 1;
+       return __lastJobId;
+}
 
-       return lastJobId;
+unsigned int JobManager::__addRunner(JobRunner* runner)
+{
+       __jobRunners.push_back(runner);
+       return __jobRunners.size();
 }
 
-JobRunner* JobManager::__findJobRunner(const std::string& ownerId, int jobId)
+bool JobManager::__removeRunner(JobRunner* runner)
 {
-       auto runnerMapIterator = __jobRunners.find(ownerId);
-       IF_FAIL_RETURN_TAG(runnerMapIterator != __jobRunners.end(), NULL, _I, "%s has no job", ownerId.c_str());
+       __jobRunners.remove(runner);
+       delete runner;
+       return true;
+}
 
-       for (auto& runner : runnerMapIterator->second) {
-               if (runner->getJobInfo()->getId() == jobId)
+JobRunner* JobManager::__findRunner(const std::string& ownerId, int jobId)
+{
+       for (auto& runner : __jobRunners) {
+               if (runner->getJobId() == jobId)
                        return runner;
        }
 
        _I("%s does not have the Job-%d", ownerId.c_str(), jobId);
        return NULL;
 }
+
+void JobManager::__restore()
+{
+       int maxJobId = 0;
+       auto storedJobs = __jobInfoDatabase.getAll();
+
+       _I("Restoring %u jobs", storedJobs.size());
+
+       for (auto& storedJob : storedJobs) {
+               const std::string& owner = storedJob.first;
+               JobInfo* jobInfo = storedJob.second;
+
+               maxJobId = MAX(maxJobId, jobInfo->getId());
+
+               JobRunner* runner = new JobRunner(owner, jobInfo);
+               if (jobInfo->isStarted())
+                       runner->start();
+
+               __addRunner(runner);
+       }
+
+       __lastJobId = maxJobId;
+}
+
+void JobManager::__release()
+{
+       for (auto& runner : __jobRunners) {
+               runner->stop();
+               delete runner;
+       }
+
+       __jobRunners.clear();
+}
+
+void JobManager::__dump()
+{
+       for (auto& runner : __jobRunners) {
+               _D("%s : %d", runner->getOwner().c_str(), runner->getJobId());
+       }
+}
index de649ae..acf9f38 100644 (file)
 #ifndef __CONTEXT_JOB_SCHEDULER_JOB_MANAGER_H__
 #define __CONTEXT_JOB_SCHEDULER_JOB_MANAGER_H__
 
-#include <vector>
-#include <map>
+#include <list>
 #include <JobInfo.h>
 #include <JobContext.h>
 #include <IClient.h>
+#include "JobInfoDatabase.h"
 
 namespace ctx {
 
@@ -55,10 +55,20 @@ namespace ctx {
                void __verifyAction(JobInfo* jobInfo, IClient* owner);
 
                int __generateJobId();
-               JobRunner* __findJobRunner(const std::string& ownerId, int jobId);
+
+               unsigned int __addRunner(JobRunner* runner);
+               bool __removeRunner(JobRunner* runner);
+               JobRunner* __findRunner(const std::string& ownerId, int jobId);
+               std::vector<JobRunner*> __findRunners(const std::string& ownerId);
+
+               void __restore();
+               void __release();
+               void __dump();
 
                uid_t __uid;
-               std::map<std::string, std::vector<JobRunner*>> __jobRunners;
+               std::list<JobRunner*> __jobRunners;
+
+               JobInfoDatabase __jobInfoDatabase;
        };
 
 }
index 7c48720..643b390 100644 (file)
 
 using namespace ctx;
 
-JobRunner::JobRunner(JobInfo* jobInfo) :
+JobRunner::JobRunner(const std::string& owner, JobInfo* jobInfo) :
+       __owner(owner),
        __jobInfo(jobInfo)
 {
 }
 
+const std::string& JobRunner::getOwner()
+{
+       return __owner;
+}
+
+int JobRunner::getJobId()
+{
+       return __jobInfo->getId();
+}
+
+bool JobRunner::isStarted()
+{
+       return __jobInfo->isStarted();
+}
+
+bool JobRunner::isPersistent()
+{
+       return __jobInfo->isPersistent();
+}
+
 JobInfo* JobRunner::getJobInfo()
 {
        return __jobInfo;
 }
+
+void JobRunner::start()
+{
+       __jobInfo->setStarted(true);
+}
+
+void JobRunner::stop()
+{
+       __jobInfo->setStarted(false);
+}
index b8b6059..b190d5a 100644 (file)
@@ -23,11 +23,20 @@ namespace ctx {
 
        class JobRunner {
        public:
-               JobRunner(JobInfo* jobInfo);
+               JobRunner(const std::string& owner, JobInfo* jobInfo);
+
+               const std::string& getOwner();
+               int getJobId();
+               bool isStarted();
+               bool isPersistent();
 
                JobInfo* getJobInfo();
 
+               void start();
+               void stop();
+
        private:
+               std::string __owner;
                JobInfo* __jobInfo;
        };
 
index a623dee..77bfea0 100644 (file)
  * limitations under the License.
  */
 
+#include <map>
+#include <ServerUtil.h>
 #include <JobSchedulerTypesPrivate.h>
 #include <JobSchedulerService.h>
 #include "JobManager.h"
 #include "MethodCallHandler.h"
 
+#define ROOT_UID       0
+
 using namespace ctx;
 
+static std::map<uid_t, JobManager*> __jobManagers;
+
 JobSchedulerService::JobSchedulerService() :
        __serviceRunner(NULL),
        __jobManager(NULL)
@@ -52,23 +58,39 @@ IMethodCallHandler* JobSchedulerService::createMethodCallHandler(IClient* client
 
 bool JobSchedulerService::prepare()
 {
+       __jobManagers.emplace(ROOT_UID, new JobManager(ROOT_UID));
        return true;
 }
 
 void JobSchedulerService::cleanup()
 {
+       for (auto& it : __jobManagers) {
+               delete it.second;
+       }
+       __jobManagers.clear();
 }
 
 void JobSchedulerService::onUserActivated(uid_t uid)
 {
+       __jobManagers.emplace(uid, new JobManager(uid));
 }
 
 void JobSchedulerService::onUserDeactivated(uid_t uid)
 {
+       auto it = __jobManagers.find(uid);
+       IF_FAIL_VOID_TAG(it != __jobManagers.end(), _W, "Unknown UID");
+
+       delete it->second;
+       __jobManagers.erase(it);
 }
 
 JobManager* JobSchedulerService::getJobManager(uid_t uid)
 {
-       // TODO
-       return NULL;
+       if (util::isSystem(uid))
+               uid = ROOT_UID;
+
+       auto it = __jobManagers.find(uid);
+       IF_FAIL_RETURN_TAG(it != __jobManagers.end(), NULL, _W, "Unknown UID");
+
+       return it->second;
 }
index 73b8a63..a45c689 100644 (file)
@@ -169,8 +169,6 @@ void MethodCallHandler::__getJob(IMethodCall& methodCall)
        IF_FAIL_THROW(jobInfo, static_cast<int>(E_PARAM));
 
        methodCall.reply(g_variant_new("(s)", jobInfo->serialize().c_str()));
-
-       delete jobInfo;
 }
 
 void MethodCallHandler::__getAllJob(IMethodCall& methodCall)
@@ -180,12 +178,13 @@ void MethodCallHandler::__getAllJob(IMethodCall& methodCall)
        std::vector<JobInfo*> jobInfos = __getJobManager().getAllJobInfo(__caller);
        IF_FAIL_THROW(!jobInfos.empty(), static_cast<int>(E_NO_DATA));
 
+       _D("%u jobs found", jobInfos.size());
+
        GVariantBuilder builder;
        g_variant_builder_init(&builder, G_VARIANT_TYPE("as"));
 
        for (auto& info : jobInfos) {
                g_variant_builder_add(&builder, "s", info->serialize().c_str());
-               delete info;
        }
 
        GVariant* jobInfoArr = g_variant_builder_end(&builder);
index 5ac127d..14bdfb9 100644 (file)
@@ -82,6 +82,12 @@ JobInfo::~JobInfo()
        delete __action;
 }
 
+bool JobInfo::operator==(const JobInfo& rhs)
+{
+       //TODO: compare two JobInfo, but ignore jobId & started flag
+       return false;
+}
+
 const std::string& JobInfo::getUserData()
 {
        return __userData;
@@ -99,6 +105,11 @@ JobInfo& JobInfo::setPersistent(bool persistent)
        return *this;
 }
 
+bool JobInfo::isPersistent()
+{
+       return __persistent;
+}
+
 JobInfo& JobInfo::setRequirementTimeout(unsigned int timeoutMs)
 {
        __requirementTimeout = timeoutMs;
@@ -241,7 +252,7 @@ PeriodicJobInfo::~PeriodicJobInfo()
 {
 }
 
-JobInfo::Type PeriodicJobInfo::getType()
+JobInfo::Type PeriodicJobInfo::getType() const
 {
        return JobInfo::Type::PERIODIC;
 }
@@ -271,7 +282,7 @@ OnDemandJobInfo::OnDemandJobInfo(Json::Value& jsonRoot, const std::string& seria
        }
 }
 
-JobInfo::Type OnDemandJobInfo::getType()
+JobInfo::Type OnDemandJobInfo::getType() const
 {
        return JobInfo::Type::ON_DEMAND;
 }
index bec3e82..6e8480c 100644 (file)
@@ -41,12 +41,15 @@ namespace ctx {
 
                virtual ~JobInfo();
 
-               virtual JobInfo::Type getType() = 0;
+               virtual JobInfo::Type getType() const = 0;
+
+               bool operator==(const JobInfo& rhs);
 
                const std::string& getUserData();
 
                JobInfo& setOneTime(bool oneTime);
                JobInfo& setPersistent(bool persistent);
+               bool isPersistent();
                JobInfo& setRequirementTimeout(unsigned int timeoutMs);
 
                // UserData should be a string that can be a string element of Json
@@ -101,7 +104,7 @@ namespace ctx {
 
                ~PeriodicJobInfo();
 
-               JobInfo::Type getType();
+               JobInfo::Type getType() const;
 
        private:
                void __toJson(Json::Value& jsonRoot);
@@ -118,7 +121,7 @@ namespace ctx {
 
                ~OnDemandJobInfo();
 
-               JobInfo::Type getType();
+               JobInfo::Type getType() const;
 
                OnDemandJobInfo& addTrigger(JobTrigger* trigger);
                std::list<JobTrigger*>& getTriggers();