[iotcon] Implementation of Response.send().
authorPawel Andruszkiewicz <p.andruszkie@samsung.com>
Thu, 11 Feb 2016 07:48:07 +0000 (08:48 +0100)
committerPawel Andruszkiewicz <p.andruszkie@samsung.com>
Tue, 16 Feb 2016 10:23:41 +0000 (11:23 +0100)
Change-Id: Idced64c3cf411aaf2c217b3ddd9c2c34a194cb5b
Signed-off-by: Pawel Andruszkiewicz <p.andruszkie@samsung.com>
src/iotcon/iotcon_api.js
src/iotcon/iotcon_instance.cc
src/iotcon/iotcon_server_manager.cc
src/iotcon/iotcon_server_manager.h
src/iotcon/iotcon_utils.cc
src/iotcon/iotcon_utils.h

index cee7308..288447b 100644 (file)
@@ -496,11 +496,18 @@ function Response(request) {
 }
 
 Response.prototype.send = function() {
+  var args = validator.validateMethod(arguments, [{
+    name: 'iface',
+    type: types.ENUM,
+    values: T.getValues(ResourceInterface)
+  }]);
+
   var callArgs = {};
   callArgs.id = this.request[kIdKey];
   callArgs.result = this.result;
   callArgs.representation = this.representation;
   callArgs.options = this.options;
+  callArgs.iface = args.iface;
 
   var result = native.callSync('IotconResponse_send', callArgs);
 
index ae913df..3f024f6 100644 (file)
@@ -65,6 +65,7 @@ const std::string kQos = "qos";
 const std::string kChildId = "childId";
 const std::string kType = "type";
 const std::string kInterface = "iface";
+const std::string kResult = "result";
 
 const std::string kTimeout = "timeout";
 }  // namespace
