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