[Application] Refactor app_control_h construction. Fix minor bugs. 58/192558/3
authorPawel Wasowski <p.wasowski2@partner.samsung.com>
Mon, 5 Nov 2018 09:27:50 +0000 (10:27 +0100)
committerPawel Wasowski <p.wasowski2@partner.samsung.com>
Tue, 20 Nov 2018 15:43:39 +0000 (16:43 +0100)
ApplicationUtils::ApplicationControlToService() function did not set
launch_mode in an app_control_h object. As a result, methods using the
function had to set launch_mode. Now the function sets the launch mode.

Apart from that change, this commit introduces minor fixes:
* error codes returned by native functions in
ApplicationUtils::ApplicationControlToService() and
ApplicationUtils::ApplicationControlDataToServiceExtraData()
are now tested
* log messages in modified functions are more informative
* ApplicationManager::LaunchAppControl() no longer sets launch_mode of
an app_control_h object

[Verification] TCT pass rate: 100%

Change-Id: Ibc4c2625ce795c872560d13454895671777c6f2b
Signed-off-by: Pawel Wasowski <p.wasowski2@partner.samsung.com>
src/application/application_manager.cc
src/application/application_utils.cc
src/application/application_utils.h

index 23025be..837dd13 100644 (file)
@@ -520,28 +520,6 @@ void ApplicationManager::LaunchAppControl(const picojson::value& args) {
       }
     }
 
