1 //******************************************************************
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
24 * This file contains the implementation of classes and its members related
25 * to OCRepresentation.
29 #include "OCAndroid.h"
32 #include <OCRepresentation.h>
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>
42 // code needed to serialize a string=>Attribute value map
47 template<class Archive>
48 class WriteAttributeValue : public boost::static_visitor<>
51 WriteAttributeValue(const std::string& name, Archive& ar)
52 :m_name(name), m_archive(ar)
56 void operator()(const T& value) const
58 m_archive(cereal::make_nvp(m_name, value));
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)
75 template<class Archive>
76 void save(Archive& ar, const std::map<std::string, OC::AttributeValue>& vals)
78 for(const auto& kv : vals)
80 const auto& k = kv.first;
81 const auto& v = kv.second;
83 if(v.which() != OC::AttributeValueNullIndex)
85 OC::detail::WriteAttributeValue<Archive> writer(k,ar);
86 boost::apply_visitor(writer, v);
90 ar.setNextName(k.c_str());
97 template<class Archive>
98 void load(Archive& ar, std::map<std::string, OC::AttributeValue>& vals)
100 ar.loadAttributeValues(vals);
106 typedef cereal::JSONOutputArchive OutputArchiveType;
107 typedef cereal::JSONInputArchive InputArchiveType;
109 void MessageContainer::setJSONRepresentation(const std::string& payload)
111 std::stringstream os(payload);
113 InputArchiveType archive(os);
114 archive(cereal::make_nvp(OC::Key::OCKEY, m_reps));
118 void MessageContainer::setJSONRepresentation(const unsigned char* payload)
120 setJSONRepresentation(std::string(reinterpret_cast<const char*>(payload)));
123 std::string MessageContainer::getJSONRepresentation(OCInfoFormat f) const
125 std::stringstream os;
127 // note: the block is required because cereal closes the JSON string
128 // upon destruction, so the archive needs to be destroyed before accessing
131 if(f == OCInfoFormat::IncludeOC)
133 OutputArchiveType archive(os);
134 archive(cereal::make_nvp(OC::Key::OCKEY, m_reps));
136 else if(f== OCInfoFormat::ExcludeOC)
138 bool firstPrinted = false;
139 for(std::vector<OCRepresentation>::size_type i = 0; i< m_reps.size();++i)
141 if(!m_reps[i].emptyData())
148 os << m_reps[i].getJSONRepresentation();
156 const std::vector<OCRepresentation>& MessageContainer::representations() const
161 void MessageContainer::addRepresentation(const OCRepresentation& rep)
163 m_reps.push_back(rep);
169 std::string OCRepresentation::getJSONRepresentation() const
176 std::stringstream os;
178 // note: the block is required because cereal closes the JSON string
179 // upon destruction, so the archive needs to be destroyed before accessing
182 OutputArchiveType archive (os);
189 void OCRepresentation::addChild(const OCRepresentation& rep)
191 m_children.push_back(rep);
194 void OCRepresentation::clearChildren()
199 const std::vector<OCRepresentation>& OCRepresentation::getChildren() const
204 void OCRepresentation::setChildren(const std::vector<OCRepresentation>& children)
206 m_children = children;
209 void OCRepresentation::setUri(const std::string& uri)
214 std::string OCRepresentation::getUri() const
219 const std::vector<std::string>& OCRepresentation::getResourceTypes() const
221 return m_resourceTypes;
224 void OCRepresentation::setResourceTypes(const std::vector<std::string>& resourceTypes)
226 m_resourceTypes = resourceTypes;
229 const std::vector<std::string>& OCRepresentation::getResourceInterfaces() const
234 void OCRepresentation::setResourceInterfaces(const std::vector<std::string>& resourceInterfaces)
236 m_interfaces = resourceInterfaces;
239 bool OCRepresentation::hasAttribute(const std::string& str) const
241 return m_values.find(str) != m_values.end();
244 bool OCRepresentation::emptyData() const
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.
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))
263 else if((m_interfaceType == InterfaceType::None
264 || m_interfaceType == InterfaceType::BatchChild
265 || m_interfaceType == InterfaceType::DefaultParent)
266 && m_values.size()>0)
271 if(m_children.size() > 0)
279 int OCRepresentation::numberOfAttributes() const
281 return m_values.size();
284 bool OCRepresentation::erase(const std::string& str)
286 return m_values.erase(str);
289 void OCRepresentation::setNULL(const std::string& str)
291 m_values[str] = OC::NullType();
294 bool OCRepresentation::isNULL(const std::string& str) const
296 auto x = m_values.find(str);
298 if(m_values.end() != x)
300 return x->second.which() == AttributeValueNullIndex;
304 throw OCException(OC::Exception::INVALID_ATTRIBUTE+ str);
311 template <class Archive, class Val>
312 void OCRepresentation::optional_load(Archive& ar, Val&& v)
318 catch(cereal::Exception& e)
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
327 template<class Archive>
328 void OCRepresentation::save(Archive& ar) const
330 // printed for all interface types
333 ar(cereal::make_nvp(Key::URIKEY, m_uri));
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))
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));
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)
358 ar(cereal::make_nvp(Key::REPKEY, m_values));
362 template<class Archive>
363 void OCRepresentation::load(Archive& ar)
365 optional_load(ar, cereal::make_nvp(Key::URIKEY, m_uri));
367 Prop temp(m_resourceTypes, m_interfaces);
368 optional_load(ar, cereal::make_nvp(Key::PROPERTYKEY, temp));
370 optional_load(ar, cereal::make_nvp(Key::REPKEY, m_values));
373 template<class Archive>
374 void OCRepresentation::Prop::save(Archive& ar) const
376 if(m_types.size() > 0)
378 ar(cereal::make_nvp(Key::RESOURCETYPESKEY, m_types));
381 if(m_interfaces.size()>0)
383 ar(cereal::make_nvp(Key::INTERFACESKEY, m_interfaces));
387 template<class Archive>
388 void OCRepresentation::Prop::load(Archive& ar)
390 optional_load(ar, cereal::make_nvp(Key::RESOURCETYPESKEY, m_types));
391 optional_load(ar, cereal::make_nvp(Key::INTERFACESKEY, m_interfaces));
395 // note: the below is used to load an AttributeValue map out of JSON
400 enum class typeTag:uint8_t
410 typedef rapidjson::Document::GenericValue GenericValue;
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);
420 AttributeValue parseAttributeValue(const GenericValue& v)
422 // base entrance, start everything at '0'
423 unsigned int max_depth {0};
424 typeTag t {typeTag::NOTHING};
426 return parseAttributeValue(v, 0, max_depth, t);
429 AttributeValue parseAttributeValue(const GenericValue& v,
430 const unsigned int curLevel, unsigned int& maxDepth, typeTag& t)
434 return parseAttributeValueObject(v, t);
438 return parseAttributeValueArray(v, curLevel + 1, maxDepth, t);
442 return parseAttributeValuePrimitive(v,t);
446 AttributeValue parseAttributeValueObject(const GenericValue& v, typeTag& t)
448 typedef rapidjson::Value::ConstMemberIterator CMI;
449 t = typeTag::_representation;
450 OC::OCRepresentation rep;
452 for(CMI itr = v.MemberBegin(); itr!= v.MemberEnd(); ++itr)
454 std::string keyName = itr->name.GetString();
456 if(keyName == OC::Key::URIKEY)
458 rep.setUri(boost::get<std::string>(parseAttributeValue(itr->value)));
460 else if (keyName == OC::Key::PROPERTYKEY)
462 for(CMI itr2 = itr->value.MemberBegin();
463 itr->value.MemberEnd()!=itr2;
466 if(keyName == OC::Key::RESOURCETYPESKEY)
468 rep.setResourceTypes(
469 boost::get<std::vector<std::string>>(
470 parseAttributeValue(itr->value)));
472 else if(keyName == OC::Key::PROPERTYKEY)
474 rep.setResourceInterfaces(
475 boost::get<std::vector<std::string>>(
476 parseAttributeValue(itr->value)));
480 else if (keyName == OC::Key::REPKEY)
482 for(CMI itr2 = itr->value.MemberBegin();
483 itr->value.MemberEnd()!=itr2;
486 rep.setValue(itr2->name.GetString(),
487 parseAttributeValue(itr2->value));
495 AttributeValue parseAttributeValuePrimitive(const GenericValue& v, typeTag& t)
499 t = typeTag::_string;
500 return std::string(v.GetString());
502 else if (v.IsNumber())
506 t = typeTag::_double;
507 return double(v.GetDouble());
512 return int(v.GetInt());
516 throw OC::OCException(OC::Exception::INVALID_JSON_NUMERIC
517 + std::to_string(v.GetType()));
523 return bool(v.GetBool_());
527 return OC::NullType();
531 throw OC::OCException(OC::Exception::INVALID_JSON_TYPE
532 + std::to_string(v.GetType()));
536 std::vector<AttributeValue> gatherArrayContents(const GenericValue& v,
537 const unsigned int curLevel, unsigned int& maxDepth, typeTag& t)
539 std::vector<AttributeValue> out;
541 std::transform(v.Begin(), v.End(), back_inserter(out),
542 [curLevel, &maxDepth, &t](const GenericValue& x)
544 return parseAttributeValue(x, curLevel, maxDepth, t);
550 struct valueToConcrete
552 OutT operator()(const AttributeValue& v)
554 return boost::get<OutT>(v);
559 template <class OutSeqT>
560 OutSeqT valuesToConcreteVectors(const std::vector<AttributeValue>& vs)
564 std::transform(begin(vs),end(vs), back_inserter(ret),
565 valueToConcrete<typename OutSeqT::value_type>());
569 template<class valueType>
570 AttributeValue remapArrayDepth(const unsigned int curLevel,
571 const std::vector<OC::AttributeValue>& vs)
576 throw OC::OCException(OC::Exception::INVALID_JSON_ARRAY_DEPTH);
579 return valuesToConcreteVectors<std::vector<valueType>>(vs);
582 return valuesToConcreteVectors<std::vector<std::vector<valueType>>>(vs);
585 return valuesToConcreteVectors
586 <std::vector<std::vector<std::vector<valueType>>>>(vs);
591 AttributeValue convertArrayToConcretes(const typeTag t,
592 const unsigned int curLevel, const std::vector<OC::AttributeValue>& vs)
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
600 case typeTag::NOTHING:
601 throw OC::OCException(OC::Exception::INVALID_JSON_TYPE_TAG);
603 case typeTag::_string:
604 return remapArrayDepth<std::string>(curLevel, vs);
607 return remapArrayDepth<int>(curLevel, vs);
609 case typeTag::_double:
610 return remapArrayDepth<double>(curLevel, vs);
613 return remapArrayDepth<bool>(curLevel, vs);
615 case typeTag::_representation:
616 return remapArrayDepth<OCRepresentation>(curLevel, vs);
621 AttributeValue parseAttributeValueArray(const GenericValue& v,
622 const unsigned int curLevel, unsigned int& maxDepth, typeTag& t)
624 const unsigned int max_level = 3;
626 if(curLevel > max_level)
628 throw OC::OCException(OC::Exception::INVALID_JSON_ARRAY_DEPTH);
631 if(curLevel > maxDepth)
636 auto arrayItems = gatherArrayContents(v, curLevel, maxDepth, t);
637 const int remapLevel = maxDepth - (curLevel -1);
638 return convertArrayToConcretes(t, remapLevel, arrayItems);
645 void JSONInputArchive::loadAttributeValues(std::map<std::string, OC::AttributeValue>& map)
647 for(auto&b = itsIteratorStack.back();
648 b.Member && b.itsMemberItEnd != b.itsMemberItBegin+b.itsIndex;
651 std::string key = b.itsMemberItBegin[b.itsIndex].name.GetString();
652 const GenericValue& v = itsIteratorStack.back().value();
653 map[key] = OC::detail::parseAttributeValue(v);
660 std::ostream& operator <<(std::ostream& os, const AttributeType at)
664 case AttributeType::Null:
667 case AttributeType::Integer:
670 case AttributeType::Double:
673 case AttributeType::Boolean:
676 case AttributeType::String:
679 case AttributeType::OCRepresentation:
680 os << "OCRepresentation";
682 case AttributeType::Vector:
690 // STL Container For OCRepresentation
693 OCRepresentation::AttributeItem::AttributeItem(const std::string& name,
694 std::map<std::string, AttributeValue>& vals):
695 m_attrName(name), m_values(vals){}
697 OCRepresentation::AttributeItem OCRepresentation::operator[](const std::string& key)
699 OCRepresentation::AttributeItem attr{key, m_values};
700 return std::move(attr);
703 const OCRepresentation::AttributeItem OCRepresentation::operator[](const std::string& key) const
705 OCRepresentation::AttributeItem attr{key, m_values};
706 return std::move(attr);
709 const std::string& OCRepresentation::AttributeItem::attrname() const
714 template<typename T, typename = void>
717 // contains the actual type
719 // contains the inner most vector-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;
732 struct type_info<T, typename std::enable_if<is_vector<T>::value>::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;
743 struct type_introspection_visitor : boost::static_visitor<>
746 AttributeType base_type;
749 type_introspection_visitor() : boost::static_visitor<>(),
750 type(AttributeType::Null), base_type(AttributeType::Null), depth(0){}
752 template <typename T>
753 void operator()(T const& item)
755 type = type_info<T>::enum_type;
756 base_type = type_info<T>::enum_base_type;
757 depth = type_info<T>::depth;
761 AttributeType OCRepresentation::AttributeItem::type() const
763 type_introspection_visitor vis;
764 boost::apply_visitor(vis, m_values[m_attrName]);
768 AttributeType OCRepresentation::AttributeItem::base_type() const
770 type_introspection_visitor vis;
771 boost::apply_visitor(vis, m_values[m_attrName]);
772 return vis.base_type;
775 size_t OCRepresentation::AttributeItem::depth() const
777 type_introspection_visitor vis;
778 boost::apply_visitor(vis, m_values[m_attrName]);
782 OCRepresentation::iterator OCRepresentation::begin()
784 return OCRepresentation::iterator(m_values.begin(), m_values);
787 OCRepresentation::const_iterator OCRepresentation::begin() const
789 return OCRepresentation::const_iterator(m_values.begin(), m_values);
792 OCRepresentation::const_iterator OCRepresentation::cbegin() const
794 return OCRepresentation::const_iterator(m_values.cbegin(), m_values);
797 OCRepresentation::iterator OCRepresentation::end()
799 return OCRepresentation::iterator(m_values.end(), m_values);
802 OCRepresentation::const_iterator OCRepresentation::end() const
804 return OCRepresentation::const_iterator(m_values.end(), m_values);
807 OCRepresentation::const_iterator OCRepresentation::cend() const
809 return OCRepresentation::const_iterator(m_values.cend(), m_values);
812 size_t OCRepresentation::size() const
814 return m_values.size();
817 bool OCRepresentation::empty() const
819 return m_values.empty();
822 bool OCRepresentation::iterator::operator==(const OCRepresentation::iterator& rhs) const
824 return m_iterator == rhs.m_iterator;
827 bool OCRepresentation::iterator::operator!=(const OCRepresentation::iterator& rhs) const
829 return m_iterator != rhs.m_iterator;
832 bool OCRepresentation::const_iterator::operator==(
833 const OCRepresentation::const_iterator& rhs) const
835 return m_iterator == rhs.m_iterator;
838 bool OCRepresentation::const_iterator::operator!=(
839 const OCRepresentation::const_iterator& rhs) const
841 return m_iterator != rhs.m_iterator;
844 OCRepresentation::iterator::reference OCRepresentation::iterator::operator*()
849 OCRepresentation::const_iterator::const_reference
850 OCRepresentation::const_iterator::operator*() const
855 OCRepresentation::iterator::pointer OCRepresentation::iterator::operator->()
860 OCRepresentation::const_iterator::const_pointer
861 OCRepresentation::const_iterator::operator->() const
866 OCRepresentation::iterator& OCRepresentation::iterator::operator++()
869 if(m_iterator != m_item.m_values.end())
871 m_item.m_attrName = m_iterator->first;
875 m_item.m_attrName = "";
880 OCRepresentation::const_iterator& OCRepresentation::const_iterator::operator++()
883 if(m_iterator != m_item.m_values.end())
885 m_item.m_attrName = m_iterator->first;
889 m_item.m_attrName = "";
894 OCRepresentation::iterator OCRepresentation::iterator::operator++(int)
896 OCRepresentation::iterator itr(*this);
901 OCRepresentation::const_iterator OCRepresentation::const_iterator::operator++(int)
903 OCRepresentation::const_iterator itr(*this);
908 struct to_string_visitor : boost::static_visitor<>
911 template <typename T>
912 void operator()(T const& item)
914 str = boost::lexical_cast<std::string>(item);
917 template <typename T>
918 void operator()(std::vector<T> const& item)
920 to_string_visitor vis;
921 std::ostringstream stream;
924 for(const auto& i : item)
927 stream << vis.str << " ";
935 void to_string_visitor::operator()(bool const& item)
937 str = item ? "true" : "false";
941 void to_string_visitor::operator()(std::string const& item)
947 void to_string_visitor::operator()(NullType const& item)
953 void to_string_visitor::operator()(OCRepresentation const& item)
955 str = "OC::OCRepresentation";
958 std::string OCRepresentation::getValueToString(const std::string& key) const
960 auto x = m_values.find(key);
961 if(x != m_values.end())
963 to_string_visitor vis;
964 boost::apply_visitor(vis, x->second);
965 return std::move(vis.str);
971 std::string OCRepresentation::AttributeItem::getValueToString() const
973 to_string_visitor vis;
974 boost::apply_visitor(vis, m_values[m_attrName]);
975 return std::move(vis.str);
978 std::ostream& operator<<(std::ostream& os, const OCRepresentation::AttributeItem& ai)
980 os << ai.getValueToString();