*/
#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) :
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)
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");
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();
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");