-    if (!launch_mode_str.empty()) {
-      app_control_launch_mode_e launch_mode;
-
-      if ("SINGLE" == launch_mode_str) {
-        launch_mode = APP_CONTROL_LAUNCH_MODE_SINGLE;
-      } else if ("GROUP" == launch_mode_str) {
-        launch_mode = APP_CONTROL_LAUNCH_MODE_GROUP;
-      } else {
-        ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."),
-                    &response->get<picojson::object>());
-        return;
-      }
-
-      int ret = app_control_set_launch_mode(app_control_ptr.get(), launch_mode);
-      if (APP_CONTROL_ERROR_NONE != ret) {
-        LogAndReportError(PlatformResult(ErrorCode::NOT_FOUND_ERR, "Setting launch mode failed."),
-                          &response->get<picojson::object>(),
-                          ("Setting launch mode failed: %d (%s)", ret, get_error_message(ret)));
-        return;
-      }
-    }
-
     app_control_reply_cb callback = nullptr;
     struct ReplayCallbackData {
       ApplicationInstance* app_instance;
index 4a0098a..c1c4472 100644 (file)
@@ -183,64 +183,176 @@ void ApplicationUtils::CreateApplicationMetaData(const char* key, const char* va
   app_meta_data->insert(std::make_pair("value", picojson::value(value)));
 }
 
+namespace {
+
+const std::string kOperationAppControlField = "operation";
+const std::string kURIAppControlField = "uri";
+const std::string kMIMEAppControlField = "mime";
+const std::string kCategoryAppControlField = "category";
+const std::string kLaunchModeAppControlField = "launchMode";
+const std::string kDataAppControlField = "data";
+
+const std::string kGroupLaunchMode = "GROUP";
+const std::string kSingleLaunchMode = "SINGLE";
+
+using AppControlTextFieldSetter = std::function<int(app_control_h, const char*)>;
+// clang-format off
+const std::map<std::string, AppControlTextFieldSetter> AppControlTextFieldSetters = {
+  { kOperationAppControlField, app_control_set_operation },
+  { kURIAppControlField, app_control_set_uri },
+  { kMIMEAppControlField, app_control_set_mime },
+  { kCategoryAppControlField, app_control_set_category }
+};  // clang-format on
+
+PlatformResult SetAppControlTextField(app_control_h app_control, const std::string& field_name,
+                                      const std::string& value) {
+  ScopeLogger("Field: %s, value: %s", field_name.c_str(), value.c_str());
+
+  auto setter_it = AppControlTextFieldSetters.find(field_name);
+  if (AppControlTextFieldSetters.end() == setter_it) {
+    return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.");
+  }
+  auto setter = setter_it->second;
+
+  auto result = setter(app_control, value.c_str());
+  auto result_translated =
+      ApplicationUtils::TranslateAppControlError(static_cast<app_control_error_e>(result));
+
+  if (result_translated.IsError()) {
+    LoggerD("Setting app_control's %s field failed: %s", field_name.c_str(),
+            result_translated.message().c_str());
+  }
+
+  return result_translated;
+}
+
+app_control_launch_mode_e LaunchModeStringToEnum(const std::string& launch_mode) {
+  ScopeLogger();
+
+  return launch_mode == kGroupLaunchMode ? APP_CONTROL_LAUNCH_MODE_GROUP : APP_CONTROL_LAUNCH_MODE_SINGLE;
+}
+
+bool LaunchModeIsInvalid(const std::string& launch_mode) {
+  ScopeLogger();
+
+  auto is_valid = launch_mode == kSingleLaunchMode || launch_mode == kGroupLaunchMode;
+  LoggerD("Launch mode: %s (%s)", launch_mode.c_str(), is_valid ? "valid" : "invalid");
+
+  return !is_valid;
+}
+
+PlatformResult SetAppControlLaunchModeField(app_control_h app_control,
+                                            const std::string& launch_mode_str) {
+  ScopeLogger();
+
+  if (LaunchModeIsInvalid(launch_mode_str)) {
+    LoggerD("Invalid launchMode value: %s", launch_mode_str.c_str());
+    return PlatformResult(ErrorCode::INVALID_VALUES_ERR,
+                          "Invalid launchMode value: " + launch_mode_str);
+  }
+
+  auto result = app_control_set_launch_mode(app_control, LaunchModeStringToEnum(launch_mode_str));
+  return ApplicationUtils::TranslateAppControlError(static_cast<app_control_error_e>(result));
+}
+
+PlatformResult SetAppControlDataField(app_control_h app_control, const picojson::array& data) {
+  ScopeLogger();
+
+  for (auto iter = data.begin(); iter != data.end(); ++iter) {
+    if (iter->is<picojson::object>()) {
+      PlatformResult ret = ApplicationUtils::ApplicationControlDataToServiceExtraData(
+          iter->get<picojson::object>(), app_control);
+      if (ret.IsError()) {
+        return ret;
+      }
+    } else {
+      LoggerD("Invalid data value: not an object");
+      return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid data type: not an object");
+    }
+  }
+
+  return PlatformResult{ErrorCode::NO_ERROR};
+}
+
+PlatformResult SetAppControlFieldIfValueSpecified(
+    app_control_h app_control, const std::string& field_name,
+    const picojson::object::const_iterator& iterator) {
+  ScopeLogger();
+
+  if (iterator->second.is<std::string>()) {
+    if (field_name != kLaunchModeAppControlField) {
+      return SetAppControlTextField(app_control, field_name, iterator->second.get<std::string>());
+    }
+    return SetAppControlLaunchModeField(app_control, iterator->second.get<std::string>());
+  } else if (iterator->second.is<picojson::array>() && kDataAppControlField == field_name) {
+    return SetAppControlDataField(app_control, iterator->second.get<picojson::array>());
+  }
+
+  return PlatformResult{ErrorCode::NO_ERROR};
+}
+
+}  // namespace
+
 PlatformResult ApplicationUtils::ApplicationControlToService(
     const picojson::object& app_control_obj, app_control_h* app_control) {
   ScopeLogger();
-  const auto it_operation = app_control_obj.find("operation");
-  const auto it_uri = app_control_obj.find("uri");
-  const auto it_mime = app_control_obj.find("mime");
-  const auto it_category = app_control_obj.find("category");
-  const auto it_data = app_control_obj.find("data");
+
+  const auto it_operation = app_control_obj.find(kOperationAppControlField);
+  const auto it_uri = app_control_obj.find(kURIAppControlField);
+  const auto it_mime = app_control_obj.find(kMIMEAppControlField);
+  const auto it_category = app_control_obj.find(kCategoryAppControlField);
+  const auto it_data = app_control_obj.find(kDataAppControlField);
+  const auto it_launch_mode = app_control_obj.find(kLaunchModeAppControlField);
   const auto it_app_control_end = app_control_obj.end();
 
   if (it_operation == it_app_control_end || it_uri == it_app_control_end ||
       it_mime == it_app_control_end || it_category == it_app_control_end ||
       it_data == it_app_control_end || !it_operation->second.is<std::string>() ||
-      !it_data->second.is<picojson::array>()) {
+      !it_data->second.is<picojson::array>() || it_launch_mode == it_app_control_end) {
     return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter was passed.");
   }
 
   app_control_h app_control_tmp = nullptr;
   int result = app_control_create(&app_control_tmp);
-
   if (APP_CONTROL_ERROR_NONE != result) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Creation AppControl failed.",
-                              ("Problem with create handle."));
+    LoggerD("app_control_create() failed: %d (%s)", result, get_error_message(result));
+    return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.");
   }
 
   std::unique_ptr<std::remove_pointer<app_control_h>::type, int (*)(app_control_h)> app_control_ptr(
       app_control_tmp, &app_control_destroy);
 
