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