ocpayload: Supports multiple data model versions (DMV) using CSV
[platform/upstream/iotivity.git] / resource / src / OCRepresentation.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 /**
22  * @file
23  *
24  * This file contains the implementation of classes and its members related
25  * to OCRepresentation.
26  */
27
28
29 #include <OCRepresentation.h>
30
31 #include <boost/lexical_cast.hpp>
32 #include <algorithm>
33 #include "ocpayload.h"
34 #include "ocrandom.h"
35 #include "oic_malloc.h"
36 #include "oic_string.h"
37
38 namespace OC
39 {
40     static const char COAP[] = "coap://";
41     static const char COAPS[] = "coaps://";
42     static const char COAP_TCP[] = "coap+tcp://";
43
44     void MessageContainer::setPayload(const OCPayload* rep)
45     {
46         if (rep == nullptr)
47         {
48             return;
49         }
50
51         switch(rep->type)
52         {
53             case PAYLOAD_TYPE_REPRESENTATION:
54                 setPayload(reinterpret_cast<const OCRepPayload*>(rep));
55                 break;
56             case PAYLOAD_TYPE_DEVICE:
57                 setPayload(reinterpret_cast<const OCDevicePayload*>(rep));
58                 break;
59             case PAYLOAD_TYPE_PLATFORM:
60                 setPayload(reinterpret_cast<const OCPlatformPayload*>(rep));
61                 break;
62             default:
63                 throw OC::OCException("Invalid Payload type in setPayload");
64                 break;
65         }
66     }
67
68     void MessageContainer::setPayload(const OCDevicePayload* payload)
69     {
70         if (payload == nullptr)
71         {
72             return;
73         }
74
75         OCRepresentation rep;
76         rep[OC_RSRVD_DEVICE_ID] = (payload->sid) ?
77             std::string(payload->sid) :
78             std::string();
79         rep[OC_RSRVD_DEVICE_NAME] = payload->deviceName ?
80             std::string(payload->deviceName) :
81             std::string();
82         rep[OC_RSRVD_SPEC_VERSION] = payload->specVersion ?
83             std::string(payload->specVersion) :
84             std::string();
85         for (OCStringLL *strll = payload->dataModelVersions; strll; strll = strll->next)
86         {
87             rep.addDataModelVersion(strll->value);
88         }
89         for (OCStringLL *strll = payload->types; strll; strll = strll->next)
90         {
91            rep.addResourceType(strll->value);
92         }
93         m_reps.push_back(std::move(rep));
94     }
95
96     void MessageContainer::setPayload(const OCPlatformPayload* payload)
97     {
98         if (payload == nullptr)
99         {
100             return;
101         }
102
103         OCRepresentation rep;
104         rep[OC_RSRVD_PLATFORM_ID] = payload->info.platformID ?
105             std::string(payload->info.platformID) :
106             std::string();
107         rep[OC_RSRVD_MFG_NAME] = payload->info.manufacturerName ?
108             std::string(payload->info.manufacturerName) :
109             std::string();
110         rep[OC_RSRVD_MFG_URL] = payload->info.manufacturerUrl ?
111             std::string(payload->info.manufacturerUrl) :
112             std::string();
113         rep[OC_RSRVD_MODEL_NUM] = payload->info.modelNumber ?
114             std::string(payload->info.modelNumber) :
115             std::string();
116         rep[OC_RSRVD_MFG_DATE] = payload->info.dateOfManufacture ?
117             std::string(payload->info.dateOfManufacture) :
118             std::string();
119         rep[OC_RSRVD_PLATFORM_VERSION] = payload->info.platformVersion ?
120             std::string(payload->info.platformVersion) :
121             std::string();
122         rep[OC_RSRVD_OS_VERSION] = payload->info.operatingSystemVersion ?
123             std::string(payload->info.operatingSystemVersion) :
124             std::string();
125         rep[OC_RSRVD_HARDWARE_VERSION] = payload->info.hardwareVersion ?
126             std::string(payload->info.hardwareVersion) :
127             std::string();
128         rep[OC_RSRVD_FIRMWARE_VERSION] = payload->info.firmwareVersion ?
129             std::string(payload->info.firmwareVersion) :
130             std::string();
131         rep[OC_RSRVD_SUPPORT_URL] = payload->info.supportUrl ?
132             std::string(payload->info.supportUrl) :
133             std::string();
134         rep[OC_RSRVD_SYSTEM_TIME] = payload->info.systemTime ?
135             std::string(payload->info.systemTime) :
136             std::string();
137
138         for (OCStringLL *strll = payload->rt; strll; strll = strll->next)
139         {
140             rep.addResourceType(strll->value);
141         }
142         for (OCStringLL *strll = payload->interfaces; strll; strll = strll->next)
143         {
144             rep.addResourceInterface(strll->value);
145         }
146
147         m_reps.push_back(std::move(rep));
148     }
149
150     void MessageContainer::setPayload(const OCRepPayload* payload)
151     {
152         const OCRepPayload* pl = payload;
153         while(pl)
154         {
155             OCRepresentation cur;
156             cur.setPayload(pl);
157
158             pl = pl->next;
159             this->addRepresentation(cur);
160         }
161     }
162
163     OCRepPayload* MessageContainer::getPayload() const
164     {
165         OCRepPayload* root = nullptr;
166         for(const auto& r : representations())
167         {
168             if (!root)
169             {
170                 root = r.getPayload();
171             }
172             else
173             {
174                 OCRepPayloadAppend(root, r.getPayload());
175             }
176         }
177
178         return root;
179     }
180
181     const std::vector<OCRepresentation>& MessageContainer::representations() const
182     {
183         return m_reps;
184     }
185
186     void MessageContainer::addRepresentation(const OCRepresentation& rep)
187     {
188         m_reps.push_back(rep);
189     }
190 }
191
192 namespace OC
193 {
194     struct get_payload_array: boost::static_visitor<>
195     {
196         template<typename T>
197         void operator()(T& /*arr*/)
198         {
199             throw std::logic_error("Invalid calc_dimensions_visitor type");
200         }
201
202         template<typename T>
203         void operator()(std::vector<T>& arr)
204         {
205             root_size_calc<T>();
206             dimensions[0] = arr.size();
207             dimensions[1] = 0;
208             dimensions[2] = 0;
209             dimTotal = calcDimTotal(dimensions);
210
211             array = (void*)OICMalloc(dimTotal * root_size);
212
213             for(size_t i = 0; i < dimensions[0]; ++i)
214             {
215                 copy_to_array(arr[i], array, i);
216             }
217
218         }
219         template<typename T>
220         void operator()(std::vector<std::vector<T>>& arr)
221         {
222             root_size_calc<T>();
223             dimensions[0] = arr.size();
224             dimensions[1] = 0;
225             dimensions[2] = 0;
226             for(size_t i = 0; i < arr.size(); ++i)
227             {
228                 dimensions[1] = std::max(dimensions[1], arr[i].size());
229             }
230             dimTotal = calcDimTotal(dimensions);
231             array = (void*)OICCalloc(1, dimTotal * root_size);
232
233             for(size_t i = 0; i < dimensions[0]; ++i)
234             {
235                 for(size_t j = 0; j < dimensions[1] && j < arr[i].size(); ++j)
236                 {
237                     copy_to_array(arr[i][j], array, i*dimensions[1] + j);
238                 }
239             }
240         }
241         template<typename T>
242         void operator()(std::vector<std::vector<std::vector<T>>>& arr)
243         {
244             root_size_calc<T>();
245             dimensions[0] = arr.size();
246             dimensions[1] = 0;
247             dimensions[2] = 0;
248             for(size_t i = 0; i < arr.size(); ++i)
249             {
250                 dimensions[1] = std::max(dimensions[1], arr[i].size());
251
252                 for(size_t j = 0; j < arr[i].size(); ++j)
253                 {
254                     dimensions[2] = std::max(dimensions[2], arr[i][j].size());
255                 }
256             }
257
258             dimTotal = calcDimTotal(dimensions);
259             array = (void*)OICCalloc(1, dimTotal * root_size);
260
261             for(size_t i = 0; i < dimensions[0]; ++i)
262             {
263                 for(size_t j = 0; j < dimensions[1] && j < arr[i].size(); ++j)
264                 {
265                     for(size_t k = 0; k < dimensions[2] && k < arr[i][j].size(); ++k)
266                     {
267                         copy_to_array(arr[i][j][k], array,
268                                 dimensions[2] * j +
269                                 dimensions[2] * dimensions[1] * i +
270                                 k);
271                     }
272                 }
273             }
274         }
275
276         template<typename T>
277         void root_size_calc()
278         {
279             root_size = sizeof(T);
280         }
281
282         template<typename T>
283         void copy_to_array(T item, void* array, size_t pos)
284         {
285             ((T*)array)[pos] = item;
286         }
287
288         size_t dimensions[MAX_REP_ARRAY_DEPTH];
289         size_t root_size;
290         size_t dimTotal;
291         void* array;
292     };
293
294     template<>
295     void get_payload_array::root_size_calc<int>()
296     {
297         root_size = sizeof(int64_t);
298     }
299
300     template<>
301     void get_payload_array::root_size_calc<std::string>()
302     {
303         root_size = sizeof(char*);
304     }
305
306     template<>
307     void get_payload_array::root_size_calc<OC::OCRepresentation>()
308     {
309         root_size = sizeof(OCRepPayload*);
310     }
311
312     template<>
313     void get_payload_array::copy_to_array(int item, void* array, size_t pos)
314     {
315         ((int64_t*)array)[pos] = item;
316     }
317
318     template<>
319     void get_payload_array::copy_to_array(std::_Bit_reference br, void* array, size_t pos)
320     {
321         ((bool*)array)[pos] = static_cast<bool>(br);
322     }
323
324     template<>
325     void get_payload_array::copy_to_array(std::string item, void* array, size_t pos)
326     {
327         ((char**)array)[pos] = OICStrdup(item.c_str());
328     }
329
330     template<>
331     void get_payload_array::copy_to_array(std::string& item, void* array, size_t pos)
332     {
333         ((char**)array)[pos] = OICStrdup(item.c_str());
334     }
335
336     template<>
337     void get_payload_array::copy_to_array(const std::string& item, void* array, size_t pos)
338     {
339         ((char**)array)[pos] = OICStrdup(item.c_str());
340     }
341
342     template<>
343     void get_payload_array::copy_to_array(OC::OCRepresentation item, void* array, size_t pos)
344     {
345         ((OCRepPayload**)array)[pos] = item.getPayload();
346     }
347
348     void OCRepresentation::getPayloadArray(OCRepPayload* payload,
349                     const OCRepresentation::AttributeItem& item) const
350     {
351         get_payload_array vis{};
352         boost::apply_visitor(vis, m_values[item.attrname()]);
353
354
355         switch(item.base_type())
356         {
357             case AttributeType::Integer:
358                 OCRepPayloadSetIntArrayAsOwner(payload, item.attrname().c_str(),
359                         (int64_t*)vis.array,
360                         vis.dimensions);
361                 break;
362             case AttributeType::Double:
363                 OCRepPayloadSetDoubleArrayAsOwner(payload, item.attrname().c_str(),
364                         (double*)vis.array,
365                         vis.dimensions);
366                 break;
367             case AttributeType::Boolean:
368                 OCRepPayloadSetBoolArrayAsOwner(payload, item.attrname().c_str(),
369                         (bool*)vis.array,
370                         vis.dimensions);
371                 break;
372             case AttributeType::String:
373                 OCRepPayloadSetStringArrayAsOwner(payload, item.attrname().c_str(),
374                         (char**)vis.array,
375                         vis.dimensions);
376                 break;
377             case AttributeType::OCRepresentation:
378                 OCRepPayloadSetPropObjectArrayAsOwner(payload, item.attrname().c_str(),
379                         (OCRepPayload**)vis.array, vis.dimensions);
380                 break;
381             default:
382                 throw std::logic_error(std::string("GetPayloadArray: Not Implemented") +
383                         std::to_string((int)item.base_type()));
384         }
385     }
386
387     OCRepPayload* OCRepresentation::getPayload() const
388     {
389         OCRepPayload* root = OCRepPayloadCreate();
390         if (!root)
391         {
392             throw std::bad_alloc();
393         }
394
395         OCRepPayloadSetUri(root, getUri().c_str());
396
397         for(const std::string& type : getResourceTypes())
398         {
399             OCRepPayloadAddResourceType(root, type.c_str());
400         }
401
402         for(const std::string& iface : getResourceInterfaces())
403         {
404             OCRepPayloadAddInterface(root, iface.c_str());
405         }
406
407         for(auto& val : *this)
408         {
409             switch(val.type())
410             {
411                 case AttributeType::Null:
412                     OCRepPayloadSetNull(root, val.attrname().c_str());
413                     break;
414                 case AttributeType::Integer:
415                     OCRepPayloadSetPropInt(root, val.attrname().c_str(), static_cast<int>(val));
416                     break;
417                 case AttributeType::Double:
418                     OCRepPayloadSetPropDouble(root, val.attrname().c_str(),
419                             val.getValue<double>());
420                     break;
421                 case AttributeType::Boolean:
422                     OCRepPayloadSetPropBool(root, val.attrname().c_str(), val.getValue<bool>());
423                     break;
424                 case AttributeType::String:
425                     OCRepPayloadSetPropString(root, val.attrname().c_str(),
426                             static_cast<std::string>(val).c_str());
427                     break;
428                 case AttributeType::OCRepresentation:
429                     OCRepPayloadSetPropObjectAsOwner(root, val.attrname().c_str(),
430                             static_cast<OCRepresentation>(val).getPayload());
431                     break;
432                 case AttributeType::Vector:
433                     getPayloadArray(root, val);
434                     break;
435                 case AttributeType::Binary:
436                     OCRepPayloadSetPropByteString(root, val.attrname().c_str(),
437                             OCByteString{const_cast<uint8_t*>(val.getValue<std::vector<uint8_t>>().data()),
438                             val.getValue<std::vector<uint8_t>>().size()});
439                     break;
440                 default:
441                     throw std::logic_error(std::string("Getpayload: Not Implemented") +
442                             std::to_string((int)val.type()));
443                     break;
444             }
445         }
446
447         return root;
448     }
449
450     size_t calcArrayDepth(const size_t dimensions[MAX_REP_ARRAY_DEPTH])
451     {
452         if (dimensions[0] == 0)
453         {
454             throw std::logic_error("invalid calcArrayDepth");
455         }
456         else if (dimensions[1] == 0)
457         {
458             return 1;
459         }
460         else if (dimensions[2] == 0)
461         {
462             return 2;
463         }
464         else
465         {
466             return 3;
467         }
468     }
469
470     template<typename T>
471     T OCRepresentation::payload_array_helper_copy(size_t index, const OCRepPayloadValue* pl)
472     {
473         throw std::logic_error("payload_array_helper_copy: unsupported type");
474     }
475     template<>
476     int OCRepresentation::payload_array_helper_copy<int>(size_t index, const OCRepPayloadValue* pl)
477     {
478         return pl->arr.iArray[index];
479     }
480     template<>
481     double OCRepresentation::payload_array_helper_copy<double>(size_t index, const OCRepPayloadValue* pl)
482     {
483         return pl->arr.dArray[index];
484     }
485     template<>
486     bool OCRepresentation::payload_array_helper_copy<bool>(size_t index, const OCRepPayloadValue* pl)
487     {
488         return pl->arr.bArray[index];
489     }
490     template<>
491     std::string OCRepresentation::payload_array_helper_copy<std::string>(
492             size_t index, const OCRepPayloadValue* pl)
493     {
494         if (pl->arr.strArray[index])
495         {
496             return std::string(pl->arr.strArray[index]);
497         }
498         else
499         {
500             return std::string{};
501         }
502     }
503     template<>
504     OCRepresentation OCRepresentation::payload_array_helper_copy<OCRepresentation>(
505             size_t index, const OCRepPayloadValue* pl)
506     {
507         OCRepresentation r;
508         if (pl->arr.objArray[index])
509         {
510             r.setPayload(pl->arr.objArray[index]);
511         }
512         return r;
513     }
514
515     template<typename T>
516     void OCRepresentation::payload_array_helper(const OCRepPayloadValue* pl, size_t depth)
517     {
518         if (depth == 1)
519         {
520             std::vector<T> val(pl->arr.dimensions[0]);
521
522             for(size_t i = 0; i < pl->arr.dimensions[0]; ++i)
523             {
524                 val[i] = payload_array_helper_copy<T>(i, pl);
525             }
526             this->setValue(std::string(pl->name), val);
527         }
528         else if (depth == 2)
529         {
530             std::vector<std::vector<T>> val(pl->arr.dimensions[0]);
531             for(size_t i = 0; i < pl->arr.dimensions[0]; ++i)
532             {
533                 val[i].resize(pl->arr.dimensions[1]);
534                 for(size_t j = 0; j < pl->arr.dimensions[1]; ++j)
535                 {
536                     val[i][j] = payload_array_helper_copy<T>(
537                             i * pl->arr.dimensions[1] + j, pl);
538                 }
539             }
540             this->setValue(std::string(pl->name), val);
541         }
542         else if (depth == 3)
543         {
544             std::vector<std::vector<std::vector<T>>> val(pl->arr.dimensions[0]);
545             for(size_t i = 0; i < pl->arr.dimensions[0]; ++i)
546             {
547                 val[i].resize(pl->arr.dimensions[1]);
548                 for(size_t j = 0; j < pl->arr.dimensions[1]; ++j)
549                 {
550                     val[i][j].resize(pl->arr.dimensions[2]);
551                     for(size_t k = 0; k < pl->arr.dimensions[2]; ++k)
552                     {
553                         val[i][j][k] = payload_array_helper_copy<T>(
554                                 pl->arr.dimensions[2] * j +
555                                 pl->arr.dimensions[2] * pl->arr.dimensions[1] * i +
556                                 k,
557                                 pl);
558                     }
559                 }
560             }
561             this->setValue(std::string(pl->name), val);
562         }
563         else
564         {
565             throw std::logic_error("Invalid depth in payload_array_helper");
566         }
567     }
568
569     void OCRepresentation::setPayloadArray(const OCRepPayloadValue* pl)
570     {
571
572         switch(pl->arr.type)
573         {
574             case OCREP_PROP_INT:
575                 payload_array_helper<int>(pl, calcArrayDepth(pl->arr.dimensions));
576                 break;
577             case OCREP_PROP_DOUBLE:
578                 payload_array_helper<double>(pl, calcArrayDepth(pl->arr.dimensions));
579                 break;
580             case OCREP_PROP_BOOL:
581                 payload_array_helper<bool>(pl, calcArrayDepth(pl->arr.dimensions));
582                 break;
583             case OCREP_PROP_STRING:
584                 payload_array_helper<std::string>(pl, calcArrayDepth(pl->arr.dimensions));
585                 break;
586             case OCREP_PROP_OBJECT:
587                 payload_array_helper<OCRepresentation>(pl, calcArrayDepth(pl->arr.dimensions));
588                 break;
589             default:
590                 throw std::logic_error("setPayload array invalid type");
591                 break;
592         }
593     }
594
595     void OCRepresentation::setPayload(const OCRepPayload* pl)
596     {
597         setUri(pl->uri);
598
599         OCStringLL* ll = pl->types;
600         while(ll)
601         {
602             addResourceType(ll->value);
603             ll = ll->next;
604         }
605
606         ll = pl->interfaces;
607         while(ll)
608         {
609             addResourceInterface(ll->value);
610             ll = ll->next;
611         }
612
613         OCRepPayloadValue* val = pl->values;
614
615         while(val)
616         {
617             switch(val->type)
618             {
619                 case OCREP_PROP_NULL:
620                     setNULL(val->name);
621                     break;
622                 case OCREP_PROP_INT:
623                     setValue<int>(val->name, val->i);
624                     break;
625                 case OCREP_PROP_DOUBLE:
626                     setValue<double>(val->name, val->d);
627                     break;
628                 case OCREP_PROP_BOOL:
629                     setValue<bool>(val->name, val->b);
630                     break;
631                 case OCREP_PROP_STRING:
632                     setValue<std::string>(val->name, val->str);
633                     break;
634                 case OCREP_PROP_OBJECT:
635                     {
636                         OCRepresentation cur;
637                         cur.setPayload(val->obj);
638                         setValue<OCRepresentation>(val->name, cur);
639                     }
640                     break;
641                 case OCREP_PROP_ARRAY:
642                     setPayloadArray(val);
643                     break;
644                 case OCREP_PROP_BYTE_STRING:
645                     setValue(val->name,
646                             std::vector<uint8_t>
647                             (val->ocByteStr.bytes, val->ocByteStr.bytes + val->ocByteStr.len)
648                             );
649                     break;
650                 default:
651                     throw std::logic_error(std::string("Not Implemented!") +
652                             std::to_string((int)val->type));
653                     break;
654             }
655             val = val->next;
656         }
657     }
658
659     void OCRepresentation::addChild(const OCRepresentation& rep)
660     {
661         m_children.push_back(rep);
662     }
663
664     void OCRepresentation::clearChildren()
665     {
666         m_children.clear();
667     }
668
669     const std::vector<OCRepresentation>& OCRepresentation::getChildren() const
670     {
671         return m_children;
672     }
673
674     void OCRepresentation::setChildren(const std::vector<OCRepresentation>& children)
675     {
676         m_children = children;
677     }
678
679     void OCRepresentation::setDevAddr(const OCDevAddr m_devAddr)
680     {
681         std::ostringstream ss;
682         if (m_devAddr.flags & OC_SECURE)
683         {
684             ss << COAPS;
685         }
686         else if (m_devAddr.adapter & OC_ADAPTER_TCP)
687         {
688             ss << COAP_TCP;
689         }
690         else
691         {
692             ss << COAP;
693         }
694         if (m_devAddr.flags & OC_IP_USE_V6)
695         {
696             ss << '[' << m_devAddr.addr << ']';
697         }
698         else
699         {
700             ss << m_devAddr.addr;
701         }
702         if (m_devAddr.port)
703         {
704             ss << ':' << m_devAddr.port;
705         }
706         m_host = ss.str();
707     }
708
709     const std::string OCRepresentation::getHost() const
710     {
711         return m_host;
712     }
713
714     void OCRepresentation::setUri(const char* uri)
715     {
716         m_uri = uri ? uri : "";
717     }
718
719     void OCRepresentation::setUri(const std::string& uri)
720     {
721         m_uri = uri;
722     }
723
724     std::string OCRepresentation::getUri() const
725     {
726         return m_uri;
727     }
728
729     const std::vector<std::string>& OCRepresentation::getResourceTypes() const
730     {
731         return m_resourceTypes;
732     }
733
734     void OCRepresentation::setResourceTypes(const std::vector<std::string>& resourceTypes)
735     {
736         m_resourceTypes = resourceTypes;
737     }
738
739     void OCRepresentation::addResourceType(const std::string& str)
740     {
741         m_resourceTypes.push_back(str);
742     }
743
744     const std::vector<std::string>& OCRepresentation::getResourceInterfaces() const
745     {
746         return m_interfaces;
747     }
748
749     void OCRepresentation::addResourceInterface(const std::string& str)
750     {
751         m_interfaces.push_back(str);
752     }
753
754     void OCRepresentation::setResourceInterfaces(const std::vector<std::string>& resourceInterfaces)
755     {
756         m_interfaces = resourceInterfaces;
757     }
758
759     const std::vector<std::string>& OCRepresentation::getDataModelVersions() const
760     {
761         return m_dataModelVersions;
762     }
763
764     void OCRepresentation::addDataModelVersion(const std::string& str)
765     {
766         m_dataModelVersions.push_back(str);
767     }
768
769     bool OCRepresentation::hasAttribute(const std::string& str) const
770     {
771         return m_values.find(str) != m_values.end();
772     }
773
774     bool OCRepresentation::emptyData() const
775     {
776         // This logic is meant to determine whether based on the JSON serialization rules
777         // if this object will result in empty JSON.  URI is only serialized if there is valid
778         // data, ResourceType and Interfaces are only serialized if we are a nothing, a
779         // child of a default or link item.
780         // Our values array is only printed in the if we are the child of a Batch resource,
781         // the parent in a 'default' situation, or not in a child/parent relationship.
782         if (!m_uri.empty())
783         {
784             return false;
785         }
786         else if ((m_interfaceType == InterfaceType::None
787                         || m_interfaceType==InterfaceType::DefaultChild
788                         || m_interfaceType==InterfaceType::LinkChild)
789                     && (m_resourceTypes.size()>0 || m_interfaces.size()>0
790                         || m_dataModelVersions.size()>0))
791         {
792             return false;
793         }
794         else if ((m_interfaceType == InterfaceType::None
795                         || m_interfaceType == InterfaceType::BatchChild
796                         || m_interfaceType == InterfaceType::DefaultParent)
797                     && m_values.size()>0)
798         {
799             return false;
800         }
801
802         if (m_children.size() > 0)
803         {
804             return false;
805         }
806
807         return true;
808     }
809
810     int OCRepresentation::numberOfAttributes() const
811     {
812         return m_values.size();
813     }
814
815     bool OCRepresentation::erase(const std::string& str)
816     {
817         return m_values.erase(str);
818     }
819
820     void OCRepresentation::setNULL(const std::string& str)
821     {
822         m_values[str] = OC::NullType();
823     }
824
825     bool OCRepresentation::isNULL(const std::string& str) const
826     {
827         auto x = m_values.find(str);
828
829         if (m_values.end() != x)
830         {
831             return x->second.which() == AttributeValueNullIndex;
832         }
833         else
834         {
835             throw OCException(OC::Exception::INVALID_ATTRIBUTE+ str);
836         }
837     }
838 }
839
840 namespace OC
841 {
842     std::ostream& operator <<(std::ostream& os, const AttributeType at)
843     {
844         switch(at)
845         {
846             case AttributeType::Null:
847                 os << "Null";
848                 break;
849             case AttributeType::Integer:
850                 os << "Integer";
851                 break;
852             case AttributeType::Double:
853                 os << "Double";
854                 break;
855             case AttributeType::Boolean:
856                 os << "Boolean";
857                 break;
858             case AttributeType::String:
859                 os << "String";
860                 break;
861             case AttributeType::OCRepresentation:
862                 os << "OCRepresentation";
863                 break;
864             case AttributeType::Vector:
865                 os << "Vector";
866                 break;
867             case AttributeType::Binary:
868                 os<< "Binary";
869         }
870         return os;
871     }
872 }
873
874 // STL Container For OCRepresentation
875 namespace OC
876 {
877     OCRepresentation::AttributeItem::AttributeItem(const std::string& name,
878             std::map<std::string, AttributeValue>& vals):
879             m_attrName(name), m_values(vals){}
880
881     OCRepresentation::AttributeItem OCRepresentation::operator[](const std::string& key)
882     {
883         OCRepresentation::AttributeItem attr{key, m_values};
884         return std::move(attr);
885     }
886
887     const OCRepresentation::AttributeItem OCRepresentation::operator[](const std::string& key) const
888     {
889         OCRepresentation::AttributeItem attr{key, m_values};
890         return std::move(attr);
891     }
892
893     const std::string& OCRepresentation::AttributeItem::attrname() const
894     {
895         return m_attrName;
896     }
897
898     template<typename T, typename = void>
899     struct type_info
900     {
901         // contains the actual type
902         typedef T type;
903         // contains the inner most vector-type
904         typedef T base_type;
905         // contains the AttributeType for this item
906         constexpr static AttributeType enum_type =
907             AttributeTypeConvert<T>::type;
908         // contains the AttributeType for this base-type
909         constexpr static AttributeType enum_base_type =
910             AttributeTypeConvert<T>::type;
911         // depth of the vector
912         constexpr static size_t depth = 0;
913     };
914
915     template<typename T>
916     struct type_info<
917         T,
918         typename std::enable_if<
919             is_vector<T>::value &&
920             !std::is_same<uint8_t, typename T::value_type>::value
921         >::type
922     >
923     {
924         typedef T type;
925         typedef typename type_info<typename T::value_type>::base_type base_type;
926         constexpr static AttributeType enum_type = AttributeType::Vector;
927         constexpr static AttributeType enum_base_type =
928             type_info<typename T::value_type>::enum_base_type;
929         constexpr static size_t depth = 1 +
930             type_info<typename T::value_type>::depth;
931     };
932
933     // special case for binary data, which is a std::vector<uint8_t>
934     template<>
935     struct type_info<std::vector<uint8_t>, void>
936     {
937         typedef std::vector<uint8_t> type;
938         typedef std::vector<uint8_t> base_type;
939         constexpr static AttributeType enum_type = AttributeType::Binary;
940         constexpr static AttributeType enum_base_type = AttributeType::Binary;
941         constexpr static size_t depth = 0;
942     };
943
944
945     struct type_introspection_visitor : boost::static_visitor<>
946     {
947         AttributeType type;
948         AttributeType base_type;
949         size_t depth;
950
951         type_introspection_visitor() : boost::static_visitor<>(),
952             type(AttributeType::Null), base_type(AttributeType::Null), depth(0){}
953
954         template <typename T>
955         void operator()(T const& /*item*/)
956         {
957             type = type_info<T>::enum_type;
958             base_type = type_info<T>::enum_base_type;
959             depth = type_info<T>::depth;
960         }
961     };
962
963     AttributeType OCRepresentation::AttributeItem::type() const
964     {
965         type_introspection_visitor vis;
966         boost::apply_visitor(vis, m_values[m_attrName]);
967         return vis.type;
968     }
969
970     AttributeType OCRepresentation::AttributeItem::base_type() const
971     {
972         type_introspection_visitor vis;
973         boost::apply_visitor(vis, m_values[m_attrName]);
974         return vis.base_type;
975     }
976
977     size_t OCRepresentation::AttributeItem::depth() const
978     {
979         type_introspection_visitor vis;
980         boost::apply_visitor(vis, m_values[m_attrName]);
981         return vis.depth;
982     }
983
984     OCRepresentation::iterator OCRepresentation::begin()
985     {
986         return OCRepresentation::iterator(m_values.begin(), m_values);
987     }
988
989     OCRepresentation::const_iterator OCRepresentation::begin() const
990     {
991          return OCRepresentation::const_iterator(m_values.begin(), m_values);
992     }
993
994     OCRepresentation::const_iterator OCRepresentation::cbegin() const
995     {
996         return OCRepresentation::const_iterator(m_values.cbegin(), m_values);
997     }
998
999     OCRepresentation::iterator OCRepresentation::end()
1000     {
1001         return OCRepresentation::iterator(m_values.end(), m_values);
1002     }
1003
1004     OCRepresentation::const_iterator OCRepresentation::end() const
1005     {
1006         return OCRepresentation::const_iterator(m_values.end(), m_values);
1007     }
1008
1009     OCRepresentation::const_iterator OCRepresentation::cend() const
1010     {
1011         return OCRepresentation::const_iterator(m_values.cend(), m_values);
1012     }
1013
1014     size_t OCRepresentation::size() const
1015     {
1016         return m_values.size();
1017     }
1018
1019     bool OCRepresentation::empty() const
1020     {
1021         return m_values.empty();
1022     }
1023
1024     bool OCRepresentation::iterator::operator==(const OCRepresentation::iterator& rhs) const
1025     {
1026         return m_iterator == rhs.m_iterator;
1027     }
1028
1029     bool OCRepresentation::iterator::operator!=(const OCRepresentation::iterator& rhs) const
1030     {
1031         return m_iterator != rhs.m_iterator;
1032     }
1033
1034     bool OCRepresentation::const_iterator::operator==(
1035             const OCRepresentation::const_iterator& rhs) const
1036     {
1037         return m_iterator == rhs.m_iterator;
1038     }
1039
1040     bool OCRepresentation::const_iterator::operator!=(
1041             const OCRepresentation::const_iterator& rhs) const
1042     {
1043         return m_iterator != rhs.m_iterator;
1044     }
1045
1046     OCRepresentation::iterator::reference OCRepresentation::iterator::operator*()
1047     {
1048         return m_item;
1049     }
1050
1051     OCRepresentation::const_iterator::const_reference
1052         OCRepresentation::const_iterator::operator*() const
1053     {
1054         return m_item;
1055     }
1056
1057     OCRepresentation::iterator::pointer OCRepresentation::iterator::operator->()
1058     {
1059         return &m_item;
1060     }
1061
1062     OCRepresentation::const_iterator::const_pointer
1063         OCRepresentation::const_iterator::operator->() const
1064     {
1065         return &m_item;
1066     }
1067
1068     OCRepresentation::iterator& OCRepresentation::iterator::operator++()
1069     {
1070         m_iterator++;
1071         if (m_iterator != m_item.m_values.end())
1072         {
1073             m_item.m_attrName = m_iterator->first;
1074         }
1075         else
1076         {
1077             m_item.m_attrName = "";
1078         }
1079         return *this;
1080     }
1081
1082     OCRepresentation::const_iterator& OCRepresentation::const_iterator::operator++()
1083     {
1084         m_iterator++;
1085         if (m_iterator != m_item.m_values.end())
1086         {
1087             m_item.m_attrName = m_iterator->first;
1088         }
1089         else
1090         {
1091             m_item.m_attrName = "";
1092         }
1093         return *this;
1094     }
1095
1096     OCRepresentation::iterator OCRepresentation::iterator::operator++(int)
1097     {
1098         OCRepresentation::iterator itr(*this);
1099         ++(*this);
1100         return itr;
1101     }
1102
1103     OCRepresentation::const_iterator OCRepresentation::const_iterator::operator++(int)
1104     {
1105         OCRepresentation::const_iterator itr(*this);
1106         ++(*this);
1107         return itr;
1108     }
1109
1110     struct to_string_visitor : boost::static_visitor<>
1111     {
1112         std::string str;
1113         template <typename T>
1114         void operator()(T const& item)
1115         {
1116             str = boost::lexical_cast<std::string>(item);
1117         }
1118
1119         template <typename T>
1120         void operator()(std::vector<T> const& item)
1121         {
1122             to_string_visitor vis;
1123             std::ostringstream stream;
1124             stream << "[";
1125
1126             for(const auto& i : item)
1127             {
1128                 vis(i);
1129                 stream << vis.str  << " ";
1130             }
1131             stream << "]";
1132             str = stream.str();
1133         }
1134     };
1135
1136     template<>
1137     void to_string_visitor::operator()(bool const& item)
1138     {
1139         str = item ? "true" : "false";
1140     }
1141
1142     template<>
1143     void to_string_visitor::operator()(std::string const& item)
1144     {
1145         str = item;
1146     }
1147
1148     template<>
1149     void to_string_visitor::operator()(NullType const& /*item*/)
1150     {
1151         str = "(null)";
1152     }
1153
1154     template<>
1155     void to_string_visitor::operator()(OCRepresentation const& /*item*/)
1156     {
1157         str = "OC::OCRepresentation";
1158     }
1159
1160     std::string OCRepresentation::getValueToString(const std::string& key) const
1161     {
1162         auto x = m_values.find(key);
1163         if (x != m_values.end())
1164         {
1165             to_string_visitor vis;
1166             boost::apply_visitor(vis, x->second);
1167             return std::move(vis.str);
1168         }
1169
1170         return "";
1171     }
1172
1173     std::string OCRepresentation::AttributeItem::getValueToString() const
1174     {
1175         to_string_visitor vis;
1176         boost::apply_visitor(vis, m_values[m_attrName]);
1177         return std::move(vis.str);
1178     }
1179
1180     std::ostream& operator<<(std::ostream& os, const OCRepresentation::AttributeItem& ai)
1181     {
1182         os << ai.getValueToString();
1183         return os;
1184     }
1185 }