[IOT-3055]Fixed Handle collection resource payload 99/27299/14
authorkoushik.girijala <g.koushik@samsung.com>
Mon, 22 Oct 2018 10:01:16 +0000 (15:31 +0530)
committerNathan Heldt-Sheller <nathan.heldt-sheller@intel.com>
Wed, 14 Nov 2018 06:33:38 +0000 (06:33 +0000)
Fixed Handle collection resource payload for all interfaces
And also fixed batch interface for normal respources

Change-Id: I35c11597f2f55d1e3d40317209fe127cdd076d46
Signed-off-by: koushik.girijala <g.koushik@samsung.com>
12 files changed:
resource/csdk/include/octypes.h
resource/csdk/stack/include/ocpayload.h
resource/csdk/stack/octbstack_product.def
resource/csdk/stack/samples/linux/SimpleClientServer/ocservercoll.cpp
resource/csdk/stack/src/occollection.c
resource/csdk/stack/src/ocpayload.c
resource/csdk/stack/src/ocpayloadconvert.c
resource/csdk/stack/src/ocserverrequest.c
resource/csdk/stack/src/ocstack.c
resource/include/OCRepresentation.h
resource/include/OCResourceResponse.h
resource/src/OCRepresentation.cpp

index e2e49a6..f632d0f 100644 (file)
@@ -1447,12 +1447,23 @@ typedef enum
     PAYLOAD_TYPE_INTROSPECTION
 } OCPayloadType;
 
