Implemented OCRepresentation::setChildren
[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 #ifdef __ANDROID__
29 #include "OCAndroid.h"
30 #endif
31
32 #include <OCRepresentation.h>
33
34 #include <boost/lexical_cast.hpp>
35 #include <cereal/cereal.hpp>
36 #include <cereal/types/map.hpp>
37 #include <cereal/types/vector.hpp>
38 #include <cereal/types/utility.hpp>
39 #include <OicJsonSerializer.hpp>
40 #include <algorithm>
41
42 // code needed to serialize a string=>Attribute value map
43 namespace OC
44 {
45     namespace detail
46     {
47         template<class Archive>
48         class WriteAttributeValue : public boost::static_visitor<>
49         {
50             public:
51                 WriteAttributeValue(const std::string& name, Archive& ar)
52                     :m_name(name), m_archive(ar)
53                 {}
54
55                 template<class T>
56                 void operator()(const T& value) const
57                 {
58                     m_archive(cereal::make_nvp(m_name, value));
59                 }
60             private:
61                 std::string m_name;
62                 Archive& m_archive;
63         };
64     }
65 }
66
67 namespace cereal
68 {
69     // take no action when serializing the null type, because the 'save' below
70     // doesn't use the visitor for this type.
71     template <class Archive>
72     void serialize(Archive&, OC::NullType t)
73     {}
74
75     template<class Archive>
76     void save(Archive& ar, const std::map<std::string, OC::AttributeValue>& vals)
77     {
78         for(const auto& kv : vals)
79         {
80             const auto& k = kv.first;
81             const auto& v = kv.second;
82
83             if(v.which() != OC::AttributeValueNullIndex)
84             {
85                 OC::detail::WriteAttributeValue<Archive> writer(k,ar);
86                 boost::apply_visitor(writer, v);
87             }
88             else
89             {
90                 ar.setNextName(k.c_str());
91                 ar.writeName();
92                 ar.saveValue();
93             }
94         }
95     }
96
97     template<class Archive>
98     void load(Archive& ar, std::map<std::string, OC::AttributeValue>& vals)
99     {
100         ar.loadAttributeValues(vals);
101     }
102 }
103
104 namespace OC
105 {
106     typedef cereal::JSONOutputArchive OutputArchiveType;
107     typedef cereal::JSONInputArchive InputArchiveType;
108
109     void MessageContainer::setJSONRepresentation(const std::string& payload)
110     {
111         std::stringstream os(payload);
112         {
113             InputArchiveType archive(os);
114             archive(cereal::make_nvp(OC::Key::OCKEY, m_reps));
115         }
116     }
117
118     void MessageContainer::setJSONRepresentation(const unsigned char* payload)
119     {
120         setJSONRepresentation(std::string(reinterpret_cast<const char*>(payload)));
121     }
122
123     std::string MessageContainer::getJSONRepresentation(OCInfoFormat f) const
124     {
125         std::stringstream os;
126
127         // note: the block is required because cereal closes the JSON string
128         // upon destruction, so the archive needs to be destroyed before accessing
129         // the data
130         {
131             if(f == OCInfoFormat::IncludeOC)
132             {
133                 OutputArchiveType archive(os);
134                 archive(cereal::make_nvp(OC::Key::OCKEY, m_reps));
135             }
136             else if(f== OCInfoFormat::ExcludeOC)
137             {
138                 bool firstPrinted = false;
139                 for(std::vector<OCRepresentation>::size_type i = 0; i< m_reps.size();++i)
140                 {
141                     if(!m_reps[i].emptyData())
142                     {
143                         if(firstPrinted)
144                         {
145                             os<<',';
146                         }
147                         firstPrinted=true;
148                         os << m_reps[i].getJSONRepresentation();
149                     }
150                 }
151             }
152         }
153         return os.str();
154     }
155
156     const std::vector<OCRepresentation>& MessageContainer::representations() const
157     {
158         return m_reps;
159     }
160
161     void MessageContainer::addRepresentation(const OCRepresentation& rep)
162     {
163         m_reps.push_back(rep);
164     }
165 }
166
167 namespace OC
168 {
169     std::string OCRepresentation::getJSONRepresentation() const
170     {
171         if(emptyData())
172         {
173             return "{}";
174         }
175
176         std::stringstream os;
177
178         // note: the block is required because cereal closes the JSON string
179         // upon destruction, so the archive needs to be destroyed before accessing
180         // the data
181         {
182             OutputArchiveType archive (os);
183             save(archive);
184         }
185
186         return os.str();
187     }
188
189     void OCRepresentation::addChild(const OCRepresentation& rep)
190     {
191         m_children.push_back(rep);
192     }
193
194     void OCRepresentation::clearChildren()
195     {
196         m_children.clear();
197     }
198
199     const std::vector<OCRepresentation>& OCRepresentation::getChildren() const
200     {
201         return m_children;
202     }
203
204     void OCRepresentation::setChildren(const std::vector<OCRepresentation>& children)
205     {
206         m_children = children;
207     }
208
209     void OCRepresentation::setUri(const std::string& uri)
210     {
211         m_uri = uri;
212     }
213
214     std::string OCRepresentation::getUri() const
215     {
216         return m_uri;
217     }
218
219     const std::vector<std::string>& OCRepresentation::getResourceTypes() const
220     {
221         return m_resourceTypes;
222     }
223
224     void OCRepresentation::setResourceTypes(const std::vector<std::string>& resourceTypes)
225     {
226         m_resourceTypes = resourceTypes;
227     }
228
229     const std::vector<std::string>& OCRepresentation::getResourceInterfaces() const
230     {
231         return m_interfaces;
232     }
233
234     void OCRepresentation::setResourceInterfaces(const std::vector<std::string>& resourceInterfaces)
235     {
236         m_interfaces = resourceInterfaces;
237     }
238
239     bool OCRepresentation::hasAttribute(const std::string& str) const
240     {
241         return m_values.find(str) != m_values.end();
242     }
243
244     bool OCRepresentation::emptyData() const
245     {
246         // This logic is meant to determine whether based on the JSON serialization rules
247         // if this object will result in empty JSON.  URI is only serialized if there is valid
248         // data, ResourceType and Interfaces are only serialized if we are a nothing, a
249         // child of a default or link item.
250         // Our values array is only printed in the if we are the child of a Batch resource,
251         // the parent in a 'default' situation, or not in a child/parent relationship.
252         if(!m_uri.empty())
253         {
254             return false;
255         }
256         else if ((m_interfaceType == InterfaceType::None
257                         || m_interfaceType==InterfaceType::DefaultChild
258                         || m_interfaceType==InterfaceType::LinkChild)
259                     && (m_resourceTypes.size()>0 || m_interfaces.size()>0))
260         {
261             return false;
262         }
263         else if((m_interfaceType == InterfaceType::None
264                         || m_interfaceType == InterfaceType::BatchChild
265                         || m_interfaceType == InterfaceType::DefaultParent)
266                     && m_values.size()>0)
267         {
268             return false;
269         }
270
271         if(m_children.size() > 0)
272         {
273             return false;
274         }
275
276         return true;
277     }
278
279     int OCRepresentation::numberOfAttributes() const
280     {
281         return m_values.size();
282     }
283
284     bool OCRepresentation::erase(const std::string& str)
285     {
286         return m_values.erase(str);
287     }
288
289     void OCRepresentation::setNULL(const std::string& str)
290     {
291         m_values[str] = OC::NullType();
292     }
293
294     bool OCRepresentation::isNULL(const std::string& str) const
295     {
296         auto x = m_values.find(str);
297
298         if(m_values.end() != x)
299         {
300             return x->second.which() == AttributeValueNullIndex;
301         }
302         else
303         {
304             throw OCException(OC::Exception::INVALID_ATTRIBUTE+ str);
305         }
306     }
307 }
308
309 namespace OC
310 {
311     template <class Archive, class Val>
312     void OCRepresentation::optional_load(Archive& ar, Val&& v)
313     {
314         try
315         {
316             ar(v);
317         }
318         catch(cereal::Exception& e)
319         {
320             ar.setNextName(nullptr);
321             // Loading a key that doesn't exist results in an exception
322             // Since "Not Found" is a valid condition for us, we swallow
323             // this exception and the archive will not load anything
324         }
325     }
326
327     template<class Archive>
328     void OCRepresentation::save(Archive& ar) const
329     {
330         // printed for all interface types
331         if(!m_uri.empty())
332         {
333             ar(cereal::make_nvp(Key::URIKEY, m_uri));
334         }
335
336         if((m_interfaceType == InterfaceType::None
337                     || m_interfaceType==InterfaceType::DefaultChild
338                     || m_interfaceType==InterfaceType::LinkChild)
339                 && (m_resourceTypes.size()>0 || m_interfaces.size()>0))
340         {
341             // The Prop object requires that it refer to non-const vectors
342             // so that it can alter them in the 'load' case.  In the save case
343             // (initiated here) it will not modify the object.  So, to keep the
344             // compiler happy, removing the 'const' context here is necessary.
345             const std::vector<std::string>& rt(m_resourceTypes);
346             const std::vector<std::string>& intf(m_interfaces);
347             Prop temp(const_cast<std::vector<std::string>&>(rt),
348                     const_cast<std::vector<std::string>&>(intf));
349             ar(cereal::make_nvp(Key::PROPERTYKEY, temp));
350         }
351
352         // printed only for BatchChildren and DefaultParent
353         if((m_interfaceType == InterfaceType::None
354                     || m_interfaceType == InterfaceType::BatchChild
355                     || m_interfaceType == InterfaceType::DefaultParent)
356                 && m_values.size()>0)
357         {
358             ar(cereal::make_nvp(Key::REPKEY, m_values));
359         }
360     }
361
362     template<class Archive>
363     void OCRepresentation::load(Archive& ar)
364     {
365         optional_load(ar, cereal::make_nvp(Key::URIKEY, m_uri));
366         {
367             Prop temp(m_resourceTypes, m_interfaces);
368             optional_load(ar, cereal::make_nvp(Key::PROPERTYKEY, temp));
369         }
370         optional_load(ar, cereal::make_nvp(Key::REPKEY, m_values));
371     }
372
373     template<class Archive>
374     void OCRepresentation::Prop::save(Archive& ar) const
375     {
376         if(m_types.size() > 0)
377         {
378             ar(cereal::make_nvp(Key::RESOURCETYPESKEY, m_types));
379         }
380
381         if(m_interfaces.size()>0)
382         {
383             ar(cereal::make_nvp(Key::INTERFACESKEY, m_interfaces));
384         }
385     }
386
387     template<class Archive>
388     void OCRepresentation::Prop::load(Archive& ar)
389     {
390         optional_load(ar, cereal::make_nvp(Key::RESOURCETYPESKEY, m_types));
391         optional_load(ar, cereal::make_nvp(Key::INTERFACESKEY, m_interfaces));
392     }
393 }
394
395 // note: the below is used to load an AttributeValue map out of JSON
396 namespace OC
397 {
398     namespace detail
399     {
400         enum class typeTag:uint8_t
401         {
402             NOTHING = 0,
403             _string,
404             _int,
405             _double,
406             _bool,
407             _representation
408         };
409
410         typedef rapidjson::Document::GenericValue GenericValue;
411
412         AttributeValue parseAttributeValue(const GenericValue& v);
413         AttributeValue parseAttributeValue(const GenericValue& v,
414                 const unsigned int curLevel, unsigned int& maxDepth, typeTag& t);
415         AttributeValue parseAttributeValueObject(const GenericValue& v, typeTag& t);
416         AttributeValue parseAttributeValueArray(const GenericValue& v,
417                 const unsigned int curLevel, unsigned int& maxDepth, typeTag& t);
418         AttributeValue parseAttributeValuePrimitive(const GenericValue& v, typeTag& t);
419
420         AttributeValue parseAttributeValue(const GenericValue& v)
421         {
422             // base entrance, start everything at '0'
423             unsigned int max_depth {0};
424             typeTag t {typeTag::NOTHING};
425
426             return parseAttributeValue(v, 0, max_depth, t);
427         }
428
429         AttributeValue parseAttributeValue(const GenericValue& v,
430                 const unsigned int curLevel, unsigned int& maxDepth, typeTag& t)
431         {
432             if(v.IsObject())
433             {
434                 return parseAttributeValueObject(v, t);
435             }
436             else if(v.IsArray())
437             {
438                 return parseAttributeValueArray(v, curLevel + 1, maxDepth, t);
439             }
440             else
441             {
442                 return parseAttributeValuePrimitive(v,t);
443             }
444         }
445
446         AttributeValue parseAttributeValueObject(const GenericValue& v, typeTag& t)
447         {
448             typedef rapidjson::Value::ConstMemberIterator CMI;
449             t = typeTag::_representation;
450             OC::OCRepresentation rep;
451
452             for(CMI itr = v.MemberBegin(); itr!= v.MemberEnd(); ++itr)
453             {
454                 std::string keyName = itr->name.GetString();
455
456                 if(keyName == OC::Key::URIKEY)
457                 {
458                     rep.setUri(boost::get<std::string>(parseAttributeValue(itr->value)));
459                 }
460                 else if (keyName == OC::Key::PROPERTYKEY)
461                 {
462                     for(CMI itr2 = itr->value.MemberBegin();
463                             itr->value.MemberEnd()!=itr2;
464                             ++itr2)
465                     {
466                         if(keyName == OC::Key::RESOURCETYPESKEY)
467                         {
468                             rep.setResourceTypes(
469                                     boost::get<std::vector<std::string>>(
470                                         parseAttributeValue(itr->value)));
471                         }
472                         else if(keyName == OC::Key::PROPERTYKEY)
473                         {
474                             rep.setResourceInterfaces(
475                                     boost::get<std::vector<std::string>>(
476                                         parseAttributeValue(itr->value)));
477                         }
478                     }
479                 }
480                 else if (keyName == OC::Key::REPKEY)
481                 {
482                     for(CMI itr2 = itr->value.MemberBegin();
483                             itr->value.MemberEnd()!=itr2;
484                             ++itr2)
485                     {
486                         rep.setValue(itr2->name.GetString(),
487                                 parseAttributeValue(itr2->value));
488                     }
489                 }
490             }
491
492             return rep;
493         }
494
495         AttributeValue parseAttributeValuePrimitive(const GenericValue& v, typeTag& t)
496         {
497             if(v.IsString())
498             {
499                 t = typeTag::_string;
500                 return std::string(v.GetString());
501             }
502             else if (v.IsNumber())
503             {
504                 if(v.IsDouble())
505                 {
506                     t = typeTag::_double;
507                     return double(v.GetDouble());
508                 }
509                 else if (v.IsInt())
510                 {
511                     t = typeTag::_int;
512                     return int(v.GetInt());
513                 }
514                 else
515                 {
516                     throw OC::OCException(OC::Exception::INVALID_JSON_NUMERIC
517                             + std::to_string(v.GetType()));
518                 }
519             }
520             else if(v.IsBool_())
521             {
522                 t=typeTag::_bool;
523                 return bool(v.GetBool_());
524             }
525             else if(v.IsNull_())
526             {
527                 return OC::NullType();
528             }
529             else
530             {
531                 throw OC::OCException(OC::Exception::INVALID_JSON_TYPE
532                         + std::to_string(v.GetType()));
533             }
534         }
535
536         std::vector<AttributeValue> gatherArrayContents(const GenericValue& v,
537                 const unsigned int curLevel, unsigned int& maxDepth, typeTag& t)
538         {
539             std::vector<AttributeValue> out;
540
541             std::transform(v.Begin(), v.End(), back_inserter(out),
542                     [curLevel, &maxDepth, &t](const GenericValue& x)
543                     {
544                         return parseAttributeValue(x, curLevel, maxDepth, t);
545                     });
546             return out;
547         }
548
549         template<class OutT>
550         struct valueToConcrete
551         {
552             OutT operator()(const AttributeValue& v)
553             {
554                 return boost::get<OutT>(v);
555             }
556
557         };
558
559         template <class OutSeqT>
560         OutSeqT valuesToConcreteVectors(const std::vector<AttributeValue>& vs)
561         {
562             OutSeqT ret;
563
564             std::transform(begin(vs),end(vs), back_inserter(ret),
565                 valueToConcrete<typename OutSeqT::value_type>());
566             return ret;
567         }
568
569         template<class valueType>
570         AttributeValue remapArrayDepth(const unsigned int curLevel,
571                 const std::vector<OC::AttributeValue>& vs)
572         {
573             switch(curLevel)
574             {
575                 default:
576                     throw OC::OCException(OC::Exception::INVALID_JSON_ARRAY_DEPTH);
577                     break;
578                 case 1:
579                     return valuesToConcreteVectors<std::vector<valueType>>(vs);
580                     break;
581                 case 2:
582                     return valuesToConcreteVectors<std::vector<std::vector<valueType>>>(vs);
583                     break;
584                 case 3:
585                     return valuesToConcreteVectors
586                         <std::vector<std::vector<std::vector<valueType>>>>(vs);
587                     break;
588             }
589         }
590
591         AttributeValue convertArrayToConcretes(const typeTag t,
592                 const unsigned int curLevel, const std::vector<OC::AttributeValue>& vs)
593         {
594             // This function converts a std::vector of AttributeValue to a std::vector
595             // of concrete types.  Since we don't use a recursive Variant, we need
596             // to get back to a 'base' primitive type
597             switch(t)
598             {
599                 default:
600                 case typeTag::NOTHING:
601                     throw OC::OCException(OC::Exception::INVALID_JSON_TYPE_TAG);
602                     break;
603                 case typeTag::_string:
604                     return remapArrayDepth<std::string>(curLevel, vs);
605                     break;
606                 case typeTag::_int:
607                     return remapArrayDepth<int>(curLevel, vs);
608                     break;
609                 case typeTag::_double:
610                     return remapArrayDepth<double>(curLevel, vs);
611                     break;
612                 case typeTag::_bool:
613                     return remapArrayDepth<bool>(curLevel, vs);
614                     break;
615                 case typeTag::_representation:
616                     return remapArrayDepth<OCRepresentation>(curLevel, vs);
617                     break;
618             }
619         }
620
621         AttributeValue parseAttributeValueArray(const GenericValue& v,
622                 const unsigned int curLevel, unsigned int& maxDepth, typeTag& t)
623         {
624             const unsigned int max_level = 3;
625
626             if(curLevel > max_level)
627             {
628                 throw OC::OCException(OC::Exception::INVALID_JSON_ARRAY_DEPTH);
629             }
630
631             if(curLevel > maxDepth)
632             {
633                 maxDepth = curLevel;
634             }
635
636             auto arrayItems = gatherArrayContents(v, curLevel, maxDepth, t);
637             const int remapLevel = maxDepth - (curLevel -1);
638             return convertArrayToConcretes(t, remapLevel, arrayItems);
639         }
640     }
641 }
642
643 namespace cereal
644 {
645    void JSONInputArchive::loadAttributeValues(std::map<std::string, OC::AttributeValue>& map)
646    {
647        for(auto&b = itsIteratorStack.back();
648            b.Member && b.itsMemberItEnd != b.itsMemberItBegin+b.itsIndex;
649            ++b)
650        {
651            std::string key = b.itsMemberItBegin[b.itsIndex].name.GetString();
652            const GenericValue& v = itsIteratorStack.back().value();
653            map[key] = OC::detail::parseAttributeValue(v);
654        }
655    }
656 }
657
658 namespace OC
659 {
660     std::ostream& operator <<(std::ostream& os, const AttributeType at)
661     {
662         switch(at)
663         {
664             case AttributeType::Null:
665                 os << "Null";
666                 break;
667             case AttributeType::Integer:
668                 os << "Integer";
669                 break;
670             case AttributeType::Double:
671                 os << "Double";
672                 break;
673             case AttributeType::Boolean:
674                 os << "Boolean";
675                 break;
676             case AttributeType::String:
677                 os << "String";
678                 break;
679             case AttributeType::OCRepresentation:
680                 os << "OCRepresentation";
681                 break;
682             case AttributeType::Vector:
683                 os << "Vector";
684                 break;
685         }
686         return os;
687     }
688 }
689
690 // STL Container For OCRepresentation
691 namespace OC
692 {
693     OCRepresentation::AttributeItem::AttributeItem(const std::string& name,
694             std::map<std::string, AttributeValue>& vals):
695             m_attrName(name), m_values(vals){}
696
697     OCRepresentation::AttributeItem OCRepresentation::operator[](const std::string& key)
698     {
699         OCRepresentation::AttributeItem attr{key, m_values};
700         return std::move(attr);
701     }
702
703     const OCRepresentation::AttributeItem OCRepresentation::operator[](const std::string& key) const
704     {
705         OCRepresentation::AttributeItem attr{key, m_values};
706         return std::move(attr);
707     }
708
709     const std::string& OCRepresentation::AttributeItem::attrname() const
710     {
711         return m_attrName;
712     }
713
714     template<typename T, typename = void>
715     struct type_info
716     {
717         // contains the actual type
718         typedef T type;
719         // contains the inner most vector-type
720         typedef T base_type;
721         // contains the AttributeType for this item
722         constexpr static AttributeType enum_type =
723             AttributeTypeConvert<T>::type;
724         // contains the AttributeType for this base-type
725         constexpr static AttributeType enum_base_type =
726             AttributeTypeConvert<T>::type;
727         // depth of the vector
728         constexpr static size_t depth = 0;
729     };
730
731     template<typename T>
732     struct type_info<T, typename std::enable_if<is_vector<T>::value>::type>
733     {
734         typedef T type;
735         typedef typename type_info<typename T::value_type>::base_type base_type;
736         constexpr static AttributeType enum_type = AttributeType::Vector;
737         constexpr static AttributeType enum_base_type =
738             type_info<typename T::value_type>::enum_base_type;
739         constexpr static size_t depth = 1 +
740             type_info<typename T::value_type>::depth;
741     };
742
743     struct type_introspection_visitor : boost::static_visitor<>
744     {
745         AttributeType type;
746         AttributeType base_type;
747         size_t depth;
748
749         type_introspection_visitor() : boost::static_visitor<>(),
750             type(AttributeType::Null), base_type(AttributeType::Null), depth(0){}
751
752         template <typename T>
753         void operator()(T const& item)
754         {
755             type = type_info<T>::enum_type;
756             base_type = type_info<T>::enum_base_type;
757             depth = type_info<T>::depth;
758         }
759     };
760
761     AttributeType OCRepresentation::AttributeItem::type() const
762     {
763         type_introspection_visitor vis;
764         boost::apply_visitor(vis, m_values[m_attrName]);
765         return vis.type;
766     }
767
768     AttributeType OCRepresentation::AttributeItem::base_type() const
769     {
770         type_introspection_visitor vis;
771         boost::apply_visitor(vis, m_values[m_attrName]);
772         return vis.base_type;
773     }
774
775     size_t OCRepresentation::AttributeItem::depth() const
776     {
777         type_introspection_visitor vis;
778         boost::apply_visitor(vis, m_values[m_attrName]);
779         return vis.depth;
780     }
781
782     OCRepresentation::iterator OCRepresentation::begin()
783     {
784         return OCRepresentation::iterator(m_values.begin(), m_values);
785     }
786
787     OCRepresentation::const_iterator OCRepresentation::begin() const
788     {
789          return OCRepresentation::const_iterator(m_values.begin(), m_values);
790     }
791
792     OCRepresentation::const_iterator OCRepresentation::cbegin() const
793     {
794         return OCRepresentation::const_iterator(m_values.cbegin(), m_values);
795     }
796
797     OCRepresentation::iterator OCRepresentation::end()
798     {
799         return OCRepresentation::iterator(m_values.end(), m_values);
800     }
801
802     OCRepresentation::const_iterator OCRepresentation::end() const
803     {
804         return OCRepresentation::const_iterator(m_values.end(), m_values);
805     }
806
807     OCRepresentation::const_iterator OCRepresentation::cend() const
808     {
809         return OCRepresentation::const_iterator(m_values.cend(), m_values);
810     }
811
812     size_t OCRepresentation::size() const
813     {
814         return m_values.size();
815     }
816
817     bool OCRepresentation::empty() const
818     {
819         return m_values.empty();
820     }
821
822     bool OCRepresentation::iterator::operator==(const OCRepresentation::iterator& rhs) const
823     {
824         return m_iterator == rhs.m_iterator;
825     }
826
827     bool OCRepresentation::iterator::operator!=(const OCRepresentation::iterator& rhs) const
828     {
829         return m_iterator != rhs.m_iterator;
830     }
831
832     bool OCRepresentation::const_iterator::operator==(
833             const OCRepresentation::const_iterator& rhs) const
834     {
835         return m_iterator == rhs.m_iterator;
836     }
837
838     bool OCRepresentation::const_iterator::operator!=(
839             const OCRepresentation::const_iterator& rhs) const
840     {
841         return m_iterator != rhs.m_iterator;
842     }
843
844     OCRepresentation::iterator::reference OCRepresentation::iterator::operator*()
845     {
846         return m_item;
847     }
848
849     OCRepresentation::const_iterator::const_reference
850         OCRepresentation::const_iterator::operator*() const
851     {
852         return m_item;
853     }
854
855     OCRepresentation::iterator::pointer OCRepresentation::iterator::operator->()
856     {
857         return &m_item;
858     }
859
860     OCRepresentation::const_iterator::const_pointer
861         OCRepresentation::const_iterator::operator->() const
862     {
863         return &m_item;
864     }
865
866     OCRepresentation::iterator& OCRepresentation::iterator::operator++()
867     {
868         m_iterator++;
869         if(m_iterator != m_item.m_values.end())
870         {
871             m_item.m_attrName = m_iterator->first;
872         }
873         else
874         {
875             m_item.m_attrName = "";
876         }
877         return *this;
878     }
879
880     OCRepresentation::const_iterator& OCRepresentation::const_iterator::operator++()
881     {
882         m_iterator++;
883         if(m_iterator != m_item.m_values.end())
884         {
885             m_item.m_attrName = m_iterator->first;
886         }
887         else
888         {
889             m_item.m_attrName = "";
890         }
891         return *this;
892     }
893
894     OCRepresentation::iterator OCRepresentation::iterator::operator++(int)
895     {
896         OCRepresentation::iterator itr(*this);
897         ++(*this);
898         return itr;
899     }
900
901     OCRepresentation::const_iterator OCRepresentation::const_iterator::operator++(int)
902     {
903         OCRepresentation::const_iterator itr(*this);
904         ++(*this);
905         return itr;
906     }
907
908     struct to_string_visitor : boost::static_visitor<>
909     {
910         std::string str;
911         template <typename T>
912         void operator()(T const& item)
913         {
914             str = boost::lexical_cast<std::string>(item);
915         }
916
917         template <typename T>
918         void operator()(std::vector<T> const& item)
919         {
920             to_string_visitor vis;
921             std::ostringstream stream;
922             stream << "[";
923
924             for(const auto& i : item)
925             {
926                 vis(i);
927                 stream << vis.str  << " ";
928             }
929             stream << "]";
930             str = stream.str();
931         }
932     };
933
934     template<>
935     void to_string_visitor::operator()(bool const& item)
936     {
937         str = item ? "true" : "false";
938     }
939
940     template<>
941     void to_string_visitor::operator()(std::string const& item)
942     {
943         str = item;
944     }
945
946     template<>
947     void to_string_visitor::operator()(NullType const& item)
948     {
949         str = "(null)";
950     }
951
952     template<>
953     void to_string_visitor::operator()(OCRepresentation const& item)
954     {
955         str = "OC::OCRepresentation";
956     }
957
958     std::string OCRepresentation::getValueToString(const std::string& key) const
959     {
960         auto x = m_values.find(key);
961         if(x != m_values.end())
962         {
963             to_string_visitor vis;
964             boost::apply_visitor(vis, x->second);
965             return std::move(vis.str);
966         }
967
968         return "";
969     }
970
971     std::string OCRepresentation::AttributeItem::getValueToString() const
972     {
973         to_string_visitor vis;
974         boost::apply_visitor(vis, m_values[m_attrName]);
975         return std::move(vis.str);
976     }
977
978     std::ostream& operator<<(std::ostream& os, const OCRepresentation::AttributeItem& ai)
979     {
980         os << ai.getValueToString();
981         return os;
982     }
983 }