blob: 801257fad9ec79a902ea72f8b85a216b053293a5 [file] [log] [blame]
/*
*
* Copyright (c) 2016-2017 Nest Labs, Inc.
* All rights reserved.
*
* Licensed 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.
*/
/**
* @file
* Defines catalogs that are used to house trait data sources/sinks and can be used with the
* various WDM engines to correctly map to/from resources specified in a WDM path to actual trait
* data instances.
*
*/
#ifndef _WEAVE_DATA_MANAGEMENT_TRAIT_DATA_CATALOG_CURRENT_H
#define _WEAVE_DATA_MANAGEMENT_TRAIT_DATA_CATALOG_CURRENT_H
#include <Weave/Profiles/data-management/Current/WdmManagedNamespace.h>
#include <Weave/Core/WeaveCore.h>
#include <Weave/Core/WeaveMessageLayer.h>
#include <Weave/Profiles/ProfileCommon.h>
#include <Weave/Profiles/data-management/TraitData.h>
#include <Weave/Profiles/data-management/MessageDef.h>
#include <Weave/Support/CodeUtils.h>
namespace nl {
namespace Weave {
namespace Profiles {
namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current) {
/* Unique handle to a particular trait data instance within a catalog */
typedef uint16_t TraitDataHandle;
/* A structure representing a path to a property or set of properties within a trait instance belonging to a particular resource */
struct TraitPath
{
TraitPath() { }
TraitPath(TraitDataHandle aDataHandle, PropertyPathHandle aPropertyPathHandle) : mTraitDataHandle(aDataHandle), mPropertyPathHandle(aPropertyPathHandle) { }
bool operator == (const TraitPath &rhs) const { return ((rhs.mTraitDataHandle == mTraitDataHandle) && (rhs.mPropertyPathHandle == mPropertyPathHandle)); }
bool IsValid() { return !(mPropertyPathHandle == kNullPropertyPathHandle); }
TraitDataHandle mTraitDataHandle;
PropertyPathHandle mPropertyPathHandle;
};
struct VersionedTraitPath : public TraitPath
{
VersionedTraitPath() { }
VersionedTraitPath(TraitDataHandle aDataHandle, PropertyPathHandle aPropertyPathHandle, SchemaVersionRange aRequestedVersionRange)
: TraitPath(aDataHandle, aPropertyPathHandle) { mRequestedVersionRange = aRequestedVersionRange; }
SchemaVersionRange mRequestedVersionRange;
};
/**
* Trait handle iterator
*/
typedef void (*IteratorCallback)(void *aTraitInstance, TraitDataHandle aHandle, void *aContext);
/*
* @class TraitCatalogBase
*
* @brief A catalog interface that all concrete catalogs need to adhere to.
*
*/
template <typename T>
class TraitCatalogBase
{
public:
/**
* Given a reader positioned at the Path::kCsTag_RootSection structure on a WDM path, parse that structure
* and return the matching handle to the trait.
*/
virtual WEAVE_ERROR AddressToHandle(TLV::TLVReader &aReader, TraitDataHandle &aHandle, SchemaVersionRange &aSchemaVersionRange) const = 0;
/**
* Given a trait handle, write out the TLV for the Path::kCsTag_RootSection structure.
*/
virtual WEAVE_ERROR HandleToAddress(TraitDataHandle aHandle, TLV::TLVWriter &aWriter, SchemaVersionRange &aSchemaVersionRange) const = 0;
/**
* Given a handle, return a reference to the matching trait data instance.
*/
virtual WEAVE_ERROR Locate(TraitDataHandle aHandle, T **aTraitInstance) const = 0;
/**
* Reverse
*/
virtual WEAVE_ERROR Locate(T *aTraitInstance, TraitDataHandle &aHandle) const = 0;
/**
* Dispatch an event to all trait data instance housed in this catalog.
*/
virtual WEAVE_ERROR DispatchEvent(uint16_t aEvent, void *aContext) const = 0;
virtual void Iterate(IteratorCallback aCallback, void *aContext) = 0;
};
/**
* This structure provides a way to represent the identity of a resource
* either by way of the NodeId of the device, or a UUID.
*/
struct ResourceIdentifier {
ResourceIdentifier(uint64_t aNodeId) {
mSelector = kNodeId;
mNodeId = aNodeId;
}
ResourceIdentifier(uint8_t *aUUID) {
mSelector = kUUID;
memcpy(mUUID, aUUID, 6);
}
/* Defines a special value for NodeId that refers to 'self'. In certain WDM interactions, having a value of
* self for resource allows for compressing out that information as it is redundant to the source node id of
* the device expressed in the Weave message itself
*/
static const uint64_t SELF_NODE_ID = 0;
enum { kNodeId, kUUID } mSelector;
union {
uint64_t mNodeId;
uint8_t mUUID[16];
};
};
/*
* @class SingleResourceTraitCatalog
*
* @brief A Weave provided implementation of the TraitCatalogBase interface for a collection of trait data instances
* that all refer to the same resource. It provides an array-backed, bounded storage for these instances.
*/
template <typename T>
class SingleResourceTraitCatalog : public TraitCatalogBase<T>
{
public:
struct CatalogItem {
uint64_t mInstanceId;
T *mItem;
};
/*
* Instances a trait catalog given a pointer to the underlying array store.
*/
SingleResourceTraitCatalog(ResourceIdentifier aResourceIdentifier, CatalogItem *aCatalogStore, uint32_t aNumMaxCatalogItems);
/*
* Add a new trait data instance into the catalog and return a handle to it.
*/
WEAVE_ERROR Add(uint64_t aInstanceId, T *aItem, TraitDataHandle &aHandle);
/*
* Add a new trait data instance bound to a user-selected trait handle (which in this particular implementation, denotes the offset in the array).
* The handle is to be between 0 and the size of the array. Also, the caller should ensure no gaps form after every call made to this method.
*/
WEAVE_ERROR AddAt(uint64_t aInstanceId, T *aItem, TraitDataHandle aHandle);
/**
* Removes a trait instance from the catalog.
*/
WEAVE_ERROR Remove(TraitDataHandle aHandle);
WEAVE_ERROR Locate(uint64_t aProfileId, uint64_t aInstanceId, TraitDataHandle &aHandle) const;
public: // TraitCatalogBase
WEAVE_ERROR AddressToHandle(TLV::TLVReader &aReader, TraitDataHandle &aHandle, SchemaVersionRange &aSchemaVersionRange) const;
WEAVE_ERROR HandleToAddress(TraitDataHandle aHandle, TLV::TLVWriter &aWriter, SchemaVersionRange &aSchemaVersionRange) const;
WEAVE_ERROR Locate(TraitDataHandle aHandle, T **aTraitInstance) const;
WEAVE_ERROR Locate(T *aTraitInstance, TraitDataHandle &aHandle) const;
WEAVE_ERROR DispatchEvent(uint16_t aEvent, void *aContext) const;
void Iterate(IteratorCallback aCallback, void *aContext);
private:
CatalogItem *mCatalogStore;
ResourceIdentifier mResourceId;
uint32_t mNumMaxCatalogItems;
uint32_t mNumCurCatalogItems;
};
typedef SingleResourceTraitCatalog<TraitDataSink> SingleResourceSinkTraitCatalog;
typedef SingleResourceTraitCatalog<TraitDataSource> SingleResourceSourceTraitCatalog;
template <typename T>
SingleResourceTraitCatalog<T>::SingleResourceTraitCatalog(ResourceIdentifier aResourceIdentifier, CatalogItem *aCatalogStore, uint32_t aNumMaxCatalogItems)
: mResourceId(aResourceIdentifier)
{
mCatalogStore = aCatalogStore;
mNumMaxCatalogItems = aNumMaxCatalogItems;
mNumCurCatalogItems = 0;
}
template <typename T>
WEAVE_ERROR
SingleResourceTraitCatalog<T>::Add(uint64_t aInstanceId, T *aItem, TraitDataHandle &aHandle)
{
if (mNumCurCatalogItems >= mNumMaxCatalogItems) {
return WEAVE_ERROR_NO_MEMORY;
}
mCatalogStore[mNumCurCatalogItems].mInstanceId = aInstanceId;
mCatalogStore[mNumCurCatalogItems].mItem = aItem;
aHandle = mNumCurCatalogItems++;
return WEAVE_NO_ERROR;
}
template <typename T>
WEAVE_ERROR
SingleResourceTraitCatalog<T>::AddAt(uint64_t aInstanceId, T *aItem, TraitDataHandle aHandle)
{
if (aHandle >= mNumMaxCatalogItems) {
return WEAVE_ERROR_INVALID_ARGUMENT;
}
mCatalogStore[aHandle].mInstanceId = aInstanceId;
mCatalogStore[aHandle].mItem = aItem;
mNumCurCatalogItems++;
return WEAVE_NO_ERROR;
}
template <typename T>
WEAVE_ERROR
SingleResourceTraitCatalog<T>::Remove(TraitDataHandle aHandle)
{
if (aHandle >= mNumCurCatalogItems) {
return WEAVE_ERROR_INVALID_ARGUMENT;
}
memcpy(mCatalogStore + aHandle, mCatalogStore + aHandle + 1, (mNumCurCatalogItems - 1 - aHandle) * sizeof(CatalogItem));
mNumCurCatalogItems--;
return WEAVE_NO_ERROR;
}
template <typename T>
WEAVE_ERROR
SingleResourceTraitCatalog<T>::AddressToHandle(TLV::TLVReader &aReader, TraitDataHandle &aHandle, SchemaVersionRange &aSchemaVersionRange) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
uint32_t profileId = 0;
uint64_t instanceId = 0;
Path::Parser path;
err = path.Init(aReader);
SuccessOrExit(err);
err = path.GetProfileID(&profileId, &aSchemaVersionRange);
SuccessOrExit(err);
err = path.GetInstanceID(&instanceId);
if ((WEAVE_NO_ERROR != err) && (WEAVE_END_OF_TLV != err))
{
ExitNow();
}
if (ResourceIdentifier::kNodeId == mResourceId.mSelector)
{
uint64_t resourceId;
err = path.GetResourceID(&resourceId);
if ((WEAVE_NO_ERROR != err) && (WEAVE_END_OF_TLV != err))
{
ExitNow();
}
}
path.GetTags(&aReader);
VerifyOrExit(profileId != 0, err = WEAVE_ERROR_TLV_TAG_NOT_FOUND);
err = Locate(profileId, instanceId, aHandle);
SuccessOrExit(err);
exit:
return err;
}
template <typename T>
WEAVE_ERROR
SingleResourceTraitCatalog<T>::Locate(uint64_t aProfileId, uint64_t aInstanceId, TraitDataHandle &aHandle) const
{
for (uint32_t i = 0; i < mNumCurCatalogItems; i++) {
if ((mCatalogStore[i].mItem->GetSchemaEngine()->GetProfileId() == aProfileId) && (mCatalogStore[i].mInstanceId == aInstanceId)) {
aHandle = i;
return WEAVE_NO_ERROR;
}
}
return WEAVE_ERROR_INVALID_PROFILE_ID;
}
template <typename T>
WEAVE_ERROR
SingleResourceTraitCatalog<T>::HandleToAddress(TraitDataHandle aHandle, TLV::TLVWriter &aWriter, SchemaVersionRange &aSchemaVersionRange) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
CatalogItem *item;
TLV::TLVType type;
VerifyOrExit(aHandle < mNumCurCatalogItems, err = WEAVE_ERROR_INVALID_ARGUMENT);
item = &mCatalogStore[aHandle];
VerifyOrExit(aSchemaVersionRange.IsValid(), err = WEAVE_ERROR_INVALID_ARGUMENT);
err = aWriter.StartContainer(TLV::ContextTag(Path::kCsTag_InstanceLocator), TLV::kTLVType_Structure, type);
SuccessOrExit(err);
if (aSchemaVersionRange.mMinVersion != 1 || aSchemaVersionRange.mMaxVersion != 1) {
TLV::TLVType type2;
err = aWriter.StartContainer(TLV::ContextTag(Path::kCsTag_TraitProfileID), TLV::kTLVType_Array, type2);
SuccessOrExit(err);
err = aWriter.Put(TLV::AnonymousTag, item->mItem->GetSchemaEngine()->GetProfileId());
SuccessOrExit(err);
// Only encode the max version if it isn't 1.
if (aSchemaVersionRange.mMaxVersion != 1) {
err = aWriter.Put(TLV::AnonymousTag, aSchemaVersionRange.mMaxVersion);
SuccessOrExit(err);
}
// Only encode the min version if it isn't 1.
if (aSchemaVersionRange.mMinVersion != 1) {
err = aWriter.Put(TLV::AnonymousTag, aSchemaVersionRange.mMinVersion);
SuccessOrExit(err);
}
err = aWriter.EndContainer(type2);
SuccessOrExit(err);
}
else {
err = aWriter.Put(TLV::ContextTag(Path::kCsTag_TraitProfileID), item->mItem->GetSchemaEngine()->GetProfileId());
SuccessOrExit(err);
}
if (item->mInstanceId) {
err = aWriter.Put(TLV::ContextTag(Path::kCsTag_TraitInstanceID), item->mInstanceId);
SuccessOrExit(err);
}
if (mResourceId.mSelector == ResourceIdentifier::kNodeId && mResourceId.mNodeId != ResourceIdentifier::SELF_NODE_ID) {
err = aWriter.Put(TLV::ContextTag(Path::kCsTag_ResourceID), mResourceId.mNodeId);
SuccessOrExit(err);
}
else if (mResourceId.mSelector == ResourceIdentifier::kUUID) {
err = aWriter.PutBytes(TLV::ContextTag(Path::kCsTag_ResourceID), mResourceId.mUUID, sizeof(mResourceId.mUUID));
SuccessOrExit(err);
}
err = aWriter.EndContainer(type);
SuccessOrExit(err);
exit:
return err;
}
template <typename T>
WEAVE_ERROR
SingleResourceTraitCatalog<T>::Locate(TraitDataHandle aHandle, T **aTraitInstance) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
VerifyOrExit(aHandle < mNumCurCatalogItems, err = WEAVE_ERROR_INVALID_ARGUMENT);
*aTraitInstance = mCatalogStore[aHandle].mItem;
exit:
return err;
}
template <typename T>
WEAVE_ERROR
SingleResourceTraitCatalog<T>::Locate(T *aTraitInstance, TraitDataHandle &aHandle) const
{
for (uint32_t i = 0; i < mNumCurCatalogItems; i++) {
if (mCatalogStore[i].mItem == aTraitInstance) {
aHandle = i;
return WEAVE_NO_ERROR;
}
}
return WEAVE_ERROR_KEY_NOT_FOUND;
}
template <typename T>
void
SingleResourceTraitCatalog<T>::Iterate(IteratorCallback aCallback, void *aContext)
{
for (uint32_t i = 0; i < mNumCurCatalogItems; i++) {
aCallback(mCatalogStore[i].mItem, i, aContext);
}
}
template <typename T>
WEAVE_ERROR
SingleResourceTraitCatalog<T>::DispatchEvent(uint16_t aEvent, void *aContext) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
for (uint32_t i = 0; i < mNumCurCatalogItems; i++) {
mCatalogStore[i].mItem->OnEvent(aEvent, aContext);
}
return err;
}
}; // WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current)
}; // Profiles
}; // Weave
}; // nl
#endif // _WEAVE_DATA_MANAGEMENT_TRAIT_DATA_CATALOG_CURRENT_H