/* * * 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/SchemaImpl.h" #include "qmf/PrivateImplRef.h" #include "qmf/exceptions.h" #include "qmf/SchemaTypes.h" #include "qmf/SchemaIdImpl.h" #include "qmf/SchemaPropertyImpl.h" #include "qmf/SchemaMethodImpl.h" #include "qmf/Hash.h" #include "qpid/log/Statement.h" #include "qpid/management/Buffer.h" #include using namespace std; using qpid::types::Variant; using namespace qmf; typedef PrivateImplRef PI; Schema::Schema(SchemaImpl* impl) { PI::ctor(*this, impl); } Schema::Schema(const Schema& s) : qmf::Handle() { PI::copy(*this, s); } Schema::~Schema() { PI::dtor(*this); } Schema& Schema::operator=(const Schema& s) { return PI::assign(*this, s); } Schema::Schema(int t, const string& p, const string& c) { PI::ctor(*this, new SchemaImpl(t, p, c)); } const SchemaId& Schema::getSchemaId() const { return impl->getSchemaId(); } void Schema::finalize() { impl->finalize(); } bool Schema::isFinalized() const { return impl->isFinalized(); } void Schema::addProperty(const SchemaProperty& p) { impl->addProperty(p); } void Schema::addMethod(const SchemaMethod& m) { impl->addMethod(m); } void Schema::setDesc(const string& d) { impl->setDesc(d); } const string& Schema::getDesc() const { return impl->getDesc(); } void Schema::setDefaultSeverity(int s) { impl->setDefaultSeverity(s); } int Schema::getDefaultSeverity() const { return impl->getDefaultSeverity(); } uint32_t Schema::getPropertyCount() const { return impl->getPropertyCount(); } SchemaProperty Schema::getProperty(uint32_t i) const { return impl->getProperty(i); } uint32_t Schema::getMethodCount() const { return impl->getMethodCount(); } SchemaMethod Schema::getMethod(uint32_t i) const { return impl->getMethod(i); } //======================================================================================== // Impl Method Bodies //======================================================================================== SchemaImpl::SchemaImpl(const Variant::Map& map) : finalized(false) { Variant::Map::const_iterator iter; Variant::List::const_iterator lIter; iter = map.find("_schema_id"); if (iter == map.end()) throw QmfException("Schema map missing _schema_id element"); schemaId = SchemaId(new SchemaIdImpl(iter->second.asMap())); iter = map.find("_desc"); if (iter != map.end()) description = iter->second.asString(); iter = map.find("_default_severity"); if (iter != map.end()) defaultSeverity = int(iter->second.asUint32()); iter = map.find("_properties"); if (iter != map.end()) { const Variant::List& props(iter->second.asList()); for (lIter = props.begin(); lIter != props.end(); lIter++) addProperty(SchemaProperty(new SchemaPropertyImpl(lIter->asMap()))); } iter = map.find("_methods"); if (iter != map.end()) { const Variant::List& meths(iter->second.asList()); for (lIter = meths.begin(); lIter != meths.end(); lIter++) addMethod(SchemaMethod(new SchemaMethodImpl(lIter->asMap()))); } finalized = true; } Variant::Map SchemaImpl::asMap() const { Variant::Map map; Variant::List propList; Variant::List methList; checkNotFinal(); map["_schema_id"] = SchemaIdImplAccess::get(schemaId).asMap(); if (!description.empty()) map["_desc"] = description; if (schemaId.getType() == SCHEMA_TYPE_EVENT) map["_default_severity"] = uint32_t(defaultSeverity); for (list::const_iterator pIter = properties.begin(); pIter != properties.end(); pIter++) propList.push_back(SchemaPropertyImplAccess::get(*pIter).asMap()); for (list::const_iterator mIter = methods.begin(); mIter != methods.end(); mIter++) methList.push_back(SchemaMethodImplAccess::get(*mIter).asMap()); map["_properties"] = propList; map["_methods"] = methList; return map; } SchemaImpl::SchemaImpl(qpid::management::Buffer& buffer) : finalized(false) { int schemaType; string packageName; string className; uint8_t hash[16]; schemaType = int(buffer.getOctet()); buffer.getShortString(packageName); buffer.getShortString(className); buffer.getBin128(hash); schemaId = SchemaId(schemaType, packageName, className); schemaId.setHash(qpid::types::Uuid(hash)); if (schemaType == SCHEMA_TYPE_DATA) { uint16_t propCount(buffer.getShort()); uint16_t statCount(buffer.getShort()); uint16_t methCount(buffer.getShort()); for (uint16_t idx = 0; idx < propCount + statCount; idx++) addProperty(new SchemaPropertyImpl(buffer)); for (uint16_t idx = 0; idx < methCount; idx++) addMethod(new SchemaMethodImpl(buffer)); } finalized = true; } string SchemaImpl::asV1Content(uint32_t sequence) const { #define RAW_BUF_SIZE 65536 char rawBuf[RAW_BUF_SIZE]; qpid::management::Buffer buffer(rawBuf, RAW_BUF_SIZE); // // Encode the QMFv1 Header // buffer.putOctet('A'); buffer.putOctet('M'); buffer.putOctet('2'); buffer.putOctet('s'); buffer.putLong(sequence); // // Encode the common schema information // buffer.putOctet(uint8_t(schemaId.getType())); buffer.putShortString(schemaId.getPackageName()); buffer.putShortString(schemaId.getName()); buffer.putBin128(schemaId.getHash().data()); if (schemaId.getType() == SCHEMA_TYPE_DATA) { buffer.putShort(properties.size()); buffer.putShort(0); buffer.putShort(methods.size()); for (list::const_iterator pIter = properties.begin(); pIter != properties.end(); pIter++) SchemaPropertyImplAccess::get(*pIter).encodeV1(buffer, false, false); for (list::const_iterator mIter = methods.begin(); mIter != methods.end(); mIter++) SchemaMethodImplAccess::get(*mIter).encodeV1(buffer); } else { buffer.putShort(properties.size()); for (list::const_iterator pIter = properties.begin(); pIter != properties.end(); pIter++) SchemaPropertyImplAccess::get(*pIter).encodeV1(buffer, true, false); } return string(rawBuf, buffer.getPosition()); } bool SchemaImpl::isValidProperty(const std::string& k, const Variant& v) const { for (list::const_iterator iter = properties.begin(); iter != properties.end(); iter++) if (iter->getName() == k) return (isCompatibleType(iter->getType(), v.getType())); return false; } bool SchemaImpl::isValidMethodInArg(const std::string& m, const std::string& k, const Variant& v) const { for (list::const_iterator mIter = methods.begin(); mIter != methods.end(); mIter++) { if (mIter->getName() == m) { uint32_t count(mIter->getArgumentCount()); for (uint32_t i = 0; i < count; i++) { const SchemaProperty prop(mIter->getArgument(i)); if (prop.getName() == k) { if (prop.getDirection() == DIR_IN || prop.getDirection() == DIR_IN_OUT) return (isCompatibleType(prop.getType(), v.getType())); else return false; } } } } return false; } bool SchemaImpl::isValidMethodOutArg(const std::string& m, const std::string& k, const Variant& v) const { for (list::const_iterator mIter = methods.begin(); mIter != methods.end(); mIter++) { if (mIter->getName() == m) { uint32_t count(mIter->getArgumentCount()); for (uint32_t i = 0; i < count; i++) { const SchemaProperty prop(mIter->getArgument(i)); if (prop.getName() == k) { if (prop.getDirection() == DIR_OUT || prop.getDirection() == DIR_IN_OUT) return (isCompatibleType(prop.getType(), v.getType())); else return false; } } } } return false; } void SchemaImpl::finalize() { Hash hash; hash.update((uint8_t) schemaId.getType()); hash.update(schemaId.getPackageName()); hash.update(schemaId.getName()); for (list::const_iterator pIter = properties.begin(); pIter != properties.end(); pIter++) SchemaPropertyImplAccess::get(*pIter).updateHash(hash); for (list::const_iterator mIter = methods.begin(); mIter != methods.end(); mIter++) SchemaMethodImplAccess::get(*mIter).updateHash(hash); schemaId.setHash(hash.asUuid()); QPID_LOG(debug, "Schema Finalized: " << schemaId.getPackageName() << ":" << schemaId.getName() << ":" << schemaId.getHash()); finalized = true; } SchemaProperty SchemaImpl::getProperty(uint32_t i) const { uint32_t count = 0; for (list::const_iterator iter = properties.begin(); iter != properties.end(); iter++) if (count++ == i) return *iter; throw IndexOutOfRange(); } SchemaMethod SchemaImpl::getMethod(uint32_t i) const { uint32_t count = 0; for (list::const_iterator iter = methods.begin(); iter != methods.end(); iter++) if (count++ == i) return *iter; throw IndexOutOfRange(); } void SchemaImpl::checkFinal() const { if (finalized) throw QmfException("Modification of a finalized schema is forbidden"); } void SchemaImpl::checkNotFinal() const { if (!finalized) throw QmfException("Schema is not yet finalized/registered"); } bool SchemaImpl::isCompatibleType(int qmfType, qpid::types::VariantType qpidType) const { bool typeValid(false); switch (qpidType) { case qpid::types::VAR_VOID: if (qmfType == SCHEMA_DATA_VOID) typeValid = true; break; case qpid::types::VAR_BOOL: if (qmfType == SCHEMA_DATA_BOOL) typeValid = true; break; case qpid::types::VAR_UINT8: case qpid::types::VAR_UINT16: case qpid::types::VAR_UINT32: case qpid::types::VAR_UINT64: case qpid::types::VAR_INT8: case qpid::types::VAR_INT16: case qpid::types::VAR_INT32: case qpid::types::VAR_INT64: if (qmfType == SCHEMA_DATA_INT) typeValid = true; break; case qpid::types::VAR_FLOAT: case qpid::types::VAR_DOUBLE: if (qmfType == SCHEMA_DATA_FLOAT) typeValid = true; break; case qpid::types::VAR_STRING: if (qmfType == SCHEMA_DATA_STRING) typeValid = true; break; case qpid::types::VAR_MAP: if (qmfType == SCHEMA_DATA_MAP) typeValid = true; break; case qpid::types::VAR_LIST: if (qmfType == SCHEMA_DATA_LIST) typeValid = true; break; case qpid::types::VAR_UUID: if (qmfType == SCHEMA_DATA_UUID) typeValid = true; break; } return typeValid; } SchemaImpl& SchemaImplAccess::get(Schema& item) { return *item.impl; } const SchemaImpl& SchemaImplAccess::get(const Schema& item) { return *item.impl; }