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