[iotcon] Implementation of Resource.addChildResource()/removeChildResource().
authorPawel Andruszkiewicz <p.andruszkie@samsung.com>
Wed, 10 Feb 2016 09:59:19 +0000 (10:59 +0100)
committerPawel Andruszkiewicz <p.andruszkie@samsung.com>
Mon, 15 Feb 2016 13:44:41 +0000 (22:44 +0900)
Change-Id: I94f127970b3ea39da131e7f893c02da2e3c2cdbd
Signed-off-by: Pawel Andruszkiewicz <p.andruszkie@samsung.com>
src/iotcon/iotcon_api.js
src/iotcon/iotcon_instance.cc
src/iotcon/iotcon_instance.h
src/iotcon/iotcon_server_manager.cc
src/iotcon/iotcon_utils.cc
src/iotcon/iotcon_utils.h

index 98e7ffc2d5556b658f0543cf686a988ec4987562..5a8a331a717c5f8f9c3cca4394c0016234932859 100644 (file)
@@ -381,40 +381,47 @@ Resource.prototype.addResourceInterfaces = function() {
 Resource.prototype.addChildResource = function() {
   var args = validator.validateMethod(arguments, [{
     name: 'resource',
-    type: types_.PLATFORM_OBJECT,
-    values: Resource,
-    optional: false,
-    nullable: false
+    type: types.PLATFORM_OBJECT,
+    values: Resource
   }]);
 
   var callArgs = {};
   callArgs.id = this[kIdKey];
-  callArgs.resource = args.resource;
+  callArgs.childId = args.resource[kIdKey];
 
-  var result = native.call('IotconResource_addChildResource', callArgs);
+  var result = native.callSync('IotconResource_addChildResource', callArgs);
 
   if (native.isFailure(result)) {
     throw native.getErrorObject(result);
+  } else {
+    var children = this.resources;
+    children.push(args.resource);
+    updateWithInternalData({ resources: children }, this);
   }
 };
 
 Resource.prototype.removeChildResource = function() {
   var args = validator.validateMethod(arguments, [{
     name: 'resource',
-    type: types_.PLATFORM_OBJECT,
-    values: Resource,
-    optional: false,
-    nullable: false
+    type: types.PLATFORM_OBJECT,
+    values: Resource
   }]);
 
   var callArgs = {};
   callArgs.id = this[kIdKey];
-  callArgs.resource = args.resource;
+  callArgs.childId = args.resource[kIdKey];
 
-  var result = native.call('IotconResource_removeChildResource', callArgs);
+  var result = native.callSync('IotconResource_removeChildResource', callArgs);
 
   if (native.isFailure(result)) {
     throw native.getErrorObject(result);
+  } else {
+    var children = this.resources;
+    var position = children.indexOf(args.resource);
+    if (-1 !== position) {
+      children.splice(position, 1);
+      updateWithInternalData({ resources: children }, this);
+    }
   }
 };
 
index 73243eab9346f65a32527deaa30085c888bf4807..092ae134d8e4170993eba25a78d4c325b2536bac 100644 (file)
@@ -58,6 +58,7 @@ const common::ListenerToken kResourceRequestListenerToken{"ResourceRequestListen
 
 const std::string kObserverIds = "observerIds";
 const std::string kQos = "qos";
+const std::string kChildId = "childId";
 
 }  // namespace
 
@@ -72,6 +73,8 @@ IotconInstance::IotconInstance() {
 
   REGISTER_SYNC("IotconResource_getObserverIds", ResourceGetObserverIds);
   REGISTER_SYNC("IotconResource_notify", ResourceNotify);
+  REGISTER_SYNC("IotconResource_addChildResource", ResourceAddChildResource);
+  REGISTER_SYNC("IotconResource_removeChildResource", ResourceRemoveChildResource);
   REGISTER_SYNC("IotconResource_setRequestListener", ResourceSetRequestListener);
   REGISTER_SYNC("IotconResource_unsetRequestListener", ResourceUnsetRequestListener);
   REGISTER_SYNC("IotconResponse_send", ResponseSend);
@@ -96,8 +99,6 @@ IotconInstance::IotconInstance() {
 
   REGISTER_ASYNC("IotconResource_addResourceTypes", ResourceAddResourceTypes);
   REGISTER_ASYNC("IotconResource_addResourceInterfaces", ResourceAddResourceInterfaces);
-  REGISTER_ASYNC("IotconResource_addChildResource", ResourceAddChildResource);
-  REGISTER_ASYNC("IotconResource_removeChildResource", ResourceRemoveChildResource);
   REGISTER_ASYNC("IotconRemoteResource_methodGet", RemoteResourceMethodGet);
   REGISTER_ASYNC("IotconRemoteResource_methodPut", RemoteResourceMethodPut);
   REGISTER_ASYNC("IotconRemoteResource_methodPost", RemoteResourceMethodPost);
@@ -246,16 +247,66 @@ common::TizenResult IotconInstance::ResourceAddResourceInterfaces(const picojson
   return common::UnknownError("Not implemented");
 }
 
-common::TizenResult IotconInstance::ResourceAddChildResource(const picojson::object& args,
-                                                             const common::AsyncToken& token) {
+common::TizenResult IotconInstance::ResourceAddChildResource(const picojson::object& args) {
   ScopeLogger();
-  return common::UnknownError("Not implemented");
+
+  CHECK_EXIST(args, kId);
+  CHECK_EXIST(args, kChildId);
+
+  ResourceInfoPtr parent;
+  auto result = IotconServerManager::GetInstance().GetResourceById(GetId(args), &parent);
+  if (!result) {
+    LogAndReturnTizenError(result, ("GetResourceById() parent failed"));
+  }
+
+  long long child_id = static_cast<long long>(GetArg(args, kChildId).get<double>());
+  ResourceInfoPtr child;
+
+  result = IotconServerManager::GetInstance().GetResourceById(child_id, &child);
+  if (!result) {
+    LogAndReturnTizenError(result, ("GetResourceById() failed"));
+  }
+
+  result = IotconUtils::ConvertIotconError(iotcon_resource_bind_child_resource(parent->handle, child->handle));
+  if (!result) {
+    LogAndReturnTizenError(result, ("iotcon_resource_bind_child_resource() failed"));
+  }
+
+  parent->children.insert(child);
+  child->parents.insert(parent);
+
+  return common::TizenSuccess();
 }
 
-common::TizenResult IotconInstance::ResourceRemoveChildResource(const picojson::object& args,
-                                                                const common::AsyncToken& token) {
+common::TizenResult IotconInstance::ResourceRemoveChildResource(const picojson::object& args) {
   ScopeLogger();
-  return common::UnknownError("Not implemented");
+
+  CHECK_EXIST(args, kId);
+  CHECK_EXIST(args, kChildId);
+
+  ResourceInfoPtr parent;
+  auto result = IotconServerManager::GetInstance().GetResourceById(GetId(args), &parent);
+  if (!result) {
+    LogAndReturnTizenError(result, ("GetResourceById() parent failed"));
+  }
+
+  long long child_id = static_cast<long long>(GetArg(args, kChildId).get<double>());
+  ResourceInfoPtr child;
+
+  result = IotconServerManager::GetInstance().GetResourceById(child_id, &child);
+  if (!result) {
+    LogAndReturnTizenError(result, ("GetResourceById() failed"));
+  }
+
+  result = IotconUtils::ConvertIotconError(iotcon_resource_unbind_child_resource(parent->handle, child->handle));
+  if (!result) {
+    LogAndReturnTizenError(result, ("iotcon_resource_unbind_child_resource() failed"));
+  }
+
+  parent->children.erase(child);
+  child->parents.erase(parent);
+
+  return common::TizenSuccess();
 }
 
 common::TizenResult IotconInstance::ResourceSetRequestListener(const picojson::object& args) {
index 57b9c19491ed1cae31da31f9b66caea7c01dea94..960ba49788ca69101a0843893e0f70b68819c15c 100644 (file)
@@ -37,10 +37,8 @@ class IotconInstance : public common::TizenInstance {
                                                const common::AsyncToken& token);
   common::TizenResult ResourceAddResourceInterfaces(const picojson::object& args,
                                                     const common::AsyncToken& token);
-  common::TizenResult ResourceAddChildResource(const picojson::object& args,
-                                               const common::AsyncToken& token);
-  common::TizenResult ResourceRemoveChildResource(const picojson::object& args,
-                                                  const common::AsyncToken& token);
+  common::TizenResult ResourceAddChildResource(const picojson::object& args);
+  common::TizenResult ResourceRemoveChildResource(const picojson::object& args);
   common::TizenResult ResourceSetRequestListener(const picojson::object& args);
   common::TizenResult ResourceUnsetRequestListener(const picojson::object& args);
   common::TizenResult ResponseSend(const picojson::object& args);
index 19ae602c2babad959130c0788ed25a8c1a225d58..9a1144eb639d385949d3877c5358e6f4b155581f 100644 (file)
@@ -43,14 +43,15 @@ IotconServerManager& IotconServerManager::GetInstance() {
 TizenResult IotconServerManager::RestoreHandles() {
   ScopeLogger();
 
-  for (auto it = resource_map_.begin(); it != resource_map_.end(); ++it) {
-    LoggerD ("Restoring handle for resource with id: %lld", it->first);
-    ResourceInfoPtr resource = it->second;
+  for (const auto& it : resource_map_) {
+    LoggerD("Restoring handle for resource with id: %lld", it.first);
 
+    ResourceInfoPtr resource = it.second;
     char* uri_path = nullptr;
     iotcon_resource_types_h res_types = nullptr;
     int ifaces = 0;
     int properties = 0;
+
     auto res = IotconUtils::ExtractFromResource(resource, &uri_path,
                                                 &res_types, &ifaces, &properties);
     if (!res){
@@ -76,9 +77,16 @@ TizenResult IotconServerManager::RestoreHandles() {
       iotcon_resource_destroy(old_handle);
     }
   }
-  // TODO
-  // bind children (consider if it is necessary?
-  //    Maybe holding children in resource_map is enough)
+
+  // rebind children
+  for (const auto& it : resource_map_) {
+    for (const auto& child : it.second->children) {
+      auto result = IotconUtils::ConvertIotconError(iotcon_resource_bind_child_resource(it.second->handle, child->handle));
+      if (!result) {
+        LogAndReturnTizenError(result, ("iotcon_resource_bind_child_resource() failed"));
+      }
+    }
+  }
 
   return TizenSuccess();
 }
@@ -206,8 +214,7 @@ TizenResult IotconServerManager::GetResourceById(long long id,
 
   auto it = resource_map_.find(id);
   if (it == resource_map_.end()) {
-    LoggerE("Not found such resource");
-    return LogAndCreateTizenError(NotFoundError, "Not found such resource");
+    return LogAndCreateTizenError(NotFoundError, "Resource with specified ID does not exist");
   }
   LoggerE("Resource found");
   *res_pointer = it->second;
@@ -218,11 +225,25 @@ TizenResult IotconServerManager::GetResourceById(long long id,
 common::TizenResult IotconServerManager::DestroyResource(long long id) {
   ScopeLogger();
 
-  if (resource_map_.erase(id)) {
-    return TizenSuccess();
-  } else {
-    return LogAndCreateTizenError(NotFoundError, "Resource with specified ID does not exist");
+  ResourceInfoPtr resource;
+  auto result = GetResourceById(id, &resource);
+  if (!result) {
+    LogAndReturnTizenError(result, ("GetResourceById() failed"));
   }
+
+  // do not allow to destroy a resource which has a parent resource
+  if (resource->parents.size() > 0) {
+    return LogAndCreateTizenError(InvalidStateError, "Cannot destroy child resource, remove it from parent first");
+  }
+
+  // notify children they've lost a parent :(
+  for (const auto& child : resource->children) {
+    child->parents.erase(resource);
+  }
+
+  resource_map_.erase(id);
+
+  return TizenSuccess();
 }
 
 common::TizenResult IotconServerManager::GetResourceByHandle(
index b91060e5c649a35b833b13cc958be54d79f6d5e1..7b19dc89102db1bd724e328513e37811e58a5c11 100644 (file)
@@ -260,26 +260,15 @@ TizenResult IotconUtils::ResourceToJson(ResourceInfoPtr pointer,
   res->insert(std::make_pair(kIsExplicitDiscoverable, picojson::value(value)));
 
   picojson::array children;
-  for (auto iter = pointer->children_ids.begin(); iter != pointer->children_ids.end(); ++iter) {
-    if (pointer->id == (*iter)) {
-      // prevent infinite recurrence
-      continue;
-    }
-    ResourceInfoPtr resource;
-    ret = IotconServerManager::GetInstance().GetResourceById((*iter), &resource);
+  for (const auto& child_resource : pointer->children) {
+    picojson::value child = picojson::value(picojson::object());
+    ret = IotconUtils::ResourceToJson(child_resource, &(child.get<picojson::object>()));
     if (ret.IsSuccess()) {
-      LoggerD("Found children RESOURCE\nid: %lld\nhandle: %p", resource->id, resource->handle);
-
-      picojson::value child = picojson::value(picojson::object());
-      ret = IotconUtils::ResourceToJson(resource, &(child.get<picojson::object>()));
-      if (ret.IsSuccess()) {
-        children.push_back(child);
-      }
-    } else {
-      LoggerD("Not found such resource");
+      children.push_back(child);
     }
   }
   res->insert(std::make_pair(kResourceChildren, picojson::value(children)));
+
   // observerIds would be done on demand from JS
 
   return TizenSuccess();
index efe13f23526cf5551b27952496c2ef3eef2a71d0..bfcfd74777618844bd7080f617f164b9ec2a416a 100644 (file)
@@ -48,13 +48,19 @@ extern const std::string kId;
 extern const std::string kHostAddress;
 extern const std::string kConnectivityType;
 
+class ResourceInfo;
+typedef std::shared_ptr<ResourceInfo> ResourceInfoPtr;
+typedef std::map<long long, ResourceInfoPtr> ResourceInfoMap;
+
 struct ResourceInfo {
   long long id;
-  std::vector<long long> children_ids;
   iotcon_resource_h handle;
   std::set<int> observers;
   common::PostCallback request_listener;
   std::unordered_map<long long, iotcon_response_h> unhandled_responses;
+  std::set<ResourceInfoPtr> children;
+  std::set<ResourceInfoPtr> parents;
+
   ResourceInfo() :
     id(0), handle(nullptr) {}
   ~ResourceInfo() {
@@ -65,9 +71,6 @@ struct ResourceInfo {
   }
 };
 
-typedef std::shared_ptr<ResourceInfo> ResourceInfoPtr;
-typedef std::map<long long, ResourceInfoPtr> ResourceInfoMap;
-
 class IotconUtils {
  public:
   static common::TizenResult ArrayToInterfaces(const picojson::array& interfaces, int* res);