[trigger] Added template verification 41/146041/2
authorSomin Kim <somin926.kim@samsung.com>
Thu, 24 Aug 2017 14:49:51 +0000 (23:49 +0900)
committerSomin Kim <somin926.kim@samsung.com>
Fri, 25 Aug 2017 05:34:41 +0000 (05:34 +0000)
Change-Id: Ic05ef1139013282251debd761469ee3613f665e1
Signed-off-by: Somin Kim <somin926.kim@samsung.com>
src/trigger/CustomTemplate.cpp
src/trigger/CustomTemplate.h
src/trigger/context_trigger.cpp

index 780a86e..4741fb5 100644 (file)
  */
 
 #include <regex>
+#include <context_trigger.h>
 #include "CustomTemplate.h"
 
+#define CT_KEY_MIN "minimum"
+#define CT_KEY_MAX "maximum"
+#define CT_KEY_TYPE "type"
+#define CT_TYPE_INTEGER "integer"
+#define CT_TYPE_STRING "string"
+#define CT_TYPE_ENUM "enum"
+#define CT_TYPE_DOUBLE "double"
+
 static std::list<CustomTemplate> __instances;
 
 CustomTemplate::CustomTemplate(const std::string& name, const Json::Value& templateJson) :
@@ -30,35 +39,192 @@ const std::string& CustomTemplate::getName() const
        return __name;
 }
 
-bool CustomTemplate::match(const std::string& fact)
+int CustomTemplate::match(const std::string& fact)
+{
+       // true if the given fact is valid w.r.t. the template
+       Json::Reader reader;
+       Json::Value factJson;
+
+       // Error: Invalid Json
+       if (!reader.parse(fact, factJson)) {
+               _E("Fact: invalid json");
+               return CONTEXT_TRIGGER_ERROR_INVALID_PARAMETER;
+       }
+
+       // Error: Invalid fact
+       IF_FAIL_RETURN_TAG(isValidFact(__templateJson, factJson), CONTEXT_TRIGGER_ERROR_INVALID_DATA, _E, "Invalid fact");
+
+       return CONTEXT_TRIGGER_ERROR_NONE;
+}
+
+bool CustomTemplate::isValidFact(const Json::Value& tmplJson, const Json::Value& factJson)
+{
+       Json::Value::Members keys = factJson.getMemberNames();
+
+       std::string dataType;
+       for (auto& key : keys) {
+               // Get type
+               if (tmplJson[key].isMember(CT_TYPE_ENUM)) {
+                       dataType = CT_TYPE_ENUM;
+               } else if (tmplJson[key].isMember(CT_KEY_TYPE)) {
+                       dataType = tmplJson[key][CT_KEY_TYPE].asString();
+               }
+
+               if (dataType == CT_TYPE_INTEGER) {
+                       IF_FAIL_RETURN_TAG(factJson[key].isInt(), false, _E, "Custom fact: Invalid data type");
+
+                       int val = factJson[key].asInt();
+                       if (tmplJson[key].isMember(CT_KEY_MIN)) {
+                               IF_FAIL_RETURN_TAG(val >= tmplJson[key][CT_KEY_MIN].asInt(), false, _E, "Custom fact: Invalid value");
+                       }
+                       if (tmplJson[key].isMember(CT_KEY_MAX)) {
+                               IF_FAIL_RETURN_TAG(val <= tmplJson[key][CT_KEY_MAX].asInt(), false, _E, "Custom fact: Invalid value");
+                       }
+               } else if (dataType == CT_TYPE_STRING) {
+                       IF_FAIL_RETURN_TAG(factJson[key].isString(), false, _E, "Custom fact: Invalid data type");
+               } else if (dataType == CT_TYPE_ENUM) {
+                       IF_FAIL_RETURN_TAG(factJson[key].isString(), false, _E, "Custom fact: Invalid data type");
+
+                       std::string val = factJson[key].asString();
+
+                       bool found = false;
+                       Json::Value::Members tmplValues;
+                       for (auto& tmplValue : tmplValues) {
+                               if (tmplValue == val)
+                                       found = true;
+                       }
+
+                       IF_FAIL_RETURN_TAG(found, false, _E, "Custom fact: Invalid value");
+               } else {
+                       _E("Custom fact: Invalid data type");
+                       return false;
+               }
+       }
+       return true;
+}
+
+bool CustomTemplate::isValidTemplate(const Json::Value& tmplJson)
 {
-       //TODO: true if the given fact is valid w.r.t. the template
+       bool success = false;
+       Json::Value::Members keys = tmplJson.getMemberNames();
+
+       std::string dataType;
+       for (auto& key : keys) {
+               // Get type
+               if (tmplJson[key].isMember(CT_TYPE_ENUM)) {
+                       success = tmplJson[key][CT_TYPE_ENUM].isArray();
+                       IF_FAIL_RETURN_TAG(success, false, _E, "Invalid template");
+                       dataType = CT_TYPE_ENUM;
+               } else if (tmplJson[key].isMember(CT_KEY_TYPE)) {
+                       dataType = tmplJson[key][CT_KEY_TYPE].asString();
+                       IF_FAIL_RETURN_TAG(dataType == CT_TYPE_INTEGER || dataType == CT_TYPE_STRING,
+                               false, _E, "Invalid template");
+               }
+
+               if (dataType == CT_TYPE_INTEGER) {
+                       success = checkTemplateInt(tmplJson[key]);
+                       IF_FAIL_RETURN(success, false);
+               } else if (dataType == CT_TYPE_STRING) {
+                       success = checkTemplateString(tmplJson[key]);
+                       IF_FAIL_RETURN(success, false);
+               } else if (dataType == CT_TYPE_ENUM) {
+                       success = checkTemplateEnum(tmplJson[key]);
+                       IF_FAIL_RETURN(success, false);
+               }
+       }
+
        return true;
 }
 
