trigger: Implement rule info validators on ContextItem 28/142528/2
authorMu-Woong Lee <muwoong.lee@samsung.com>
Fri, 4 Aug 2017 07:10:15 +0000 (16:10 +0900)
committerMu-Woong Lee <muwoong.lee@samsung.com>
Mon, 7 Aug 2017 03:48:54 +0000 (03:48 +0000)
Change-Id: I50db18979590ee7053a7e887aed545792e792d81
Signed-off-by: Mu-Woong Lee <muwoong.lee@samsung.com>
src/trigger/ContextItem.cpp
src/trigger/ContextItem.h
src/trigger/context_trigger.cpp

index 9568cae..ee43604 100644 (file)
  */
 
 #include <map>
+#include <vector>
+#include <algorithm>
+#include <json/json.h>
+#include <SharedUtil.h>
+#include <job_scheduler_internal.h>
 #include <job_scheduler_types_internal.h>
 #include <context_trigger.h>
 #include "PrivilegeChecker.h"
 #include "ContextItem.h"
 
+#define CTX_SCHED_URI_ALARM                    CTX_SCHED_URI_PREFIX "event/time"
+#define CTX_SCHED_URI_CALL                     CTX_SCHED_URI_PREFIX "state/email"
+#define CTX_SCHED_URI_EMAIL                    CTX_SCHED_URI_PREFIX "event/email"
+#define CTX_SCHED_URI_MESSAGE          CTX_SCHED_URI_PREFIX "event/message"
+#define CTX_SCHED_URI_APP_FREQ         CTX_SCHED_URI_PREFIX "stats/app"
+#define CTX_SCHED_URI_COMM_FREQ                CTX_SCHED_URI_PREFIX "stats/comm"
+#define CTX_SCHED_URI_MUSIC_FREQ       CTX_SCHED_URI_PREFIX "stats/music"
+#define CTX_SCHED_URI_VIDEO_FREQ       CTX_SCHED_URI_PREFIX "stats/video"
+
 #define URI(x)      CTX_SCHED_URI_##x
 #define NAME(x)     CTX_SCHED_ATTR_NAME_##x
-#define VALUE(x)    CTX_SCHED_ATTR_VALUE_##x
 
 ContextItem::ContextItem(int cx) :
-       __context(cx)
+       __context(cx),
+       __uri(NULL)
 {
 }
 
@@ -36,26 +50,188 @@ bool ContextItem::allowed()
 
 bool ContextItem::isValid(ctx_sched_job_context_h jobContext)
 {
-       //TODO: Check if the context has all mandatory fields
+       IF_FAIL_RETURN(jobContext, false);
+
+       struct MandatoryEntry {
+               const char* uri;
+               std::vector<const char*> attributes;
+       };
+
+       static std::vector<MandatoryEntry> mandatories = {
+               { URI(ALARM),           {NAME(TIME_OF_DAY)} },
+               { URI(GEOFENCE),        {NAME(PLACE_ID)} },
+               { URI(APP_FREQ),        {CONTEXT_TRIGGER_APP_ID} }
+               //TODO
+       };
+
+       const char* serialized = ctx_sched_job_context_serialize(jobContext);
+       IF_FAIL_RETURN(serialized, false);
+
+       Json::Value jCtx;
+
+       try {
+               Json::Reader reader;
+               if (!reader.parse(serialized, jCtx)) {
+                       _E("Parsing failed");
+                       return false;
+               }
+       } catch (const Json::Exception& e) {
+               _E("Exception: %s", e.what());
+               return false;
+       }
+
+       IF_FAIL_RETURN(jCtx.isMember("Attribute"), false);
+
+       Json::Value& attributes = jCtx["Attribute"];
+
+       for (auto& entry : mandatories) {
+               if (!STR_EQ(entry.uri, getUri()))
+                       continue;
+
+               for (auto& mandatoryAttr : entry.attributes) {
+                       // The mandatory attribute should be exist
+                       if (!attributes.isMember(mandatoryAttr))
+                               return false;
+
+                       // If exist, at least one target value needs to be designated
+                       if (attributes[mandatoryAttr]["Target"].size() == 0)
+                               return false;
+               }
+
+               return true;
+       }
+
        return true;
 }
 
