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