ocpayload: Supports multiple data model versions (DMV) using CSV
authorPhil Coval <philippe.coval@osg.samsung.com>
Thu, 16 Jun 2016 08:25:44 +0000 (10:25 +0200)
committerZiran Sun <ziran.sun@samsung.com>
Tue, 28 Jun 2016 14:11:17 +0000 (14:11 +0000)
DMV can be CVS if multiple values are supplied.

OIC 1.1 has a single value but future spec is expected to have multiple values

For more details about this specification please refer to:

  20160531-OIC_Core_Specification_v1.1.0_r0.13.docx
  Section 11.3.4,
  Table 18 for property description
  & Section D.3.4 for RAML definition.

For now it's supporting simple patterns like "one-1,two-2"
In the longer term a full implementation of rfc4180 might be desired.

Internally those items are stored in OCStringLL (linked list of strings),
and later it would make sense to relocate those helper functions
in a common place.

This change has been tested on Tizen:3.0:IVI

Bug: https://jira.iotivity.org/browse/IOT-1101
Change-Id: I7274d74ba525aedda49b78398743aa24a7999c00
Signed-off-by: Phil Coval <philippe.coval@osg.samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/8707
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Uze Choi <uzchoi@samsung.com>
Reviewed-by: Ziran Sun <ziran.sun@samsung.com>
Reviewed-by: Dwarkaprasad Dayama <dwarka.dayama@samsung.com>
16 files changed:
plugins/samples/linux/IotivityandZigbeeServer.c
resource/csdk/stack/include/ocpayload.h
resource/csdk/stack/include/octypes.h
resource/csdk/stack/include/payload_logging.h
resource/csdk/stack/samples/linux/SimpleClientServer/ocserver.cpp
resource/csdk/stack/samples/tizen/SimpleClientServer/ocserver.cpp
resource/csdk/stack/samples/tizen/build/packaging/com.oic.ri.spec
resource/csdk/stack/src/ocpayload.c
resource/csdk/stack/src/ocpayloadconvert.c
resource/csdk/stack/src/ocpayloadparse.c
resource/csdk/stack/src/ocresource.c
resource/examples/devicediscoveryserver.cpp
resource/include/OCRepresentation.h
resource/src/OCRepresentation.cpp
resource/unittests/OCPlatformTest.cpp
resource/unittests/OCRepresentationEncodingTest.cpp

index df8db7e..8caa729 100644 (file)
@@ -140,8 +140,10 @@ OCStackResult SetDeviceInfo()
         {
             .deviceName = "IoTivity/Zigbee Server Sample",
             .specVersion = "IoTivity/Zigbee Device Spec Version",
-            .dataModelVersion = "IoTivity/Zigbee Data Model Version",
         };
+    char *dmv = OICStrdup("IoTivity/Zigbee Data Model Version");
+    deviceInfo.dataModelVersions = (OCStringLL *)OICCalloc(1, sizeof(OCStringLL));
+    deviceInfo.dataModelVersions->value = dmv;
     char *dup = OICStrdup("oic.wk.d");
     deviceInfo.types = (OCStringLL *)OICCalloc(1, sizeof(OCStringLL));
     deviceInfo.types->value = dup;
index 7e4ed99..992adc8 100644 (file)
@@ -75,6 +75,7 @@ bool OCRepPayloadSetUri(OCRepPayload* payload, const char* uri);
 
 bool OCRepPayloadAddResourceType(OCRepPayload* payload, const char* resourceType);
 bool OCRepPayloadAddInterface(OCRepPayload* payload, const char* interface);
+bool OCRepPayloadAddModelVersion(OCRepPayload* payload, const char* dmv);
 
 bool OCRepPayloadAddResourceTypeAsOwner(OCRepPayload* payload, char* resourceType);
 bool OCRepPayloadAddInterfaceAsOwner(OCRepPayload* payload, char* interface);
@@ -258,6 +259,22 @@ void OCPresencePayloadDestroy(OCPresencePayload* payload);
 OCStringLL* CloneOCStringLL (OCStringLL* ll);
 void OCFreeOCStringLL(OCStringLL* ll);
 