-bool ContextItem::isValid(const std::string& attribute)
+bool ContextItem::isValidData(const char* attribute)
 {
-       //TODO: Check if the attribute is valid for this __context
-       return true;
+       return (isValidData(attribute, 1) || isValidData(attribute, static_cast<const char*>(NULL)));
 }
 
-bool ContextItem::isValid(const std::string& attribute, int value)
+bool ContextItem::isValidData(const char* attribute, int value)
 {
-       //TODO: Check if the attribute & value pair is valid for this __context
-       return true;
+       static std::vector<IntAttributeRange> attributeRanges = {
+               { URI(ALARM),           NAME(TIME_OF_DAY),      0,      1439 },
+               { URI(TIME),            NAME(TIME_OF_DAY),      0,      1439 },
+               { URI(TIME),            NAME(DAY_OF_MONTH),     1,      31 },
+               { URI(BATTERY),         NAME(IS_CHARGING),      0,      1 },
+               { URI(CHARGER),         NAME(IS_CONNECTED),     0,      1 },
+               { URI(EARJACK),         NAME(IS_CONNECTED),     0,      1 },
+               { URI(USB),                     NAME(IS_CONNECTED),     0,      1 },
+               { URI(POWERSAVE),       NAME(IS_ENABLED),       0,      1 }
+               //TODO: unsupported items
+       };
+
+       _D("Verify %s, %d", attribute, value);
+
+       return __isValid(attributeRanges, attribute, value);
 }
 
