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 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21 /// @file OCRepresentation.cpp
23 /// @brief This file contains the implementation of classes and its members
24 /// related to OCRepresentation
26 #include <cereal/cereal.hpp>
27 #include <cereal/types/map.hpp>
28 #include <cereal/types/vector.hpp>
29 #include <cereal/types/utility.hpp>
31 #include <OCRepresentation.h>
34 typedef cereal::JSONOutputArchive OutputArchiveType;
35 typedef cereal::JSONInputArchive InputArchiveType;
37 void MessageContainer::setJSONRepresentation(const std::string& payload)
39 std::stringstream os(payload);
41 InputArchiveType archive(os);
42 archive(cereal::make_nvp(OC::Key::OCKEY, m_reps));
46 void MessageContainer::setJSONRepresentation(const unsigned char* payload)
48 setJSONRepresentation(std::string(reinterpret_cast<const char*>(payload)));
51 std::string MessageContainer::getJSONRepresentation(OCInfoFormat f) const
55 // note: the block is required because cereal closes the JSON string
56 // upon destruction, so the archive needs to be destroyed before accessing
59 if(f == OCInfoFormat::IncludeOC)
61 OutputArchiveType archive(os);
62 archive(cereal::make_nvp(OC::Key::OCKEY, m_reps));
64 else if(f== OCInfoFormat::ExcludeOC)
66 bool firstPrinted = false;
67 for(std::vector<OCRepresentation>::size_type i = 0; i< m_reps.size();++i)
69 if(!m_reps[i].empty())
76 os << m_reps[i].getJSONRepresentation();
84 const std::vector<OCRepresentation>& MessageContainer::representations() const
89 void MessageContainer::addRepresentation(const OCRepresentation& rep)
91 m_reps.push_back(rep);
97 OCRepresentation::OCRepresentation()
98 :m_interfaceType(InterfaceType::None)
100 std::string OCRepresentation::getJSONRepresentation() const
102 std::stringstream os;
104 // note: the block is required because cereal closes the JSON string
105 // upon destruction, so the archive needs to be destroyed before accessing
108 OutputArchiveType archive (os);
115 void OCRepresentation::addChild(const OCRepresentation& rep)
117 m_children.push_back(rep);
120 void OCRepresentation::clearChildren()
125 const std::vector<OCRepresentation>& OCRepresentation::getChildren() const
130 void OCRepresentation::setUri(const std::string& uri)
135 std::string OCRepresentation::getUri() const
140 const std::vector<std::string>& OCRepresentation::getResourceTypes() const
142 return m_resourceTypes;
145 void OCRepresentation::setResourceTypes(const std::vector<std::string>& resourceTypes)
147 m_resourceTypes = resourceTypes;
150 const std::vector<std::string>& OCRepresentation::getResourceInterfaces() const
155 void OCRepresentation::setResourceInterfaces(const std::vector<std::string>& resourceInterfaces)
157 m_interfaces = resourceInterfaces;
160 bool OCRepresentation::hasAttribute(const std::string& str) const
162 return m_values.find(str) != m_values.end();
165 bool OCRepresentation::empty() const
167 // This logic is meant to determine whether based on the JSON serialization rules
168 // if this object will result in empty JSON. URI is only serialized if there is valid
169 // data, ResourceType and Interfaces are only serialized if we are a nothing, a
170 // child of a default or link item.
171 // Our values array is only printed in the if we are the child of a Batch resource,
172 // the parent in a 'default' situation, or not in a child/parent relationship.
177 else if ((m_interfaceType == InterfaceType::None
178 || m_interfaceType==InterfaceType::DefaultChild
179 || m_interfaceType==InterfaceType::LinkChild)
180 && (m_resourceTypes.size()>0 || m_interfaces.size()>0))
184 else if((m_interfaceType == InterfaceType::None
185 || m_interfaceType == InterfaceType::BatchChild
186 || m_interfaceType == InterfaceType::DefaultParent)
187 && m_values.size()>0)
195 int OCRepresentation::numberOfAttributes() const
197 return m_values.size();
200 bool OCRepresentation::erase(const std::string& str)
202 return m_values.erase(str);
205 void OCRepresentation::setNULL(const std::string& str)
207 m_values[str] = OC::NullType();
210 bool OCRepresentation::isNULL(const std::string& str) const
212 auto x = m_values.find(str);
214 if(m_values.end() != x)
216 return x->second.which() == AttributeValueNullIndex;
220 throw OCException(OC::Exception::INVALID_ATTRIBUTE+ str);
225 // note: the below is used to load an AttributeValue map out of JSON
230 enum class typeTag:uint8_t
240 typedef rapidjson::Document::GenericValue GenericValue;
242 AttributeValue parseAttributeValue(const GenericValue& v);
243 AttributeValue parseAttributeValue(const GenericValue& v,
244 const unsigned int curLevel, unsigned int& maxDepth, typeTag& t);
245 AttributeValue parseAttributeValueObject(const GenericValue& v, typeTag& t);
246 AttributeValue parseAttributeValueArray(const GenericValue& v,
247 const unsigned int curLevel, unsigned int& maxDepth, typeTag& t);
248 AttributeValue parseAttributeValuePrimitive(const GenericValue& v, typeTag& t);
250 AttributeValue parseAttributeValue(const GenericValue& v)
252 // base entrance, start everything at '0'
253 unsigned int max_depth {0};
254 typeTag t {typeTag::NOTHING};
256 return parseAttributeValue(v, 0, max_depth, t);
259 AttributeValue parseAttributeValue(const GenericValue& v,
260 const unsigned int curLevel, unsigned int& maxDepth, typeTag& t)
264 return parseAttributeValueObject(v, t);
268 return parseAttributeValueArray(v, curLevel + 1, maxDepth, t);
272 return parseAttributeValuePrimitive(v,t);
276 AttributeValue parseAttributeValueObject(const GenericValue& v, typeTag& t)
278 typedef rapidjson::Value::ConstMemberIterator CMI;
279 t = typeTag::_representation;
280 OC::OCRepresentation rep;
282 for(CMI itr = v.MemberBegin(); itr!= v.MemberEnd(); ++itr)
284 std::string keyName = itr->name.GetString();
286 if(keyName == OC::Key::URIKEY)
288 rep.setUri(boost::get<std::string>(parseAttributeValue(itr->value)));
290 else if (keyName == OC::Key::PROPERTYKEY)
292 for(CMI itr2 = itr->value.MemberBegin();
293 itr->value.MemberEnd()!=itr2;
296 if(keyName == OC::Key::RESOURCETYPESKEY)
298 rep.setResourceTypes(
299 boost::get<std::vector<std::string>>(
300 parseAttributeValue(itr->value)));
302 else if(keyName == OC::Key::PROPERTYKEY)
304 rep.setResourceInterfaces(
305 boost::get<std::vector<std::string>>(
306 parseAttributeValue(itr->value)));
310 else if (keyName == OC::Key::REPKEY)
312 for(CMI itr2 = itr->value.MemberBegin();
313 itr->value.MemberEnd()!=itr2;
316 rep.setValue(itr2->name.GetString(),
317 parseAttributeValue(itr2->value));
325 AttributeValue parseAttributeValuePrimitive(const GenericValue& v, typeTag& t)
329 t = typeTag::_string;
330 return std::string(v.GetString());
332 else if (v.IsNumber())
336 t = typeTag::_double;
337 return double(v.GetDouble());
342 return int(v.GetInt());
346 throw OC::OCException(OC::Exception::INVALID_JSON_NUMERIC
347 + std::to_string(v.GetType()));
353 return bool(v.GetBool_());
357 return OC::NullType();
361 throw OC::OCException(OC::Exception::INVALID_JSON_TYPE
362 + std::to_string(v.GetType()));
366 std::vector<AttributeValue> gatherArrayContents(const GenericValue& v,
367 const unsigned int curLevel, unsigned int& maxDepth, typeTag& t)
369 std::vector<AttributeValue> out;
371 std::transform(v.Begin(), v.End(), back_inserter(out),
372 [curLevel, &maxDepth, &t](const GenericValue& x)
374 return parseAttributeValue(x, curLevel, maxDepth, t);
380 struct valueToConcrete
382 OutT operator()(const AttributeValue& v)
384 return boost::get<OutT>(v);
389 template <class OutSeqT>
390 OutSeqT valuesToConcreteVectors(const std::vector<AttributeValue>& vs)
394 std::transform(begin(vs),end(vs), back_inserter(ret),
395 valueToConcrete<typename OutSeqT::value_type>());
399 template<class valueType>
400 AttributeValue remapArrayDepth(const unsigned int curLevel,
401 const std::vector<OC::AttributeValue>& vs)
406 throw OC::OCException(OC::Exception::INVALID_JSON_ARRAY_DEPTH);
409 return valuesToConcreteVectors<std::vector<valueType>>(vs);
412 return valuesToConcreteVectors<std::vector<std::vector<valueType>>>(vs);
415 return valuesToConcreteVectors
416 <std::vector<std::vector<std::vector<valueType>>>>(vs);
421 AttributeValue convertArrayToConcretes(const typeTag t,
422 const unsigned int curLevel, const std::vector<OC::AttributeValue>& vs)
424 // This function converts a std::vector of AttributeValue to a std::vector
425 // of concrete types. Since we don't use a recursive Variant, we need
426 // to get back to a 'base' primitive type
430 case typeTag::NOTHING:
431 throw OC::OCException(OC::Exception::INVALID_JSON_TYPE_TAG);
433 case typeTag::_string:
434 return remapArrayDepth<std::string>(curLevel, vs);
437 return remapArrayDepth<int>(curLevel, vs);
439 case typeTag::_double:
440 return remapArrayDepth<double>(curLevel, vs);
443 return remapArrayDepth<bool>(curLevel, vs);
445 case typeTag::_representation:
446 return remapArrayDepth<OCRepresentation>(curLevel, vs);
451 AttributeValue parseAttributeValueArray(const GenericValue& v,
452 const unsigned int curLevel, unsigned int& maxDepth, typeTag& t)
454 const unsigned int max_level = 3;
456 if(curLevel > max_level)
458 throw OC::OCException(OC::Exception::INVALID_JSON_ARRAY_DEPTH);
461 if(curLevel > maxDepth)
466 auto arrayItems = gatherArrayContents(v, curLevel, maxDepth, t);
467 const int remapLevel = maxDepth - (curLevel -1);
468 return convertArrayToConcretes(t, remapLevel, arrayItems);
475 void JSONInputArchive::loadAttributeValues(std::map<std::string, OC::AttributeValue>& map)
477 for(auto&b = itsIteratorStack.back();
478 b.Member && b.itsMemberItEnd != b.itsMemberItBegin+b.itsIndex;
481 std::string key = b.itsMemberItBegin[b.itsIndex].name.GetString();
482 const GenericValue& v = itsIteratorStack.back().value();
483 map[key] = OC::detail::parseAttributeValue(v);