X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=resource%2Fsrc%2FOCRepresentation.cpp;h=f0e8dca23af31241cd6ced7af89070a5e08e1abf;hb=fcf665585275bc75c7698c1ce99a58d614855a55;hp=71487cd978dd5578d34672beba57afcdccb71590;hpb=27178e2d0135760d6e8cf8b1e0936d658d192fff;p=platform%2Fupstream%2Fiotivity.git diff --git a/resource/src/OCRepresentation.cpp b/resource/src/OCRepresentation.cpp index 71487cd..f0e8dca 100644 --- a/resource/src/OCRepresentation.cpp +++ b/resource/src/OCRepresentation.cpp @@ -18,169 +18,641 @@ // //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -/// @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 -#include -#include -#include -#include -#include +#include #include +#include "ocpayload.h" +#include "ocrandom.h" +#include "oic_malloc.h" +#include "oic_string.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 WriteAttributeValue : public boost::static_visitor<> + if (rep == nullptr) { - public: - WriteAttributeValue(const std::string& name, Archive& ar) - :m_name(name), m_archive(ar) - {} + return; + } - template - 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(rep)); + break; + case PAYLOAD_TYPE_DEVICE: + setPayload(reinterpret_cast(rep)); + break; + case PAYLOAD_TYPE_PLATFORM: + setPayload(reinterpret_cast(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 - void serialize(Archive&, OC::NullType t) - {} + void MessageContainer::setPayload(const OCDevicePayload* payload) + { + if (payload == nullptr) + { + return; + } + + OCRepresentation rep; + rep[OC_RSRVD_DEVICE_ID] = (payload->sid) ? + std::string(payload->sid) : + std::string(); + rep[OC_RSRVD_DEVICE_NAME] = payload->deviceName ? + std::string(payload->deviceName) : + std::string(); + rep[OC_RSRVD_SPEC_VERSION] = payload->specVersion ? + std::string(payload->specVersion) : + std::string(); + rep[OC_RSRVD_DATA_MODEL_VERSION] = payload->dataModelVersion ? + std::string(payload->dataModelVersion) : + std::string(); + for (OCStringLL *strll = payload->types; strll; strll = strll->next) + { + rep.addResourceType(strll->value); + } + m_reps.push_back(std::move(rep)); + } + + void MessageContainer::setPayload(const OCPlatformPayload* payload) + { + if (payload == nullptr) + { + return; + } + + OCRepresentation rep; + rep[OC_RSRVD_PLATFORM_ID] = payload->info.platformID ? + std::string(payload->info.platformID) : + std::string(); + rep[OC_RSRVD_MFG_NAME] = payload->info.manufacturerName ? + std::string(payload->info.manufacturerName) : + std::string(); + rep[OC_RSRVD_MFG_URL] = payload->info.manufacturerUrl ? + std::string(payload->info.manufacturerUrl) : + std::string(); + rep[OC_RSRVD_MODEL_NUM] = payload->info.modelNumber ? + std::string(payload->info.modelNumber) : + std::string(); + rep[OC_RSRVD_MFG_DATE] = payload->info.dateOfManufacture ? + std::string(payload->info.dateOfManufacture) : + std::string(); + rep[OC_RSRVD_PLATFORM_VERSION] = payload->info.platformVersion ? + std::string(payload->info.platformVersion) : + std::string(); + rep[OC_RSRVD_OS_VERSION] = payload->info.operatingSystemVersion ? + std::string(payload->info.operatingSystemVersion) : + std::string(); + rep[OC_RSRVD_HARDWARE_VERSION] = payload->info.hardwareVersion ? + std::string(payload->info.hardwareVersion) : + std::string(); + rep[OC_RSRVD_FIRMWARE_VERSION] = payload->info.firmwareVersion ? + std::string(payload->info.firmwareVersion) : + std::string(); + rep[OC_RSRVD_SUPPORT_URL] = payload->info.supportUrl ? + std::string(payload->info.supportUrl) : + std::string(); + rep[OC_RSRVD_SYSTEM_TIME] = payload->info.systemTime ? + std::string(payload->info.systemTime) : + std::string(); + + for (OCStringLL *strll = payload->rt; strll; strll = strll->next) + { + rep.addResourceType(strll->value); + } + for (OCStringLL *strll = payload->interfaces; strll; strll = strll->next) + { + rep.addResourceInterface(strll->value); + } + + m_reps.push_back(std::move(rep)); + } - template - void save(Archive& ar, const std::map& 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 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 - void load(Archive& ar, std::map& vals) + const std::vector& 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 + void operator()(T& /*arr*/) + { + throw std::logic_error("Invalid calc_dimensions_visitor type"); + } - void MessageContainer::setJSONRepresentation(const std::string& payload) + template + void operator()(std::vector& arr) + { + root_size_calc(); + 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 + void operator()(std::vector>& arr) + { + root_size_calc(); + 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 + void operator()(std::vector>>& arr) + { + root_size_calc(); + 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 + void root_size_calc() + { + root_size = sizeof(T); + } + + template + 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() + { + root_size = sizeof(int64_t); + } + + template<> + void get_payload_array::root_size_calc() + { + root_size = sizeof(char*); + } + + template<> + void get_payload_array::root_size_calc() + { + root_size = sizeof(OCRepPayload*); + } + + template<> + void get_payload_array::copy_to_array(int item, void* array, size_t pos) + { + ((int64_t*)array)[pos] = item; + } + + template<> + void get_payload_array::copy_to_array(std::_Bit_reference br, void* array, size_t pos) { - std::stringstream os(payload); + ((bool*)array)[pos] = static_cast(br); + } + + 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(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::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())); + } + } + + OCRepPayload* OCRepresentation::getPayload() const + { + OCRepPayload* root = OCRepPayloadCreate(); + if (!root) + { + 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(val)); + break; + case AttributeType::Double: + OCRepPayloadSetPropDouble(root, val.attrname().c_str(), + val.getValue()); + break; + case AttributeType::Boolean: + OCRepPayloadSetPropBool(root, val.attrname().c_str(), val.getValue()); + break; + case AttributeType::String: + OCRepPayloadSetPropString(root, val.attrname().c_str(), + static_cast(val).c_str()); + break; + case AttributeType::OCRepresentation: + OCRepPayloadSetPropObjectAsOwner(root, val.attrname().c_str(), + static_cast(val).getPayload()); + break; + case AttributeType::Vector: + getPayloadArray(root, val); + break; + case AttributeType::Binary: + OCRepPayloadSetPropByteString(root, val.attrname().c_str(), + OCByteString{const_cast(val.getValue>().data()), + val.getValue>().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) { - InputArchiveType archive(os); - archive(cereal::make_nvp(OC::Key::OCKEY, m_reps)); + throw std::logic_error("invalid calcArrayDepth"); + } + else if (dimensions[1] == 0) + { + return 1; + } + else if (dimensions[2] == 0) + { + return 2; + } + else + { + return 3; } } - void MessageContainer::setJSONRepresentation(const unsigned char* payload) + template + 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(size_t index, const OCRepPayloadValue* pl) + { + return pl->arr.iArray[index]; + } + template<> + double OCRepresentation::payload_array_helper_copy(size_t index, const OCRepPayloadValue* pl) + { + return pl->arr.dArray[index]; + } + template<> + bool OCRepresentation::payload_array_helper_copy(size_t index, const OCRepPayloadValue* pl) { - setJSONRepresentation(std::string(reinterpret_cast(payload))); + return pl->arr.bArray[index]; + } + template<> + std::string OCRepresentation::payload_array_helper_copy( + size_t index, const OCRepPayloadValue* pl) + { + if (pl->arr.strArray[index]) + { + return std::string(pl->arr.strArray[index]); + } + else + { + return std::string{}; + } + } + template<> + OCRepresentation OCRepresentation::payload_array_helper_copy( + size_t index, const OCRepPayloadValue* pl) + { + OCRepresentation r; + if (pl->arr.objArray[index]) + { + r.setPayload(pl->arr.objArray[index]); + } + return r; } - std::string MessageContainer::getJSONRepresentation(OCInfoFormat f) const + template + void OCRepresentation::payload_array_helper(const OCRepPayloadValue* pl, size_t depth) { - std::stringstream os; + if (depth == 1) + { + std::vector 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(i, pl); + } + this->setValue(std::string(pl->name), val); + } + else if (depth == 2) { - if(f == OCInfoFormat::IncludeOC) + std::vector> 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( + 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>> val(pl->arr.dimensions[0]); + for(size_t i = 0; i < pl->arr.dimensions[0]; ++i) { - bool firstPrinted = false; - for(std::vector::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( + 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& 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(pl, calcArrayDepth(pl->arr.dimensions)); + break; + case OCREP_PROP_DOUBLE: + payload_array_helper(pl, calcArrayDepth(pl->arr.dimensions)); + break; + case OCREP_PROP_BOOL: + payload_array_helper(pl, calcArrayDepth(pl->arr.dimensions)); + break; + case OCREP_PROP_STRING: + payload_array_helper(pl, calcArrayDepth(pl->arr.dimensions)); + break; + case OCREP_PROP_OBJECT: + payload_array_helper(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(val->name, val->i); + break; + case OCREP_PROP_DOUBLE: + setValue(val->name, val->d); + break; + case OCREP_PROP_BOOL: + setValue(val->name, val->b); + break; + case OCREP_PROP_STRING: + setValue(val->name, val->str); + break; + case OCREP_PROP_OBJECT: + { + OCRepresentation cur; + cur.setPayload(val->obj); + setValue(val->name, cur); + } + break; + case OCREP_PROP_ARRAY: + setPayloadArray(val); + break; + case OCREP_PROP_BYTE_STRING: + setValue(val->name, + std::vector + (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) @@ -198,6 +670,51 @@ namespace OC return m_children; } + void OCRepresentation::setChildren(const std::vector& children) + { + m_children = children; + } + + void OCRepresentation::setDevAddr(const OCDevAddr m_devAddr) + { + std::ostringstream ss; + if (m_devAddr.flags & OC_SECURE) + { + ss << COAPS; + } + else if (m_devAddr.adapter & OC_ADAPTER_TCP) + { + ss << COAP_TCP; + } + else + { + ss << COAP; + } + if (m_devAddr.flags & OC_IP_USE_V6) + { + ss << '[' << m_devAddr.addr << ']'; + } + else + { + ss << m_devAddr.addr; + } + if (m_devAddr.port) + { + ss << ':' << m_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; @@ -218,11 +735,21 @@ namespace OC m_resourceTypes = resourceTypes; } + void OCRepresentation::addResourceType(const std::string& str) + { + m_resourceTypes.push_back(str); + } + const std::vector& OCRepresentation::getResourceInterfaces() const { return m_interfaces; } + void OCRepresentation::addResourceInterface(const std::string& str) + { + m_interfaces.push_back(str); + } + void OCRepresentation::setResourceInterfaces(const std::vector& resourceInterfaces) { m_interfaces = resourceInterfaces; @@ -233,7 +760,7 @@ namespace OC 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 @@ -241,7 +768,7 @@ namespace OC // 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; } @@ -252,7 +779,7 @@ namespace OC { 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) @@ -260,7 +787,7 @@ namespace OC return false; } - if(m_children.size() > 0) + if (m_children.size() > 0) { return false; } @@ -287,7 +814,7 @@ namespace OC { auto x = m_values.find(str); - if(m_values.end() != x) + if (m_values.end() != x) { return x->second.which() == AttributeValueNullIndex; } @@ -300,349 +827,347 @@ namespace OC namespace OC { - template - 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::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& vals): + m_attrName(name), m_values(vals){} - template - 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& rt(m_resourceTypes); - const std::vector& intf(m_interfaces); - Prop temp(const_cast&>(rt), - const_cast&>(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 - void OCRepresentation::load(Archive& ar) + template + 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 + constexpr static AttributeType enum_type = + AttributeTypeConvert::type; + // contains the AttributeType for this base-type + constexpr static AttributeType enum_base_type = + AttributeTypeConvert::type; + // depth of the vector + constexpr static size_t depth = 0; + }; + + template + struct type_info< + T, + typename std::enable_if< + is_vector::value && + !std::is_same::value + >::type + > + { + typedef T type; + typedef typename type_info::base_type base_type; + constexpr static AttributeType enum_type = AttributeType::Vector; + constexpr static AttributeType enum_base_type = + type_info::enum_base_type; + constexpr static size_t depth = 1 + + type_info::depth; + }; + + // special case for binary data, which is a std::vector + template<> + struct type_info, void> + { + typedef std::vector type; + typedef std::vector base_type; + constexpr static AttributeType enum_type = AttributeType::Binary; + constexpr static AttributeType enum_base_type = AttributeType::Binary; + constexpr static 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 + void operator()(T const& /*item*/) { - Prop temp(m_resourceTypes, m_interfaces); - optional_load(ar, cereal::make_nvp(Key::PROPERTYKEY, temp)); + type = type_info::enum_type; + base_type = type_info::enum_base_type; + depth = type_info::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 - 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 - 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(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>( - parseAttributeValue(itr->value))); - } - else if(keyName == OC::Key::PROPERTYKEY) - { - rep.setResourceInterfaces( - boost::get>( - 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 gatherArrayContents(const GenericValue& v, - const unsigned int curLevel, unsigned int& maxDepth, typeTag& t) - { - std::vector 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 - struct valueToConcrete - { - OutT operator()(const AttributeValue& v) - { - return boost::get(v); - } + OCRepresentation::iterator::pointer OCRepresentation::iterator::operator->() + { + return &m_item; + } - }; + OCRepresentation::const_iterator::const_pointer + OCRepresentation::const_iterator::operator->() const + { + return &m_item; + } - template - OutSeqT valuesToConcreteVectors(const std::vector& vs) + OCRepresentation::iterator& OCRepresentation::iterator::operator++() + { + m_iterator++; + if (m_iterator != m_item.m_values.end()) { - OutSeqT ret; - - std::transform(begin(vs),end(vs), back_inserter(ret), - valueToConcrete()); - return ret; + m_item.m_attrName = m_iterator->first; + } + else + { + m_item.m_attrName = ""; } + return *this; + } - template - AttributeValue remapArrayDepth(const unsigned int curLevel, - const std::vector& vs) + OCRepresentation::const_iterator& OCRepresentation::const_iterator::operator++() + { + m_iterator++; + if (m_iterator != m_item.m_values.end()) { - switch(curLevel) - { - default: - throw OC::OCException(OC::Exception::INVALID_JSON_ARRAY_DEPTH); - break; - case 1: - return valuesToConcreteVectors>(vs); - break; - case 2: - return valuesToConcreteVectors>>(vs); - break; - case 3: - return valuesToConcreteVectors - >>>(vs); - break; - } + 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; + } - AttributeValue convertArrayToConcretes(const typeTag t, - const unsigned int curLevel, const std::vector& vs) + OCRepresentation::const_iterator OCRepresentation::const_iterator::operator++(int) + { + OCRepresentation::const_iterator itr(*this); + ++(*this); + return itr; + } + + struct to_string_visitor : boost::static_visitor<> + { + std::string str; + template + void operator()(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) - { - default: - case typeTag::NOTHING: - throw OC::OCException(OC::Exception::INVALID_JSON_TYPE_TAG); - break; - case typeTag::_string: - return remapArrayDepth(curLevel, vs); - break; - case typeTag::_int: - return remapArrayDepth(curLevel, vs); - break; - case typeTag::_double: - return remapArrayDepth(curLevel, vs); - break; - case typeTag::_bool: - return remapArrayDepth(curLevel, vs); - break; - case typeTag::_representation: - return remapArrayDepth(curLevel, vs); - break; - } + str = boost::lexical_cast(item); } - AttributeValue parseAttributeValueArray(const GenericValue& v, - const unsigned int curLevel, unsigned int& maxDepth, typeTag& t) + template + void operator()(std::vector const& item) { - const unsigned int max_level = 3; + to_string_visitor vis; + std::ostringstream stream; + stream << "["; - if(curLevel > max_level) + for(const auto& i : item) { - throw OC::OCException(OC::Exception::INVALID_JSON_ARRAY_DEPTH); + vis(i); + stream << vis.str << " "; } + stream << "]"; + str = stream.str(); + } + }; - if(curLevel > maxDepth) - { - maxDepth = curLevel; - } + template<> + void to_string_visitor::operator()(bool const& item) + { + str = item ? "true" : "false"; + } + + template<> + void to_string_visitor::operator()(std::string const& item) + { + str = item; + } + + template<> + void to_string_visitor::operator()(NullType const& /*item*/) + { + str = "(null)"; + } - auto arrayItems = gatherArrayContents(v, curLevel, maxDepth, t); - const int remapLevel = maxDepth - (curLevel -1); - return convertArrayToConcretes(t, remapLevel, arrayItems); + template<> + void to_string_visitor::operator()(OCRepresentation const& /*item*/) + { + str = "OC::OCRepresentation"; + } + + 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& 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; + } }