-/** Enum to describe payload interface interface.*/
+/** Enum to describe payload representation for collection and non collection resources.*/
 typedef enum
 {
-    PAYLOAD_NON_BATCH_INTERFACE,
-    PAYLOAD_BATCH_INTERFACE
-} OCPayloadInterfaceType;
+    /** Used for collection resource when the payload to be created for representation
+     *  with one or more resource representations should be created as an array of object/ objects
+     *  1. Collection resource with Link list and Batch interface etc.
+     */
+    PAYLOAD_REP_ARRAY,
+
+    /** Used for Non Collection resources when payload to be created for the representation with
+     *  zero or one child representation should be created as an Object and the payload with more
+     *  than one representation should be created as an Array of Objects.
+     *  1. Non Collection resource with Link list, Default interfaces etc.
+     *  2. Collection resource with Default interface.
+     */
+    PAYLOAD_REP_OBJECT_ARRAY
+} OCPayloadRepresentationType;
 
 /**
  * A generic struct representing a payload returned from a resource operation
@@ -1533,11 +1544,11 @@ typedef struct OCRepPayloadValue
 typedef struct OCRepPayload
 {
     OCPayload base;
-    OCPayloadInterfaceType ifType;
     char* uri;
     OCStringLL* types;
     OCStringLL* interfaces;
     OCRepPayloadValue* values;
+    OCPayloadRepresentationType repType;
     struct OCRepPayload* next;
 } OCRepPayload;
 
index 8be4206..a2ca3fc 100644 (file)
@@ -114,7 +114,8 @@ void OC_CALL OCRepPayloadAppend(OCRepPayload* parent, OCRepPayload* child);
 
 bool OC_CALL OCRepPayloadSetUri(OCRepPayload* payload, const char* uri);
 
-bool OC_CALL OCRepPayloadSetInterfaceType(OCRepPayload* payload, OCPayloadInterfaceType type);
+bool OC_CALL OCRepPayloadSetPayloadRepType(OCRepPayload* payload,
+                                           OCPayloadRepresentationType type);
 
 bool OC_CALL OCRepPayloadAddResourceType(OCRepPayload* payload, const char* resourceType);
 bool OC_CALL OCRepPayloadAddInterface(OCRepPayload* payload, const char* iface);
index b840797..3116b76 100644 (file)
@@ -120,7 +120,7 @@ OCRepPayloadSetPropStringAsOwner
 OCRepPayloadSetStringArray
 OCRepPayloadSetStringArrayAsOwner
 OCRepPayloadSetUri
-OCRepPayloadSetInterfaceType
+OCRepPayloadSetPayloadRepType
 OCResourcePayloadAddNewEndpoint
 OCResourcePayloadAddStringLL
 OCSecurityPayloadCreate
index 3dd5f20..fb72ab9 100644 (file)
@@ -198,6 +198,7 @@ OCEntityHandlerResult OCEntityHandlerRoomCb(OCEntityHandlerFlag flag,
             else if(query.find(OC_RSRVD_INTERFACE_LL) != std::string::npos)
             {
                 OCRepPayloadSetUri(payload, gRoomResourceUri);
+                OCRepPayloadSetPayloadRepType(payload, PAYLOAD_REP_ARRAY);
 
                 OCRepPayload *tempPayload = OCRepPayloadCreate();
                 OCRepPayloadSetUri(tempPayload, gLightResourceUri);
@@ -211,7 +212,7 @@ OCEntityHandlerResult OCEntityHandlerRoomCb(OCEntityHandlerFlag flag,
             {
 
                 OCRepPayloadSetUri(payload, gRoomResourceUri);
-                OCRepPayloadSetInterfaceType(payload, PAYLOAD_BATCH_INTERFACE);
+                OCRepPayloadSetPayloadRepType(payload, PAYLOAD_REP_ARRAY);
 
                 OCRepPayload *tempPayload = OCRepPayloadCreate();
                 OCRepPayloadSetUri(tempPayload, gLightResourceUri);
index 0a512f1..081f10c 100644 (file)
@@ -190,6 +190,15 @@ static OCStackResult HandleLinkedListInterface(OCEntityHandlerRequest *ehRequest
         ret = OC_STACK_OK;
     }
 exit:
+    if (0 == strcmp(ifQueryParam, OC_RSRVD_INTERFACE_LL))
+    {
+        OCRepPayloadSetPayloadRepType(colPayload, PAYLOAD_REP_ARRAY);
+    }
+    else
+    {
+        OCRepPayloadSetPayloadRepType(colPayload, PAYLOAD_REP_OBJECT_ARRAY);
+    }
+
     if (ret == OC_STACK_OK)
     {
         ehResult = OC_EH_OK;
@@ -583,7 +592,7 @@ OCRepPayload** BuildCollectionLinksPayloadArray(const char* resourceUri,
                 OIC_LOG(ERROR, TAG, "Failed setting rel property");
                 result = false;
                 goto exit;
-            } 
+            }
         }
         result = true;
     }
index 6e34b56..6b0b3df 100644 (file)
@@ -85,7 +85,7 @@ OCRepPayload* OC_CALL OCRepPayloadCreate(void)
         return NULL;
     }
 
-    payload->ifType = PAYLOAD_NON_BATCH_INTERFACE;
+    payload->repType = PAYLOAD_REP_OBJECT_ARRAY;
     payload->base.type = PAYLOAD_TYPE_REPRESENTATION;
 
     return payload;
@@ -496,14 +496,14 @@ bool OC_CALL OCRepPayloadSetUri(OCRepPayload* payload, const char*  uri)
     return payload->uri != NULL;
 }
 
-bool OC_CALL OCRepPayloadSetInterfaceType(OCRepPayload* payload, OCPayloadInterfaceType type)
+bool OC_CALL OCRepPayloadSetPayloadRepType(OCRepPayload* payload, OCPayloadRepresentationType type)
 {
     if (!payload)
     {
         return false;
     }
 
-    payload->ifType = type;
+    payload->repType = type;
     return true;
 }
 
@@ -1634,7 +1634,7 @@ OCRepPayload* OC_CALL OCRepPayloadBatchClone(const OCRepPayload* repPayload)
     }
 
     clone->types  = CloneOCStringLL(repPayload->types);
-    clone->ifType = repPayload->ifType;
+    clone->repType = repPayload->repType;
     clone->interfaces  = CloneOCStringLL(repPayload->interfaces);
     clone->values = OCRepPayloadValueClone(repPayload->values);
     OCRepPayloadSetPropObjectAsOwner(newPayload, OC_RSRVD_REPRESENTATION, clone);
index ac06847..3f7eb3d 100644 (file)
@@ -942,28 +942,36 @@ static int64_t OCConvertRepPayload(OCRepPayload *payload, uint8_t *outPayload, s
 
     cbor_encoder_init(&encoder, outPayload, *size, 0);
 
-    int isBatch = 0;
-    if (payload != NULL && payload->ifType == PAYLOAD_BATCH_INTERFACE)
+    size_t objectCount = 0;
+    for (OCRepPayload *temp = payload; temp; temp = temp->next)
     {
-        isBatch = 1;
+        objectCount++;
     }
 
-    size_t arrayCount = 0;
-    for (OCRepPayload *temp = payload; temp; temp = temp->next)
+    int isColResource = 0;
+    if (payload != NULL && (payload->repType == PAYLOAD_REP_ARRAY))
     {
-        arrayCount++;
+        isColResource = 1;
     }
+
+    // As per OCF spec
+    // 1. Create an array of objects for collection resource payload when 0 <=objectCount <=1
+    //    for ll and batch interfaces.
+    // 2. Create single object for non collection resource payload when 0 <= objectCount <= 1
+    //    for non batch interfaces.
+    // 3. Create an array of objects for any kind of resource when objectCount > 1 and for any
+    //    interfaces.
     CborEncoder rootArray;
-    if (arrayCount > 1 || isBatch)
+    if ((objectCount > 1) ||(objectCount <= 1 && isColResource))
     {
-        err |= cbor_encoder_create_array(&encoder, &rootArray, arrayCount);
+        err |= cbor_encoder_create_array(&encoder, &rootArray, objectCount);
         VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, err, "Failed adding rep root map");
     }
 
     while (payload != NULL && (err == CborNoError))
     {
         CborEncoder rootMap;
-        err |= cbor_encoder_create_map(((arrayCount == 1 && !isBatch)? &encoder: &rootArray),
+        err |= cbor_encoder_create_map(((objectCount == 1 && !isColResource)? &encoder: &rootArray),
                                             &rootMap, CborIndefiniteLength);
         VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, err, "Failed creating root map");
 
@@ -971,12 +979,13 @@ static int64_t OCConvertRepPayload(OCRepPayload *payload, uint8_t *outPayload, s
         VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, err, "Failed setting rep payload");
 
         // Close main array
-        err |= cbor_encoder_close_container(((arrayCount == 1 && !isBatch) ? &encoder: &rootArray),
+        err |= cbor_encoder_close_container(((objectCount == 1 && !isColResource) ? &encoder: &rootArray),
                 &rootMap);
         VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, err, "Failed closing root map");
         payload = payload->next;
     }
-    if (arrayCount > 1 || isBatch)
+
+    if (objectCount > 1 || (objectCount <= 1 && isColResource))
     {
         err |= cbor_encoder_close_container(&encoder, &rootArray);
         VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, err, "Failed closing root array");
index d1224e6..6e3e85a 100644 (file)
@@ -875,9 +875,10 @@ OCStackResult HandleAggregateResponse(OCEntityHandlerResponse * ehResponse)
 
         OCRepPayload *newPayload = OCRepPayloadBatchClone((OCRepPayload *)ehResponse->payload);
 
+        OCRepPayloadSetPayloadRepType(newPayload, PAYLOAD_REP_ARRAY);
+
         if(!serverResponse->payload)
         {
-            OCRepPayloadSetInterfaceType(newPayload, PAYLOAD_BATCH_INTERFACE);
             serverResponse->payload = (OCPayload *)newPayload;
         }
         else
index e24bcfa..092e87b 100644 (file)
@@ -3544,6 +3544,44 @@ OCStackResult OC_CALL OCDoRequest(OCDoHandle *handle,
         }
         requestInfo.info.payloadVersion = payloadVersion;
 
+        // for fixing collection resource POST/PUT requests
+        if (payload->type == PAYLOAD_TYPE_REPRESENTATION)
+        {
+            OCRepPayload *repPayload = (OCRepPayload *)payload;
+
+            // PAYLOAD_REP_ARRAY is set only for case of collection resource
+            // Here we are differentiating DEFAULT with LL and BATCH interface
+            // For DEFAULT interface repType will be PAYLOAD_REP_OBJECT_ARRAY
+            if (requestUri && repPayload->repType == PAYLOAD_REP_ARRAY)
+            {
+                char *interfaceName = NULL;
+                char *rtTypeName = NULL;
+                char *uriQuery = NULL;
+                char *uriWithoutQuery = NULL;
+                if (OC_STACK_OK == getQueryFromUri(requestUri, &uriQuery, &uriWithoutQuery))
+                {
+                    if (OC_STACK_OK == ExtractFiltersFromQuery(uriQuery, &interfaceName,
+                        &rtTypeName))
+                    {
+                        if (interfaceName &&
+                            (0 == strcmp(OC_RSRVD_INTERFACE_DEFAULT, interfaceName)))
+                        {
+                            repPayload->repType = PAYLOAD_REP_OBJECT_ARRAY;
+                        }
+                    }
+                    else if (NULL == uriQuery)
+                    {
+                        repPayload->repType = PAYLOAD_REP_OBJECT_ARRAY;
+                    }
+                }
+
+                OICFree(interfaceName);
+                OICFree(rtTypeName);
+                OICFree(uriQuery);
+                OICFree(uriWithoutQuery);
+            }
+        }
+
         if ((result =
             OCConvertPayload(payload, CAToOCPayloadFormat(requestInfo.info.payloadFormat),
                             &requestInfo.info.payload, &requestInfo.info.payloadSize))
index d7b079c..2f005a1 100644 (file)
@@ -106,6 +106,10 @@ namespace OC
 
             InterfaceType getInterfaceType() const;
 
+            void setIsCollectionResource(bool isColResource);
+
+            bool isCollectionResource() const;
+
             void addChild(const OCRepresentation&);
 
             void clearChildren();
@@ -480,6 +484,7 @@ namespace OC
             std::vector<std::string> m_dataModelVersions;
 
             InterfaceType m_interfaceType;
+            bool m_isCollectionResource;
     };
 
     std::ostream& operator <<(std::ostream& os, const OCRepresentation::AttributeItem& ai);
index bbe5455..23838ed 100644 (file)
@@ -52,7 +52,8 @@ namespace OC
             m_representation{},
             m_requestHandle{nullptr},
             m_resourceHandle{nullptr},
-            m_responseResult{}
+            m_responseResult{},
+            m_isCollectionResource{}
         {
         }
 
@@ -64,7 +65,8 @@ namespace OC
             m_representation(std::move(o.m_representation)),
             m_requestHandle(std::move(o.m_requestHandle)),
             m_resourceHandle(std::move(o.m_resourceHandle)),
-            m_responseResult(std::move(o.m_responseResult))
+            m_responseResult(std::move(o.m_responseResult)),
+            m_isCollectionResource(std::move(o.m_isCollectionResource))
         {
         }
         OCResourceResponse& operator=(OCResourceResponse&& o)
@@ -76,6 +78,7 @@ namespace OC
             m_requestHandle = std::move(o.m_requestHandle);
             m_resourceHandle = std::move(o.m_resourceHandle);
             m_responseResult = std::move(o.m_responseResult);
+            m_isCollectionResource = std::move(o.m_isCollectionResource);
         }
 #else
         OCResourceResponse(OCResourceResponse&&) = default;
@@ -140,6 +143,29 @@ namespace OC
             m_responseResult = responseResult;
         }
 
+        /**
+        *  API to set the entire resource attribute representation
+        *  @param rep reference to the resource's representation
+        *  @param iface specifies the interface
+        */
+        void setResourceRepresentation(OCRepresentation& rep, std::string iface,
+                                       bool isCollectionResource)
+        {
+            m_interface = iface;
+            m_representation = rep;
+            m_isCollectionResource = isCollectionResource;
+        }
+
+        /**
+        *  API to set the entire resource attribute representation
+        *  @param rep rvalue reference to the resource's representation
+        *  @param iface specifies the interface
+        */
+        void setResourceRepresentation(OCRepresentation&& rep, std::string iface,
+                                       bool isCollectionResource) {
+            setResourceRepresentation(rep, iface, isCollectionResource);
+        }
+
         /**
         *  API to set the entire resource attribute representation
         *  @param rep reference to the resource's representation
@@ -148,6 +174,7 @@ namespace OC
         void setResourceRepresentation(OCRepresentation& rep, std::string iface) {
             m_interface = iface;
             m_representation = rep;
+            m_isCollectionResource = false;
         }
 
         /**
@@ -167,6 +194,7 @@ namespace OC
             // Call the default
             m_interface = DEFAULT_INTERFACE;
             m_representation = rep;
+            m_isCollectionResource = false;
         }
 
         /**
@@ -185,6 +213,7 @@ namespace OC
         OCRequestHandle m_requestHandle;
         OCResourceHandle m_resourceHandle;
         OCEntityHandlerResult m_responseResult;
+        bool m_isCollectionResource;
 
     private:
         friend class InProcServerWrapper;
@@ -207,6 +236,8 @@ namespace OC
                 first.setInterfaceType(InterfaceType::DefaultParent);
             }
 
+            first.setIsCollectionResource(m_isCollectionResource);
+
             inf.addRepresentation(first);
 
             for(const OCRepresentation& rep : m_representation.getChildren())
@@ -249,6 +280,14 @@ namespace OC
             return m_headerOptions;
         }
 
+        /**
+         * Get the resource type collection/non-collection
+         */
+        bool isCollectionResource() const
+        {
+            return m_isCollectionResource;
+        }
+
         /**
         * This API retrieves the request handle
         *
index 970a2fb..1d0d029 100644 (file)
@@ -83,9 +83,13 @@ namespace OC
             if (!root)
             {
                 root = r.getPayload();
-                if (r.getInterfaceType() == InterfaceType::BatchParent)
+                if (r.isCollectionResource())
                 {
-                    root->ifType = PAYLOAD_BATCH_INTERFACE;
+                    root->repType = PAYLOAD_REP_ARRAY;
+                }
+                else
+                {
+                    root->repType = PAYLOAD_REP_OBJECT_ARRAY;
                 }
             }
             else
@@ -403,6 +407,16 @@ namespace OC
         return m_interfaceType;
     }
 
+    void OCRepresentation::setIsCollectionResource(bool isColResource)
+    {
+        m_isCollectionResource = isColResource;
+    }
+
+    bool OCRepresentation::isCollectionResource() const
+    {
+        return m_isCollectionResource;
+    }
+
     size_t calcArrayDepth(const size_t dimensions[MAX_REP_ARRAY_DEPTH])
     {
         if (dimensions[0] == 0)