/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "qmf/SchemaPropertyImpl.h" #include "qmf/PrivateImplRef.h" #include "qmf/exceptions.h" #include "qmf/SchemaTypes.h" #include "qmf/SchemaProperty.h" #include "qmf/Hash.h" #include "qpid/messaging/AddressParser.h" #include #include using namespace std; using qpid::types::Variant; using namespace qmf; typedef PrivateImplRef PI; SchemaProperty::SchemaProperty(SchemaPropertyImpl* impl) { PI::ctor(*this, impl); } SchemaProperty::SchemaProperty(const SchemaProperty& s) : qmf::Handle() { PI::copy(*this, s); } SchemaProperty::~SchemaProperty() { PI::dtor(*this); } SchemaProperty& SchemaProperty::operator=(const SchemaProperty& s) { return PI::assign(*this, s); } SchemaProperty::SchemaProperty(const string& n, int t, const string& o) { PI::ctor(*this, new SchemaPropertyImpl(n, t, o)); } void SchemaProperty::setAccess(int a) { impl->setAccess(a); } void SchemaProperty::setIndex(bool i) { impl->setIndex(i); } void SchemaProperty::setOptional(bool o) { impl->setOptional(o); } void SchemaProperty::setUnit(const string& u) { impl->setUnit(u); } void SchemaProperty::setDesc(const string& d) { impl->setDesc(d); } void SchemaProperty::setSubtype(const string& s) { impl->setSubtype(s); } void SchemaProperty::setDirection(int d) { impl->setDirection(d); } const string& SchemaProperty::getName() const { return impl->getName(); } int SchemaProperty::getType() const { return impl->getType(); } int SchemaProperty::getAccess() const { return impl->getAccess(); } bool SchemaProperty::isIndex() const { return impl->isIndex(); } bool SchemaProperty::isOptional() const { return impl->isOptional(); } const string& SchemaProperty::getUnit() const { return impl->getUnit(); } const string& SchemaProperty::getDesc() const { return impl->getDesc(); } const string& SchemaProperty::getSubtype() const { return impl->getSubtype(); } int SchemaProperty::getDirection() const { return impl->getDirection(); } //======================================================================================== // Impl Method Bodies //======================================================================================== SchemaPropertyImpl::SchemaPropertyImpl(const string& n, int t, const string options) : name(n), dataType(t), access(ACCESS_READ_ONLY), index(false), optional(false), direction(DIR_IN) { if (!options.empty()) { qpid::messaging::AddressParser parser = qpid::messaging::AddressParser(options); Variant::Map optMap; Variant::Map::iterator iter; parser.parseMap(optMap); iter = optMap.find("access"); if (iter != optMap.end()) { const string& v(iter->second.asString()); if (v == "RC") access = ACCESS_READ_CREATE; else if (v == "RO") access = ACCESS_READ_ONLY; else if (v == "RW") access = ACCESS_READ_WRITE; else throw QmfException("Invalid value for 'access' option. Expected RC, RO, or RW"); optMap.erase(iter); } iter = optMap.find("index"); if (iter != optMap.end()) { index = iter->second.asBool(); optMap.erase(iter); } iter = optMap.find("optional"); if (iter != optMap.end()) { optional = iter->second.asBool(); optMap.erase(iter); } iter = optMap.find("unit"); if (iter != optMap.end()) { unit = iter->second.asString(); optMap.erase(iter); } iter = optMap.find("desc"); if (iter != optMap.end()) { desc = iter->second.asString(); optMap.erase(iter); } iter = optMap.find("subtype"); if (iter != optMap.end()) { subtype = iter->second.asString(); optMap.erase(iter); } iter = optMap.find("dir"); if (iter != optMap.end()) { const string& v(iter->second.asString()); if (v == "IN") direction = DIR_IN; else if (v == "OUT") direction = DIR_OUT; else if (v == "INOUT") direction = DIR_IN_OUT; else throw QmfException("Invalid value for 'dir' option. Expected IN, OUT, or INOUT"); optMap.erase(iter); } if (!optMap.empty()) throw QmfException("Unexpected option: " + optMap.begin()->first); } } SchemaPropertyImpl::SchemaPropertyImpl(const Variant::Map& map) : access(ACCESS_READ_ONLY), index(false), optional(false), direction(DIR_IN) { Variant::Map::const_iterator iter; iter = map.find("_name"); if (iter == map.end()) throw QmfException("SchemaProperty without a _name element"); name = iter->second.asString(); iter = map.find("_type"); if (iter == map.end()) throw QmfException("SchemaProperty without a _type element"); const string& ts(iter->second.asString()); if (ts == "TYPE_VOID") dataType = SCHEMA_DATA_VOID; else if (ts == "TYPE_BOOL") dataType = SCHEMA_DATA_BOOL; else if (ts == "TYPE_INT") dataType = SCHEMA_DATA_INT; else if (ts == "TYPE_FLOAT") dataType = SCHEMA_DATA_FLOAT; else if (ts == "TYPE_STRING") dataType = SCHEMA_DATA_STRING; else if (ts == "TYPE_MAP") dataType = SCHEMA_DATA_MAP; else if (ts == "TYPE_LIST") dataType = SCHEMA_DATA_LIST; else if (ts == "TYPE_UUID") dataType = SCHEMA_DATA_UUID; else throw QmfException("SchemaProperty with an invalid type code: " + ts); iter = map.find("_access"); if (iter != map.end()) { const string& as(iter->second.asString()); if (as == "RO") access = ACCESS_READ_ONLY; else if (as == "RC") access = ACCESS_READ_CREATE; else if (as == "RW") access = ACCESS_READ_WRITE; else throw QmfException("SchemaProperty with an invalid access code: " + as); } iter = map.find("_unit"); if (iter != map.end()) unit = iter->second.asString(); iter = map.find("_dir"); if (iter != map.end()) { const string& ds(iter->second.asString()); if (ds == "I") direction = DIR_IN; else if (ds == "O") direction = DIR_OUT; else if (ds == "IO") direction = DIR_IN_OUT; else throw QmfException("SchemaProperty with an invalid direction code: " + ds); } iter = map.find("_desc"); if (iter != map.end()) desc = iter->second.asString(); iter = map.find("_index"); if (iter != map.end()) index = iter->second.asBool(); iter = map.find("_subtype"); if (iter != map.end()) subtype = iter->second.asString(); } Variant::Map SchemaPropertyImpl::asMap() const { Variant::Map map; string ts; map["_name"] = name; switch (dataType) { case SCHEMA_DATA_VOID: ts = "TYPE_VOID"; break; case SCHEMA_DATA_BOOL: ts = "TYPE_BOOL"; break; case SCHEMA_DATA_INT: ts = "TYPE_INT"; break; case SCHEMA_DATA_FLOAT: ts = "TYPE_FLOAT"; break; case SCHEMA_DATA_STRING: ts = "TYPE_STRING"; break; case SCHEMA_DATA_MAP: ts = "TYPE_MAP"; break; case SCHEMA_DATA_LIST: ts = "TYPE_LIST"; break; case SCHEMA_DATA_UUID: ts = "TYPE_UUID"; break; } map["_type"] = ts; switch (access) { case ACCESS_READ_ONLY: ts = "RO"; break; case ACCESS_READ_CREATE: ts = "RC"; break; case ACCESS_READ_WRITE: ts = "RW"; break; } map["_access"] = ts; if (!unit.empty()) map["_unit"] = unit; switch (direction) { case DIR_IN: ts = "I"; break; case DIR_OUT: ts = "O"; break; case DIR_IN_OUT: ts = "IO"; break; } map["_dir"] = ts; if (!desc.empty()) map["_desc"] = desc; if (index) map["_index"] = true; if (!subtype.empty()) map["_subtype"] = subtype; return map; } SchemaPropertyImpl::SchemaPropertyImpl(qpid::management::Buffer& buffer) : access(ACCESS_READ_ONLY), index(false), optional(false), direction(DIR_IN) { Variant::Map::const_iterator iter; Variant::Map pmap; buffer.getMap(pmap); iter = pmap.find("name"); if (iter == pmap.end()) throw QmfException("Received V1 Schema property without a name"); name = iter->second.asString(); iter = pmap.find("type"); if (iter == pmap.end()) throw QmfException("Received V1 Schema property without a type"); fromV1TypeCode(iter->second.asInt8()); iter = pmap.find("unit"); if (iter != pmap.end()) unit = iter->second.asString(); iter = pmap.find("desc"); if (iter != pmap.end()) desc = iter->second.asString(); iter = pmap.find("access"); if (iter != pmap.end()) { int8_t val = iter->second.asInt8(); if (val < 1 || val > 3) throw QmfException("Received V1 Schema property with invalid 'access' code"); access = val; } iter = pmap.find("index"); if (iter != pmap.end()) index = iter->second.asInt64() != 0; iter = pmap.find("optional"); if (iter != pmap.end()) optional = iter->second.asInt64() != 0; iter = pmap.find("dir"); if (iter != pmap.end()) { string dirStr(iter->second.asString()); if (dirStr == "I") direction = DIR_IN; else if (dirStr == "O") direction = DIR_OUT; else if (dirStr == "IO") direction = DIR_IN_OUT; else throw QmfException("Received V1 Schema property with invalid 'dir' code"); } } void SchemaPropertyImpl::updateHash(Hash& hash) const { hash.update(name); hash.update((uint8_t) dataType); hash.update(subtype); hash.update((uint8_t) access); hash.update(index); hash.update(optional); hash.update(unit); hash.update(desc); hash.update((uint8_t) direction); } void SchemaPropertyImpl::encodeV1(qpid::management::Buffer& buffer, bool isArg, bool isMethodArg) const { Variant::Map pmap; pmap["name"] = name; pmap["type"] = v1TypeCode(); if (!unit.empty()) pmap["unit"] = unit; if (!desc.empty()) pmap["desc"] = desc; if (!isArg) { pmap["access"] = access; pmap["index"] = index ? 1 : 0; pmap["optional"] = optional ? 1 : 0; } else { if (isMethodArg) { string dirStr; switch (direction) { case DIR_IN : dirStr = "I"; break; case DIR_OUT : dirStr = "O"; break; case DIR_IN_OUT : dirStr = "IO"; break; } pmap["dir"] = dirStr; } } buffer.putMap(pmap); } uint8_t SchemaPropertyImpl::v1TypeCode() const { switch (dataType) { case SCHEMA_DATA_VOID: return 1; case SCHEMA_DATA_BOOL: return 11; case SCHEMA_DATA_INT: if (subtype == "timestamp") return 8; if (subtype == "duration") return 9; return 19; case SCHEMA_DATA_FLOAT: return 13; case SCHEMA_DATA_STRING: return 7; case SCHEMA_DATA_LIST: return 21; case SCHEMA_DATA_UUID: return 14; case SCHEMA_DATA_MAP: if (subtype == "reference") return 10; if (subtype == "data") return 20; return 15; } return 1; } void SchemaPropertyImpl::fromV1TypeCode(int8_t code) { switch (code) { case 1: // U8 case 2: // U16 case 3: // U32 case 4: // U64 dataType = SCHEMA_DATA_INT; break; case 6: // SSTR case 7: // LSTR dataType = SCHEMA_DATA_STRING; break; case 8: // ABSTIME dataType = SCHEMA_DATA_INT; subtype = "timestamp"; break; case 9: // DELTATIME dataType = SCHEMA_DATA_INT; subtype = "duration"; break; case 10: // REF dataType = SCHEMA_DATA_MAP; subtype = "reference"; break; case 11: // BOOL dataType = SCHEMA_DATA_BOOL; break; case 12: // FLOAT case 13: // DOUBLE dataType = SCHEMA_DATA_FLOAT; break; case 14: // UUID dataType = SCHEMA_DATA_UUID; break; case 15: // FTABLE dataType = SCHEMA_DATA_MAP; break; case 16: // S8 case 17: // S16 case 18: // S32 case 19: // S64 dataType = SCHEMA_DATA_INT; break; case 20: // OBJECT dataType = SCHEMA_DATA_MAP; subtype = "data"; break; case 21: // LIST case 22: // ARRAY dataType = SCHEMA_DATA_LIST; break; default: throw QmfException("Received V1 schema with an unknown data type"); } } SchemaPropertyImpl& SchemaPropertyImplAccess::get(SchemaProperty& item) { return *item.impl; } const SchemaPropertyImpl& SchemaPropertyImplAccess::get(const SchemaProperty& item) { return *item.impl; }