From: Mu-Woong Lee Date: Fri, 4 Aug 2017 07:10:15 +0000 (+0900) Subject: trigger: Implement rule info validators on ContextItem X-Git-Tag: submit/tizen/20170926.083539^2~11 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=fdd9af2d32a320b241a3e12affe794540ccf680a;p=platform%2Fcore%2Fapi%2Fcontext.git trigger: Implement rule info validators on ContextItem Change-Id: I50db18979590ee7053a7e887aed545792e792d81 Signed-off-by: Mu-Woong Lee --- diff --git a/src/trigger/ContextItem.cpp b/src/trigger/ContextItem.cpp index 9568cae..ee43604 100644 --- a/src/trigger/ContextItem.cpp +++ b/src/trigger/ContextItem.cpp @@ -15,17 +15,31 @@ */ #include +#include +#include +#include +#include +#include #include #include #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 attributes; + }; + + static std::vector 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(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 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 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(NULL))); +} + +bool ContextItem::isValidOption(const char* attribute, int value) +{ + static std::vector 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 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& 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& 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 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() diff --git a/src/trigger/ContextItem.h b/src/trigger/ContextItem.h index 088d6de..dd555b9 100644 --- a/src/trigger/ContextItem.h +++ b/src/trigger/ContextItem.h @@ -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 values; + }; + + bool __isValid(const std::vector& attributeRanges, const char* attribute, int value); + bool __isValid(const std::vector& attributeValues, const char* attribute, const char* value); }; diff --git a/src/trigger/context_trigger.cpp b/src/trigger/context_trigger.cpp index 46d5298..eda8254 100644 --- a/src/trigger/context_trigger.cpp +++ b/src/trigger/context_trigger.cpp @@ -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);