-  // operation
-  app_control_set_operation(app_control_tmp, it_operation->second.get<std::string>().c_str());
+  auto set_field_result = PlatformResult(ErrorCode::UNKNOWN_ERR);
 
-  // uri
-  if (it_uri->second.is<std::string>()) {
-    app_control_set_uri(app_control_tmp, it_uri->second.get<std::string>().c_str());
+  set_field_result = SetAppControlFieldIfValueSpecified(app_control_tmp, kOperationAppControlField, it_operation);
+  if (set_field_result.IsError()) {
+    return set_field_result;
   }
 
-  // mime
-  if (it_mime->second.is<std::string>()) {
-    app_control_set_mime(app_control_tmp, it_mime->second.get<std::string>().c_str());
+  set_field_result = SetAppControlFieldIfValueSpecified(app_control_tmp, kURIAppControlField, it_uri);
+  if (set_field_result.IsError()) {
+    return set_field_result;
   }
 
-  // category
-  if (it_category->second.is<std::string>()) {
-    app_control_set_category(app_control_tmp, it_category->second.get<std::string>().c_str());
+  set_field_result = SetAppControlFieldIfValueSpecified(app_control_tmp, kMIMEAppControlField, it_mime);
+  if (set_field_result.IsError()) {
+    return set_field_result;
   }
 
-  // ApplicationControlData
-  const picojson::array& data = it_data->second.get<picojson::array>();
+  set_field_result = SetAppControlFieldIfValueSpecified(app_control_tmp, kCategoryAppControlField, it_category);
+  if (set_field_result.IsError()) {
+    return set_field_result;
+  }
 
-  for (auto iter = data.begin(); iter != data.end(); ++iter) {
-    if (iter->is<picojson::object>()) {
-      PlatformResult ret =
-          ApplicationControlDataToServiceExtraData(iter->get<picojson::object>(), app_control_tmp);
-      if (ret.IsError()) {
-        LoggerE("Failed ApplicationControlDataToServiceExtraData()");
-        return ret;
-      }
-    }
+  set_field_result =
+      SetAppControlFieldIfValueSpecified(app_control_tmp, kLaunchModeAppControlField, it_launch_mode);
+  if (set_field_result.IsError()) {
+    return set_field_result;
+  }
+
+  set_field_result = SetAppControlFieldIfValueSpecified(app_control_tmp, kDataAppControlField, it_data);
+  if (set_field_result.IsError()) {
+    return set_field_result;
   }
 
   *app_control = app_control_ptr.release();
@@ -259,27 +371,34 @@ PlatformResult ApplicationUtils::ApplicationControlDataToServiceExtraData(
   if (it_key == it_app_control_data_end || it_value == it_app_control_data_end ||
       !it_key->second.is<std::string>() || !it_value->second.is<picojson::array>()) {
     return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter was passed.",
-                              ("Problem with key or value."));
+                              ("Invalid key or value."));
   }
 
   const std::string& key = it_key->second.get<std::string>();
   const picojson::array& value = it_value->second.get<picojson::array>();
 
-  const size_t size = value.size();
-  const char** arr = new const char*[size];
-  size_t i = 0;
+  std::vector<const char*> value_data;
 
-  for (auto iter = value.begin(); iter != value.end(); ++iter, ++i) {
-    arr[i] = iter->get<std::string>().c_str();
+  for (auto& v : value) {
+    value_data.push_back(v.get<std::string>().c_str());
   }
 
-  if (1 == size) {
-    app_control_add_extra_data(app_control, key.c_str(), arr[0]);
-  } else {
-    app_control_add_extra_data_array(app_control, key.c_str(), arr, size);
+  auto result = app_control_add_extra_data_array(app_control, key.c_str(), value_data.data(),
+                                                 value_data.size());
+  if (APP_CONTROL_ERROR_INVALID_PARAMETER == result) {
+    if (0 == key.length()) {
+      LoggerD("app_control_add_extra_data_array failed: zero-length key");
+      return PlatformResult(ErrorCode::INVALID_VALUES_ERR,
+                            "Invalid AppControlData key: key length is 0.");
+    }
+    LoggerD("app_control_add_extra_data_array failed: invalid parameter passed");
+    return PlatformResult(ErrorCode::INVALID_VALUES_ERR,
+                          "Invalid AppControlData value, associated with key: " + key);
+  } else if (APP_CONTROL_ERROR_KEY_REJECTED == result) {
+    LoggerD("app_control_add_extra_data_array failed: key rejected");
+    return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid AppControlData's key: " + key);
   }
 
-  delete[] arr;
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
@@ -299,7 +418,7 @@ void ApplicationUtils::ServiceToApplicationControl(app_control_h app_control,
     LoggerE("Get operation failed: %d (%s)", ret, get_error_message(ret));
   } else if (tmp_str) {
     LoggerD("operation: %s", tmp_str);
-    app_control_obj->insert(std::make_pair("operation", picojson::value(std::string(tmp_str))));
+    app_control_obj->insert(std::make_pair(kOperationAppControlField, picojson::value(std::string(tmp_str))));
   } else {
     LoggerD("operation field is empty");
   }
@@ -310,7 +429,7 @@ void ApplicationUtils::ServiceToApplicationControl(app_control_h app_control,
     LoggerE("Get URI failed: %d (%s)", ret, get_error_message(ret));
   } else if (tmp_str) {
     LoggerD("URI: %s", tmp_str);
-    app_control_obj->insert(std::make_pair("uri", picojson::value(std::string(tmp_str))));
+    app_control_obj->insert(std::make_pair(kURIAppControlField, picojson::value(std::string(tmp_str))));
   } else {
     LoggerD("URI field is empty");
   }
@@ -321,7 +440,7 @@ void ApplicationUtils::ServiceToApplicationControl(app_control_h app_control,
     LoggerE("Get MIME failed: %d (%s)", ret, get_error_message(ret));
   } else if (tmp_str) {
     LoggerD("MIME: %s", tmp_str);
-    app_control_obj->insert(std::make_pair("mime", picojson::value(std::string(tmp_str))));
+    app_control_obj->insert(std::make_pair(kMIMEAppControlField, picojson::value(std::string(tmp_str))));
   } else {
     LoggerD("MIME field is empty");
   }
@@ -332,7 +451,7 @@ void ApplicationUtils::ServiceToApplicationControl(app_control_h app_control,
     LoggerE("Get category failed: %d (%s)", ret, get_error_message(ret));
   } else if (tmp_str) {
     LoggerD("category: %s", tmp_str);
-    app_control_obj->insert(std::make_pair("category", picojson::value(std::string(tmp_str))));
+    app_control_obj->insert(std::make_pair(kCategoryAppControlField, picojson::value(std::string(tmp_str))));
   } else {
     LoggerD("category field is empty");
   }
@@ -343,14 +462,15 @@ void ApplicationUtils::ServiceToApplicationControl(app_control_h app_control,
   if (APP_CONTROL_ERROR_NONE != ret) {
     LoggerE("Get launch mode failed: %d (%s)", ret, get_error_message(ret));
   } else {
-    std::string launch_mode_str = launch_mode == APP_CONTROL_LAUNCH_MODE_SINGLE ? "SINGLE" : "GROUP";
+    std::string launch_mode_str =
+        launch_mode == APP_CONTROL_LAUNCH_MODE_SINGLE ? kSingleLaunchMode : kGroupLaunchMode;
     LoggerD("launch mode: %s", launch_mode_str.c_str());
-    app_control_obj->insert(std::make_pair("launchMode", picojson::value(launch_mode_str)));
+    app_control_obj->insert(std::make_pair(kLaunchModeAppControlField, picojson::value(launch_mode_str)));
   }
 
-  app_control_obj->insert(std::make_pair("data", picojson::value(picojson::array())));
+  app_control_obj->insert(std::make_pair(kDataAppControlField, picojson::value(picojson::array())));
   ServiceToApplicationControlDataArray(
-      app_control, &app_control_obj->find("data")->second.get<picojson::array>());
+      app_control, &app_control_obj->find(kDataAppControlField)->second.get<picojson::array>());
 }
 
 void ApplicationUtils::ServiceExtraDataToApplicationControlData(
@@ -411,6 +531,36 @@ bool ApplicationUtils::ServiceToApplicationControlDataArray(app_control_h app_co
   return APP_CONTROL_ERROR_NONE == ret;
 }
 
+PlatformResult ApplicationUtils::TranslateAppControlError(app_control_error_e return_code) {
+  ScopeLogger("Return code: %d (%s)", static_cast<int>(return_code),
+              get_error_message(static_cast<int>(return_code)));
+
+  switch (return_code) {
+    case APP_CONTROL_ERROR_NONE:
+      return PlatformResult(ErrorCode::NO_ERROR);
+
+    case APP_CONTROL_ERROR_INVALID_PARAMETER:
+      return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
+
+    case APP_CONTROL_ERROR_APP_NOT_FOUND:
+      return PlatformResult(ErrorCode::NOT_FOUND_ERR, "No matched application found.");
+
+    case APP_CONTROL_ERROR_PERMISSION_DENIED:
+      return PlatformResult(ErrorCode::SECURITY_ERR, "Permission denied.");
+
+    case APP_CONTROL_ERROR_OUT_OF_MEMORY:
+    case APP_CONTROL_ERROR_KEY_NOT_FOUND:
+    case APP_CONTROL_ERROR_KEY_REJECTED:
+    case APP_CONTROL_ERROR_INVALID_DATA_TYPE:
+    case APP_CONTROL_ERROR_LAUNCH_REJECTED:
+    case APP_CONTROL_ERROR_LAUNCH_FAILED:
+    case APP_CONTROL_ERROR_TIMED_OUT:
+    case APP_CONTROL_ERROR_IO_ERROR:
+    default:
+      return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error.");
+  }
+}
+
 bool ApplicationUtils::ServiceExtraDataCallback(app_control_h app_control, const char* key,
                                                 void* user_data) {
   ScopeLogger();
index 455f197..308827b 100644 (file)
@@ -59,6 +59,8 @@ class ApplicationUtils {
   static bool ServiceToApplicationControlDataArray(app_control_h app_control,
                                                    picojson::array* data);
 
+  static common::PlatformResult TranslateAppControlError(app_control_error_e error_code);
+
  private:
   static bool ServiceExtraDataCallback(app_control_h app_control, const char* key, void* user_data);
 };