//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-/// @file OCRepresentation.cpp
-
-/// @brief This file contains the implementation of classes and its members
-/// related to OCRepresentation
+/**
+ * @file
+ *
+ * This file contains the implementation of classes and its members related
+ * to OCRepresentation.
+ */
#include <OCRepresentation.h>
-#include <cereal/cereal.hpp>
-#include <cereal/types/map.hpp>
-#include <cereal/types/vector.hpp>
-#include <cereal/types/utility.hpp>
-#include <OicJsonSerializer.hpp>
+#include <boost/lexical_cast.hpp>
#include <algorithm>
+#include <iomanip>
+#include "ocpayload.h"
+#include "ocrandom.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
+#include "ocstack.h"
-// code needed to serialize a string=>Attribute value map
namespace OC
{
- namespace detail
+ static const char COAP[] = "coap://";
+ static const char COAPS[] = "coaps://";
+ static const char COAP_TCP[] = "coap+tcp://";
+
+ void MessageContainer::setPayload(const OCPayload* rep)
{
- template<class Archive>
- class WriteAttributeValue : public boost::static_visitor<>
+ if (rep == nullptr)
{
- public:
- WriteAttributeValue(const std::string& name, Archive& ar)
- :m_name(name), m_archive(ar)
- {}
+ return;
+ }
- template<class T>
- void operator()(const T& value) const
- {
- m_archive(cereal::make_nvp(m_name, value));
- }
- private:
- std::string m_name;
- Archive& m_archive;
- };
+ switch(rep->type)
+ {
+ case PAYLOAD_TYPE_REPRESENTATION:
+ setPayload(reinterpret_cast<const OCRepPayload*>(rep));
+ break;
+ default:
+ throw OC::OCException("Invalid Payload type in setPayload");
+ break;
+ }
}
-}
-
-namespace cereal
-{
- // take no action when serializing the null type, because the 'save' below
- // doesn't use the visitor for this type.
- template <class Archive>
- void serialize(Archive&, OC::NullType t)
- {}
- template<class Archive>
- void save(Archive& ar, const std::map<std::string, OC::AttributeValue>& vals)
+ void MessageContainer::setPayload(const OCRepPayload* payload)
{
- for(const auto& kv : vals)
+ const OCRepPayload* pl = payload;
+ while (pl)
{
- const auto& k = kv.first;
- const auto& v = kv.second;
+ OCRepresentation cur;
+ cur.setPayload(pl);
- if(v.which() != OC::AttributeValueNullIndex)
+ pl = pl->next;
+ this->addRepresentation(cur);
+ }
+ }
+
+ OCRepPayload* MessageContainer::getPayload() const
+ {
+ OCRepPayload* root = nullptr;
+ for(const auto& r : representations())
+ {
+ if (!root)
{
- OC::detail::WriteAttributeValue<Archive> writer(k,ar);
- boost::apply_visitor(writer, v);
+ root = r.getPayload();
}
else
{
- ar.setNextName(k.c_str());
- ar.writeName();
- ar.saveValue();
+ OCRepPayloadAppend(root, r.getPayload());
}
}
+
+ return root;
}
- template<class Archive>
- void load(Archive& ar, std::map<std::string, OC::AttributeValue>& vals)
+ const std::vector<OCRepresentation>& MessageContainer::representations() const
{
- ar.loadAttributeValues(vals);
+ return m_reps;
+ }
+
+ void MessageContainer::addRepresentation(const OCRepresentation& rep)
+ {
+ m_reps.push_back(rep);
}
}
namespace OC
{
- typedef cereal::JSONOutputArchive OutputArchiveType;
- typedef cereal::JSONInputArchive InputArchiveType;
+ struct get_payload_array: boost::static_visitor<>
+ {
+ template<typename T>
+ void operator()(T& /*arr*/)
+ {
+ throw std::logic_error("Invalid calc_dimensions_visitor type");
+ }
+
+ template<typename T>
+ void operator()(std::vector<T>& arr)
+ {
+ root_size_calc<T>();
+ dimensions[0] = arr.size();
+ dimensions[1] = 0;
+ dimensions[2] = 0;
+ dimTotal = calcDimTotal(dimensions);
+
+ array = (void*)OICMalloc(dimTotal * root_size);
+
+ for(size_t i = 0; i < dimensions[0]; ++i)
+ {
+ copy_to_array(arr[i], array, i);
+ }
+
+ }
+ template<typename T>
+ void operator()(std::vector<std::vector<T>>& arr)
+ {
+ root_size_calc<T>();
+ dimensions[0] = arr.size();
+ dimensions[1] = 0;
+ dimensions[2] = 0;
+ for(size_t i = 0; i < arr.size(); ++i)
+ {
+ dimensions[1] = std::max(dimensions[1], arr[i].size());
+ }
+ dimTotal = calcDimTotal(dimensions);
+ array = (void*)OICCalloc(1, dimTotal * root_size);
+
+ for(size_t i = 0; i < dimensions[0]; ++i)
+ {
+ for(size_t j = 0; j < dimensions[1] && j < arr[i].size(); ++j)
+ {
+ copy_to_array(arr[i][j], array, i*dimensions[1] + j);
+ }
+ }
+ }
+ template<typename T>
+ void operator()(std::vector<std::vector<std::vector<T>>>& arr)
+ {
+ root_size_calc<T>();
+ dimensions[0] = arr.size();
+ dimensions[1] = 0;
+ dimensions[2] = 0;
+ for(size_t i = 0; i < arr.size(); ++i)
+ {
+ dimensions[1] = std::max(dimensions[1], arr[i].size());
+
+ for(size_t j = 0; j < arr[i].size(); ++j)
+ {
+ dimensions[2] = std::max(dimensions[2], arr[i][j].size());
+ }
+ }
+
+ dimTotal = calcDimTotal(dimensions);
+ array = (void*)OICCalloc(1, dimTotal * root_size);
+
+ for(size_t i = 0; i < dimensions[0]; ++i)
+ {
+ for(size_t j = 0; j < dimensions[1] && j < arr[i].size(); ++j)
+ {
+ for(size_t k = 0; k < dimensions[2] && k < arr[i][j].size(); ++k)
+ {
+ copy_to_array(arr[i][j][k], array,
+ dimensions[2] * j +
+ dimensions[2] * dimensions[1] * i +
+ k);
+ }
+ }
+ }
+ }
+
+ template<typename T>
+ void root_size_calc()
+ {
+ root_size = sizeof(T);
+ }
+
+ template<typename T>
+ void copy_to_array(T item, void* array, size_t pos)
+ {
+ ((T*)array)[pos] = item;
+ }
+
+ size_t dimensions[MAX_REP_ARRAY_DEPTH];
+ size_t root_size;
+ size_t dimTotal;
+ void* array;
+ };
+
+ template<>
+ void get_payload_array::root_size_calc<int>()
+ {
+ root_size = sizeof(int64_t);
+ }
+
+ template<>
+ void get_payload_array::root_size_calc<std::string>()
+ {
+ root_size = sizeof(char*);
+ }
+
+ template<>
+ void get_payload_array::root_size_calc<OC::OCRepresentation>()
+ {
+ root_size = sizeof(OCRepPayload*);
+ }
+
+ template<>
+ void get_payload_array::copy_to_array(int item, void* array, size_t pos)
+ {
+ ((int64_t*)array)[pos] = item;
+ }
+
+#if !(defined(_MSC_VER) || defined(__APPLE__))
+ template<>
+ void get_payload_array::copy_to_array(std::_Bit_reference br, void* array, size_t pos)
+ {
+ ((bool*)array)[pos] = static_cast<bool>(br);
+ }
+#endif
+
+ template<>
+ void get_payload_array::copy_to_array(std::string item, void* array, size_t pos)
+ {
+ ((char**)array)[pos] = OICStrdup(item.c_str());
+ }
+
+ template<>
+ void get_payload_array::copy_to_array(std::string& item, void* array, size_t pos)
+ {
+ ((char**)array)[pos] = OICStrdup(item.c_str());
+ }
+
+ template<>
+ void get_payload_array::copy_to_array(const std::string& item, void* array, size_t pos)
+ {
+ ((char**)array)[pos] = OICStrdup(item.c_str());
+ }
+
+ template<>
+ void get_payload_array::copy_to_array(OCByteString item, void *array, size_t pos)
+ {
+ ((OCByteString *)array)[pos] = item;
+ }
+
+ template<>
+ void get_payload_array::copy_to_array(OCByteString &item, void *array, size_t pos)
+ {
+ ((OCByteString *)array)[pos] = item;
+ }
+
+ template<>
+ void get_payload_array::copy_to_array(const OCByteString &item, void *array, size_t pos)
+ {
+ ((OCByteString *)array)[pos] = item;
+ }
+
+ template<>
+ void get_payload_array::copy_to_array(OC::OCRepresentation item, void* array, size_t pos)
+ {
+ ((OCRepPayload**)array)[pos] = item.getPayload();
+ }
+
+ void OCRepresentation::getPayloadArray(OCRepPayload* payload,
+ const OCRepresentation::AttributeItem& item) const
+ {
+ get_payload_array vis{};
+ boost::apply_visitor(vis, m_values[item.attrname()]);
+
+
+ switch(item.base_type())
+ {
+ case AttributeType::Integer:
+ OCRepPayloadSetIntArrayAsOwner(payload, item.attrname().c_str(),
+ (int64_t*)vis.array,
+ vis.dimensions);
+ break;
+ case AttributeType::Double:
+ OCRepPayloadSetDoubleArrayAsOwner(payload, item.attrname().c_str(),
+ (double*)vis.array,
+ vis.dimensions);
+ break;
+ case AttributeType::Boolean:
+ OCRepPayloadSetBoolArrayAsOwner(payload, item.attrname().c_str(),
+ (bool*)vis.array,
+ vis.dimensions);
+ break;
+ case AttributeType::String:
+ OCRepPayloadSetStringArrayAsOwner(payload, item.attrname().c_str(),
+ (char**)vis.array,
+ vis.dimensions);
+ break;
+ case AttributeType::OCByteString:
+ OCRepPayloadSetByteStringArrayAsOwner(payload, item.attrname().c_str(),
+ (OCByteString *)vis.array, vis.dimensions);
+ break;
+ case AttributeType::OCRepresentation:
+ OCRepPayloadSetPropObjectArrayAsOwner(payload, item.attrname().c_str(),
+ (OCRepPayload**)vis.array, vis.dimensions);
+ break;
+ default:
+ throw std::logic_error(std::string("GetPayloadArray: Not Implemented") +
+ std::to_string((int)item.base_type()));
+ }
+ }
- void MessageContainer::setJSONRepresentation(const std::string& payload)
+ OCRepPayload* OCRepresentation::getPayload() const
{
- std::stringstream os(payload);
+ OCRepPayload* root = OCRepPayloadCreate();
+ if (!root)
{
- InputArchiveType archive(os);
- archive(cereal::make_nvp(OC::Key::OCKEY, m_reps));
+ throw std::bad_alloc();
}
+
+ OCRepPayloadSetUri(root, getUri().c_str());
+
+ for(const std::string& type : getResourceTypes())
+ {
+ OCRepPayloadAddResourceType(root, type.c_str());
+ }
+
+ for(const std::string& iface : getResourceInterfaces())
+ {
+ OCRepPayloadAddInterface(root, iface.c_str());
+ }
+
+ for(auto& val : *this)
+ {
+ switch(val.type())
+ {
+ case AttributeType::Null:
+ OCRepPayloadSetNull(root, val.attrname().c_str());
+ break;
+ case AttributeType::Integer:
+ OCRepPayloadSetPropInt(root, val.attrname().c_str(), static_cast<int>(val));
+ break;
+ case AttributeType::Double:
+ OCRepPayloadSetPropDouble(root, val.attrname().c_str(),
+ val.getValue<double>());
+ break;
+ case AttributeType::Boolean:
+ OCRepPayloadSetPropBool(root, val.attrname().c_str(), val.getValue<bool>());
+ break;
+ case AttributeType::String:
+ OCRepPayloadSetPropString(root, val.attrname().c_str(),
+ static_cast<std::string>(val).c_str());
+ break;
+ case AttributeType::OCByteString:
+ OCRepPayloadSetPropByteString(root, val.attrname().c_str(), val.getValue<OCByteString>());
+ break;
+ case AttributeType::OCRepresentation:
+ OCRepPayloadSetPropObjectAsOwner(root, val.attrname().c_str(),
+ static_cast<OCRepresentation>(val).getPayload());
+ break;
+ case AttributeType::Vector:
+ getPayloadArray(root, val);
+ break;
+ case AttributeType::Binary:
+ OCRepPayloadSetPropByteString(root, val.attrname().c_str(),
+ OCByteString{const_cast<uint8_t*>(val.getValue<std::vector<uint8_t>>().data()),
+ val.getValue<std::vector<uint8_t>>().size()});
+ break;
+ default:
+ throw std::logic_error(std::string("Getpayload: Not Implemented") +
+ std::to_string((int)val.type()));
+ break;
+ }
+ }
+
+ return root;
+ }
+
+ size_t calcArrayDepth(const size_t dimensions[MAX_REP_ARRAY_DEPTH])
+ {
+ if (dimensions[0] == 0)
+ {
+ throw std::logic_error("invalid calcArrayDepth");
+ }
+ else if (dimensions[1] == 0)
+ {
+ return 1;
+ }
+ else if (dimensions[2] == 0)
+ {
+ return 2;
+ }
+ else
+ {
+ return 3;
+ }
+ }
+
+ template<typename T>
+ T OCRepresentation::payload_array_helper_copy(size_t index, const OCRepPayloadValue* pl)
+ {
+ throw std::logic_error("payload_array_helper_copy: unsupported type");
+ }
+ template<>
+ int OCRepresentation::payload_array_helper_copy<int>(size_t index, const OCRepPayloadValue* pl)
+ {
+ return pl->arr.iArray[index];
+ }
+ template<>
+ double OCRepresentation::payload_array_helper_copy<double>(size_t index, const OCRepPayloadValue* pl)
+ {
+ return pl->arr.dArray[index];
+ }
+ template<>
+ bool OCRepresentation::payload_array_helper_copy<bool>(size_t index, const OCRepPayloadValue* pl)
+ {
+ return pl->arr.bArray[index];
+ }
+ template<>
+ std::string OCRepresentation::payload_array_helper_copy<std::string>(
+ size_t index, const OCRepPayloadValue* pl)
+ {
+ if (pl->arr.strArray[index])
+ {
+ return std::string(pl->arr.strArray[index]);
+ }
+ else
+ {
+ return std::string{};
+ }
+ }
+
+ template<>
+ OCByteString OCRepresentation::payload_array_helper_copy<OCByteString>(
+ size_t index, const OCRepPayloadValue *pl)
+ {
+ OCByteString result {NULL, 0};
+ if (pl->arr.ocByteStrArray[index].len)
+ {
+ result = (pl->arr.ocByteStrArray[index]);
+ }
+ return result;
}
- void MessageContainer::setJSONRepresentation(const unsigned char* payload)
+ template<>
+ OCRepresentation OCRepresentation::payload_array_helper_copy<OCRepresentation>(
+ size_t index, const OCRepPayloadValue* pl)
{
- setJSONRepresentation(std::string(reinterpret_cast<const char*>(payload)));
+ OCRepresentation r;
+ if (pl->arr.objArray[index])
+ {
+ r.setPayload(pl->arr.objArray[index]);
+ }
+ return r;
}
- std::string MessageContainer::getJSONRepresentation(OCInfoFormat f) const
+ template<typename T>
+ void OCRepresentation::payload_array_helper(const OCRepPayloadValue* pl, size_t depth)
{
- std::stringstream os;
+ if (depth == 1)
+ {
+ std::vector<T> val(pl->arr.dimensions[0]);
- // note: the block is required because cereal closes the JSON string
- // upon destruction, so the archive needs to be destroyed before accessing
- // the data
+ for(size_t i = 0; i < pl->arr.dimensions[0]; ++i)
+ {
+ val[i] = payload_array_helper_copy<T>(i, pl);
+ }
+ this->setValue(std::string(pl->name), val);
+ }
+ else if (depth == 2)
{
- if(f == OCInfoFormat::IncludeOC)
+ std::vector<std::vector<T>> val(pl->arr.dimensions[0]);
+ for(size_t i = 0; i < pl->arr.dimensions[0]; ++i)
{
- OutputArchiveType archive(os);
- archive(cereal::make_nvp(OC::Key::OCKEY, m_reps));
+ val[i].resize(pl->arr.dimensions[1]);
+ for(size_t j = 0; j < pl->arr.dimensions[1]; ++j)
+ {
+ val[i][j] = payload_array_helper_copy<T>(
+ i * pl->arr.dimensions[1] + j, pl);
+ }
}
- else if(f== OCInfoFormat::ExcludeOC)
+ this->setValue(std::string(pl->name), val);
+ }
+ else if (depth == 3)
+ {
+ std::vector<std::vector<std::vector<T>>> val(pl->arr.dimensions[0]);
+ for(size_t i = 0; i < pl->arr.dimensions[0]; ++i)
{
- bool firstPrinted = false;
- for(std::vector<OCRepresentation>::size_type i = 0; i< m_reps.size();++i)
+ val[i].resize(pl->arr.dimensions[1]);
+ for(size_t j = 0; j < pl->arr.dimensions[1]; ++j)
{
- if(!m_reps[i].empty())
+ val[i][j].resize(pl->arr.dimensions[2]);
+ for(size_t k = 0; k < pl->arr.dimensions[2]; ++k)
{
- if(firstPrinted)
- {
- os<<',';
- }
- firstPrinted=true;
- os << m_reps[i].getJSONRepresentation();
+ val[i][j][k] = payload_array_helper_copy<T>(
+ pl->arr.dimensions[2] * j +
+ pl->arr.dimensions[2] * pl->arr.dimensions[1] * i +
+ k,
+ pl);
}
}
}
+ this->setValue(std::string(pl->name), val);
+ }
+ else
+ {
+ throw std::logic_error("Invalid depth in payload_array_helper");
}
- return os.str();
}
- const std::vector<OCRepresentation>& MessageContainer::representations() const
+ void OCRepresentation::setPayloadArray(const OCRepPayloadValue* pl)
{
- return m_reps;
- }
- void MessageContainer::addRepresentation(const OCRepresentation& rep)
- {
- m_reps.push_back(rep);
+ switch(pl->arr.type)
+ {
+ case OCREP_PROP_INT:
+ payload_array_helper<int>(pl, calcArrayDepth(pl->arr.dimensions));
+ break;
+ case OCREP_PROP_DOUBLE:
+ payload_array_helper<double>(pl, calcArrayDepth(pl->arr.dimensions));
+ break;
+ case OCREP_PROP_BOOL:
+ payload_array_helper<bool>(pl, calcArrayDepth(pl->arr.dimensions));
+ break;
+ case OCREP_PROP_STRING:
+ payload_array_helper<std::string>(pl, calcArrayDepth(pl->arr.dimensions));
+ break;
+ case OCREP_PROP_BYTE_STRING:
+ payload_array_helper<OCByteString>(pl, calcArrayDepth(pl->arr.dimensions));
+ break;
+ case OCREP_PROP_OBJECT:
+ payload_array_helper<OCRepresentation>(pl, calcArrayDepth(pl->arr.dimensions));
+ break;
+ default:
+ throw std::logic_error("setPayload array invalid type");
+ break;
+ }
}
-}
-namespace OC
-{
- OCRepresentation::OCRepresentation()
- :m_interfaceType(InterfaceType::None)
- { }
- std::string OCRepresentation::getJSONRepresentation() const
+ void OCRepresentation::setPayload(const OCRepPayload* pl)
{
- if(empty())
+ setUri(pl->uri);
+
+ OCStringLL* ll = pl->types;
+ while(ll)
{
- return "{}";
+ addResourceType(ll->value);
+ ll = ll->next;
}
- std::stringstream os;
-
- // note: the block is required because cereal closes the JSON string
- // upon destruction, so the archive needs to be destroyed before accessing
- // the data
+ ll = pl->interfaces;
+ while(ll)
{
- OutputArchiveType archive (os);
- save(archive);
+ addResourceInterface(ll->value);
+ ll = ll->next;
}
- return os.str();
+ OCRepPayloadValue* val = pl->values;
+
+ while(val)
+ {
+ switch(val->type)
+ {
+ case OCREP_PROP_NULL:
+ setNULL(val->name);
+ break;
+ case OCREP_PROP_INT:
+ setValue<int>(val->name, val->i);
+ break;
+ case OCREP_PROP_DOUBLE:
+ setValue<double>(val->name, val->d);
+ break;
+ case OCREP_PROP_BOOL:
+ setValue<bool>(val->name, val->b);
+ break;
+ case OCREP_PROP_STRING:
+ setValue<std::string>(val->name, val->str);
+ break;
+ case OCREP_PROP_OBJECT:
+ {
+ OCRepresentation cur;
+ cur.setPayload(val->obj);
+ setValue<OCRepresentation>(val->name, cur);
+ }
+ break;
+ case OCREP_PROP_ARRAY:
+ setPayloadArray(val);
+ break;
+ case OCREP_PROP_BYTE_STRING:
+ setValue(val->name,
+ std::vector<uint8_t>
+ (val->ocByteStr.bytes, val->ocByteStr.bytes + val->ocByteStr.len)
+ );
+ break;
+ default:
+ throw std::logic_error(std::string("Not Implemented!") +
+ std::to_string((int)val->type));
+ break;
+ }
+ val = val->next;
+ }
}
void OCRepresentation::addChild(const OCRepresentation& rep)
return m_children;
}
+ void OCRepresentation::setChildren(const std::vector<OCRepresentation>& children)
+ {
+ m_children = children;
+ }
+
+ void OCRepresentation::setDevAddr(const OCDevAddr& devAddr)
+ {
+ std::ostringstream ss;
+ if (devAddr.flags & OC_SECURE)
+ {
+ ss << COAPS;
+ }
+ else if (devAddr.adapter & OC_ADAPTER_TCP)
+ {
+ ss << COAP_TCP;
+ }
+ else
+ {
+ ss << COAP;
+ }
+ if (devAddr.flags & OC_IP_USE_V6)
+ {
+ char addressEncoded[128] = {0};
+
+ OCStackResult result = OCEncodeAddressForRFC6874(addressEncoded,
+ sizeof(addressEncoded),
+ devAddr.addr);
+ if (OC_STACK_OK != result)
+ {
+ throw OC::OCException("Invalid address in setDevAddr");
+ }
+ ss << '[' << addressEncoded << ']';
+ }
+ else
+ {
+ ss << devAddr.addr;
+ }
+ if (devAddr.port)
+ {
+ ss << ':' << devAddr.port;
+ }
+ m_host = ss.str();
+ }
+
+ const std::string OCRepresentation::getHost() const
+ {
+ return m_host;
+ }
+
+ void OCRepresentation::setUri(const char* uri)
+ {
+ m_uri = uri ? uri : "";
+ }
+
void OCRepresentation::setUri(const std::string& uri)
{
m_uri = uri;
m_resourceTypes = resourceTypes;
}
+ void OCRepresentation::addResourceType(const std::string& str)
+ {
+ m_resourceTypes.push_back(str);
+ }
+
const std::vector<std::string>& OCRepresentation::getResourceInterfaces() const
{
return m_interfaces;
}
+ void OCRepresentation::addResourceInterface(const std::string& str)
+ {
+ m_interfaces.push_back(str);
+ }
+
void OCRepresentation::setResourceInterfaces(const std::vector<std::string>& resourceInterfaces)
{
m_interfaces = resourceInterfaces;
}
+ const std::vector<std::string>& OCRepresentation::getDataModelVersions() const
+ {
+ return m_dataModelVersions;
+ }
+
+ void OCRepresentation::addDataModelVersion(const std::string& str)
+ {
+ m_dataModelVersions.push_back(str);
+ }
+
bool OCRepresentation::hasAttribute(const std::string& str) const
{
return m_values.find(str) != m_values.end();
}
- bool OCRepresentation::empty() const
+ bool OCRepresentation::emptyData() const
{
// This logic is meant to determine whether based on the JSON serialization rules
// if this object will result in empty JSON. URI is only serialized if there is valid
// child of a default or link item.
// Our values array is only printed in the if we are the child of a Batch resource,
// the parent in a 'default' situation, or not in a child/parent relationship.
- if(!m_uri.empty())
+ if (!m_uri.empty())
{
return false;
}
else if ((m_interfaceType == InterfaceType::None
|| m_interfaceType==InterfaceType::DefaultChild
|| m_interfaceType==InterfaceType::LinkChild)
- && (m_resourceTypes.size()>0 || m_interfaces.size()>0))
+ && (m_resourceTypes.size()>0 || m_interfaces.size()>0
+ || m_dataModelVersions.size()>0))
{
return false;
}
- else if((m_interfaceType == InterfaceType::None
+ else if ((m_interfaceType == InterfaceType::None
|| m_interfaceType == InterfaceType::BatchChild
|| m_interfaceType == InterfaceType::DefaultParent)
&& m_values.size()>0)
return false;
}
- if(m_children.size() > 0)
+ if (m_children.size() > 0)
{
return false;
}
{
auto x = m_values.find(str);
- if(m_values.end() != x)
+ if (m_values.end() != x)
{
return x->second.which() == AttributeValueNullIndex;
}
namespace OC
{
- template <class Archive, class Val>
- void OCRepresentation::optional_load(Archive& ar, Val&& v)
+ std::ostream& operator <<(std::ostream& os, const AttributeType at)
{
- try
- {
- ar(v);
- }
- catch(cereal::Exception& e)
+ switch(at)
{
- ar.setNextName(nullptr);
- // Loading a key that doesn't exist results in an exception
- // Since "Not Found" is a valid condition for us, we swallow
- // this exception and the archive will not load anything
+ case AttributeType::Null:
+ os << "Null";
+ break;
+ case AttributeType::Integer:
+ os << "Integer";
+ break;
+ case AttributeType::Double:
+ os << "Double";
+ break;
+ case AttributeType::Boolean:
+ os << "Boolean";
+ break;
+ case AttributeType::String:
+ os << "String";
+ break;
+ case AttributeType::OCByteString:
+ os << "OCByteString";
+ break;
+ case AttributeType::OCRepresentation:
+ os << "OCRepresentation";
+ break;
+ case AttributeType::Vector:
+ os << "Vector";
+ break;
+ case AttributeType::Binary:
+ os<< "Binary";
}
+ return os;
}
+}
+
+// STL Container For OCRepresentation
+namespace OC
+{
+ OCRepresentation::AttributeItem::AttributeItem(const std::string& name,
+ std::map<std::string, AttributeValue>& vals):
+ m_attrName(name), m_values(vals){}
- template<class Archive>
- void OCRepresentation::save(Archive& ar) const
+ OCRepresentation::AttributeItem OCRepresentation::operator[](const std::string& key)
{
- // printed for all interface types
- if(!m_uri.empty())
- {
- ar(cereal::make_nvp(Key::URIKEY, m_uri));
- }
+ OCRepresentation::AttributeItem attr{key, m_values};
+ return std::move(attr);
+ }
- if((m_interfaceType == InterfaceType::None
- || m_interfaceType==InterfaceType::DefaultChild
- || m_interfaceType==InterfaceType::LinkChild)
- && (m_resourceTypes.size()>0 || m_interfaces.size()>0))
- {
- // The Prop object requires that it refer to non-const vectors
- // so that it can alter them in the 'load' case. In the save case
- // (initiated here) it will not modify the object. So, to keep the
- // compiler happy, removing the 'const' context here is necessary.
- const std::vector<std::string>& rt(m_resourceTypes);
- const std::vector<std::string>& intf(m_interfaces);
- Prop temp(const_cast<std::vector<std::string>&>(rt),
- const_cast<std::vector<std::string>&>(intf));
- ar(cereal::make_nvp(Key::PROPERTYKEY, temp));
- }
+ const OCRepresentation::AttributeItem OCRepresentation::operator[](const std::string& key) const
+ {
+ OCRepresentation::AttributeItem attr{key, m_values};
+ return std::move(attr);
+ }
- // printed only for BatchChildren and DefaultParent
- if((m_interfaceType == InterfaceType::None
- || m_interfaceType == InterfaceType::BatchChild
- || m_interfaceType == InterfaceType::DefaultParent)
- && m_values.size()>0)
- {
- ar(cereal::make_nvp(Key::REPKEY, m_values));
- }
+ const std::string& OCRepresentation::AttributeItem::attrname() const
+ {
+ return m_attrName;
}
- template<class Archive>
- void OCRepresentation::load(Archive& ar)
+ template<typename T, typename = void>
+ struct type_info
+ {
+ // contains the actual type
+ typedef T type;
+ // contains the inner most vector-type
+ typedef T base_type;
+ // contains the AttributeType for this item
+ BOOST_STATIC_CONSTEXPR AttributeType enum_type =
+ AttributeTypeConvert<T>::type;
+ // contains the AttributeType for this base-type
+ BOOST_STATIC_CONSTEXPR AttributeType enum_base_type =
+ AttributeTypeConvert<T>::type;
+ // depth of the vector
+ BOOST_STATIC_CONSTEXPR size_t depth = 0;
+ };
+
+ template<typename T>
+ struct type_info<
+ T,
+ typename std::enable_if<
+ is_vector<T>::value &&
+ !std::is_same<uint8_t, typename T::value_type>::value
+ >::type
+ >
+ {
+ typedef T type;
+ typedef typename type_info<typename T::value_type>::base_type base_type;
+ BOOST_STATIC_CONSTEXPR AttributeType enum_type = AttributeType::Vector;
+ BOOST_STATIC_CONSTEXPR AttributeType enum_base_type =
+ type_info<typename T::value_type>::enum_base_type;
+ BOOST_STATIC_CONSTEXPR size_t depth = 1 +
+ type_info<typename T::value_type>::depth;
+ };
+
+ // special case for binary data, which is a std::vector<uint8_t>
+ template<>
+ struct type_info<std::vector<uint8_t>, void>
+ {
+ typedef std::vector<uint8_t> type;
+ typedef std::vector<uint8_t> base_type;
+ BOOST_STATIC_CONSTEXPR AttributeType enum_type = AttributeType::Binary;
+ BOOST_STATIC_CONSTEXPR AttributeType enum_base_type = AttributeType::Binary;
+ BOOST_STATIC_CONSTEXPR size_t depth = 0;
+ };
+
+
+ struct type_introspection_visitor : boost::static_visitor<>
{
- optional_load(ar, cereal::make_nvp(Key::URIKEY, m_uri));
+ AttributeType type;
+ AttributeType base_type;
+ size_t depth;
+
+ type_introspection_visitor() : boost::static_visitor<>(),
+ type(AttributeType::Null), base_type(AttributeType::Null), depth(0){}
+
+ template <typename T>
+ void operator()(T const& /*item*/)
{
- Prop temp(m_resourceTypes, m_interfaces);
- optional_load(ar, cereal::make_nvp(Key::PROPERTYKEY, temp));
+ type = type_info<T>::enum_type;
+ base_type = type_info<T>::enum_base_type;
+ depth = type_info<T>::depth;
}
- optional_load(ar, cereal::make_nvp(Key::REPKEY, m_values));
+ };
+
+ AttributeType OCRepresentation::AttributeItem::type() const
+ {
+ type_introspection_visitor vis;
+ boost::apply_visitor(vis, m_values[m_attrName]);
+ return vis.type;
}
- template<class Archive>
- void OCRepresentation::Prop::save(Archive& ar) const
+ AttributeType OCRepresentation::AttributeItem::base_type() const
{
- if(m_types.size() > 0)
- {
- ar(cereal::make_nvp(Key::RESOURCETYPESKEY, m_types));
- }
+ type_introspection_visitor vis;
+ boost::apply_visitor(vis, m_values[m_attrName]);
+ return vis.base_type;
+ }
- if(m_interfaces.size()>0)
- {
- ar(cereal::make_nvp(Key::INTERFACESKEY, m_interfaces));
- }
+ size_t OCRepresentation::AttributeItem::depth() const
+ {
+ type_introspection_visitor vis;
+ boost::apply_visitor(vis, m_values[m_attrName]);
+ return vis.depth;
}
- template<class Archive>
- void OCRepresentation::Prop::load(Archive& ar)
+ OCRepresentation::iterator OCRepresentation::begin()
{
- optional_load(ar, cereal::make_nvp(Key::RESOURCETYPESKEY, m_types));
- optional_load(ar, cereal::make_nvp(Key::INTERFACESKEY, m_interfaces));
+ return OCRepresentation::iterator(m_values.begin(), m_values);
}
-}
-// note: the below is used to load an AttributeValue map out of JSON
-namespace OC
-{
- namespace detail
+ OCRepresentation::const_iterator OCRepresentation::begin() const
{
- enum class typeTag:uint8_t
- {
- NOTHING = 0,
- _string,
- _int,
- _double,
- _bool,
- _representation
- };
+ return OCRepresentation::const_iterator(m_values.begin(), m_values);
+ }
- typedef rapidjson::Document::GenericValue GenericValue;
+ OCRepresentation::const_iterator OCRepresentation::cbegin() const
+ {
+ return OCRepresentation::const_iterator(m_values.cbegin(), m_values);
+ }
- AttributeValue parseAttributeValue(const GenericValue& v);
- AttributeValue parseAttributeValue(const GenericValue& v,
- const unsigned int curLevel, unsigned int& maxDepth, typeTag& t);
- AttributeValue parseAttributeValueObject(const GenericValue& v, typeTag& t);
- AttributeValue parseAttributeValueArray(const GenericValue& v,
- const unsigned int curLevel, unsigned int& maxDepth, typeTag& t);
- AttributeValue parseAttributeValuePrimitive(const GenericValue& v, typeTag& t);
+ OCRepresentation::iterator OCRepresentation::end()
+ {
+ return OCRepresentation::iterator(m_values.end(), m_values);
+ }
- AttributeValue parseAttributeValue(const GenericValue& v)
- {
- // base entrance, start everything at '0'
- unsigned int max_depth {0};
- typeTag t {typeTag::NOTHING};
+ OCRepresentation::const_iterator OCRepresentation::end() const
+ {
+ return OCRepresentation::const_iterator(m_values.end(), m_values);
+ }
- return parseAttributeValue(v, 0, max_depth, t);
- }
+ OCRepresentation::const_iterator OCRepresentation::cend() const
+ {
+ return OCRepresentation::const_iterator(m_values.cend(), m_values);
+ }
- AttributeValue parseAttributeValue(const GenericValue& v,
- const unsigned int curLevel, unsigned int& maxDepth, typeTag& t)
- {
- if(v.IsObject())
- {
- return parseAttributeValueObject(v, t);
- }
- else if(v.IsArray())
- {
- return parseAttributeValueArray(v, curLevel + 1, maxDepth, t);
- }
- else
- {
- return parseAttributeValuePrimitive(v,t);
- }
- }
+ size_t OCRepresentation::size() const
+ {
+ return m_values.size();
+ }
- AttributeValue parseAttributeValueObject(const GenericValue& v, typeTag& t)
- {
- typedef rapidjson::Value::ConstMemberIterator CMI;
- t = typeTag::_representation;
- OC::OCRepresentation rep;
+ bool OCRepresentation::empty() const
+ {
+ return m_values.empty();
+ }
- for(CMI itr = v.MemberBegin(); itr!= v.MemberEnd(); ++itr)
- {
- std::string keyName = itr->name.GetString();
+ bool OCRepresentation::iterator::operator==(const OCRepresentation::iterator& rhs) const
+ {
+ return m_iterator == rhs.m_iterator;
+ }
- if(keyName == OC::Key::URIKEY)
- {
- rep.setUri(boost::get<std::string>(parseAttributeValue(itr->value)));
- }
- else if (keyName == OC::Key::PROPERTYKEY)
- {
- for(CMI itr2 = itr->value.MemberBegin();
- itr->value.MemberEnd()!=itr2;
- ++itr2)
- {
- if(keyName == OC::Key::RESOURCETYPESKEY)
- {
- rep.setResourceTypes(
- boost::get<std::vector<std::string>>(
- parseAttributeValue(itr->value)));
- }
- else if(keyName == OC::Key::PROPERTYKEY)
- {
- rep.setResourceInterfaces(
- boost::get<std::vector<std::string>>(
- parseAttributeValue(itr->value)));
- }
- }
- }
- else if (keyName == OC::Key::REPKEY)
- {
- for(CMI itr2 = itr->value.MemberBegin();
- itr->value.MemberEnd()!=itr2;
- ++itr2)
- {
- rep.setValue(itr2->name.GetString(),
- parseAttributeValue(itr2->value));
- }
- }
- }
+ bool OCRepresentation::iterator::operator!=(const OCRepresentation::iterator& rhs) const
+ {
+ return m_iterator != rhs.m_iterator;
+ }
- return rep;
- }
+ bool OCRepresentation::const_iterator::operator==(
+ const OCRepresentation::const_iterator& rhs) const
+ {
+ return m_iterator == rhs.m_iterator;
+ }
- AttributeValue parseAttributeValuePrimitive(const GenericValue& v, typeTag& t)
- {
- if(v.IsString())
- {
- t = typeTag::_string;
- return std::string(v.GetString());
- }
- else if (v.IsNumber())
- {
- if(v.IsDouble())
- {
- t = typeTag::_double;
- return double(v.GetDouble());
- }
- else if (v.IsInt())
- {
- t = typeTag::_int;
- return int(v.GetInt());
- }
- else
- {
- throw OC::OCException(OC::Exception::INVALID_JSON_NUMERIC
- + std::to_string(v.GetType()));
- }
- }
- else if(v.IsBool_())
- {
- t=typeTag::_bool;
- return bool(v.GetBool_());
- }
- else if(v.IsNull_())
- {
- return OC::NullType();
- }
- else
- {
- throw OC::OCException(OC::Exception::INVALID_JSON_TYPE
- + std::to_string(v.GetType()));
- }
- }
+ bool OCRepresentation::const_iterator::operator!=(
+ const OCRepresentation::const_iterator& rhs) const
+ {
+ return m_iterator != rhs.m_iterator;
+ }
- std::vector<AttributeValue> gatherArrayContents(const GenericValue& v,
- const unsigned int curLevel, unsigned int& maxDepth, typeTag& t)
- {
- std::vector<AttributeValue> out;
+ OCRepresentation::iterator::reference OCRepresentation::iterator::operator*()
+ {
+ return m_item;
+ }
- std::transform(v.Begin(), v.End(), back_inserter(out),
- [curLevel, &maxDepth, &t](const GenericValue& x)
- {
- return parseAttributeValue(x, curLevel, maxDepth, t);
- });
- return out;
- }
+ OCRepresentation::const_iterator::const_reference
+ OCRepresentation::const_iterator::operator*() const
+ {
+ return m_item;
+ }
- template<class OutT>
- struct valueToConcrete
- {
- OutT operator()(const AttributeValue& v)
- {
- return boost::get<OutT>(v);
- }
+ OCRepresentation::iterator::pointer OCRepresentation::iterator::operator->()
+ {
+ return &m_item;
+ }
- };
+ OCRepresentation::const_iterator::const_pointer
+ OCRepresentation::const_iterator::operator->() const
+ {
+ return &m_item;
+ }
- template <class OutSeqT>
- OutSeqT valuesToConcreteVectors(const std::vector<AttributeValue>& vs)
+ OCRepresentation::iterator& OCRepresentation::iterator::operator++()
+ {
+ m_iterator++;
+ if (m_iterator != m_item.m_values.end())
{
- OutSeqT ret;
+ m_item.m_attrName = m_iterator->first;
+ }
+ else
+ {
+ m_item.m_attrName = "";
+ }
+ return *this;
+ }
- std::transform(begin(vs),end(vs), back_inserter(ret),
- valueToConcrete<typename OutSeqT::value_type>());
- return ret;
+ OCRepresentation::const_iterator& OCRepresentation::const_iterator::operator++()
+ {
+ m_iterator++;
+ if (m_iterator != m_item.m_values.end())
+ {
+ m_item.m_attrName = m_iterator->first;
+ }
+ else
+ {
+ m_item.m_attrName = "";
}
+ return *this;
+ }
+
+ OCRepresentation::iterator OCRepresentation::iterator::operator++(int)
+ {
+ OCRepresentation::iterator itr(*this);
+ ++(*this);
+ return itr;
+ }
+
+ OCRepresentation::const_iterator OCRepresentation::const_iterator::operator++(int)
+ {
+ OCRepresentation::const_iterator itr(*this);
+ ++(*this);
+ return itr;
+ }
- template<class valueType>
- AttributeValue remapArrayDepth(const unsigned int curLevel,
- const std::vector<OC::AttributeValue>& vs)
+ struct to_string_visitor : boost::static_visitor<>
+ {
+ std::string str;
+ template <typename T>
+ void operator()(T const& item)
{
- switch(curLevel)
- {
- default:
- throw OC::OCException(OC::Exception::INVALID_JSON_ARRAY_DEPTH);
- break;
- case 1:
- return valuesToConcreteVectors<std::vector<valueType>>(vs);
- break;
- case 2:
- return valuesToConcreteVectors<std::vector<std::vector<valueType>>>(vs);
- break;
- case 3:
- return valuesToConcreteVectors
- <std::vector<std::vector<std::vector<valueType>>>>(vs);
- break;
- }
+ str = boost::lexical_cast<std::string>(item);
}
- AttributeValue convertArrayToConcretes(const typeTag t,
- const unsigned int curLevel, const std::vector<OC::AttributeValue>& vs)
+ template <typename T>
+ void operator()(std::vector<T> const& item)
{
- // This function converts a std::vector of AttributeValue to a std::vector
- // of concrete types. Since we don't use a recursive Variant, we need
- // to get back to a 'base' primitive type
- switch(t)
+ to_string_visitor vis;
+ std::ostringstream stream;
+ stream << "[";
+
+ for(const auto& i : item)
{
- default:
- case typeTag::NOTHING:
- throw OC::OCException(OC::Exception::INVALID_JSON_TYPE_TAG);
- break;
- case typeTag::_string:
- return remapArrayDepth<std::string>(curLevel, vs);
- break;
- case typeTag::_int:
- return remapArrayDepth<int>(curLevel, vs);
- break;
- case typeTag::_double:
- return remapArrayDepth<double>(curLevel, vs);
- break;
- case typeTag::_bool:
- return remapArrayDepth<bool>(curLevel, vs);
- break;
- case typeTag::_representation:
- return remapArrayDepth<OCRepresentation>(curLevel, vs);
- break;
+ vis(i);
+ stream << vis.str << " ";
}
+ stream << "]";
+ str = stream.str();
}
+ };
+
+ template<>
+ void to_string_visitor::operator()(bool const& item)
+ {
+ str = item ? "true" : "false";
+ }
- AttributeValue parseAttributeValueArray(const GenericValue& v,
- const unsigned int curLevel, unsigned int& maxDepth, typeTag& t)
+ template<>
+ void to_string_visitor::operator()(std::string const& item)
+ {
+ str = item;
+ }
+
+ template<>
+ void to_string_visitor::operator()(NullType const& /*item*/)
+ {
+ str = "(null)";
+ }
+
+ template <>
+ void to_string_visitor::operator()(std::vector<uint8_t> const &item)
+ {
+ std::ostringstream stream;
+ for (size_t i = 0; i < item.size(); i++ )
{
- const unsigned int max_level = 3;
+ stream << "\\x" << std::hex << (int) item[i];
+ }
+ str = stream.str();
+ }
- if(curLevel > max_level)
- {
- throw OC::OCException(OC::Exception::INVALID_JSON_ARRAY_DEPTH);
- }
+ template<>
+ void to_string_visitor::operator()(OCByteString const &item)
+ {
+ std::vector<uint8_t> v(item.bytes, item.bytes + item.len);
+ operator()(v);
+ }
- if(curLevel > maxDepth)
- {
- maxDepth = curLevel;
- }
+ template<>
+ void to_string_visitor::operator()(OCRepresentation const& /*item*/)
+ {
+ str = "OC::OCRepresentation";
+ }
- auto arrayItems = gatherArrayContents(v, curLevel, maxDepth, t);
- const int remapLevel = maxDepth - (curLevel -1);
- return convertArrayToConcretes(t, remapLevel, arrayItems);
+ std::string OCRepresentation::getValueToString(const std::string& key) const
+ {
+ auto x = m_values.find(key);
+ if (x != m_values.end())
+ {
+ to_string_visitor vis;
+ boost::apply_visitor(vis, x->second);
+ return std::move(vis.str);
}
+
+ return "";
}
-}
-namespace cereal
-{
- void JSONInputArchive::loadAttributeValues(std::map<std::string, OC::AttributeValue>& map)
- {
- for(auto&b = itsIteratorStack.back();
- b.Member && b.itsMemberItEnd != b.itsMemberItBegin+b.itsIndex;
- ++b)
- {
- std::string key = b.itsMemberItBegin[b.itsIndex].name.GetString();
- const GenericValue& v = itsIteratorStack.back().value();
- map[key] = OC::detail::parseAttributeValue(v);
- }
- }
+ std::string OCRepresentation::AttributeItem::getValueToString() const
+ {
+ to_string_visitor vis;
+ boost::apply_visitor(vis, m_values[m_attrName]);
+ return std::move(vis.str);
+ }
+
+ std::ostream& operator<<(std::ostream& os, const OCRepresentation::AttributeItem& ai)
+ {
+ os << ai.getValueToString();
+ return os;
+ }
}