Home | History | Annotate | Download | only in parameter
      1 /*
      2  * Copyright (c) 2011-2015, Intel Corporation
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without modification,
      6  * are permitted provided that the following conditions are met:
      7  *
      8  * 1. Redistributions of source code must retain the above copyright notice, this
      9  * list of conditions and the following disclaimer.
     10  *
     11  * 2. Redistributions in binary form must reproduce the above copyright notice,
     12  * this list of conditions and the following disclaimer in the documentation and/or
     13  * other materials provided with the distribution.
     14  *
     15  * 3. Neither the name of the copyright holder nor the names of its contributors
     16  * may be used to endorse or promote products derived from this software without
     17  * specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
     23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 #include "ConfigurableElement.h"
     31 #include "MappingData.h"
     32 #include "SyncerSet.h"
     33 #include "ConfigurableDomain.h"
     34 #include "ConfigurationAccessContext.h"
     35 #include "ConfigurableElementAggregator.h"
     36 #include "AreaConfiguration.h"
     37 #include "Iterator.hpp"
     38 #include "Utility.h"
     39 #include "XmlParameterSerializingContext.h"
     40 #include <assert.h>
     41 
     42 #define base CElement
     43 
     44 CConfigurableElement::CConfigurableElement(const std::string &strName) : base(strName)
     45 {
     46 }
     47 
     48 bool CConfigurableElement::fromXml(const CXmlElement &xmlElement,
     49                                    CXmlSerializingContext &serializingContext)
     50 {
     51     auto &context = static_cast<CXmlParameterSerializingContext &>(serializingContext);
     52     auto &accessContext = context.getAccessContext();
     53 
     54     if (accessContext.serializeSettings()) {
     55         // As serialization and deserialisation are handled through the *same* function
     56         // the (de)serialize object can not be const in `serializeXmlSettings` signature.
     57         // As a result a const_cast is unavoidable :(.
     58         // Fixme: split serializeXmlSettings in two functions (in and out) to avoid the `const_cast`
     59         return serializeXmlSettings(const_cast<CXmlElement &>(xmlElement),
     60                                     static_cast<CConfigurationAccessContext &>(accessContext));
     61     }
     62     return structureFromXml(xmlElement, serializingContext);
     63 }
     64 
     65 void CConfigurableElement::toXml(CXmlElement &xmlElement,
     66                                  CXmlSerializingContext &serializingContext) const
     67 {
     68     auto &context = static_cast<CXmlParameterSerializingContext &>(serializingContext);
     69     auto &accessContext = context.getAccessContext();
     70     if (accessContext.serializeSettings()) {
     71 
     72         serializeXmlSettings(xmlElement, static_cast<CConfigurationAccessContext &>(accessContext));
     73     } else {
     74 
     75         structureToXml(xmlElement, serializingContext);
     76     }
     77 }
     78 
     79 // XML configuration settings parsing
     80 bool CConfigurableElement::serializeXmlSettings(
     81     CXmlElement &xmlConfigurationSettingsElementContent,
     82     CConfigurationAccessContext &configurationAccessContext) const
     83 {
     84     size_t uiNbChildren = getNbChildren();
     85 
     86     if (!configurationAccessContext.serializeOut()) {
     87         // Just do basic checks and propagate to children
     88         CXmlElement::CChildIterator it(xmlConfigurationSettingsElementContent);
     89 
     90         CXmlElement xmlChildConfigurableElementSettingsElement;
     91 
     92         // Propagate to children
     93         for (size_t index = 0; index < uiNbChildren; index++) {
     94 
     95             // Get child
     96             const CConfigurableElement *pChildConfigurableElement =
     97                 static_cast<const CConfigurableElement *>(getChild(index));
     98 
     99             if (!it.next(xmlChildConfigurableElementSettingsElement)) {
    100 
    101                 // Structure error
    102                 configurationAccessContext.setError(
    103                     "Configuration settings parsing: missing child node " +
    104                     pChildConfigurableElement->getXmlElementName() + " (name:" +
    105                     pChildConfigurableElement->getName() + ") in " + getName());
    106 
    107                 return false;
    108             }
    109 
    110             // Check element type matches in type
    111             if (xmlChildConfigurableElementSettingsElement.getType() !=
    112                 pChildConfigurableElement->getXmlElementName()) {
    113 
    114                 // "Component" tag has been renamed to "ParameterBlock", but retro-compatibility
    115                 // shall be ensured.
    116                 //
    117                 // So checking if this case occurs, i.e. element name is "ParameterBlock"
    118                 // but xml setting name is "Component".
    119                 bool compatibilityCase =
    120                     (pChildConfigurableElement->getXmlElementName() == "ParameterBlock") &&
    121                     (xmlChildConfigurableElementSettingsElement.getType() == "Component");
    122 
    123                 // Error if the compatibility case does not occur.
    124                 if (!compatibilityCase) {
    125 
    126                     // Type error
    127                     configurationAccessContext.setError(
    128                         "Configuration settings parsing: Settings "
    129                         "for configurable element " +
    130                         pChildConfigurableElement->getQualifiedPath() +
    131                         " does not match expected type: " +
    132                         xmlChildConfigurableElementSettingsElement.getType() + " instead of " +
    133                         pChildConfigurableElement->getKind());
    134                     return false;
    135                 }
    136             }
    137 
    138             // Check element type matches in name
    139             if (xmlChildConfigurableElementSettingsElement.getNameAttribute() !=
    140                 pChildConfigurableElement->getName()) {
    141 
    142                 // Name error
    143                 configurationAccessContext.setError(
    144                     "Configuration settings parsing: Under configurable element " +
    145                     getQualifiedPath() + ", expected element name " +
    146                     pChildConfigurableElement->getName() + " but found " +
    147                     xmlChildConfigurableElementSettingsElement.getNameAttribute() + " instead");
    148 
    149                 return false;
    150             }
    151 
    152             // Parse child configurable element's settings
    153             if (!pChildConfigurableElement->serializeXmlSettings(
    154                     xmlChildConfigurableElementSettingsElement, configurationAccessContext)) {
    155 
    156                 return false;
    157             }
    158         }
    159         // There should remain no configurable element to parse
    160         if (it.next(xmlChildConfigurableElementSettingsElement)) {
    161 
    162             // Structure error
    163             configurationAccessContext.setError(
    164                 "Configuration settings parsing: Unexpected xml element node " +
    165                 xmlChildConfigurableElementSettingsElement.getType() + " in " + getQualifiedPath());
    166 
    167             return false;
    168         }
    169     } else {
    170         // Handle element name attribute
    171         xmlConfigurationSettingsElementContent.setNameAttribute(getName());
    172 
    173         // Propagate to children
    174         for (size_t index = 0; index < uiNbChildren; index++) {
    175 
    176             const CConfigurableElement *pChildConfigurableElement =
    177                 static_cast<const CConfigurableElement *>(getChild(index));
    178 
    179             // Create corresponding child element
    180             CXmlElement xmlChildConfigurableElementSettingsElement;
    181 
    182             xmlConfigurationSettingsElementContent.createChild(
    183                 xmlChildConfigurableElementSettingsElement,
    184                 pChildConfigurableElement->getXmlElementName());
    185 
    186             // Propagate
    187             pChildConfigurableElement->serializeXmlSettings(
    188                 xmlChildConfigurableElementSettingsElement, configurationAccessContext);
    189         }
    190     }
    191     // Done
    192     return true;
    193 }
    194 
    195 // AreaConfiguration creation
    196 CAreaConfiguration *CConfigurableElement::createAreaConfiguration(
    197     const CSyncerSet *pSyncerSet) const
    198 {
    199     return new CAreaConfiguration(this, pSyncerSet);
    200 }
    201 
    202 // Parameter access
    203 bool CConfigurableElement::accessValue(CPathNavigator &pathNavigator, std::string &strValue,
    204                                        bool bSet,
    205                                        CParameterAccessContext &parameterAccessContext) const
    206 {
    207     std::string *pStrChildName = pathNavigator.next();
    208 
    209     if (!pStrChildName) {
    210 
    211         parameterAccessContext.setError((bSet ? "Can't set " : "Can't get ") +
    212                                         pathNavigator.getCurrentPath() +
    213                                         " because it is not a parameter");
    214 
    215         return false;
    216     }
    217 
    218     const CConfigurableElement *pChild =
    219         static_cast<const CConfigurableElement *>(findChild(*pStrChildName));
    220 
    221     if (!pChild) {
    222 
    223         parameterAccessContext.setError("Path not found: " + pathNavigator.getCurrentPath());
    224 
    225         return false;
    226     }
    227 
    228     return pChild->accessValue(pathNavigator, strValue, bSet, parameterAccessContext);
    229 }
    230 
    231 // Whole element access
    232 void CConfigurableElement::getSettingsAsBytes(std::vector<uint8_t> &bytes,
    233                                               CParameterAccessContext &parameterAccessContext) const
    234 {
    235     bytes.resize(getFootPrint());
    236 
    237     parameterAccessContext.getParameterBlackboard()->readBytes(
    238         bytes, getOffset() - parameterAccessContext.getBaseOffset());
    239 }
    240 
    241 bool CConfigurableElement::setSettingsAsBytes(const std::vector<uint8_t> &bytes,
    242                                               CParameterAccessContext &parameterAccessContext) const
    243 {
    244     CParameterBlackboard *pParameterBlackboard = parameterAccessContext.getParameterBlackboard();
    245 
    246     // Size
    247     size_t size = getFootPrint();
    248 
    249     // Check sizes match
    250     if (size != bytes.size()) {
    251 
    252         parameterAccessContext.setError(std::string("Wrong size: Expected: ") +
    253                                         std::to_string(size) + " Provided: " +
    254                                         std::to_string(bytes.size()));
    255 
    256         return false;
    257     }
    258 
    259     // Write bytes
    260     pParameterBlackboard->writeBytes(bytes, getOffset() - parameterAccessContext.getBaseOffset());
    261 
    262     if (not parameterAccessContext.getAutoSync()) {
    263         // Auto sync is not activated, sync will be defered until an explicit request
    264         return true;
    265     }
    266 
    267     CSyncerSet syncerSet;
    268     fillSyncerSet(syncerSet);
    269     core::Results res;
    270     if (not syncerSet.sync(*parameterAccessContext.getParameterBlackboard(), false, &res)) {
    271 
    272         parameterAccessContext.setError(utility::asString(res));
    273         return false;
    274     }
    275     return true;
    276 }
    277 
    278 std::list<const CConfigurableElement *> CConfigurableElement::getConfigurableElementContext() const
    279 {
    280     std::list<const CConfigurableElement *> configurableElementPath;
    281 
    282     const CElement *element = this;
    283     while (element != nullptr and isOfConfigurableElementType(element)) {
    284         auto configurableElement = static_cast<const CConfigurableElement *>(element);
    285 
    286         configurableElementPath.push_back(configurableElement);
    287         element = element->getParent();
    288     }
    289 
    290     return configurableElementPath;
    291 }
    292 
    293 // Used for simulation and virtual subsystems
    294 void CConfigurableElement::setDefaultValues(CParameterAccessContext &parameterAccessContext) const
    295 {
    296     // Propagate to children
    297     size_t uiNbChildren = getNbChildren();
    298 
    299     for (size_t index = 0; index < uiNbChildren; index++) {
    300 
    301         const CConfigurableElement *pConfigurableElement =
    302             static_cast<const CConfigurableElement *>(getChild(index));
    303 
    304         pConfigurableElement->setDefaultValues(parameterAccessContext);
    305     }
    306 }
    307 
    308 // Element properties
    309 void CConfigurableElement::showProperties(std::string &strResult) const
    310 {
    311     base::showProperties(strResult);
    312 
    313     strResult += "Total size: " + getFootprintAsString() + "\n";
    314 }
    315 
    316 std::string CConfigurableElement::logValue(utility::ErrorContext &context) const
    317 {
    318     return logValue(static_cast<CParameterAccessContext &>(context));
    319 }
    320 
    321 std::string CConfigurableElement::logValue(CParameterAccessContext & /*ctx*/) const
    322 {
    323     // By default, an element does not have a value. Only leaf elements have
    324     // one. This method could be pure virtual but then, several derived classes
    325     // would need to implement it in order to simply return an empty string.
    326     return "";
    327 }
    328 
    329 // Offset
    330 void CConfigurableElement::setOffset(size_t offset)
    331 {
    332     // Assign offset locally
    333     _offset = offset;
    334 
    335     // Propagate to children
    336     size_t uiNbChildren = getNbChildren();
    337 
    338     for (size_t index = 0; index < uiNbChildren; index++) {
    339 
    340         CConfigurableElement *pConfigurableElement =
    341             static_cast<CConfigurableElement *>(getChild(index));
    342 
    343         pConfigurableElement->setOffset(offset);
    344 
    345         offset += pConfigurableElement->getFootPrint();
    346     }
    347 }
    348 
    349 size_t CConfigurableElement::getOffset() const
    350 {
    351     return _offset;
    352 }
    353 
    354 // Memory
    355 size_t CConfigurableElement::getFootPrint() const
    356 {
    357     size_t uiSize = 0;
    358     size_t uiNbChildren = getNbChildren();
    359 
    360     for (size_t index = 0; index < uiNbChildren; index++) {
    361 
    362         const CConfigurableElement *pConfigurableElement =
    363             static_cast<const CConfigurableElement *>(getChild(index));
    364 
    365         uiSize += pConfigurableElement->getFootPrint();
    366     }
    367 
    368     return uiSize;
    369 }
    370 
    371 // Browse parent path to find syncer
    372 ISyncer *CConfigurableElement::getSyncer() const
    373 {
    374     // Check parent
    375     const CElement *pParent = getParent();
    376 
    377     if (isOfConfigurableElementType(pParent)) {
    378 
    379         return static_cast<const CConfigurableElement *>(pParent)->getSyncer();
    380     }
    381     return NULL;
    382 }
    383 
    384 // Syncer set (me, ascendant or descendant ones)
    385 void CConfigurableElement::fillSyncerSet(CSyncerSet &syncerSet) const
    386 {
    387     //  Try me or ascendants
    388     ISyncer *pMineOrAscendantSyncer = getSyncer();
    389 
    390     if (pMineOrAscendantSyncer) {
    391 
    392         // Provide found syncer object
    393         syncerSet += pMineOrAscendantSyncer;
    394 
    395         // Done
    396         return;
    397     }
    398     // Fetch descendant ones
    399     fillSyncerSetFromDescendant(syncerSet);
    400 }
    401 
    402 // Syncer set (descendant)
    403 void CConfigurableElement::fillSyncerSetFromDescendant(CSyncerSet &syncerSet) const
    404 {
    405     // Dig
    406     size_t uiNbChildren = getNbChildren();
    407 
    408     for (size_t index = 0; index < uiNbChildren; index++) {
    409 
    410         const CConfigurableElement *pConfigurableElement =
    411             static_cast<const CConfigurableElement *>(getChild(index));
    412 
    413         pConfigurableElement->fillSyncerSetFromDescendant(syncerSet);
    414     }
    415 }
    416 
    417 // Configurable domain association
    418 void CConfigurableElement::addAttachedConfigurableDomain(
    419     const CConfigurableDomain *pConfigurableDomain)
    420 {
    421     _configurableDomainList.push_back(pConfigurableDomain);
    422 }
    423 
    424 void CConfigurableElement::removeAttachedConfigurableDomain(
    425     const CConfigurableDomain *pConfigurableDomain)
    426 {
    427     _configurableDomainList.remove(pConfigurableDomain);
    428 }
    429 
    430 // Belonging domain
    431 bool CConfigurableElement::belongsTo(const CConfigurableDomain *pConfigurableDomain) const
    432 {
    433     if (containsConfigurableDomain(pConfigurableDomain)) {
    434 
    435         return true;
    436     }
    437     return belongsToDomainAscending(pConfigurableDomain);
    438 }
    439 
    440 // Belonging domains
    441 void CConfigurableElement::getBelongingDomains(
    442     std::list<const CConfigurableDomain *> &configurableDomainList) const
    443 {
    444     configurableDomainList.insert(configurableDomainList.end(), _configurableDomainList.begin(),
    445                                   _configurableDomainList.end());
    446 
    447     // Check parent
    448     const CElement *pParent = getParent();
    449 
    450     if (isOfConfigurableElementType(pParent)) {
    451 
    452         static_cast<const CConfigurableElement *>(pParent)->getBelongingDomains(
    453             configurableDomainList);
    454     }
    455 }
    456 
    457 void CConfigurableElement::listBelongingDomains(std::string &strResult, bool bVertical) const
    458 {
    459     // Get belonging domain list
    460     std::list<const CConfigurableDomain *> configurableDomainList;
    461 
    462     getBelongingDomains(configurableDomainList);
    463 
    464     // Fill list
    465     listDomains(configurableDomainList, strResult, bVertical);
    466 }
    467 
    468 // Elements with no domains
    469 void CConfigurableElement::listRogueElements(std::string &strResult) const
    470 {
    471     // Get rogue element aggregate list (no associated domain)
    472     std::list<const CConfigurableElement *> rogueElementList;
    473 
    474     CConfigurableElementAggregator configurableElementAggregator(
    475         rogueElementList, &CConfigurableElement::hasNoDomainAssociated);
    476 
    477     configurableElementAggregator.aggegate(this);
    478 
    479     // Build list as std::string
    480     std::list<const CConfigurableElement *>::const_iterator it;
    481 
    482     for (it = rogueElementList.begin(); it != rogueElementList.end(); ++it) {
    483 
    484         const CConfigurableElement *pConfigurableElement = *it;
    485 
    486         strResult += pConfigurableElement->getPath() + "\n";
    487     }
    488 }
    489 
    490 bool CConfigurableElement::isRogue() const
    491 {
    492     // Check not belonging to any domin from current level and towards ascendents
    493     if (getBelongingDomainCount() != 0) {
    494 
    495         return false;
    496     }
    497 
    498     // Get a list of elements (current + descendants) with no domains associated
    499     std::list<const CConfigurableElement *> rogueElementList;
    500 
    501     CConfigurableElementAggregator agregator(rogueElementList,
    502                                              &CConfigurableElement::hasNoDomainAssociated);
    503 
    504     agregator.aggegate(this);
    505 
    506     // Check only one element found which ought to be current one
    507     return (rogueElementList.size() == 1) && (rogueElementList.front() == this);
    508 }
    509 
    510 // Footprint as string
    511 std::string CConfigurableElement::getFootprintAsString() const
    512 {
    513     // Get size as string
    514     return std::to_string(getFootPrint()) + " byte(s)";
    515 }
    516 
    517 // Matching check for no domain association
    518 bool CConfigurableElement::hasNoDomainAssociated() const
    519 {
    520     return _configurableDomainList.empty();
    521 }
    522 
    523 // Matching check for no valid associated domains
    524 bool CConfigurableElement::hasNoValidDomainAssociated() const
    525 {
    526     if (_configurableDomainList.empty()) {
    527 
    528         // No domains associated
    529         return true;
    530     }
    531 
    532     ConfigurableDomainListConstIterator it;
    533 
    534     // Browse all configurable domains for validity checking
    535     for (it = _configurableDomainList.begin(); it != _configurableDomainList.end(); ++it) {
    536 
    537         const CConfigurableDomain *pConfigurableDomain = *it;
    538 
    539         if (pConfigurableDomain->isApplicableConfigurationValid(this)) {
    540 
    541             return false;
    542         }
    543     }
    544 
    545     return true;
    546 }
    547 
    548 // Owning domains
    549 void CConfigurableElement::listAssociatedDomains(std::string &strResult, bool bVertical) const
    550 {
    551     // Fill list
    552     listDomains(_configurableDomainList, strResult, bVertical);
    553 }
    554 
    555 size_t CConfigurableElement::getBelongingDomainCount() const
    556 {
    557     // Get belonging domain list
    558     std::list<const CConfigurableDomain *> configurableDomainList;
    559 
    560     getBelongingDomains(configurableDomainList);
    561 
    562     return configurableDomainList.size();
    563 }
    564 
    565 void CConfigurableElement::listDomains(
    566     const std::list<const CConfigurableDomain *> &configurableDomainList, std::string &strResult,
    567     bool bVertical) const
    568 {
    569     // Fill list
    570     ConfigurableDomainListConstIterator it;
    571     bool bFirst = true;
    572 
    573     // Browse all configurable domains for comparison
    574     for (it = configurableDomainList.begin(); it != configurableDomainList.end(); ++it) {
    575 
    576         const CConfigurableDomain *pConfigurableDomain = *it;
    577 
    578         if (!bVertical && !bFirst) {
    579 
    580             strResult += ", ";
    581         }
    582 
    583         strResult += pConfigurableDomain->getName();
    584 
    585         if (bVertical) {
    586 
    587             strResult += "\n";
    588         } else {
    589 
    590             bFirst = false;
    591         }
    592     }
    593 }
    594 
    595 bool CConfigurableElement::containsConfigurableDomain(
    596     const CConfigurableDomain *pConfigurableDomain) const
    597 {
    598     ConfigurableDomainListConstIterator it;
    599 
    600     // Browse all configurable domains for comparison
    601     for (it = _configurableDomainList.begin(); it != _configurableDomainList.end(); ++it) {
    602 
    603         if (pConfigurableDomain == *it) {
    604 
    605             return true;
    606         }
    607     }
    608     return false;
    609 }
    610 
    611 // Belonging domain ascending search
    612 bool CConfigurableElement::belongsToDomainAscending(
    613     const CConfigurableDomain *pConfigurableDomain) const
    614 {
    615     // Check parent
    616     const CElement *pParent = getParent();
    617 
    618     if (isOfConfigurableElementType(pParent)) {
    619 
    620         return static_cast<const CConfigurableElement *>(pParent)->belongsTo(pConfigurableDomain);
    621     }
    622     return false;
    623 }
    624 
    625 // Belonging subsystem
    626 const CSubsystem *CConfigurableElement::getBelongingSubsystem() const
    627 {
    628     const CElement *pParent = getParent();
    629 
    630     // Stop at system class
    631     if (!pParent->getParent()) {
    632 
    633         return NULL;
    634     }
    635 
    636     return static_cast<const CConfigurableElement *>(pParent)->getBelongingSubsystem();
    637 }
    638 
    639 // Check element is a parameter
    640 bool CConfigurableElement::isParameter() const
    641 {
    642     return false;
    643 }
    644 
    645 // Check parent is still of current type (by structure knowledge)
    646 bool CConfigurableElement::isOfConfigurableElementType(const CElement *pParent) const
    647 {
    648     assert(pParent);
    649 
    650     // Up to system class
    651     return !!pParent->getParent();
    652 }
    653