-bool ContextItem::isValid(const std::string& attribute, const std::string& value)
+bool ContextItem::isValidData(const char* attribute, const char* value)
 {
-       //TODO: Check if the attribute & value pair is valid for this __context
-       return true;
+       static std::vector<StrAttributeValues> attributeValues = {
+               { URI(ALARM),           NAME(DAY_OF_WEEK),      {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Weekday", "Weekend"} },
+               { URI(TIME),            NAME(DAY_OF_WEEK),      {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Weekday", "Weekend"} },
+               { URI(BATTERY),         NAME(LEVEL),    {"Empty", "Critical", "Low", "Normal", "High", "Full"} },
+               { URI(GEOFENCE),        NAME(EVENT),    {"In", "Out"} },
+               { URI(GPS),                     NAME(STATE),    {"Disabled","Searching","Connected"} },
+               { URI(EARJACK),         NAME(TYPE),             {"Normal", "Headset", "Bluetooth"} },
+               { URI(WIFI),            NAME(STATE),    {"Disabled","Unconnected","Connected"} },
+               { URI(WIFI),            NAME(BSSID),    {} },
+               { URI(STATIONARY),      NAME(EVENT),    {"Detected"} },
+               { URI(WALKING),         NAME(EVENT),    {"Detected"} },
+               { URI(RUNNING),         NAME(EVENT),    {"Detected"} },
+               { URI(IN_VEHICLE),      NAME(EVENT),    {"Detected"} },
+               { URI(CONTACTS_DB),     NAME(EVENT),    {"Changed"} },
+               { URI(CONTACTS_DB),     NAME(TYPE),             {"MyProfile", "Person"} }
+               //TODO: unsupported items
+       };
+
+       _D("Verify %s, %s", attribute, value);
+
+       return __isValid(attributeValues, attribute, value);
+}
+
+bool ContextItem::isValidOption(const char* attribute)
+{
+       return (isValidOption(attribute, 1) || isValidOption(attribute, static_cast<const char*>(NULL)));
+}
+
+bool ContextItem::isValidOption(const char* attribute, int value)
+{
+       static std::vector<IntAttributeRange> attributeRanges = {
+               { URI(GEOFENCE),        NAME(PLACE_ID), 1,      INT_MAX }
+               //TODO: unsupported items
+       };
+
+       _D("Verify %s, %d", attribute, value);
+
+       return __isValid(attributeRanges, attribute, value);
+}
+
+bool ContextItem::isValidOption(const char* attribute, const char* value)
+{
+       static std::vector<StrAttributeValues> attributeValues = {
+               { URI(STATIONARY),      NAME(ACCURACY), {"Low", "Normal", "High"} },
+               { URI(WALKING),         NAME(ACCURACY), {"Low", "Normal", "High"} },
+               { URI(RUNNING),         NAME(ACCURACY), {"Low", "Normal", "High"} },
+               { URI(IN_VEHICLE),      NAME(ACCURACY), {"Low", "Normal", "High"} }
+               //TODO: unsupported items
+       };
+
+       _D("Verify %s, %s", attribute, value);
+
+       return __isValid(attributeValues, attribute, value);
+}
+
+bool ContextItem::__isValid(const std::vector<IntAttributeRange>& attributeRanges, const char* attribute, int value)
+{
+       for (auto& range : attributeRanges) {
+               if (!STR_EQ(range.uri, getUri()))
+                       continue;
+
+               if (!STR_EQ(range.attribute, attribute))
+                       continue;
+
+               if (value < range.min || value > range.max)
+                       return false;
+
+               return true;
+       }
+
+       return false;
+}
+
+bool ContextItem::__isValid(const std::vector<StrAttributeValues>& attributeValues, const char* attribute, const char* value)
+{
+       for (auto& values : attributeValues) {
+               if (!STR_EQ(values.uri, getUri()))
+                       continue;
+
+               if (!STR_EQ(values.attribute, attribute))
+                       continue;
+
+               // NULL value is a wildcard
+               if (!value)
+                       return true;
+
+               // Accept any strings
+               if (values.values.empty())
+                       return true;
+
+               auto it = std::find_if(values.values.begin(), values.values.end(),
+                               [&value](const char* validValue)->bool {
+                                       return STR_EQ(value, validValue);
+                               });
+
+               if (it == values.values.end())
+                       return false;
+
+               return true;
+       }
+
+       return false;
 }
 
 EventItem::EventItem(int event) :
@@ -80,7 +256,7 @@ bool EventItem::deprecated()
 const char* EventItem::getUri()
 {
        static const std::map<int, const char*> uriMap = {
-               {CONTEXT_TRIGGER_EVENT_TIME,      CTX_SCHED_URI_PREFIX "event/time"},
+               {CONTEXT_TRIGGER_EVENT_TIME,                            URI(ALARM)},
                {CONTEXT_TRIGGER_EVENT_BATTERY,             URI(BATTERY)},
                {CONTEXT_TRIGGER_EVENT_CHARGER,             URI(CHARGER)},
                {CONTEXT_TRIGGER_EVENT_GPS,                 URI(GPS)},
@@ -88,9 +264,9 @@ const char* EventItem::getUri()
                {CONTEXT_TRIGGER_EVENT_POWER_SAVING_MODE,   URI(POWERSAVE)},
                {CONTEXT_TRIGGER_EVENT_USB,                 URI(USB)},
                {CONTEXT_TRIGGER_EVENT_WIFI,                URI(WIFI)},
-               {CONTEXT_TRIGGER_EVENT_CALL,      CTX_SCHED_URI_PREFIX "state/call"},
-               {CONTEXT_TRIGGER_EVENT_EMAIL,     CTX_SCHED_URI_PREFIX "event/email"},
-               {CONTEXT_TRIGGER_EVENT_MESSAGE,   CTX_SCHED_URI_PREFIX "event/message"},
+               {CONTEXT_TRIGGER_EVENT_CALL,                            URI(CALL)},
+               {CONTEXT_TRIGGER_EVENT_EMAIL,                           URI(EMAIL)},
+               {CONTEXT_TRIGGER_EVENT_MESSAGE,                         URI(MESSAGE)},
                {CONTEXT_TRIGGER_EVENT_CONTACTS,            URI(CONTACTS_DB)},
                {CONTEXT_TRIGGER_EVENT_ACTIVITY_STATIONARY, URI(STATIONARY)},
                {CONTEXT_TRIGGER_EVENT_ACTIVITY_WALKING,    URI(WALKING)},
@@ -99,12 +275,14 @@ const char* EventItem::getUri()
                {CONTEXT_TRIGGER_EVENT_PLACE,               URI(GEOFENCE)}
        };
 
+       if (__uri) return __uri;
+
        auto it = uriMap.find(__context);
 
        if (it == uriMap.end())
                return NULL;
 
-       return it->second;
+       return (__uri = it->second);
 }
 
 const char* EventItem::__getPrivilege()
@@ -161,19 +339,21 @@ const char* ConditionItem::getUri()
                {CONTEXT_TRIGGER_CONDITION_POWER_SAVING_MODE, URI(POWERSAVE)},
                {CONTEXT_TRIGGER_CONDITION_USB,               URI(USB)},
                {CONTEXT_TRIGGER_CONDITION_WIFI,              URI(WIFI)},
-               {CONTEXT_TRIGGER_CONDITION_CALL,                     CTX_SCHED_URI_PREFIX "state/call"},
-               {CONTEXT_TRIGGER_CONDITION_APP_USE_FREQUENCY,        CTX_SCHED_URI_PREFIX "stats/app"},
-               {CONTEXT_TRIGGER_CONDITION_COMMUNICATION_FREQUENCY,  CTX_SCHED_URI_PREFIX "stats/comm"},
-               {CONTEXT_TRIGGER_CONDITION_MUSIC_PLAYBACK_FREQUENCY, CTX_SCHED_URI_PREFIX "stats/music"},
-               {CONTEXT_TRIGGER_CONDITION_VIDEO_PLAYBACK_FREQUENCY, CTX_SCHED_URI_PREFIX "stats/video"}
+               {CONTEXT_TRIGGER_CONDITION_CALL,                     URI(CALL)},
+               {CONTEXT_TRIGGER_CONDITION_APP_USE_FREQUENCY,        URI(APP_FREQ)},
+               {CONTEXT_TRIGGER_CONDITION_COMMUNICATION_FREQUENCY,  URI(COMM_FREQ)},
+               {CONTEXT_TRIGGER_CONDITION_MUSIC_PLAYBACK_FREQUENCY, URI(MUSIC_FREQ)},
+               {CONTEXT_TRIGGER_CONDITION_VIDEO_PLAYBACK_FREQUENCY, URI(VIDEO_FREQ)}
        };
 
+       if (__uri) return __uri;
+
        auto it = uriMap.find(__context);
 
        if (it == uriMap.end())
                return NULL;
 
-       return it->second;
+       return (__uri = it->second);
 }
 
 const char* ConditionItem::__getPrivilege()
index 088d6de..dd555b9 100644 (file)
@@ -29,18 +29,41 @@ public:
        virtual const char* getUri() = 0;
 
        bool allowed();
+
        bool isValid(ctx_sched_job_context_h jobContext);
-       bool isValid(const std::string& attribute);
-       bool isValid(const std::string& attribute, int value);
-       bool isValid(const std::string& attribute, const std::string& value);
+
+       bool isValidData(const char* attribute);
+       bool isValidData(const char* attribute, int value);
+       bool isValidData(const char* attribute, const char* value);
+
+       bool isValidOption(const char* attribute);
+       bool isValidOption(const char* attribute, int value);
+       bool isValidOption(const char*, const char* value);
 
 protected:
        ContextItem(int cx);
 
        int __context;
+       const char* __uri;
 
 private:
        virtual const char* __getPrivilege() = 0;
+
+       struct IntAttributeRange {
+               const char* uri;
+               const char* attribute;
+               int min;
+               int max;
+       };
+
+       struct StrAttributeValues {
+               const char* uri;
+               const char* attribute;
+               std::vector<const char*> values;
+       };
+
+       bool __isValid(const std::vector<IntAttributeRange>& attributeRanges, const char* attribute, int value);
+       bool __isValid(const std::vector<StrAttributeValues>& attributeValues, const char* attribute, const char* value);
 };
 
 
index 46d5298..eda8254 100644 (file)
@@ -710,7 +710,7 @@ EXPORT_API int context_trigger_rule_entry_add_option_int(context_trigger_rule_en
        ContextItem* contextItem = __get_context_item(entry);
        IF_FAIL_RETURN(contextItem, E_FAILED);
 
-       bool valid = contextItem->isValid(option_key, value);
+       bool valid = contextItem->isValidOption(option_key, value);
        delete contextItem;
        IF_FAIL_RETURN(valid, E_INV_RULE);
 
@@ -726,7 +726,7 @@ EXPORT_API int context_trigger_rule_entry_add_option_string(context_trigger_rule
        ContextItem* contextItem = __get_context_item(entry);
        IF_FAIL_RETURN(contextItem, E_FAILED);
 
-       bool valid = contextItem->isValid(option_key, value);
+       bool valid = contextItem->isValidOption(option_key, value);
        delete contextItem;
        IF_FAIL_RETURN(valid, E_INV_RULE);
 
@@ -741,7 +741,7 @@ EXPORT_API int context_trigger_rule_entry_add_option(context_trigger_rule_entry_
        IF_FAIL_RETURN(entry->category == CATEGORY_CONDITION, E_INV_RULE);
 
        ConditionItem contextItem(entry->type);
-       IF_FAIL_RETURN(contextItem.isValid(option_key), E_INV_RULE);
+       IF_FAIL_RETURN(contextItem.isValidOption(option_key), E_INV_RULE);
 
        ctx_sched_job_context_prepare_attribute_str(entry->jobContext, option_key);
        return ctx_sched_job_context_attribute_add_eq_str(entry->jobContext, option_key, event_data_key);
@@ -767,7 +767,7 @@ EXPORT_API int context_trigger_rule_entry_add_key(context_trigger_rule_entry_h e
        ContextItem* contextItem = __get_context_item(entry);
        IF_FAIL_RETURN(contextItem, E_FAILED);
 
-       bool valid = contextItem->isValid(key);
+       bool valid = contextItem->isValidData(key);
        delete contextItem;
        IF_FAIL_RETURN_TAG(valid, E_INV_RULE, _E, "Invalid parameter");
        IF_FAIL_RETURN(!__is_member_key(entry, key), E_INV_RULE);
@@ -787,7 +787,7 @@ EXPORT_API int context_trigger_rule_entry_add_comparison(context_trigger_rule_en
        IF_FAIL_RETURN(entry->category == CATEGORY_CONDITION, E_INV_RULE);
 
        ConditionItem contextItem(entry->type);
-       IF_FAIL_RETURN(contextItem.isValid(key), E_INV_RULE);
+       IF_FAIL_RETURN(contextItem.isValidData(key), E_INV_RULE);
        IF_FAIL_RETURN(__is_member_key(entry, key), E_NO_DATA);
 
        ctx_sched_job_context_prepare_attribute_str(entry->jobContext, key);
@@ -809,7 +809,7 @@ EXPORT_API int context_trigger_rule_entry_add_comparison_int(context_trigger_rul
        ContextItem* contextItem = __get_context_item(entry);
        IF_FAIL_RETURN(contextItem, E_FAILED);
 
-       bool valid = contextItem->isValid(key, value);
+       bool valid = contextItem->isValidData(key, value);
        delete contextItem;
        IF_FAIL_RETURN_TAG(valid, E_INV_RULE, _E, "Invalid parameter");
        IF_FAIL_RETURN(__is_member_key(entry, key), E_NO_DATA);
@@ -846,7 +846,7 @@ EXPORT_API int context_trigger_rule_entry_add_comparison_string(context_trigger_
        ContextItem* contextItem = __get_context_item(entry);
        IF_FAIL_RETURN(contextItem, E_FAILED);
 
-       bool valid = contextItem->isValid(key, value);
+       bool valid = contextItem->isValidData(key, value);
        delete contextItem;
        IF_FAIL_RETURN_TAG(valid, E_INV_RULE, _E, "Invalid parameter");
        IF_FAIL_RETURN(__is_member_key(entry, key), E_NO_DATA);