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