-bool CustomTemplate::add(const std::string& name, const std::string& attrTmpl)
+bool CustomTemplate::checkTemplateInt(const Json::Value& elem)
 {
-       IF_FAIL_RETURN(!get(name), false);
+       bool min = false;
+       bool max = false;
+       int minVal = 0;
+       int maxVal = 0;
+
+       Json::Value::Members elemKeys = elem.getMemberNames();
 
+       for (auto& elemKey : elemKeys) {
+               if (elemKey == CT_KEY_MIN) {
+                       min = true;
+                       minVal = elem[elemKey].asInt();
+               } else if (elemKey == CT_KEY_MAX) {
+                       max = true;
+                       maxVal = elem[elemKey].asInt();
+               } else {
+                       IF_FAIL_RETURN_TAG(elemKey == CT_KEY_TYPE, false, _E, "invalid key");
+               }
+       }
+
+       if (min && max) {
+               IF_FAIL_RETURN_TAG(minVal <= maxVal, false, _E, "Invalid min, max value");
+       }
+
+       return true;
+}
+
+bool CustomTemplate::checkTemplateString(const Json::Value& elem)
+{
+       Json::Value::Members elemKeys = elem.getMemberNames();
+
+       for (auto& elemKey : elemKeys) {
+               IF_FAIL_RETURN_TAG(elemKey == CT_KEY_TYPE, false, _E, "invalid key");
+       }
+
+       return true;
+}
+
+bool CustomTemplate::checkTemplateEnum(const Json::Value& elem)
+{
+       Json::Value::Members elemKeys = elem.getMemberNames();
+
+       for (auto& elemKey : elemKeys) {
+               if (elemKey == CT_TYPE_ENUM) {
+                       IF_FAIL_RETURN_TAG(!elem[CT_TYPE_ENUM].empty(), false, _E, "Invalid enum");
+
+                       for (unsigned int i = 0; i < elem[CT_TYPE_ENUM].size(); i++) {
+                               IF_FAIL_RETURN_TAG(elem[CT_TYPE_ENUM][i].isString(), false, _E, "Enum value sholud be string");
+                       }
+               } else {
+                       IF_FAIL_RETURN_TAG(elemKey == CT_KEY_TYPE, false, _E, "invalid key");
+               }
+       }
+
+       return true;
+}
+
+int CustomTemplate::add(const std::string& name, const std::string& attrTmpl)
+{
        static std::regex nameRegex(R"~(^[\w-\._\/]+$)~", std::regex::optimize);
-       IF_FAIL_RETURN_TAG(std::regex_match(name, nameRegex), false, _E, "Invalid name");
+       IF_FAIL_RETURN_TAG(std::regex_match(name, nameRegex), CONTEXT_TRIGGER_ERROR_INVALID_PARAMETER, _E, "Invalid name");
 
        Json::Reader reader;
        Json::Value tmplJson;
 
-       try {
-               reader.parse(attrTmpl, tmplJson);
-       } catch (const Json::Exception& e) {
-               _E("Exception: %s", e.what());
-               return false;
+       // Error: Invalid Json
+       if (!reader.parse(attrTmpl, tmplJson)) {
+               _E("Template: invalid json");
+               return CONTEXT_TRIGGER_ERROR_INVALID_PARAMETER;
        }
 
-       //TODO: further validity check of the template
-       // Does it contain all necessary fields, ...?
+       // Error: already exist
+       CustomTemplate* tmpl = get(name);
+       if (tmpl) {
+               if (tmplJson == tmpl->__templateJson)
+                       return CONTEXT_TRIGGER_ERROR_NONE;
+               else {
+                       _E("Template already exists");
+                       return CONTEXT_TRIGGER_ERROR_DATA_EXIST;
+               }
+       }
+
+       // Error: Invalid template
+       IF_FAIL_RETURN_TAG(isValidTemplate(tmplJson), CONTEXT_TRIGGER_ERROR_INVALID_DATA, _E, "Invalid template");
 
        __instances.emplace_back(name, tmplJson);
 
-       return true;
+       return CONTEXT_TRIGGER_ERROR_NONE;
 }
 
 void CustomTemplate::remove(const std::string& name)
index 751202d..2bbf579 100644 (file)
@@ -27,12 +27,19 @@ public:
        CustomTemplate(const std::string& name, const Json::Value& templateJson);
 
        const std::string& getName() const;
-       bool match(const std::string& fact);
+       int match(const std::string& fact);
 
-       static bool add(const std::string& name, const std::string& attrTmpl);
+       static int add(const std::string& name, const std::string& attrTmpl);
        static void remove(const std::string& name);
        static CustomTemplate* get(const std::string& name);
 
+       static bool isValidTemplate(const Json::Value& tmplJson);
+       static bool checkTemplateInt(const Json::Value& elem);
+       static bool checkTemplateString(const Json::Value& elem);
+       static bool checkTemplateEnum(const Json::Value& elem);
+       static bool isValidFact(const Json::Value& tmplJson, const Json::Value& factJson);
+
+
 private:
        std::string __name;
        Json::Value __templateJson;
index 0a869af..730bbac 100644 (file)
@@ -905,11 +905,8 @@ EXPORT_API int context_trigger_custom_register(const char* name, const char* att
        INIT_SCHED;
        ASSERT_NOT_NULL(name && attr_template);
 
-       //TODO: Is it allowed to overwrite a template?
-       CustomTemplate::remove(name);
-
-       bool success = CustomTemplate::add(name, attr_template);
-       IF_FAIL_RETURN_TAG(success, CONTEXT_TRIGGER_ERROR_INVALID_DATA, _E, "Invalid template");
+       int error = CustomTemplate::add(name, attr_template);
+       IF_FAIL_RETURN_TAG(error == E_NONE, error, _E, "Failed to add template");
 
        const char* pkgId = __get_pkg_id();
        IF_FAIL_RETURN_TAG(pkgId, E_SUPPORT, _E, "PkgId is required");
@@ -927,6 +924,9 @@ EXPORT_API int context_trigger_custom_unregister(const char* name)
        INIT_SCHED;
        ASSERT_NOT_NULL(name);
 
+       CustomTemplate* customTemplate = CustomTemplate::get(name);
+       IF_FAIL_RETURN_TAG(customTemplate, E_SUPPORT, _E, "Unknown custom name");
+
        CustomTemplate::remove(name);
 
        const char* pkgId = __get_pkg_id();
@@ -945,8 +945,10 @@ EXPORT_API int context_trigger_custom_publish(const char* name, const char* fact
        ASSERT_NOT_NULL(name && fact);
 
        CustomTemplate* customTemplate = CustomTemplate::get(name);
-       IF_FAIL_RETURN_TAG(customTemplate, E_PARAM, _E, "Unknown custom name");
-       IF_FAIL_RETURN(customTemplate->match(fact), CONTEXT_TRIGGER_ERROR_INVALID_DATA);
+       IF_FAIL_RETURN_TAG(customTemplate, E_SUPPORT, _E, "Unknown custom name");
+
+       int error = customTemplate->match(fact);
+       IF_FAIL_RETURN_TAG(error == E_NONE, error, _E, "Failed to publish fact");
 
        const char* pkgId = __get_pkg_id();
        IF_FAIL_RETURN_TAG(pkgId, E_SUPPORT, _E, "PkgId is required");