@@ -422,7 +423,79 @@ common::TizenResult IotconInstance::ResourceUnsetRequestListener(const picojson:
 
 common::TizenResult IotconInstance::ResponseSend(const picojson::object& args) {
   ScopeLogger();
-  return common::UnknownError("Not implemented");
+
+  CHECK_EXIST(args, kId);
+  CHECK_EXIST(args, kResult);
+  CHECK_EXIST(args, kRepresentation);
+  CHECK_EXIST(args, kOptions);
+  CHECK_EXIST(args, kInterface);
+
+  ResponsePtr response = nullptr;
+  auto result = IotconServerManager::GetInstance().GetResponseById(GetId(args), &response);
+  if (!result) {
+    LogAndReturnTizenError(result, ("GetResponseById() failed"));
+  }
+
+  {
+    const auto& js_response_result = GetArg(args, kResult);
+    if (!js_response_result.is<std::string>()) {
+      return LogAndCreateTizenError(TypeMismatchError, "ResponseResult should be a string");
+    }
+    iotcon_response_result_e response_result = IotconUtils::ToResponseResult(js_response_result.get<std::string>());
+
+    result = IotconUtils::ConvertIotconError(iotcon_response_set_result(response.get(), response_result));
+    if (!result) {
+      LogAndReturnTizenError(result, ("iotcon_response_set_result() failed"));
+    }
+  }
+
+  {
+    const auto& js_representation = GetArg(args, kRepresentation);
+    if (!js_representation.is<picojson::object>()) {
+      return LogAndCreateTizenError(TypeMismatchError, "Representation should be an object");
+    }
+    iotcon_representation_h representation = nullptr;
+    result = IotconUtils::RepresentationFromJson(js_representation.get<picojson::object>(), &representation);
+    if (!result) {
+      LogAndReturnTizenError(result, ("RepresentationFromJson() failed"));
+    }
+    SCOPE_EXIT {
+      iotcon_representation_destroy(representation);
+    };
+
+    result = IotconUtils::ConvertIotconError(iotcon_response_set_representation(response.get(), IotconUtils::ToInterface(GetArg(args, kInterface).get<std::string>()), representation));
+    if (!result) {
+      LogAndReturnTizenError(result, ("iotcon_response_set_representation() failed"));
+    }
+  }
+
+  {
+    const auto& js_options = GetArg(args, kOptions);
+
+    if (js_options.is<picojson::array>()) {
+      iotcon_options_h options = nullptr;
+
+      result = IotconUtils::OptionsFromJson(js_options.get<picojson::array>(), &options);
+      if (!result) {
+        LogAndReturnTizenError(result, ("OptionsFromJson() failed"));
+      }
+      SCOPE_EXIT {
+        iotcon_options_destroy(options);
+      };
+
+      result = IotconUtils::ConvertIotconError(iotcon_response_set_options(response.get(), options));
+      if (!result) {
+        LogAndReturnTizenError(result, ("iotcon_response_set_options() failed"));
+      }
+    }
+  }
+
+  result = IotconUtils::ConvertIotconError(iotcon_response_send(response.get()));
+  if (!result) {
+    LogAndReturnTizenError(result, ("iotcon_response_send() failed"));
+  }
+
+  return common::TizenSuccess();
 }
 
 common::TizenResult IotconInstance::RemoteResourceGetCachedRepresentation(const picojson::object& args) {
index 9a1144e..079e783 100644 (file)
@@ -161,7 +161,7 @@ void IotconServerManager::RequestHandler(iotcon_resource_h resource,
     // store data
     long long id = GetNextId();
     obj.insert(std::make_pair(kId, picojson::value{static_cast<double>(id)}));
-    r->unhandled_responses.insert(std::make_pair(id, response));
+    r->pending_responses.insert(std::make_pair(id, ResponsePtr{response, &iotcon_response_destroy}));
 
     // call listener
     r->request_listener(TizenSuccess(), value);
@@ -264,5 +264,19 @@ common::TizenResult IotconServerManager::GetResourceByHandle(
   return TizenSuccess();
 }
 
+common::TizenResult IotconServerManager::GetResponseById(long long id, ResponsePtr* out) const {
+  ScopeLogger();
+
+  for (const auto& resource : resource_map_) {
+    const auto& it = resource.second->pending_responses.find(id);
+    if (resource.second->pending_responses.end() != it) {
+      *out = it->second;
+      return TizenSuccess();
+    }
+  }
+
+  return LogAndCreateTizenError(NotFoundError, "Response with specified ID does not exist");
+}
+
 }  // namespace iotcon
 }  // namespace extension
index b15e362..3f9d8ef 100644 (file)
@@ -44,6 +44,7 @@ class IotconServerManager {
   common::TizenResult GetResourceById(long long id, ResourceInfoPtr* res_pointer) const;
   common::TizenResult DestroyResource(long long id);
   common::TizenResult GetResourceByHandle(iotcon_resource_h resource, ResourceInfoPtr* res_pointer) const;
+  common::TizenResult GetResponseById(long long id, ResponsePtr* out) const;
 
  private:
   IotconServerManager() = default;
index 88c8a71..6f2a99f 100644 (file)
@@ -76,6 +76,15 @@ namespace {
   X(IOTCON_PRESENCE_RESOURCE_UPDATED, "UPDATED") \
   XD(IOTCON_PRESENCE_RESOURCE_DESTROYED, "DESTROYED")
 
+#define IOTCON_RESPONSE_RESULT_E \
+  X(IOTCON_RESPONSE_OK, "SUCCESS") \
+  X(IOTCON_RESPONSE_ERROR, "ERROR") \
+  X(IOTCON_RESPONSE_RESOURCE_CREATED, "RESOURCE_CREATED") \
+  X(IOTCON_RESPONSE_RESOURCE_DELETED, "RESOURCE_DELETED") \
+  X(IOTCON_RESPONSE_SLOW, "SLOW") \
+  X(IOTCON_RESPONSE_FORBIDDEN, "FORBIDDEN") \
+  XD(IOTCON_RESPONSE_ERROR, "unknown")
+
 }  // namespace
 
 const std::string kIsDiscoverable = "isDiscoverable";
@@ -1338,6 +1347,155 @@ common::TizenResult IotconUtils::ExtractFromPresenceEvent(const PresenceEventPtr
   return TizenSuccess();
 }
 
+common::TizenResult IotconUtils::OptionsFromJson(const picojson::array& o,
+                                                 iotcon_options_h* out) {
+  ScopeLogger();
+
+  iotcon_options_h options = nullptr;
+
+  auto result = ConvertIotconError(iotcon_options_create(&options));
+  if (!result) {
+    LogAndReturnTizenError(result, ("iotcon_options_create() failed"));
+  }
+
+  std::unique_ptr<std::remove_pointer<iotcon_options_h>::type, void(*)(iotcon_options_h)> ptr{options, &iotcon_options_destroy};
+
+  // we ignore values with incorrect types
+  // TODO: should we convert them in JS?
+  for (const auto& option : o) {
+    if (option.is<picojson::object>()) {
+      const auto& js_id = option.get(kOptionsId);
+      const auto& js_data = option.get(kOptionsData);
+
+      if (js_id.is<double>() && js_data.is<std::string>()) {
+        result = ConvertIotconError(iotcon_options_add(options, js_id.get<double>(), js_data.get<std::string>().c_str()));
+        if (!result) {
+          LogAndReturnTizenError(result, ("iotcon_options_add() failed"));
+        }
+      }
+    }
+  }
+
+  *out = ptr.release();
+  return TizenSuccess();
+}
+
+common::TizenResult IotconUtils::RepresentationFromJson(const picojson::object& r,
+                                                        iotcon_representation_h* out) {
+  ScopeLogger();
+
+  iotcon_representation_h representation = nullptr;
+
+  auto result = ConvertIotconError(iotcon_representation_create(&representation));
+  if (!result) {
+    LogAndReturnTizenError(result, ("iotcon_representation_create() failed"));
+  }
+
+  std::unique_ptr<std::remove_pointer<iotcon_representation_h>::type, void(*)(iotcon_representation_h)> ptr{representation, &iotcon_representation_destroy};
+
+  {
+    const auto& uri_path = r.find(kUriPath);
+    if (r.end() != uri_path && uri_path->second.is<std::string>()) {
+      result = ConvertIotconError(iotcon_representation_set_uri_path(representation, uri_path->second.get<std::string>().c_str()));
+      if (!result) {
+        LogAndReturnTizenError(result, ("iotcon_representation_set_uri_path() failed"));
+      }
+    } else {
+      return LogAndCreateTizenError(TypeMismatchError, "Representation object needs to have an uriPath attribute which is a string.");
+    }
+  }
+
+  {
+    const auto& resource_types = r.find(kResourceTypes);
+    if (r.end() != resource_types && resource_types->second.is<picojson::array>()) {
+      iotcon_resource_types_h types = nullptr;
+
+      result = ArrayToTypes(resource_types->second.get<picojson::array>(), &types);
+      if (!result) {
+        LogAndReturnTizenError(result, ("ArrayToTypes() failed"));
+      }
+      SCOPE_EXIT {
+        iotcon_resource_types_destroy(types);
+      };
+
+      result = ConvertIotconError(iotcon_representation_set_resource_types(representation, types));
+      if (!result) {
+        LogAndReturnTizenError(result, ("iotcon_representation_set_resource_types() failed"));
+      }
+    } else {
+      return LogAndCreateTizenError(TypeMismatchError, "Representation object needs to have a resourceTypes attribute which is an array.");
+    }
+  }
+
+  {
+    const auto& resource_interfaces = r.find(kResourceInterfaces);
+    if (r.end() != resource_interfaces && resource_interfaces->second.is<picojson::array>()) {
+      int interfaces = IOTCON_INTERFACE_NONE;
+
+      result = ArrayToInterfaces(resource_interfaces->second.get<picojson::array>(), &interfaces);
+      if (!result) {
+        LogAndReturnTizenError(result, ("ArrayToInterfaces() failed"));
+      }
+
+      result = ConvertIotconError(iotcon_representation_set_resource_interfaces(representation, interfaces));
+      if (!result) {
+        LogAndReturnTizenError(result, ("iotcon_representation_set_resource_interfaces() failed"));
+      }
+    } else {
+      return LogAndCreateTizenError(TypeMismatchError, "Representation object needs to have a resourceInterfaces attribute which is an array.");
+    }
+  }
+
+  {
+    const auto& states = r.find(kStates);
+    if (r.end() != states && states->second.is<picojson::object>()) {
+      iotcon_state_h s = nullptr;
+
+      result = StateFromJson(states->second.get<picojson::object>(), &s);
+      if (!result) {
+        LogAndReturnTizenError(result, ("StateFromJson() failed"));
+      }
+      SCOPE_EXIT {
+        iotcon_state_destroy(s);
+      };
+
+      result = ConvertIotconError(iotcon_representation_set_state(representation, s));
+      if (!result) {
+        LogAndReturnTizenError(result, ("iotcon_representation_set_state() failed"));
+      }
+    }
+  }
+
+  {
+    const auto& representations = r.find(kRepresentations);
+    if (r.end() != representations && representations->second.is<picojson::array>()) {
+      for (const auto& js_child : representations->second.get<picojson::array>()) {
+        if (js_child.is<picojson::object>()) {
+          iotcon_representation_h child = nullptr;
+
+          result = RepresentationFromJson(js_child.get<picojson::object>(), &child);
+          if (!result) {
+            LogAndReturnTizenError(result, ("RepresentationFromJson() failed"));
+          }
+          SCOPE_EXIT {
+            iotcon_representation_destroy(child);
+          };
+
+          result = ConvertIotconError(iotcon_representation_add_child(representation, child));
+          if (!result) {
+            LogAndReturnTizenError(result, ("iotcon_representation_add_child() failed"));
+          }
+        } else {
+          return LogAndCreateTizenError(TypeMismatchError, "The Representation.representations attribute needs to be an array of Representation objects.");
+        }
+      }
+    }
+  }
+
+  *out = ptr.release();
+  return TizenSuccess();
+}
+
 common::TizenResult IotconUtils::PlatformInfoGetProperty(iotcon_platform_info_h platform,
                                                          iotcon_platform_info_e property_e,
                                                          const std::string& name,
@@ -1641,6 +1799,10 @@ iotcon_connectivity_type_e IotconUtils::ToConnectivityType(const std::string& e)
   IOTCON_CONNECTIVITY_TYPE_E
 }
 
+iotcon_response_result_e IotconUtils::ToResponseResult(const std::string& e) {
+  IOTCON_RESPONSE_RESULT_E
+}
+
 #undef X
 #undef XD
 
index b8fb934..e171dcf 100644 (file)
@@ -50,6 +50,8 @@ extern const std::string kDeviceId;
 extern const std::string kHostAddress;
 extern const std::string kConnectivityType;
 extern const std::string kResourceType;
+extern const std::string kRepresentation;
+extern const std::string kOptions;
 
 class ResourceInfo;
 class PresenceEvent;
@@ -59,12 +61,14 @@ typedef std::map<long long, ResourceInfoPtr> ResourceInfoMap;
 typedef std::shared_ptr<PresenceEvent> PresenceEventPtr;
 typedef std::map<long long, PresenceEventPtr> PresenceMap;
 
+using ResponsePtr = std::shared_ptr<std::remove_pointer<iotcon_response_h>::type>;
+
 struct ResourceInfo {
   long long id;
   iotcon_resource_h handle;
   std::set<int> observers;
   common::PostCallback request_listener;
-  std::unordered_map<long long, iotcon_response_h> unhandled_responses;
+  std::unordered_map<long long, ResponsePtr> pending_responses;
   std::set<ResourceInfoPtr> children;
   std::set<ResourceInfoPtr> parents;
 
@@ -72,9 +76,6 @@ struct ResourceInfo {
     id(0), handle(nullptr) {}
   ~ResourceInfo() {
     iotcon_resource_destroy(handle);
-    for (auto& it : unhandled_responses) {
-      iotcon_response_destroy(it.second);
-    }
   }
 };
 
@@ -161,6 +162,10 @@ class IotconUtils {
                                            iotcon_state_h* out);
   static common::TizenResult StateListFromJson(const picojson::array& list,
                                                iotcon_list_h* out);
+  static common::TizenResult OptionsFromJson(const picojson::array& options,
+                                             iotcon_options_h* out);
+  static common::TizenResult RepresentationFromJson(const picojson::object& representation,
+                                                    iotcon_representation_h* out);
 
   static common::TizenResult ConvertIotconError(int error);
   static std::string FromConnectivityType(iotcon_connectivity_type_e e);
@@ -173,6 +178,7 @@ class IotconUtils {
   static iotcon_interface_e ToInterface(const std::string& e);
   static iotcon_connectivity_type_e ToConnectivityType(const std::string& e);
   static iotcon_qos_e ToQos(const std::string& e);
+  static iotcon_response_result_e ToResponseResult(const std::string& e);
 };
 
 } // namespace iotcon