+/**
+ * This function creates a list from a string (with separated contents if several)
+ * @param text         single string or CSV text fields
+ * @return newly allocated linked list
+ * @note separator is ',' (according to rfc4180) or ';'
+ **/
+OCStringLL* OCCreateOCStringLL(const char* text);
+
+/**
+ * This function creates a string from a list (with separated contents if several)
+ * @param ll           Pointer to list
+ * @return newly allocated string
+ * @note separator is ',' (according to rfc4180)
+ **/
+char* OCCreateString(const OCStringLL* ll);
+
 #ifdef __cplusplus
 }
 #endif
index e96a648..96b8177 100644 (file)
@@ -949,8 +949,8 @@ typedef struct
     OCStringLL *types;
     /** Pointer to the device specification version.*/
     char *specVersion;
-    /** Pointer to the device data model version.*/
-    char *dataModelVersion;
+    /** Pointer to the device data model versions (in CSV format).*/
+    OCStringLL *dataModelVersions;
 } OCDeviceInfo;
 
 #ifdef RA_ADAPTER
@@ -1239,7 +1239,7 @@ typedef struct
     char *sid;
     char* deviceName;
     char* specVersion;
-    char* dataModelVersion;
+    OCStringLL *dataModelVersions;
     OCStringLL *interfaces;
     OCStringLL *types;
 } OCDevicePayload;
index c518be6..14ca4b0 100644 (file)
@@ -236,7 +236,14 @@ static inline void OCPayloadLogDevice(LogLevel level, OCDevicePayload* payload)
     OIC_LOG_V(level, PL_TAG, "\tSID:%s", payload->sid);
     OIC_LOG_V(level, PL_TAG, "\tDevice Name:%s", payload->deviceName);
     OIC_LOG_V(level, PL_TAG, "\tSpec Version:%s", payload->specVersion);
