Implement ReqVerificationState 55/140455/3
authorMu-Woong Lee <muwoong.lee@samsung.com>
Tue, 25 Jul 2017 05:18:35 +0000 (14:18 +0900)
committerMu-Woong Lee <muwoong.lee@samsung.com>
Tue, 25 Jul 2017 06:26:49 +0000 (15:26 +0900)
Change-Id: I05058aa4aad1e3122774381eb48daad39838bb0b
Signed-off-by: Mu-Woong Lee <muwoong.lee@samsung.com>
src/server/ActionState.cpp
src/server/ActionState.h
src/server/ContextPublisher.cpp
src/server/ContextPublisher.h
src/server/ReqVerificationState.cpp
src/server/ReqVerificationState.h
src/server/TriggerStandbyState.cpp

index 11667e697de59aa5bbbd556ce04816dd89bc6623..968f25afac85854d507b8f0f0b23ed76c6793cba 100644 (file)
@@ -18,7 +18,7 @@
 
 using namespace ctx;
 
-ActionState::ActionState(JobState* prevState) :
+ActionState::ActionState(JobState* prevState, bool timeout) :
        JobState(prevState)
 {
        _ENTER;
index d53ec2d7e7e52694273f9e10f9f393353a920a98..0d8240e86d06b1ce72f1038813916f8f03174115 100644 (file)
@@ -24,7 +24,7 @@ namespace ctx {
 
        class ActionState : public JobState {
        public:
-               ActionState(JobState* prevState);
+               ActionState(JobState* prevState, bool timeout);
                ~ActionState();
 
                bool execute();
index 6b142431ad74bf8506d931c3e38b31a464bd9ae3..a2a075cfcb41cec8557502a2d3436053621feec0 100644 (file)
@@ -85,6 +85,11 @@ bool ContextPublisher::isUserContext() const
        return false;
 }
 
+bool ContextPublisher::isReady()
+{
+       return !__data.isNull();
+}
+
 const Json::Value& ContextPublisher::getData()
 {
        return __data;
@@ -97,11 +102,6 @@ void ContextPublisher::notifyObservers()
        }
 }
 
-bool ContextPublisher::isReady()
-{
-       return !__data.isNull();
-}
-
 void ContextPublisher::clearData()
 {
        __data = Json::nullValue;
index ab40e1a5f30b42be54f9c8098b875d9b6266f373..27a1760bfa6ec163738a5f3336b29a65e4fa77dd 100644 (file)
@@ -47,6 +47,7 @@ namespace ctx {
                virtual bool isReadable() const;
                virtual bool isUserContext() const;
 
+               virtual bool isReady();
                virtual const Json::Value& getData();
 
                static void registerPublisher(const char* uri, ContextPublisher* (*creator)(uid_t));
@@ -59,7 +60,6 @@ namespace ctx {
                virtual void subscribe() = 0;
                virtual void unsubscribe() = 0;
 
-               virtual bool isReady();
                virtual void clearData();
 
                Json::Value __data;
index fccee1e1e75ae5db4b08cf37dfaf7232a2e712e8..dced5c51877728fbbd8acb2450354e92e3e961d6 100644 (file)
  * limitations under the License.
  */
 
+#include <algorithm>
+#include <JobContext.h>
+#include "ContextManager.h"
+#include "ContextPublisher.h"
+#include "JobRunner.h"
+#include "ActionState.h"
 #include "ReqVerificationState.h"
 
+#define MIN_TIMEOUT    20u
+
 using namespace ctx;
 
 ReqVerificationState::ReqVerificationState(JobState* prevState) :
@@ -27,15 +35,143 @@ ReqVerificationState::ReqVerificationState(JobState* prevState) :
 ReqVerificationState::~ReqVerificationState()
 {
        _EXIT;
+       __unsubscribe();
 }
 
 bool ReqVerificationState::execute()
 {
-       //TODO: Read the requirement contexts.
-       // If all satisfied, goto ActionState.
-       // If the RequirementTimeout == 0, goto restart the machine.
-       // Set the timeout.
-       // If the timeout expires, read the requirements again.
-       // If all mandatory satisfied, goto ActionState, restart otherwise.
+       if (!__subscribe())
+               return false;
+
+       unsigned int timeout = std::max(getJobInfo()->getRequirementTimeout(), MIN_TIMEOUT);
+
+       g_idle_add(__onStart, this);
+       g_timeout_add(timeout, __onTimeout, this);
+
+       return true;
+}
+
+void ReqVerificationState::contextDataReady(ContextPublisher* pubs, void* userData)
+{
+       for (auto it = __reqInfos.begin(); it != __reqInfos.end(); ++it) {
+               if ((*it).pubs != pubs)
+                       continue;
+
+               if (!(*((*it).req) <= pubs->getData()))
+                       continue;
+
+               pubs->removeObserver(this);
+               __reqInfos.erase(it);
+       }
+
+       if (__inspectAll())
+               transit(new ActionState(this, false));
+}
+
+bool ReqVerificationState::__subscribe()
+{
+       auto& reqs = getJobInfo()->getRequirements();
+
+       for (auto& req : reqs) {
+               ContextPublisher* pubs = ContextManager::getPublisher(req->getUri(), getUid());
+               IF_FAIL_RETURN(pubs, false);
+
+               pubs->addObserver(this, req);
+               __reqInfos.emplace_back(req, pubs);
+       }
+
+       return true;
+}
+
+void ReqVerificationState::__unsubscribe()
+{
+       for (auto& info : __reqInfos) {
+               info.pubs->removeObserver(this);
+       }
+
+       __reqInfos.clear();
+}
+
+void ReqVerificationState::__readLatest()
+{
+       __reqInfos.remove_if(
+                       [this](const ReqInfo& info)->bool {
+                               if (!info.pubs->isReady())
+                                       return false;
+                               if (!(*(info.req) <= info.pubs->getData()))
+                                       return false;
+                               info.pubs->removeObserver(this);
+                               return true;
+                       });
+}
+
+bool ReqVerificationState::__inspectAll()
+{
+       if (getJobInfo()->isDisjunction()) {
+               bool satisfied = __inspectDisjunction();
+               if (satisfied)
+                       __unsubscribe();
+               return satisfied;
+       }
+
+       return __reqInfos.empty();
+}
+
+bool ReqVerificationState::__inspectMandatory()
+{
+       if (getJobInfo()->isDisjunction())
+               return __inspectDisjunction();
+
+       for (auto& info : __reqInfos) {
+               if (!info.req->isOptional())
+                       return false;
+       }
+
        return true;
 }
+
+bool ReqVerificationState::__inspectDisjunction()
+{
+       unsigned int all = getJobInfo()->getRequirements().size();
+       unsigned int remaining = __reqInfos.size();
+       return remaining < all;
+}
+
+void ReqVerificationState::__onStart()
+{
+       __readLatest();
+
+       if (__inspectAll())
+               transit(new ActionState(this, false));
+}
+
+void ReqVerificationState::__onTimeout()
+{
+       if (__inspectMandatory()) {
+               __unsubscribe();
+               transit(new ActionState(this, true));
+               return;
+       }
+
+       _I("Not all mandatory requirements are satisfied");
+       __unsubscribe();
+       getJobRunner()->restart();
+}
+
+gboolean ReqVerificationState::__onStart(gpointer data)
+{
+       static_cast<ReqVerificationState*>(data)->__onStart();
+       return G_SOURCE_REMOVE;
+}
+
+gboolean ReqVerificationState::__onTimeout(gpointer data)
+{
+       static_cast<ReqVerificationState*>(data)->__onTimeout();
+       return G_SOURCE_REMOVE;
+}
+
+ReqVerificationState::ReqInfo::ReqInfo(JobRequirement* r, ContextPublisher* p) :
+       req(r),
+       pubs(p)
+{
+}
index 4919866593089ad6559b810edd070c71a0b25a38..7133147bbd340e4fd8f5271b05444266c53638bd 100644 (file)
 #ifndef __CONTEXT_JOB_SCHEDULER_REQ_VERIFICATION_STATE_H__
 #define __CONTEXT_JOB_SCHEDULER_REQ_VERIFICATION_STATE_H__
 
+#include <list>
 #include <WakeLock.h>
+#include "IContextObserver.h"
 #include "JobState.h"
 
 namespace ctx {
 
-       class ReqVerificationState : public JobState {
+       class ReqVerificationState : public JobState, public IContextObserver {
        public:
                ReqVerificationState(JobState* prevState);
                ~ReqVerificationState();
 
                bool execute();
+               void contextDataReady(ContextPublisher* pubs, void* userData);
 
        private:
+               bool __subscribe();
+               void __unsubscribe();
+               void __readLatest();
+
+               bool __inspectAll();
+               bool __inspectMandatory();
+
+               void __onStart();
+               void __onTimeout();
+
+               static gboolean __onStart(gpointer data);
+               static gboolean __onTimeout(gpointer data);
+
+               /* Legacy support */
+               bool __inspectDisjunction();
+
+               struct ReqInfo {
+                       JobRequirement* req;
+                       ContextPublisher* pubs;
+                       ReqInfo(JobRequirement* r, ContextPublisher* p);
+               };
+               std::list<ReqInfo> __reqInfos;
                WakeLock __wakeLock;
        };
 
index 288032de79eef9b8e63126d9948253416dd3c7b1..51919980f556b2159f1cb81c32917f7bcb050763 100644 (file)
@@ -43,8 +43,10 @@ void TriggerStandbyState::contextDataReady(ContextPublisher* pubs, void* userDat
 {
        JobTrigger* trigger = static_cast<JobTrigger*>(userData);
 
-       if (*trigger <= pubs->getData())
+       if (*trigger <= pubs->getData()) {
+               __unsubscribe();
                transit(new ReqVerificationState(this));
+       }
 }
 
 bool TriggerStandbyState::__subscribe()