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