-    OIC_LOG_V(level, PL_TAG, "\tData Model Version:%s", payload->dataModelVersion);
+    if (payload->dataModelVersions)
+    {
+        OIC_LOG(level, PL_TAG, "\tData Model Version:");
+        for (OCStringLL *strll = payload->dataModelVersions; strll; strll = strll->next)
+        {
+            OIC_LOG_V(level, PL_TAG, "\t\t%s", strll->value);
+        }
+    }
     if (payload->types)
     {
         OIC_LOG(level, PL_TAG, "\tResource Type:");
index abf908d..9a02020 100644 (file)
@@ -27,6 +27,7 @@
 #include <signal.h>
 #include <pthread.h>
 #include <array>
+#include "oic_malloc.h"
 #include "ocstack.h"
 #include "logger.h"
 #include "ocpayload.h"
@@ -75,7 +76,7 @@ const char *supportUrl = "mySupportUrl";
 const char *version = "myVersion";
 const char *systemTime = "2015-05-15T11.04";
 const char *specVersion = "myDeviceSpecVersion";
-const char* dataModelVersion = "myDeviceModelVersion";
+const char *dataModelVersions = "myDeviceModelVersions";
 
 // Entity handler should check for resourceTypeName and ResourceInterface in order to GET
 // the existence of a known resource
@@ -817,7 +818,7 @@ void DeleteDeviceInfo()
 {
     free (deviceInfo.deviceName);
     free (deviceInfo.specVersion);
-    free (deviceInfo.dataModelVersion);
+    OCFreeOCStringLL (deviceInfo.dataModelVersions);
 }
 
 bool DuplicateString(char** targetString, const char* sourceString)
@@ -921,7 +922,7 @@ OCStackResult SetPlatformInfo(const char* platformID, const char *manufacturerNa
     return OC_STACK_ERROR;
 }
 
-OCStackResult SetDeviceInfo(const char* deviceName, const char* specVersion, const char* dataModelVersion)
+OCStackResult SetDeviceInfo(const char* deviceName, const char* specVersion, const char* dataModelVersions)
 {
     if(!DuplicateString(&deviceInfo.deviceName, deviceName))
     {
@@ -931,7 +932,9 @@ OCStackResult SetDeviceInfo(const char* deviceName, const char* specVersion, con
     {
         return OC_STACK_ERROR;
     }
-    if(!DuplicateString(&deviceInfo.dataModelVersion, dataModelVersion))
+    OCFreeOCStringLL(deviceInfo.dataModelVersions);
+    deviceInfo.dataModelVersions = OCCreateOCStringLL(dataModelVersions);
+    if (!deviceInfo.dataModelVersions)
     {
         return OC_STACK_ERROR;
     }
@@ -1055,7 +1058,7 @@ int main(int argc, char* argv[])
         exit (EXIT_FAILURE);
     }
 
-    registrationResult = SetDeviceInfo(deviceName, specVersion, dataModelVersion);
+    registrationResult = SetDeviceInfo(deviceName, specVersion, dataModelVersions);
 
     if (registrationResult != OC_STACK_OK)
     {
index efac31e..b5fc0ca 100644 (file)
@@ -29,6 +29,7 @@
 #include <signal.h>
 #include <pthread.h>
 #include <array>
+#include "oic_malloc.h"
 #include "ocstack.h"
 #include "logger.h"
 #include "ocpayload.h"
@@ -77,7 +78,7 @@ const char *supportUrl = "mySupportUrl";
 const char *version = "myVersion";
 const char *systemTime = "2015-05-15T11.04";
 const char *specVersion = "myDeviceSpecVersion";
-const char* dataModelVersion = "myDeviceModelVersion";
+const char *dataModelVersions = "myDeviceModelVersions";
 
 // Entity handler should check for resourceTypeName and ResourceInterface in order to GET
 // the existence of a known resource
@@ -810,7 +811,7 @@ void DeleteDeviceInfo()
 {
     free (deviceInfo.deviceName);
     free (deviceInfo.specVersion);
-    free (deviceInfo.dataModelVersion);
+    OCFreeOCStringLL (deviceInfo.dataModelVersions);
 }
 
 bool DuplicateString(char** targetString, const char* sourceString)
@@ -914,7 +915,7 @@ OCStackResult SetPlatformInfo(const char* platformID, const char *manufacturerNa
     return OC_STACK_ERROR;
 }
 
-OCStackResult SetDeviceInfo(const char* deviceName, const char* specVersion, const char* dataModelVersion)
+OCStackResult SetDeviceInfo(const char* deviceName, const char* specVersion, const char* dataModelVersions)
 {
     if(!DuplicateString(&deviceInfo.deviceName, deviceName))
     {
@@ -924,7 +925,9 @@ OCStackResult SetDeviceInfo(const char* deviceName, const char* specVersion, con
     {
         return OC_STACK_ERROR;
     }
-    if(!DuplicateString(&deviceInfo.dataModelVersion, dataModelVersion))
+    OCFreeOCStringLL(deviceInfo.dataModelVersions);
+    deviceInfo.dataModelVersions = OCCreateOCStringLL(dataModelVersions);
+    if (!deviceInfo.dataModelVersions)
     {
         return OC_STACK_ERROR;
     }
@@ -1029,7 +1032,7 @@ int main(int argc, char* argv[])
         exit (EXIT_FAILURE);
     }
 
-    registrationResult = SetDeviceInfo(deviceName, specVersion, dataModelVersion);
+    registrationResult = SetDeviceInfo(deviceName, specVersion, dataModelVersions);
 
     if (registrationResult != OC_STACK_OK)
     {
index 7e559c1..5ec325e 100644 (file)
@@ -66,6 +66,7 @@ cp resource/oc_logger/include/targets/oc_ostream_logger.h %{DEST_INC_DIR}
 cp resource/csdk/stack/include/ocpresence.h %{DEST_INC_DIR}
 cp resource/csdk/stack/include/ocpayload.h %{DEST_INC_DIR}
 cp resource/c_common/platform_features.h %{DEST_INC_DIR}
+cp resource/c_common/*/include/*.h %{DEST_INC_DIR}
 cp resource/csdk/stack/include/payload_logging.h %{DEST_INC_DIR}
 cp resource/csdk/stack/include/rdpayload.h %{DEST_INC_DIR}
 cp extlibs/tinycbor/tinycbor/src/cbor.h %{DEST_INC_DIR}
index da35c63..eef8c3e 100644 (file)
 //
 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 
+// Required for strok_r
+#define _POSIX_C_SOURCE 200112L
 
+#include <stdio.h>
 #include "ocpayload.h"
 #include "octypes.h"
 #include <string.h>
@@ -30,6 +33,8 @@
 #include "rdpayload.h"
 
 #define TAG "OIC_RI_PAYLOAD"
+#define CSV_SEPARATOR ','
+#define CSV_SEPARATORS ",;"
 
 static void OCFreeRepPayloadValueContents(OCRepPayloadValue* val);
 
@@ -1281,6 +1286,82 @@ OCStringLL* CloneOCStringLL (OCStringLL* ll)
     return headOfClone;
 }
 
+OCStringLL* OCCreateOCStringLL(const char* text)
+{
+    char *token = NULL;
+    char *head = NULL;
+    char *tail = NULL;
+    char *backup  = NULL;
+    OCStringLL* result = NULL;
+    OCStringLL* iter = NULL;
+    OCStringLL* prev = NULL;
+
+    VERIFY_PARAM_NON_NULL(TAG, text, "Invalid parameter");
+    backup = OICStrdup(text);
+    VERIFY_PARAM_NON_NULL(TAG, backup, "Failed allocating memory");
+    for (head = backup; ; head = NULL)
+    {
+        token = (char *) strtok_r(head, CSV_SEPARATORS, &tail);
+        if (!token) break;
+        iter = (OCStringLL *)OICCalloc(1,sizeof(OCStringLL));
+        VERIFY_PARAM_NON_NULL(TAG, iter, "Failed allocating memory");
+        if (!result)
+        {
+             result = iter;
+        }
+        else
+        {
+             prev->next = iter;
+        }
+        iter->value = OICStrdup(token);
+        VERIFY_PARAM_NON_NULL(TAG, iter->value, "Failed allocating memory");
+        prev = iter;
+        iter = iter->next;
+    }
+    OICFree(backup);
+    return result;
+
+exit:
+    OICFree(backup);
+    OCFreeOCStringLL(result);
+    return NULL;
+}
+
+char* OCCreateString(const OCStringLL* ll)
+{
+    char *str = NULL;
+    char *pos = NULL;
+    size_t len = 0;
+    size_t sublen = 0;
+    int count = 0;
+
+    if (!ll) return NULL;
+
+    for (const OCStringLL *it = ll; it ; it = it->next )
+    {
+        len += strlen(it->value) + 1;
+    }
+    str = (char*) malloc(len + 1);
+    if (!str)
+        return NULL;
+
+    pos = str;
+    for (const OCStringLL *it = ll; it ; it = it->next )
+    {
+        sublen = strlen(it->value) + 1;
+        count = snprintf(pos, len + 1, "%s%c", it->value, CSV_SEPARATOR);
+        if (count<sublen)
+        {
+            free(str);
+            return NULL;
+        }
+        len-=sublen;
+        pos+=count;
+    }
+
+    return str;
+}
+
 OCRepPayload* OCRepPayloadClone (const OCRepPayload* payload)
 {
     if (!payload)
@@ -1627,8 +1708,8 @@ OCDevicePayload* OCDevicePayloadCreate(const char* sid, const char* dname,
         goto exit;
     }
 
-    payload->dataModelVersion = OICStrdup(dmVer);
-    if (dmVer && !payload->dataModelVersion)
+    payload->dataModelVersions = OCCreateOCStringLL(dmVer);
+    if (!payload->dataModelVersions || (dmVer && !payload->dataModelVersions->value))
     {
         goto exit;
     }
@@ -1659,7 +1740,7 @@ void OCDevicePayloadDestroy(OCDevicePayload* payload)
     OICFree(payload->sid);
     OICFree(payload->deviceName);
     OICFree(payload->specVersion);
-    OICFree(payload->dataModelVersion);
+    OCFreeOCStringLL(payload->dataModelVersions);
     OCFreeOCStringLL(payload->types);
     OCFreeOCStringLL(payload->interfaces);
     OICFree(payload);
index bcaa283..5ee09cc 100644 (file)
@@ -425,10 +425,16 @@ static int64_t OCConvertDevicePayload(OCDevicePayload *payload, uint8_t *outPayl
             sizeof(OC_RSRVD_SPEC_VERSION) - 1, payload->specVersion);
     VERIFY_CBOR_SUCCESS(TAG, err, "Failed adding data spec version");
 
-    // Device data Model Version
-    err |= ConditionalAddTextStringToMap(&repMap, OC_RSRVD_DATA_MODEL_VERSION,
-            sizeof(OC_RSRVD_DATA_MODEL_VERSION) - 1, payload->dataModelVersion);
-    VERIFY_CBOR_SUCCESS(TAG, err, "Failed adding data model version");
+    // Device data Model Versions
+    if (payload->dataModelVersions)
+    {
+        OIC_LOG(INFO, TAG, "Payload has data models versions");
+        char *str = OCCreateString(payload->dataModelVersions);
+        err |= ConditionalAddTextStringToMap(&repMap, OC_RSRVD_DATA_MODEL_VERSION,
+                sizeof(OC_RSRVD_DATA_MODEL_VERSION) - 1, str);
+        OICFree(str);
+        VERIFY_CBOR_SUCCESS(TAG, err, "Failed adding data model version");
+    }
 
     err |= cbor_encoder_close_container(&encoder, &repMap);
     VERIFY_CBOR_SUCCESS(TAG, err, "Failed closing device map");
index 8b684a6..ea2d484 100755 (executable)
@@ -444,13 +444,17 @@ static OCStackResult OCParseDevicePayload(OCPayload **outPayload, CborValue *roo
             err = cbor_value_dup_text_string(&curVal, &out->specVersion, &len, NULL);
             VERIFY_CBOR_SUCCESS(TAG, err, "to find spec version in device payload");
         }
-        // Data Model Version
+        // Data Model Versions
         err = cbor_value_map_find_value(rootValue, OC_RSRVD_DATA_MODEL_VERSION, &curVal);
-        VERIFY_CBOR_SUCCESS(TAG, err, "to find data model ver tag");
+        VERIFY_CBOR_SUCCESS(TAG, err, "to find data model versions tag");
         if (cbor_value_is_valid(&curVal))
         {
-            err = cbor_value_dup_text_string(&curVal, &out->dataModelVersion, &len, NULL);
-            VERIFY_CBOR_SUCCESS(TAG, err, "to find data model version in device payload");
+            size_t len = 0;
+            char * str = NULL;
+            err = cbor_value_dup_text_string(&curVal, &str, &len, NULL);
+            VERIFY_CBOR_SUCCESS(TAG, err, "to find data model versions in device payload");
+            out->dataModelVersions = OCCreateOCStringLL(str);
+            OICFree(str);
         }
         err = cbor_value_advance(rootValue);
         VERIFY_CBOR_SUCCESS(TAG, err, "to advance device payload");
index 469ee2c..c51ac9e 100755 (executable)
@@ -864,15 +864,24 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource
         }
         else
         {
-            payload = (OCPayload*) OCDevicePayloadCreate(deviceId, savedDeviceInfo.deviceName,
-                savedDeviceInfo.types, savedDeviceInfo.specVersion, savedDeviceInfo.dataModelVersion);
-            if (!payload)
+            char *dataModelVersions = OCCreateString(savedDeviceInfo.dataModelVersions);
+            if (!dataModelVersions)
             {
                 discoveryResult = OC_STACK_NO_MEMORY;
             }
             else
             {
-                discoveryResult = OC_STACK_OK;
+                payload = (OCPayload*) OCDevicePayloadCreate(deviceId, savedDeviceInfo.deviceName,
+                    savedDeviceInfo.types, savedDeviceInfo.specVersion, dataModelVersions);
+                if (!payload)
+                {
+                     discoveryResult = OC_STACK_NO_MEMORY;
+                }
+                else
+                {
+                     discoveryResult = OC_STACK_OK;
+                }
+                OICFree(dataModelVersions);
             }
         }
     }
@@ -1341,10 +1350,10 @@ void DeleteDeviceInfo()
     OICFree(savedDeviceInfo.deviceName);
     OCFreeOCStringLL(savedDeviceInfo.types);
     OICFree(savedDeviceInfo.specVersion);
-    OICFree(savedDeviceInfo.dataModelVersion);
+    OCFreeOCStringLL(savedDeviceInfo.dataModelVersions);
     savedDeviceInfo.deviceName = NULL;
     savedDeviceInfo.specVersion = NULL;
-    savedDeviceInfo.dataModelVersion = NULL;
+    savedDeviceInfo.dataModelVersions = NULL;
 }
 
 static OCStackResult DeepCopyDeviceInfo(OCDeviceInfo info)
@@ -1386,10 +1395,10 @@ static OCStackResult DeepCopyDeviceInfo(OCDeviceInfo info)
         }
     }
 
-    if (info.dataModelVersion)
+    if (info.dataModelVersions)
     {
-        savedDeviceInfo.dataModelVersion = OICStrdup(info.dataModelVersion);
-        if(!savedDeviceInfo.dataModelVersion && info.dataModelVersion)
+        savedDeviceInfo.dataModelVersions = CloneOCStringLL(info.dataModelVersions);
+        if(!savedDeviceInfo.dataModelVersions && info.dataModelVersions)
         {
             DeleteDeviceInfo();
             return OC_STACK_NO_MEMORY;
@@ -1397,8 +1406,13 @@ static OCStackResult DeepCopyDeviceInfo(OCDeviceInfo info)
     }
     else
     {
-        savedDeviceInfo.dataModelVersion = OICStrdup(OC_DATA_MODEL_VERSION);
-        if(!savedDeviceInfo.dataModelVersion && OC_DATA_MODEL_VERSION)
+        savedDeviceInfo.dataModelVersions = (OCStringLL *)OICCalloc(1,sizeof(OCStringLL));
+        if (!savedDeviceInfo.dataModelVersions)
+        {
+            return OC_STACK_NO_MEMORY;
+        }
+        savedDeviceInfo.dataModelVersions->value = OICStrdup(OC_DATA_MODEL_VERSION);
+        if(!savedDeviceInfo.dataModelVersions->value && OC_DATA_MODEL_VERSION)
         {
             DeleteDeviceInfo();
             return OC_STACK_NO_MEMORY;
index e97a8bf..dba1515 100644 (file)
@@ -49,7 +49,7 @@ std::string systemTime = "mySystemTime";
 //Set of strings for each of device info fields
 std::string deviceName = "Bill's Battlestar";
 std::string specVersion = "myDeviceSpecVersion";
-std::string dataModelVersion = "myDeviceModelVersion";
+std::string dataModelVersions = "myDeviceModelVersion";
 
 //OCPlatformInfo Contains all the platform info to be stored
 OCPlatformInfo platformInfo;
@@ -77,7 +77,7 @@ void DeleteDeviceInfo()
 {
     delete[] deviceInfo.deviceName;
     delete[] deviceInfo.specVersion;
-    delete[] deviceInfo.dataModelVersion;
+    OCFreeOCStringLL(deviceInfo.dataModelVersions);
 }
 
 void DuplicateString(char ** targetString, std::string sourceString)
@@ -106,15 +106,15 @@ OCStackResult SetPlatformInfo(std::string platformID, std::string manufacturerNa
 }
 
 
-OCStackResult SetDeviceInfo(std::string deviceName, std::string specVersion, std::string dataModelVersion)
+OCStackResult SetDeviceInfo(std::string deviceName, std::string specVersion, std::string dataModelVersions)
 {
     DuplicateString(&deviceInfo.deviceName, deviceName);
 
     if (!specVersion.empty())
         DuplicateString(&deviceInfo.specVersion, specVersion);
 
-    if (!dataModelVersion.empty())
-        DuplicateString(&deviceInfo.dataModelVersion, dataModelVersion);
+    if (!dataModelVersions.empty())
+        OCResourcePayloadAddStringLL(&deviceInfo.dataModelVersions, dataModelVersions.c_str());
 
     return OC_STACK_OK;
 }
@@ -148,7 +148,7 @@ int main()
     }
 
 
-    result = SetDeviceInfo(deviceName, specVersion, dataModelVersion);
+    result = SetDeviceInfo(deviceName, specVersion, dataModelVersions);
     OCResourcePayloadAddStringLL(&deviceInfo.types, "oic.wk.d");
     OCResourcePayloadAddStringLL(&deviceInfo.types, "oic.d.tv");
 
index 4a18fe7..e66719b 100644 (file)
@@ -131,6 +131,8 @@ namespace OC
 
             const std::vector<std::string>& getResourceTypes() const;
 
+            const std::vector<std::string>& getDataModelVersions() const;
+
             void setResourceTypes(const std::vector<std::string>& resourceTypes);
 
             void addResourceType(const std::string& str);
@@ -141,6 +143,8 @@ namespace OC
 
             void addResourceInterface(const std::string& str);
 
+            void addDataModelVersion(const std::string& str);
+
             bool emptyData() const;
 
             int numberOfAttributes() const;
@@ -456,6 +460,7 @@ namespace OC
             mutable std::map<std::string, AttributeValue> m_values;
             std::vector<std::string> m_resourceTypes;
             std::vector<std::string> m_interfaces;
+            std::vector<std::string> m_dataModelVersions;
 
             InterfaceType m_interfaceType;
     };
index f0e8dca..68a14fc 100644 (file)
@@ -82,9 +82,10 @@ namespace OC
         rep[OC_RSRVD_SPEC_VERSION] = payload->specVersion ?
             std::string(payload->specVersion) :
             std::string();
-        rep[OC_RSRVD_DATA_MODEL_VERSION] = payload->dataModelVersion ?
-            std::string(payload->dataModelVersion) :
-            std::string();
+        for (OCStringLL *strll = payload->dataModelVersions; strll; strll = strll->next)
+        {
+            rep.addDataModelVersion(strll->value);
+        }
         for (OCStringLL *strll = payload->types; strll; strll = strll->next)
         {
            rep.addResourceType(strll->value);
@@ -755,6 +756,16 @@ namespace OC
         m_interfaces = resourceInterfaces;
     }
 
+    const std::vector<std::string>& OCRepresentation::getDataModelVersions() const
+    {
+        return m_dataModelVersions;
+    }
+
+    void OCRepresentation::addDataModelVersion(const std::string& str)
+    {
+        m_dataModelVersions.push_back(str);
+    }
+
     bool OCRepresentation::hasAttribute(const std::string& str) const
     {
         return m_values.find(str) != m_values.end();
@@ -775,7 +786,8 @@ namespace OC
         else if ((m_interfaceType == InterfaceType::None
                         || m_interfaceType==InterfaceType::DefaultChild
                         || m_interfaceType==InterfaceType::LinkChild)
-                    && (m_resourceTypes.size()>0 || m_interfaces.size()>0))
+                    && (m_resourceTypes.size()>0 || m_interfaces.size()>0
+                        || m_dataModelVersions.size()>0))
         {
             return false;
         }
index 9855686..d5aad2e 100644 (file)
@@ -88,7 +88,7 @@ namespace OCPlatformTest
         delete[] deviceInfo.deviceName;
         DeleteStringLL(deviceInfo.types);
         delete[] deviceInfo.specVersion;
-        delete[] deviceInfo.dataModelVersion;
+        DeleteStringLL(deviceInfo.dataModelVersions);
     }
 
     void DuplicateString(char ** targetString, std::string sourceString)
@@ -750,7 +750,8 @@ namespace OCPlatformTest
         OCResourcePayloadAddStringLL(&deviceInfo.types, "oic.wk.d");
         OCResourcePayloadAddStringLL(&deviceInfo.types, "oic.d.tv");
         DuplicateString(&deviceInfo.specVersion, "mySpecVersion");
-        DuplicateString(&deviceInfo.dataModelVersion, "myDataModelVersion");
+        deviceInfo.dataModelVersions = nullptr;
+        OCResourcePayloadAddStringLL(&deviceInfo.dataModelVersions, "myDataModelVersions");
         EXPECT_EQ(OC_STACK_OK, OCPlatform::registerDeviceInfo(deviceInfo));
         EXPECT_NO_THROW(DeleteDeviceInfo(deviceInfo));
     }
index 6e41e8f..00a7c06 100644 (file)
@@ -52,7 +52,7 @@ namespace OCRepresentationEncodingTest
     static const char sid1[] = "646F6F72-4465-7669-6365-555549443030";
     static const char devicename1[] = "device name";
     static const char specver1[] = "spec version";
-    static const char dmver1[] = "data model version";
+    static const char dmver1[] = "one-1,two-2";
     static OCStringLL *types = NULL;
     // Device Payloads
     TEST(DeviceDiscoveryEncoding, Normal)
@@ -66,10 +66,14 @@ namespace OCRepresentationEncodingTest
                 types,
                 specver1,
                 dmver1);
+        EXPECT_TRUE(device);
         EXPECT_STREQ(sid1, device->sid);
         EXPECT_STREQ(devicename1, device->deviceName);
         EXPECT_STREQ(specver1, device->specVersion);
-        EXPECT_STREQ(dmver1, device->dataModelVersion);
+        EXPECT_TRUE(device->dataModelVersions);
+        EXPECT_STREQ("one-1", device->dataModelVersions->value);
+        EXPECT_TRUE(device->dataModelVersions->next);
+        EXPECT_STREQ("two-2", device->dataModelVersions->next->value);
         EXPECT_EQ(PAYLOAD_TYPE_DEVICE, ((OCPayload*)device)->type);
         EXPECT_STREQ("oic.wk.d", device->types->value);
         EXPECT_STREQ("oic.d.tv", device->types->next->value);
@@ -85,7 +89,7 @@ namespace OCRepresentationEncodingTest
         EXPECT_STREQ(device->sid, ((OCDevicePayload*)parsedDevice)->sid);
         EXPECT_STREQ(device->deviceName, ((OCDevicePayload*)parsedDevice)->deviceName);
         EXPECT_STREQ(device->specVersion, ((OCDevicePayload*)parsedDevice)->specVersion);
-        EXPECT_STREQ(device->dataModelVersion, ((OCDevicePayload*)parsedDevice)->dataModelVersion);
+        EXPECT_STREQ(device->dataModelVersions->value, ((OCDevicePayload*)parsedDevice)->dataModelVersions->value);
         EXPECT_STREQ("oic.wk.d", ((OCDevicePayload*)parsedDevice)->types->value);
         EXPECT_STREQ("oic.d.tv", ((OCDevicePayload*)parsedDevice)->types->next->value);
         EXPECT_EQ(device->base.type, ((OCDevicePayload*)parsedDevice)->base.type);
@@ -99,7 +103,8 @@ namespace OCRepresentationEncodingTest
         EXPECT_STREQ(sid1, r.getValue<std::string>(OC_RSRVD_DEVICE_ID).c_str());
         EXPECT_STREQ(devicename1, r.getValue<std::string>(OC_RSRVD_DEVICE_NAME).c_str());
         EXPECT_STREQ(specver1, r.getValue<std::string>(OC_RSRVD_SPEC_VERSION).c_str());
-        EXPECT_STREQ(dmver1, r.getValue<std::string>(OC_RSRVD_DATA_MODEL_VERSION).c_str());
+        EXPECT_STREQ("one-1", r.getDataModelVersions()[0].c_str());
+        EXPECT_STREQ("two-2", r.getDataModelVersions()[1].c_str());
 
         OCPayloadDestroy(parsedDevice);
     }