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