blob: 872aad724cb29c126c6d23f191ecf5df8a86d03c [file] [log] [blame]
/*
*
* 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 <list>
using namespace std;
using qpid::types::Variant;
using namespace qmf;
typedef PrivateImplRef<Schema> PI;
Schema::Schema(SchemaImpl* impl) { PI::ctor(*this, impl); }
Schema::Schema(const Schema& s) : qmf::Handle<SchemaImpl>() { 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<SchemaProperty>::const_iterator pIter = properties.begin(); pIter != properties.end(); pIter++)
propList.push_back(SchemaPropertyImplAccess::get(*pIter).asMap());
for (list<SchemaMethod>::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<SchemaProperty>::const_iterator pIter = properties.begin(); pIter != properties.end(); pIter++)
SchemaPropertyImplAccess::get(*pIter).encodeV1(buffer, false, false);
for (list<SchemaMethod>::const_iterator mIter = methods.begin(); mIter != methods.end(); mIter++)
SchemaMethodImplAccess::get(*mIter).encodeV1(buffer);
} else {
buffer.putShort(properties.size());
for (list<SchemaProperty>::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<SchemaProperty>::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<SchemaMethod>::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<SchemaMethod>::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<SchemaProperty>::const_iterator pIter = properties.begin(); pIter != properties.end(); pIter++)
SchemaPropertyImplAccess::get(*pIter).updateHash(hash);
for (list<SchemaMethod>::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<SchemaProperty>::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<SchemaMethod>::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;
}