diff options
Diffstat (limited to 'upstream/parameter/ConfigurableElement.cpp')
| -rw-r--r-- | upstream/parameter/ConfigurableElement.cpp | 652 |
1 files changed, 652 insertions, 0 deletions
diff --git a/upstream/parameter/ConfigurableElement.cpp b/upstream/parameter/ConfigurableElement.cpp new file mode 100644 index 0000000..615d72b --- /dev/null +++ b/upstream/parameter/ConfigurableElement.cpp @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2011-2015, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "ConfigurableElement.h" +#include "MappingData.h" +#include "SyncerSet.h" +#include "ConfigurableDomain.h" +#include "ConfigurationAccessContext.h" +#include "ConfigurableElementAggregator.h" +#include "AreaConfiguration.h" +#include "Iterator.hpp" +#include "Utility.h" +#include "XmlParameterSerializingContext.h" +#include <assert.h> + +#define base CElement + +CConfigurableElement::CConfigurableElement(const std::string &strName) : base(strName) +{ +} + +bool CConfigurableElement::fromXml(const CXmlElement &xmlElement, + CXmlSerializingContext &serializingContext) +{ + auto &context = static_cast<CXmlParameterSerializingContext &>(serializingContext); + auto &accessContext = context.getAccessContext(); + + if (accessContext.serializeSettings()) { + // As serialization and deserialisation are handled through the *same* function + // the (de)serialize object can not be const in `serializeXmlSettings` signature. + // As a result a const_cast is unavoidable :(. + // Fixme: split serializeXmlSettings in two functions (in and out) to avoid the `const_cast` + return serializeXmlSettings(const_cast<CXmlElement &>(xmlElement), + static_cast<CConfigurationAccessContext &>(accessContext)); + } + return structureFromXml(xmlElement, serializingContext); +} + +void CConfigurableElement::toXml(CXmlElement &xmlElement, + CXmlSerializingContext &serializingContext) const +{ + auto &context = static_cast<CXmlParameterSerializingContext &>(serializingContext); + auto &accessContext = context.getAccessContext(); + if (accessContext.serializeSettings()) { + + serializeXmlSettings(xmlElement, static_cast<CConfigurationAccessContext &>(accessContext)); + } else { + + structureToXml(xmlElement, serializingContext); + } +} + +// XML configuration settings parsing +bool CConfigurableElement::serializeXmlSettings( + CXmlElement &xmlConfigurationSettingsElementContent, + CConfigurationAccessContext &configurationAccessContext) const +{ + size_t uiNbChildren = getNbChildren(); + + if (!configurationAccessContext.serializeOut()) { + // Just do basic checks and propagate to children + CXmlElement::CChildIterator it(xmlConfigurationSettingsElementContent); + + CXmlElement xmlChildConfigurableElementSettingsElement; + + // Propagate to children + for (size_t index = 0; index < uiNbChildren; index++) { + + // Get child + const CConfigurableElement *pChildConfigurableElement = + static_cast<const CConfigurableElement *>(getChild(index)); + + if (!it.next(xmlChildConfigurableElementSettingsElement)) { + + // Structure error + configurationAccessContext.setError( + "Configuration settings parsing: missing child node " + + pChildConfigurableElement->getXmlElementName() + " (name:" + + pChildConfigurableElement->getName() + ") in " + getName()); + + return false; + } + + // Check element type matches in type + if (xmlChildConfigurableElementSettingsElement.getType() != + pChildConfigurableElement->getXmlElementName()) { + + // "Component" tag has been renamed to "ParameterBlock", but retro-compatibility + // shall be ensured. + // + // So checking if this case occurs, i.e. element name is "ParameterBlock" + // but xml setting name is "Component". + bool compatibilityCase = + (pChildConfigurableElement->getXmlElementName() == "ParameterBlock") && + (xmlChildConfigurableElementSettingsElement.getType() == "Component"); + + // Error if the compatibility case does not occur. + if (!compatibilityCase) { + + // Type error + configurationAccessContext.setError( + "Configuration settings parsing: Settings " + "for configurable element " + + pChildConfigurableElement->getQualifiedPath() + + " does not match expected type: " + + xmlChildConfigurableElementSettingsElement.getType() + " instead of " + + pChildConfigurableElement->getKind()); + return false; + } + } + + // Check element type matches in name + if (xmlChildConfigurableElementSettingsElement.getNameAttribute() != + pChildConfigurableElement->getName()) { + + // Name error + configurationAccessContext.setError( + "Configuration settings parsing: Under configurable element " + + getQualifiedPath() + ", expected element name " + + pChildConfigurableElement->getName() + " but found " + + xmlChildConfigurableElementSettingsElement.getNameAttribute() + " instead"); + + return false; + } + + // Parse child configurable element's settings + if (!pChildConfigurableElement->serializeXmlSettings( + xmlChildConfigurableElementSettingsElement, configurationAccessContext)) { + + return false; + } + } + // There should remain no configurable element to parse + if (it.next(xmlChildConfigurableElementSettingsElement)) { + + // Structure error + configurationAccessContext.setError( + "Configuration settings parsing: Unexpected xml element node " + + xmlChildConfigurableElementSettingsElement.getType() + " in " + getQualifiedPath()); + + return false; + } + } else { + // Handle element name attribute + xmlConfigurationSettingsElementContent.setNameAttribute(getName()); + + // Propagate to children + for (size_t index = 0; index < uiNbChildren; index++) { + + const CConfigurableElement *pChildConfigurableElement = + static_cast<const CConfigurableElement *>(getChild(index)); + + // Create corresponding child element + CXmlElement xmlChildConfigurableElementSettingsElement; + + xmlConfigurationSettingsElementContent.createChild( + xmlChildConfigurableElementSettingsElement, + pChildConfigurableElement->getXmlElementName()); + + // Propagate + pChildConfigurableElement->serializeXmlSettings( + xmlChildConfigurableElementSettingsElement, configurationAccessContext); + } + } + // Done + return true; +} + +// AreaConfiguration creation +CAreaConfiguration *CConfigurableElement::createAreaConfiguration( + const CSyncerSet *pSyncerSet) const +{ + return new CAreaConfiguration(this, pSyncerSet); +} + +// Parameter access +bool CConfigurableElement::accessValue(CPathNavigator &pathNavigator, std::string &strValue, + bool bSet, + CParameterAccessContext ¶meterAccessContext) const +{ + std::string *pStrChildName = pathNavigator.next(); + + if (!pStrChildName) { + + parameterAccessContext.setError((bSet ? "Can't set " : "Can't get ") + + pathNavigator.getCurrentPath() + + " because it is not a parameter"); + + return false; + } + + const CConfigurableElement *pChild = + static_cast<const CConfigurableElement *>(findChild(*pStrChildName)); + + if (!pChild) { + + parameterAccessContext.setError("Path not found: " + pathNavigator.getCurrentPath()); + + return false; + } + + return pChild->accessValue(pathNavigator, strValue, bSet, parameterAccessContext); +} + +// Whole element access +void CConfigurableElement::getSettingsAsBytes(std::vector<uint8_t> &bytes, + CParameterAccessContext ¶meterAccessContext) const +{ + bytes.resize(getFootPrint()); + + parameterAccessContext.getParameterBlackboard()->readBytes( + bytes, getOffset() - parameterAccessContext.getBaseOffset()); +} + +bool CConfigurableElement::setSettingsAsBytes(const std::vector<uint8_t> &bytes, + CParameterAccessContext ¶meterAccessContext) const +{ + CParameterBlackboard *pParameterBlackboard = parameterAccessContext.getParameterBlackboard(); + + // Size + size_t size = getFootPrint(); + + // Check sizes match + if (size != bytes.size()) { + + parameterAccessContext.setError(std::string("Wrong size: Expected: ") + + std::to_string(size) + " Provided: " + + std::to_string(bytes.size())); + + return false; + } + + // Write bytes + pParameterBlackboard->writeBytes(bytes, getOffset() - parameterAccessContext.getBaseOffset()); + + if (not parameterAccessContext.getAutoSync()) { + // Auto sync is not activated, sync will be defered until an explicit request + return true; + } + + CSyncerSet syncerSet; + fillSyncerSet(syncerSet); + core::Results res; + if (not syncerSet.sync(*parameterAccessContext.getParameterBlackboard(), false, &res)) { + + parameterAccessContext.setError(utility::asString(res)); + return false; + } + return true; +} + +std::list<const CConfigurableElement *> CConfigurableElement::getConfigurableElementContext() const +{ + std::list<const CConfigurableElement *> configurableElementPath; + + const CElement *element = this; + while (element != nullptr and isOfConfigurableElementType(element)) { + auto configurableElement = static_cast<const CConfigurableElement *>(element); + + configurableElementPath.push_back(configurableElement); + element = element->getParent(); + } + + return configurableElementPath; +} + +// Used for simulation and virtual subsystems +void CConfigurableElement::setDefaultValues(CParameterAccessContext ¶meterAccessContext) const +{ + // Propagate to children + size_t uiNbChildren = getNbChildren(); + + for (size_t index = 0; index < uiNbChildren; index++) { + + const CConfigurableElement *pConfigurableElement = + static_cast<const CConfigurableElement *>(getChild(index)); + + pConfigurableElement->setDefaultValues(parameterAccessContext); + } +} + +// Element properties +void CConfigurableElement::showProperties(std::string &strResult) const +{ + base::showProperties(strResult); + + strResult += "Total size: " + getFootprintAsString() + "\n"; +} + +std::string CConfigurableElement::logValue(utility::ErrorContext &context) const +{ + return logValue(static_cast<CParameterAccessContext &>(context)); +} + +std::string CConfigurableElement::logValue(CParameterAccessContext & /*ctx*/) const +{ + // By default, an element does not have a value. Only leaf elements have + // one. This method could be pure virtual but then, several derived classes + // would need to implement it in order to simply return an empty string. + return ""; +} + +// Offset +void CConfigurableElement::setOffset(size_t offset) +{ + // Assign offset locally + _offset = offset; + + // Propagate to children + size_t uiNbChildren = getNbChildren(); + + for (size_t index = 0; index < uiNbChildren; index++) { + + CConfigurableElement *pConfigurableElement = + static_cast<CConfigurableElement *>(getChild(index)); + + pConfigurableElement->setOffset(offset); + + offset += pConfigurableElement->getFootPrint(); + } +} + +size_t CConfigurableElement::getOffset() const +{ + return _offset; +} + +// Memory +size_t CConfigurableElement::getFootPrint() const +{ + size_t uiSize = 0; + size_t uiNbChildren = getNbChildren(); + + for (size_t index = 0; index < uiNbChildren; index++) { + + const CConfigurableElement *pConfigurableElement = + static_cast<const CConfigurableElement *>(getChild(index)); + + uiSize += pConfigurableElement->getFootPrint(); + } + + return uiSize; +} + +// Browse parent path to find syncer +ISyncer *CConfigurableElement::getSyncer() const +{ + // Check parent + const CElement *pParent = getParent(); + + if (isOfConfigurableElementType(pParent)) { + + return static_cast<const CConfigurableElement *>(pParent)->getSyncer(); + } + return NULL; +} + +// Syncer set (me, ascendant or descendant ones) +void CConfigurableElement::fillSyncerSet(CSyncerSet &syncerSet) const +{ + // Try me or ascendants + ISyncer *pMineOrAscendantSyncer = getSyncer(); + + if (pMineOrAscendantSyncer) { + + // Provide found syncer object + syncerSet += pMineOrAscendantSyncer; + + // Done + return; + } + // Fetch descendant ones + fillSyncerSetFromDescendant(syncerSet); +} + +// Syncer set (descendant) +void CConfigurableElement::fillSyncerSetFromDescendant(CSyncerSet &syncerSet) const +{ + // Dig + size_t uiNbChildren = getNbChildren(); + + for (size_t index = 0; index < uiNbChildren; index++) { + + const CConfigurableElement *pConfigurableElement = + static_cast<const CConfigurableElement *>(getChild(index)); + + pConfigurableElement->fillSyncerSetFromDescendant(syncerSet); + } +} + +// Configurable domain association +void CConfigurableElement::addAttachedConfigurableDomain( + const CConfigurableDomain *pConfigurableDomain) +{ + _configurableDomainList.push_back(pConfigurableDomain); +} + +void CConfigurableElement::removeAttachedConfigurableDomain( + const CConfigurableDomain *pConfigurableDomain) +{ + _configurableDomainList.remove(pConfigurableDomain); +} + +// Belonging domain +bool CConfigurableElement::belongsTo(const CConfigurableDomain *pConfigurableDomain) const +{ + if (containsConfigurableDomain(pConfigurableDomain)) { + + return true; + } + return belongsToDomainAscending(pConfigurableDomain); +} + +// Belonging domains +void CConfigurableElement::getBelongingDomains( + std::list<const CConfigurableDomain *> &configurableDomainList) const +{ + configurableDomainList.insert(configurableDomainList.end(), _configurableDomainList.begin(), + _configurableDomainList.end()); + + // Check parent + const CElement *pParent = getParent(); + + if (isOfConfigurableElementType(pParent)) { + + static_cast<const CConfigurableElement *>(pParent)->getBelongingDomains( + configurableDomainList); + } +} + +void CConfigurableElement::listBelongingDomains(std::string &strResult, bool bVertical) const +{ + // Get belonging domain list + std::list<const CConfigurableDomain *> configurableDomainList; + + getBelongingDomains(configurableDomainList); + + // Fill list + listDomains(configurableDomainList, strResult, bVertical); +} + +// Elements with no domains +void CConfigurableElement::listRogueElements(std::string &strResult) const +{ + // Get rogue element aggregate list (no associated domain) + std::list<const CConfigurableElement *> rogueElementList; + + CConfigurableElementAggregator configurableElementAggregator( + rogueElementList, &CConfigurableElement::hasNoDomainAssociated); + + configurableElementAggregator.aggegate(this); + + // Build list as std::string + std::list<const CConfigurableElement *>::const_iterator it; + + for (it = rogueElementList.begin(); it != rogueElementList.end(); ++it) { + + const CConfigurableElement *pConfigurableElement = *it; + + strResult += pConfigurableElement->getPath() + "\n"; + } +} + +bool CConfigurableElement::isRogue() const +{ + // Check not belonging to any domin from current level and towards ascendents + if (getBelongingDomainCount() != 0) { + + return false; + } + + // Get a list of elements (current + descendants) with no domains associated + std::list<const CConfigurableElement *> rogueElementList; + + CConfigurableElementAggregator agregator(rogueElementList, + &CConfigurableElement::hasNoDomainAssociated); + + agregator.aggegate(this); + + // Check only one element found which ought to be current one + return (rogueElementList.size() == 1) && (rogueElementList.front() == this); +} + +// Footprint as string +std::string CConfigurableElement::getFootprintAsString() const +{ + // Get size as string + return std::to_string(getFootPrint()) + " byte(s)"; +} + +// Matching check for no domain association +bool CConfigurableElement::hasNoDomainAssociated() const +{ + return _configurableDomainList.empty(); +} + +// Matching check for no valid associated domains +bool CConfigurableElement::hasNoValidDomainAssociated() const +{ + if (_configurableDomainList.empty()) { + + // No domains associated + return true; + } + + ConfigurableDomainListConstIterator it; + + // Browse all configurable domains for validity checking + for (it = _configurableDomainList.begin(); it != _configurableDomainList.end(); ++it) { + + const CConfigurableDomain *pConfigurableDomain = *it; + + if (pConfigurableDomain->isApplicableConfigurationValid(this)) { + + return false; + } + } + + return true; +} + +// Owning domains +void CConfigurableElement::listAssociatedDomains(std::string &strResult, bool bVertical) const +{ + // Fill list + listDomains(_configurableDomainList, strResult, bVertical); +} + +size_t CConfigurableElement::getBelongingDomainCount() const +{ + // Get belonging domain list + std::list<const CConfigurableDomain *> configurableDomainList; + + getBelongingDomains(configurableDomainList); + + return configurableDomainList.size(); +} + +void CConfigurableElement::listDomains( + const std::list<const CConfigurableDomain *> &configurableDomainList, std::string &strResult, + bool bVertical) const +{ + // Fill list + ConfigurableDomainListConstIterator it; + bool bFirst = true; + + // Browse all configurable domains for comparison + for (it = configurableDomainList.begin(); it != configurableDomainList.end(); ++it) { + + const CConfigurableDomain *pConfigurableDomain = *it; + + if (!bVertical && !bFirst) { + + strResult += ", "; + } + + strResult += pConfigurableDomain->getName(); + + if (bVertical) { + + strResult += "\n"; + } else { + + bFirst = false; + } + } +} + +bool CConfigurableElement::containsConfigurableDomain( + const CConfigurableDomain *pConfigurableDomain) const +{ + ConfigurableDomainListConstIterator it; + + // Browse all configurable domains for comparison + for (it = _configurableDomainList.begin(); it != _configurableDomainList.end(); ++it) { + + if (pConfigurableDomain == *it) { + + return true; + } + } + return false; +} + +// Belonging domain ascending search +bool CConfigurableElement::belongsToDomainAscending( + const CConfigurableDomain *pConfigurableDomain) const +{ + // Check parent + const CElement *pParent = getParent(); + + if (isOfConfigurableElementType(pParent)) { + + return static_cast<const CConfigurableElement *>(pParent)->belongsTo(pConfigurableDomain); + } + return false; +} + +// Belonging subsystem +const CSubsystem *CConfigurableElement::getBelongingSubsystem() const +{ + const CElement *pParent = getParent(); + + // Stop at system class + if (!pParent->getParent()) { + + return NULL; + } + + return static_cast<const CConfigurableElement *>(pParent)->getBelongingSubsystem(); +} + +// Check element is a parameter +bool CConfigurableElement::isParameter() const +{ + return false; +} + +// Check parent is still of current type (by structure knowledge) +bool CConfigurableElement::isOfConfigurableElementType(const CElement *pParent) const +{ + assert(pParent); + + // Up to system class + return !!pParent->getParent(); +} |
