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