Merge branch 'master' into cloud-interface
[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 #if !defined(_MSC_VER)
319     template<>
320     void get_payload_array::copy_to_array(std::_Bit_reference br, void* array, size_t pos)
321     {
322         ((bool*)array)[pos] = static_cast<bool>(br);
323     }
324 #endif
325
326     template<>
327     void get_payload_array::copy_to_array(std::string item, void* array, size_t pos)
328     {
329         ((char**)array)[pos] = OICStrdup(item.c_str());
330     }
331
332     template<>
333     void get_payload_array::copy_to_array(std::string& item, void* array, size_t pos)
334     {
335         ((char**)array)[pos] = OICStrdup(item.c_str());
336     }
337
338     template<>
339     void get_payload_array::copy_to_array(const std::string& item, void* array, size_t pos)
340     {
341         ((char**)array)[pos] = OICStrdup(item.c_str());
342     }
343
344     template<>
345     void get_payload_array::copy_to_array(OC::OCRepresentation item, void* array, size_t pos)
346     {
347         ((OCRepPayload**)array)[pos] = item.getPayload();
348     }
349
350     void OCRepresentation::getPayloadArray(OCRepPayload* payload,
351                     const OCRepresentation::AttributeItem& item) const
352     {
353         get_payload_array vis{};
354         boost::apply_visitor(vis, m_values[item.attrname()]);
355
356
357         switch(item.base_type())
358         {
359             case AttributeType::Integer:
360                 OCRepPayloadSetIntArrayAsOwner(payload, item.attrname().c_str(),
361                         (int64_t*)vis.array,
362                         vis.dimensions);
363                 break;
364             case AttributeType::Double:
365                 OCRepPayloadSetDoubleArrayAsOwner(payload, item.attrname().c_str(),
366                         (double*)vis.array,
367                         vis.dimensions);
368                 break;
369             case AttributeType::Boolean:
370                 OCRepPayloadSetBoolArrayAsOwner(payload, item.attrname().c_str(),
371                         (bool*)vis.array,
372                         vis.dimensions);
373                 break;
374             case AttributeType::String:
375                 OCRepPayloadSetStringArrayAsOwner(payload, item.attrname().c_str(),
376                         (char**)vis.array,
377                         vis.dimensions);
378                 break;
379             case AttributeType::OCRepresentation:
380                 OCRepPayloadSetPropObjectArrayAsOwner(payload, item.attrname().c_str(),
381                         (OCRepPayload**)vis.array, vis.dimensions);
382                 break;
383             default:
384                 throw std::logic_error(std::string("GetPayloadArray: Not Implemented") +
385                         std::to_string((int)item.base_type()));
386         }
387     }
388
389     OCRepPayload* OCRepresentation::getPayload() const
390     {
391         OCRepPayload* root = OCRepPayloadCreate();
392         if (!root)
393         {
394             throw std::bad_alloc();
395         }
396
397         OCRepPayloadSetUri(root, getUri().c_str());
398
399         for(const std::string& type : getResourceTypes())
400         {
401             OCRepPayloadAddResourceType(root, type.c_str());
402         }
403
404         for(const std::string& iface : getResourceInterfaces())
405         {
406             OCRepPayloadAddInterface(root, iface.c_str());
407         }
408
409         for(auto& val : *this)
410         {
411             switch(val.type())
412             {
413                 case AttributeType::Null:
414                     OCRepPayloadSetNull(root, val.attrname().c_str());
415                     break;
416                 case AttributeType::Integer:
417                     OCRepPayloadSetPropInt(root, val.attrname().c_str(), static_cast<int>(val));
418                     break;
419                 case AttributeType::Double:
420                     OCRepPayloadSetPropDouble(root, val.attrname().c_str(),
421                             val.getValue<double>());
422                     break;
423                 case AttributeType::Boolean:
424                     OCRepPayloadSetPropBool(root, val.attrname().c_str(), val.getValue<bool>());
425                     break;
426                 case AttributeType::String:
427                     OCRepPayloadSetPropString(root, val.attrname().c_str(),
428                             static_cast<std::string>(val).c_str());
429                     break;
430                 case AttributeType::OCRepresentation:
431                     OCRepPayloadSetPropObjectAsOwner(root, val.attrname().c_str(),
432                             static_cast<OCRepresentation>(val).getPayload());
433                     break;
434                 case AttributeType::Vector:
435                     getPayloadArray(root, val);
436                     break;
437                 case AttributeType::Binary:
438                     OCRepPayloadSetPropByteString(root, val.attrname().c_str(),
439                             OCByteString{const_cast<uint8_t*>(val.getValue<std::vector<uint8_t>>().data()),
440                             val.getValue<std::vector<uint8_t>>().size()});
441                     break;
442                 default:
443                     throw std::logic_error(std::string("Getpayload: Not Implemented") +
444                             std::to_string((int)val.type()));
445                     break;
446             }
447         }
448
449         return root;
450     }
451
452     size_t calcArrayDepth(const size_t dimensions[MAX_REP_ARRAY_DEPTH])
453     {
454         if (dimensions[0] == 0)
455         {
456             throw std::logic_error("invalid calcArrayDepth");
457         }
458         else if (dimensions[1] == 0)
459         {
460             return 1;
461         }
462         else if (dimensions[2] == 0)
463         {
464             return 2;
465         }
466         else
467         {
468             return 3;
469         }
470     }
471
472     template<typename T>
473     T OCRepresentation::payload_array_helper_copy(size_t index, const OCRepPayloadValue* pl)
474     {
475         throw std::logic_error("payload_array_helper_copy: unsupported type");
476     }
477     template<>
478     int OCRepresentation::payload_array_helper_copy<int>(size_t index, const OCRepPayloadValue* pl)
479     {
480         return pl->arr.iArray[index];
481     }
482     template<>
483     double OCRepresentation::payload_array_helper_copy<double>(size_t index, const OCRepPayloadValue* pl)
484     {
485         return pl->arr.dArray[index];
486     }
487     template<>
488     bool OCRepresentation::payload_array_helper_copy<bool>(size_t index, const OCRepPayloadValue* pl)
489     {
490         return pl->arr.bArray[index];
491     }
492     template<>
493     std::string OCRepresentation::payload_array_helper_copy<std::string>(
494             size_t index, const OCRepPayloadValue* pl)
495     {
496         if (pl->arr.strArray[index])
497         {
498             return std::string(pl->arr.strArray[index]);
499         }
500         else
501         {
502             return std::string{};
503         }
504     }
505     template<>
506     OCRepresentation OCRepresentation::payload_array_helper_copy<OCRepresentation>(
507             size_t index, const OCRepPayloadValue* pl)
508     {
509         OCRepresentation r;
510         if (pl->arr.objArray[index])
511         {
512             r.setPayload(pl->arr.objArray[index]);
513         }
514         return r;
515     }
516
517     template<typename T>
518     void OCRepresentation::payload_array_helper(const OCRepPayloadValue* pl, size_t depth)
519     {
520         if (depth == 1)
521         {
522             std::vector<T> val(pl->arr.dimensions[0]);
523
524             for(size_t i = 0; i < pl->arr.dimensions[0]; ++i)
525             {
526                 val[i] = payload_array_helper_copy<T>(i, pl);
527             }
528             this->setValue(std::string(pl->name), val);
529         }
530         else if (depth == 2)
531         {
532             std::vector<std::vector<T>> val(pl->arr.dimensions[0]);
533             for(size_t i = 0; i < pl->arr.dimensions[0]; ++i)
534             {
535                 val[i].resize(pl->arr.dimensions[1]);
536                 for(size_t j = 0; j < pl->arr.dimensions[1]; ++j)
537                 {
538                     val[i][j] = payload_array_helper_copy<T>(
539                             i * pl->arr.dimensions[1] + j, pl);
540                 }
541             }
542             this->setValue(std::string(pl->name), val);
543         }
544         else if (depth == 3)
545         {
546             std::vector<std::vector<std::vector<T>>> val(pl->arr.dimensions[0]);
547             for(size_t i = 0; i < pl->arr.dimensions[0]; ++i)
548             {
549                 val[i].resize(pl->arr.dimensions[1]);
550                 for(size_t j = 0; j < pl->arr.dimensions[1]; ++j)
551                 {
552                     val[i][j].resize(pl->arr.dimensions[2]);
553                     for(size_t k = 0; k < pl->arr.dimensions[2]; ++k)
554                     {
555                         val[i][j][k] = payload_array_helper_copy<T>(
556                                 pl->arr.dimensions[2] * j +
557                                 pl->arr.dimensions[2] * pl->arr.dimensions[1] * i +
558                                 k,
559                                 pl);
560                     }
561                 }
562             }
563             this->setValue(std::string(pl->name), val);
564         }
565         else
566         {
567             throw std::logic_error("Invalid depth in payload_array_helper");
568         }
569     }
570
571     void OCRepresentation::setPayloadArray(const OCRepPayloadValue* pl)
572     {
573
574         switch(pl->arr.type)
575         {
576             case OCREP_PROP_INT:
577                 payload_array_helper<int>(pl, calcArrayDepth(pl->arr.dimensions));
578                 break;
579             case OCREP_PROP_DOUBLE:
580                 payload_array_helper<double>(pl, calcArrayDepth(pl->arr.dimensions));
581                 break;
582             case OCREP_PROP_BOOL:
583                 payload_array_helper<bool>(pl, calcArrayDepth(pl->arr.dimensions));
584                 break;
585             case OCREP_PROP_STRING:
586                 payload_array_helper<std::string>(pl, calcArrayDepth(pl->arr.dimensions));
587                 break;
588             case OCREP_PROP_OBJECT:
589                 payload_array_helper<OCRepresentation>(pl, calcArrayDepth(pl->arr.dimensions));
590                 break;
591             default:
592                 throw std::logic_error("setPayload array invalid type");
593                 break;
594         }
595     }
596
597     void OCRepresentation::setPayload(const OCRepPayload* pl)
598     {
599         setUri(pl->uri);
600
601         OCStringLL* ll = pl->types;
602         while(ll)
603         {
604             addResourceType(ll->value);
605             ll = ll->next;
606         }
607
608         ll = pl->interfaces;
609         while(ll)
610         {
611             addResourceInterface(ll->value);
612             ll = ll->next;
613         }
614
615         OCRepPayloadValue* val = pl->values;
616
617         while(val)
618         {
619             switch(val->type)
620             {
621                 case OCREP_PROP_NULL:
622                     setNULL(val->name);
623                     break;
624                 case OCREP_PROP_INT:
625                     setValue<int>(val->name, val->i);
626                     break;
627                 case OCREP_PROP_DOUBLE:
628                     setValue<double>(val->name, val->d);
629                     break;
630                 case OCREP_PROP_BOOL:
631                     setValue<bool>(val->name, val->b);
632                     break;
633                 case OCREP_PROP_STRING:
634                     setValue<std::string>(val->name, val->str);
635                     break;
636                 case OCREP_PROP_OBJECT:
637                     {
638                         OCRepresentation cur;
639                         cur.setPayload(val->obj);
640                         setValue<OCRepresentation>(val->name, cur);
641                     }
642                     break;
643                 case OCREP_PROP_ARRAY:
644                     setPayloadArray(val);
645                     break;
646                 case OCREP_PROP_BYTE_STRING:
647                     setValue(val->name,
648                             std::vector<uint8_t>
649                             (val->ocByteStr.bytes, val->ocByteStr.bytes + val->ocByteStr.len)
650                             );
651                     break;
652                 default:
653                     throw std::logic_error(std::string("Not Implemented!") +
654                             std::to_string((int)val->type));
655                     break;
656             }
657             val = val->next;
658         }
659     }
660
661     void OCRepresentation::addChild(const OCRepresentation& rep)
662     {
663         m_children.push_back(rep);
664     }
665
666     void OCRepresentation::clearChildren()
667     {
668         m_children.clear();
669     }
670
671     const std::vector<OCRepresentation>& OCRepresentation::getChildren() const
672     {
673         return m_children;
674     }
675
676     void OCRepresentation::setChildren(const std::vector<OCRepresentation>& children)
677     {
678         m_children = children;
679     }
680
681     void OCRepresentation::setDevAddr(const OCDevAddr m_devAddr)
682     {
683         std::ostringstream ss;
684         if (m_devAddr.flags & OC_SECURE)
685         {
686             ss << COAPS;
687         }
688         else if (m_devAddr.adapter & OC_ADAPTER_TCP)
689         {
690             ss << COAP_TCP;
691         }
692         else
693         {
694             ss << COAP;
695         }
696         if (m_devAddr.flags & OC_IP_USE_V6)
697         {
698             ss << '[' << m_devAddr.addr << ']';
699         }
700         else
701         {
702             ss << m_devAddr.addr;
703         }
704         if (m_devAddr.port)
705         {
706             ss << ':' << m_devAddr.port;
707         }
708         m_host = ss.str();
709     }
710
711     const std::string OCRepresentation::getHost() const
712     {
713         return m_host;
714     }
715
716     void OCRepresentation::setUri(const char* uri)
717     {
718         m_uri = uri ? uri : "";
719     }
720
721     void OCRepresentation::setUri(const std::string& uri)
722     {
723         m_uri = uri;
724     }
725
726     std::string OCRepresentation::getUri() const
727     {
728         return m_uri;
729     }
730
731     const std::vector<std::string>& OCRepresentation::getResourceTypes() const
732     {
733         return m_resourceTypes;
734     }
735
736     void OCRepresentation::setResourceTypes(const std::vector<std::string>& resourceTypes)
737     {
738         m_resourceTypes = resourceTypes;
739     }
740
741     void OCRepresentation::addResourceType(const std::string& str)
742     {
743         m_resourceTypes.push_back(str);
744     }
745
746     const std::vector<std::string>& OCRepresentation::getResourceInterfaces() const
747     {
748         return m_interfaces;
749     }
750
751     void OCRepresentation::addResourceInterface(const std::string& str)
752     {
753         m_interfaces.push_back(str);
754     }
755
756     void OCRepresentation::setResourceInterfaces(const std::vector<std::string>& resourceInterfaces)
757     {
758         m_interfaces = resourceInterfaces;
759     }
760
761     const std::vector<std::string>& OCRepresentation::getDataModelVersions() const
762     {
763         return m_dataModelVersions;
764     }
765
766     void OCRepresentation::addDataModelVersion(const std::string& str)
767     {
768         m_dataModelVersions.push_back(str);
769     }
770
771     bool OCRepresentation::hasAttribute(const std::string& str) const
772     {
773         return m_values.find(str) != m_values.end();
774     }
775
776     bool OCRepresentation::emptyData() const
777     {
778         // This logic is meant to determine whether based on the JSON serialization rules
779         // if this object will result in empty JSON.  URI is only serialized if there is valid
780         // data, ResourceType and Interfaces are only serialized if we are a nothing, a
781         // child of a default or link item.
782         // Our values array is only printed in the if we are the child of a Batch resource,
783         // the parent in a 'default' situation, or not in a child/parent relationship.
784         if (!m_uri.empty())
785         {
786             return false;
787         }
788         else if ((m_interfaceType == InterfaceType::None
789                         || m_interfaceType==InterfaceType::DefaultChild
790                         || m_interfaceType==InterfaceType::LinkChild)
791                     && (m_resourceTypes.size()>0 || m_interfaces.size()>0
792                         || m_dataModelVersions.size()>0))
793         {
794             return false;
795         }
796         else if ((m_interfaceType == InterfaceType::None
797                         || m_interfaceType == InterfaceType::BatchChild
798                         || m_interfaceType == InterfaceType::DefaultParent)
799                     && m_values.size()>0)
800         {
801             return false;
802         }
803
804         if (m_children.size() > 0)
805         {
806             return false;
807         }
808
809         return true;
810     }
811
812     int OCRepresentation::numberOfAttributes() const
813     {
814         return m_values.size();
815     }
816
817     bool OCRepresentation::erase(const std::string& str)
818     {
819         return m_values.erase(str);
820     }
821
822     void OCRepresentation::setNULL(const std::string& str)
823     {
824         m_values[str] = OC::NullType();
825     }
826
827     bool OCRepresentation::isNULL(const std::string& str) const
828     {
829         auto x = m_values.find(str);
830
831         if (m_values.end() != x)
832         {
833             return x->second.which() == AttributeValueNullIndex;
834         }
835         else
836         {
837             throw OCException(OC::Exception::INVALID_ATTRIBUTE+ str);
838         }
839     }
840 }
841
842 namespace OC
843 {
844     std::ostream& operator <<(std::ostream& os, const AttributeType at)
845     {
846         switch(at)
847         {
848             case AttributeType::Null:
849                 os << "Null";
850                 break;
851             case AttributeType::Integer:
852                 os << "Integer";
853                 break;
854             case AttributeType::Double:
855                 os << "Double";
856                 break;
857             case AttributeType::Boolean:
858                 os << "Boolean";
859                 break;
860             case AttributeType::String:
861                 os << "String";
862                 break;
863             case AttributeType::OCRepresentation:
864                 os << "OCRepresentation";
865                 break;
866             case AttributeType::Vector:
867                 os << "Vector";
868                 break;
869             case AttributeType::Binary:
870                 os<< "Binary";
871         }
872         return os;
873     }
874 }
875
876 // STL Container For OCRepresentation
877 namespace OC
878 {
879     OCRepresentation::AttributeItem::AttributeItem(const std::string& name,
880             std::map<std::string, AttributeValue>& vals):
881             m_attrName(name), m_values(vals){}
882
883     OCRepresentation::AttributeItem OCRepresentation::operator[](const std::string& key)
884     {
885         OCRepresentation::AttributeItem attr{key, m_values};
886         return std::move(attr);
887     }
888
889     const OCRepresentation::AttributeItem OCRepresentation::operator[](const std::string& key) const
890     {
891         OCRepresentation::AttributeItem attr{key, m_values};
892         return std::move(attr);
893     }
894
895     const std::string& OCRepresentation::AttributeItem::attrname() const
896     {
897         return m_attrName;
898     }
899
900     template<typename T, typename = void>
901     struct type_info
902     {
903         // contains the actual type
904         typedef T type;
905         // contains the inner most vector-type
906         typedef T base_type;
907         // contains the AttributeType for this item
908         BOOST_STATIC_CONSTEXPR AttributeType enum_type =
909             AttributeTypeConvert<T>::type;
910         // contains the AttributeType for this base-type
911         BOOST_STATIC_CONSTEXPR AttributeType enum_base_type =
912             AttributeTypeConvert<T>::type;
913         // depth of the vector
914         BOOST_STATIC_CONSTEXPR size_t depth = 0;
915     };
916
917     template<typename T>
918     struct type_info<
919         T,
920         typename std::enable_if<
921             is_vector<T>::value &&
922             !std::is_same<uint8_t, typename T::value_type>::value
923         >::type
924     >
925     {
926         typedef T type;
927         typedef typename type_info<typename T::value_type>::base_type base_type;
928         BOOST_STATIC_CONSTEXPR AttributeType enum_type = AttributeType::Vector;
929         BOOST_STATIC_CONSTEXPR AttributeType enum_base_type =
930             type_info<typename T::value_type>::enum_base_type;
931         BOOST_STATIC_CONSTEXPR size_t depth = 1 +
932             type_info<typename T::value_type>::depth;
933     };
934
935     // special case for binary data, which is a std::vector<uint8_t>
936     template<>
937     struct type_info<std::vector<uint8_t>, void>
938     {
939         typedef std::vector<uint8_t> type;
940         typedef std::vector<uint8_t> base_type;
941         BOOST_STATIC_CONSTEXPR AttributeType enum_type = AttributeType::Binary;
942         BOOST_STATIC_CONSTEXPR AttributeType enum_base_type = AttributeType::Binary;
943         BOOST_STATIC_CONSTEXPR size_t depth = 0;
944     };
945
946
947     struct type_introspection_visitor : boost::static_visitor<>
948     {
949         AttributeType type;
950         AttributeType base_type;
951         size_t depth;
952
953         type_introspection_visitor() : boost::static_visitor<>(),
954             type(AttributeType::Null), base_type(AttributeType::Null), depth(0){}
955
956         template <typename T>
957         void operator()(T const& /*item*/)
958         {
959             type = type_info<T>::enum_type;
960             base_type = type_info<T>::enum_base_type;
961             depth = type_info<T>::depth;
962         }
963     };
964
965     AttributeType OCRepresentation::AttributeItem::type() const
966     {
967         type_introspection_visitor vis;
968         boost::apply_visitor(vis, m_values[m_attrName]);
969         return vis.type;
970     }
971
972     AttributeType OCRepresentation::AttributeItem::base_type() const
973     {
974         type_introspection_visitor vis;
975         boost::apply_visitor(vis, m_values[m_attrName]);
976         return vis.base_type;
977     }
978
979     size_t OCRepresentation::AttributeItem::depth() const
980     {
981         type_introspection_visitor vis;
982         boost::apply_visitor(vis, m_values[m_attrName]);
983         return vis.depth;
984     }
985
986     OCRepresentation::iterator OCRepresentation::begin()
987     {
988         return OCRepresentation::iterator(m_values.begin(), m_values);
989     }
990
991     OCRepresentation::const_iterator OCRepresentation::begin() const
992     {
993          return OCRepresentation::const_iterator(m_values.begin(), m_values);
994     }
995
996     OCRepresentation::const_iterator OCRepresentation::cbegin() const
997     {
998         return OCRepresentation::const_iterator(m_values.cbegin(), m_values);
999     }
1000
1001     OCRepresentation::iterator OCRepresentation::end()
1002     {
1003         return OCRepresentation::iterator(m_values.end(), m_values);
1004     }
1005
1006     OCRepresentation::const_iterator OCRepresentation::end() const
1007     {
1008         return OCRepresentation::const_iterator(m_values.end(), m_values);
1009     }
1010
1011     OCRepresentation::const_iterator OCRepresentation::cend() const
1012     {
1013         return OCRepresentation::const_iterator(m_values.cend(), m_values);
1014     }
1015
1016     size_t OCRepresentation::size() const
1017     {
1018         return m_values.size();
1019     }
1020
1021     bool OCRepresentation::empty() const
1022     {
1023         return m_values.empty();
1024     }
1025
1026     bool OCRepresentation::iterator::operator==(const OCRepresentation::iterator& rhs) const
1027     {
1028         return m_iterator == rhs.m_iterator;
1029     }
1030
1031     bool OCRepresentation::iterator::operator!=(const OCRepresentation::iterator& rhs) const
1032     {
1033         return m_iterator != rhs.m_iterator;
1034     }
1035
1036     bool OCRepresentation::const_iterator::operator==(
1037             const OCRepresentation::const_iterator& rhs) const
1038     {
1039         return m_iterator == rhs.m_iterator;
1040     }
1041
1042     bool OCRepresentation::const_iterator::operator!=(
1043             const OCRepresentation::const_iterator& rhs) const
1044     {
1045         return m_iterator != rhs.m_iterator;
1046     }
1047
1048     OCRepresentation::iterator::reference OCRepresentation::iterator::operator*()
1049     {
1050         return m_item;
1051     }
1052
1053     OCRepresentation::const_iterator::const_reference
1054         OCRepresentation::const_iterator::operator*() const
1055     {
1056         return m_item;
1057     }
1058
1059     OCRepresentation::iterator::pointer OCRepresentation::iterator::operator->()
1060     {
1061         return &m_item;
1062     }
1063
1064     OCRepresentation::const_iterator::const_pointer
1065         OCRepresentation::const_iterator::operator->() const
1066     {
1067         return &m_item;
1068     }
1069
1070     OCRepresentation::iterator& OCRepresentation::iterator::operator++()
1071     {
1072         m_iterator++;
1073         if (m_iterator != m_item.m_values.end())
1074         {
1075             m_item.m_attrName = m_iterator->first;
1076         }
1077         else
1078         {
1079             m_item.m_attrName = "";
1080         }
1081         return *this;
1082     }
1083
1084     OCRepresentation::const_iterator& OCRepresentation::const_iterator::operator++()
1085     {
1086         m_iterator++;
1087         if (m_iterator != m_item.m_values.end())
1088         {
1089             m_item.m_attrName = m_iterator->first;
1090         }
1091         else
1092         {
1093             m_item.m_attrName = "";
1094         }
1095         return *this;
1096     }
1097
1098     OCRepresentation::iterator OCRepresentation::iterator::operator++(int)
1099     {
1100         OCRepresentation::iterator itr(*this);
1101         ++(*this);
1102         return itr;
1103     }
1104
1105     OCRepresentation::const_iterator OCRepresentation::const_iterator::operator++(int)
1106     {
1107         OCRepresentation::const_iterator itr(*this);
1108         ++(*this);
1109         return itr;
1110     }
1111
1112     struct to_string_visitor : boost::static_visitor<>
1113     {
1114         std::string str;
1115         template <typename T>
1116         void operator()(T const& item)
1117         {
1118             str = boost::lexical_cast<std::string>(item);
1119         }
1120
1121         template <typename T>
1122         void operator()(std::vector<T> const& item)
1123         {
1124             to_string_visitor vis;
1125             std::ostringstream stream;
1126             stream << "[";
1127
1128             for(const auto& i : item)
1129             {
1130                 vis(i);
1131                 stream << vis.str  << " ";
1132             }
1133             stream << "]";
1134             str = stream.str();
1135         }
1136     };
1137
1138     template<>
1139     void to_string_visitor::operator()(bool const& item)
1140     {
1141         str = item ? "true" : "false";
1142     }
1143
1144     template<>
1145     void to_string_visitor::operator()(std::string const& item)
1146     {
1147         str = item;
1148     }
1149
1150     template<>
1151     void to_string_visitor::operator()(NullType const& /*item*/)
1152     {
1153         str = "(null)";
1154     }
1155
1156     template<>
1157     void to_string_visitor::operator()(OCRepresentation const& /*item*/)
1158     {
1159         str = "OC::OCRepresentation";
1160     }
1161
1162     std::string OCRepresentation::getValueToString(const std::string& key) const
1163     {
1164         auto x = m_values.find(key);
1165         if (x != m_values.end())
1166         {
1167             to_string_visitor vis;
1168             boost::apply_visitor(vis, x->second);
1169             return std::move(vis.str);
1170         }
1171
1172         return "";
1173     }
1174
1175     std::string OCRepresentation::AttributeItem::getValueToString() const
1176     {
1177         to_string_visitor vis;
1178         boost::apply_visitor(vis, m_values[m_attrName]);
1179         return std::move(vis.str);
1180     }
1181
1182     std::ostream& operator<<(std::ostream& os, const OCRepresentation::AttributeItem& ai)
1183     {
1184         os << ai.getValueToString();
1185         return os;
1186     }
1187 }