blob: 9b2b23e4578951e3f566e8ff2ef03704a97529b8 [file] [log] [blame]
/*
*
* Copyright (c) 2019 Google, LLC.
* 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 generic trait 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_GENERIC_TRAIT_CATALOG_IMP_H
#define _WEAVE_DATA_MANAGEMENT_GENERIC_TRAIT_CATALOG_IMP_H
#include <map>
#include <limits>
#include <Weave/Profiles/data-management/Current/WdmManagedNamespace.h>
#include <Weave/Profiles/data-management/TraitCatalog.h>
namespace nl {
namespace Weave {
namespace Profiles {
namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current) {
/*
* @class GenericTraitCatalogImpl
*
* @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 a map-backed storage for these instances.
*/
template <typename T>
class GenericTraitCatalogImpl : public TraitCatalogBase<T>
{
public:
GenericTraitCatalogImpl(void);
virtual ~GenericTraitCatalogImpl(void);
WEAVE_ERROR Add(const ResourceIdentifier & aResourceId, const uint64_t & aInstanceId, PropertyPathHandle basePathHandle, T * traitInstance, TraitDataHandle & aHandle);
WEAVE_ERROR Remove(T * traitInstance);
WEAVE_ERROR Remove(TraitDataHandle aHandle);
WEAVE_ERROR PrepareSubscriptionPathList(TraitPath * pathList, uint16_t pathListSize, uint16_t & pathListLen, TraitDataHandle aHandle, bool aNeedSubscribeAll);
WEAVE_ERROR Clear(void);
virtual WEAVE_ERROR AddressToHandle(TLV::TLVReader & aReader, TraitDataHandle & aHandle,
SchemaVersionRange & aSchemaVersionRange) const;
virtual WEAVE_ERROR HandleToAddress(TraitDataHandle aHandle, TLV::TLVWriter & aWriter,
SchemaVersionRange & aSchemaVersionRange) const;
virtual WEAVE_ERROR Locate(TraitDataHandle aHandle, T ** aTraitInstance) const;
virtual WEAVE_ERROR Locate(T * aTraitInstance, TraitDataHandle & aHandle) const;
WEAVE_ERROR Locate (uint32_t aProfileId,
uint64_t aInstanceId,
ResourceIdentifier aResourceId,
TraitDataHandle &aHandle) const;
WEAVE_ERROR Locate (uint32_t aProfileId,
uint64_t aInstanceId,
ResourceIdentifier aResourceId,
T ** aTraitInstance) const;
virtual WEAVE_ERROR DispatchEvent(uint16_t aEvent, void * aContext) const;
virtual void Iterate(IteratorCallback aCallback, void * aContext);
#if WEAVE_CONFIG_ENABLE_WDM_UPDATE
virtual WEAVE_ERROR GetInstanceId(TraitDataHandle aHandle, uint64_t &aInstanceId) const;
virtual WEAVE_ERROR GetResourceId(TraitDataHandle aHandle, ResourceIdentifier &aResourceId) const;
#endif // WEAVE_CONFIG_ENABLE_WDM_UPDATE
/**
* Return the number of trait instances in the catalog.
*/
uint32_t Count(void) const;
private:
struct CatalogItem
{
uint32_t mProfileId;
uint64_t mInstanceId;
ResourceIdentifier mResourceId;
T *mItem;
PropertyPathHandle mBasePathHandle;
};
TraitDataHandle mNextHandle;
typedef std::map<TraitDataHandle, CatalogItem*> Handle2ItemMap_t;
Handle2ItemMap_t mItemStore;
};
typedef GenericTraitCatalogImpl<TraitDataSink> GenericTraitSinkCatalog;
typedef GenericTraitCatalogImpl<TraitDataSource> GenericTraitSourceCatalog;
template <typename T>
GenericTraitCatalogImpl<T>::GenericTraitCatalogImpl(void)
: mNextHandle(0)
{
// Nothing to do.
}
template <typename T>
GenericTraitCatalogImpl<T>::~GenericTraitCatalogImpl(void)
{
Clear();
}
template <typename T>
WEAVE_ERROR GenericTraitCatalogImpl<T>::Add(const ResourceIdentifier & aResourceId, const uint64_t & aInstanceId,
PropertyPathHandle basePathHandle, T * traitInstance, TraitDataHandle & aHandle)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
CatalogItem *item = NULL;
TraitDataHandle handle;
typename Handle2ItemMap_t::iterator it;
// Make sure there is space
VerifyOrExit(mItemStore.size() < std::numeric_limits<TraitDataHandle>::max(),
err = WEAVE_ERROR_NO_MEMORY);
// Create the CatalogItem
item = new CatalogItem();
VerifyOrExit(item != NULL, err = WEAVE_ERROR_NO_MEMORY);
item->mProfileId = traitInstance->GetSchemaEngine()->GetProfileId();
item->mInstanceId = aInstanceId;
item->mResourceId = aResourceId;
item->mItem = traitInstance;
item->mBasePathHandle = basePathHandle;
// Stop if this path already exists
err = Locate(item->mProfileId, item->mInstanceId, item->mResourceId, handle);
VerifyOrExit(err != WEAVE_NO_ERROR, err = WEAVE_ERROR_DUPLICATE_KEY_ID);
do {
// Assign a new handle
aHandle = mNextHandle++;
// Make sure it's available as mNextHandle may have wrapped
it = mItemStore.find(aHandle);
} while (it != mItemStore.end());
// Store the item
mItemStore[aHandle] = item;
err = WEAVE_NO_ERROR;
exit:
if (err != WEAVE_NO_ERROR && item != NULL)
{
delete item;
}
return err;
}
template <typename T>
WEAVE_ERROR GenericTraitCatalogImpl<T>::Remove(T * traitInstance)
{
WEAVE_ERROR err = WEAVE_ERROR_INVALID_ARGUMENT;
typename Handle2ItemMap_t::const_iterator it;
// Loop through the items and delete the items
for (it = mItemStore.begin(); it != mItemStore.end(); it++)
{
CatalogItem *item = it->second;
if (item && item->mItem == traitInstance)
{
delete item;
err = WEAVE_NO_ERROR;
}
}
return err;
}
template <typename T>
WEAVE_ERROR GenericTraitCatalogImpl<T>::Remove(TraitDataHandle aHandle)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
typename Handle2ItemMap_t::iterator it;
CatalogItem *item = NULL;
// Make sure the handle exists
it = mItemStore.find(aHandle);
VerifyOrExit(it != mItemStore.end(), err = WEAVE_ERROR_INVALID_ARGUMENT);
// Remove the item and delete it
item = it->second;
mItemStore.erase(it);
delete item;
exit:
return err;
}
template <typename T>
WEAVE_ERROR
GenericTraitCatalogImpl<T>::Clear(void)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
typename Handle2ItemMap_t::iterator it;
CatalogItem *item = NULL;
// Loop through the items and remove them all
it = mItemStore.begin();
while (it != mItemStore.end())
{
item = it->second;
delete item;
it ++;
}
mItemStore.clear();
return err;
}
template <typename T>
WEAVE_ERROR
GenericTraitCatalogImpl<T>::AddressToHandle (TLV::TLVReader &aReader,
TraitDataHandle &aHandle,
SchemaVersionRange &aSchemaVersionRange) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
uint32_t profileId = 0;
uint64_t instanceId = 0;
ResourceIdentifier resourceId;
Path::Parser path;
TLV::TLVReader reader;
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();
}
err = path.GetResourceID(&reader);
if (err == WEAVE_NO_ERROR)
{
err = resourceId.FromTLV(reader);
SuccessOrExit(err);
}
else if (err == WEAVE_END_OF_TLV)
{
resourceId = ResourceIdentifier(ResourceIdentifier::RESOURCE_TYPE_RESERVED,
ResourceIdentifier::SELF_NODE_ID);
}
else if (WEAVE_NO_ERROR != err)
{
ExitNow();
}
path.GetTags(&aReader);
VerifyOrExit(profileId != 0, err = WEAVE_ERROR_TLV_TAG_NOT_FOUND);
err = Locate(profileId, instanceId, resourceId, aHandle);
SuccessOrExit(err);
exit:
return err;
}
template <typename T>
WEAVE_ERROR
GenericTraitCatalogImpl<T>::HandleToAddress (TraitDataHandle aHandle,
TLV::TLVWriter &aWriter,
SchemaVersionRange &aSchemaVersionRange) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLV::TLVType type;
typename Handle2ItemMap_t::const_iterator it;
CatalogItem *item = NULL;
// Make sure the handle exists
it = mItemStore.find(aHandle);
VerifyOrExit(it != mItemStore.end(), err = WEAVE_ERROR_INVALID_ARGUMENT);
VerifyOrExit(aSchemaVersionRange.IsValid(), err = WEAVE_ERROR_INVALID_ARGUMENT);
item = it->second;
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);
}
err = item->mResourceId.ToTLV(aWriter);
SuccessOrExit(err);
err = aWriter.EndContainer(type);
SuccessOrExit(err);
exit:
return err;
}
template <typename T>
WEAVE_ERROR
GenericTraitCatalogImpl<T>::Locate (TraitDataHandle aHandle, T **aTraitInstance) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
typename Handle2ItemMap_t::const_iterator it;
// Make sure the handle exists
it = mItemStore.find(aHandle);
VerifyOrExit(it != mItemStore.end(), err = WEAVE_ERROR_INVALID_ARGUMENT);
// Return the trait instance
*aTraitInstance = it->second->mItem;
exit:
return err;
}
template <typename T>
WEAVE_ERROR
GenericTraitCatalogImpl<T>::Locate (T *aTraitInstance,
TraitDataHandle &aHandle) const
{
WEAVE_ERROR err = WEAVE_ERROR_INVALID_ARGUMENT;
typename Handle2ItemMap_t::const_iterator it;
// Iterate and find this trait instance
for (it = mItemStore.begin(); it != mItemStore.end(); it++)
{
if (aTraitInstance == it->second->mItem)
{
aHandle = it->first;
err = WEAVE_NO_ERROR;
break;
}
}
return err;
}
template <typename T>
WEAVE_ERROR
GenericTraitCatalogImpl<T>::Locate (uint32_t aProfileId,
uint64_t aInstanceId,
ResourceIdentifier aResourceId,
TraitDataHandle &aHandle) const
{
WEAVE_ERROR err = WEAVE_ERROR_INVALID_PROFILE_ID;
typename Handle2ItemMap_t::const_iterator it;
// Loop through the items and check if the path matches
for (it = mItemStore.begin(); it != mItemStore.end(); it++)
{
CatalogItem *item = it->second;
if (item->mProfileId == aProfileId &&
item->mResourceId == aResourceId &&
item->mInstanceId == aInstanceId)
{
err = WEAVE_NO_ERROR;
aHandle = it->first;
}
}
return err;
}
template <typename T>
WEAVE_ERROR
GenericTraitCatalogImpl<T>::Locate (uint32_t aProfileId,
uint64_t aInstanceId,
ResourceIdentifier aResourceId,
T **aTraitInstance) const
{
WEAVE_ERROR err = WEAVE_ERROR_INVALID_PROFILE_ID;
typename Handle2ItemMap_t::const_iterator it;
// Loop through the items and check if the path matches
for (it = mItemStore.begin(); it != mItemStore.end(); it++)
{
CatalogItem *item = it->second;
if (item->mProfileId == aProfileId &&
item->mResourceId == aResourceId &&
item->mInstanceId == aInstanceId)
{
err = WEAVE_NO_ERROR;
*aTraitInstance = it->second->mItem;
}
}
return err;
}
template <typename T>
WEAVE_ERROR
GenericTraitCatalogImpl<T>::DispatchEvent (uint16_t aEvent, void *aContext) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
typename Handle2ItemMap_t::const_iterator it;
// Send the event to all the items
for (it = mItemStore.begin(); it != mItemStore.end(); it++)
{
CatalogItem *item = it->second;
item->mItem->OnEvent(aEvent, aContext);
}
return err;
}
template <typename T>
void
GenericTraitCatalogImpl<T>::Iterate (IteratorCallback aCallback, void *aContext)
{
typename Handle2ItemMap_t::const_iterator it;
// Send the event to all the items
for (it = mItemStore.begin(); it != mItemStore.end(); it++)
{
aCallback(it->second->mItem, it->first, aContext);
}
}
#if WEAVE_CONFIG_ENABLE_WDM_UPDATE
template <typename T>
WEAVE_ERROR GenericTraitCatalogImpl<T>::GetInstanceId (TraitDataHandle aHandle, uint64_t &aInstanceId) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
typename Handle2ItemMap_t::const_iterator it;
// Make sure the handle exists
it = mItemStore.find(aHandle);
VerifyOrExit(it != mItemStore.end(), err = WEAVE_ERROR_INVALID_ARGUMENT);
// Return the trait mInstanceId
aInstanceId = it->second->mInstanceId;
exit:
return err;
}
template <typename T>
WEAVE_ERROR GenericTraitCatalogImpl<T>::GetResourceId (TraitDataHandle aHandle, ResourceIdentifier &aResourceId) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
typename Handle2ItemMap_t::const_iterator it;
// Make sure the handle exists
it = mItemStore.find(aHandle);
VerifyOrExit(it != mItemStore.end(), err = WEAVE_ERROR_INVALID_ARGUMENT);
// Return the trait mResourceId
aResourceId = it->second->mResourceId;
exit:
return err;
}
#endif // WEAVE_CONFIG_ENABLE_WDM_UPDATE
template <typename T>
uint32_t GenericTraitCatalogImpl<T>::Count(void) const
{
uint32_t count = 0;
typename Handle2ItemMap_t::const_iterator it;
for (it = mItemStore.begin(); it != mItemStore.end(); it++)
{
CatalogItem *item = it->second;
if (item->mItem != NULL)
{
count++;
}
}
return count;
}
template <typename T>
WEAVE_ERROR GenericTraitCatalogImpl<T>::PrepareSubscriptionPathList(TraitPath * pathList, uint16_t pathListSize, uint16_t & pathListLen, TraitDataHandle aHandle, bool aNeedSubscribeAll)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
typename Handle2ItemMap_t::const_iterator it;
pathListLen = 0;
for (it = mItemStore.begin(); it != mItemStore.end(); it++)
{
CatalogItem *item = it->second;
if (item->mItem != NULL)
{
VerifyOrExit(pathListLen < pathListSize, err = WEAVE_ERROR_BUFFER_TOO_SMALL);
if (aNeedSubscribeAll)
{
*pathList++ = TraitPath(it->first, item->mBasePathHandle);
pathListLen++;
}
else
{
if (it->first == aHandle)
{
pathList[0] = TraitPath(it->first, item->mBasePathHandle);
pathListLen = 1;
err = WEAVE_NO_ERROR;
break;
}
else
{
err = WEAVE_ERROR_INVALID_ARGUMENT;
}
}
}
}
exit:
return err;
}
}; // namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current)
}; // namespace Profiles
}; // namespace Weave
}; // namespace nl
#endif // _WEAVE_DATA_MANAGEMENT_GENERIC_TRAIT_CATALOG_IMP_H