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 "DomainConfiguration.h"
     31 #include "ConfigurableElement.h"
     32 #include "CompoundRule.h"
     33 #include "Subsystem.h"
     34 #include "XmlDomainSerializingContext.h"
     35 #include "XmlDomainImportContext.h"
     36 #include "XmlDomainExportContext.h"
     37 #include "ConfigurationAccessContext.h"
     38 #include "AlwaysAssert.hpp"
     39 #include <assert.h>
     40 #include <cstdlib>
     41 #include <algorithm>
     42 #include <numeric>
     43 #include "RuleParser.h"
     44 
     45 #define base CElement
     46 
     47 using std::string;
     48 
     49 CDomainConfiguration::CDomainConfiguration(const string &strName) : base(strName)
     50 {
     51 }
     52 
     53 // Class kind
     54 string CDomainConfiguration::getKind() const
     55 {
     56     return "Configuration";
     57 }
     58 
     59 // Child dynamic creation
     60 bool CDomainConfiguration::childrenAreDynamic() const
     61 {
     62     return true;
     63 }
     64 
     65 // XML configuration settings parsing
     66 bool CDomainConfiguration::parseSettings(CXmlElement &xmlConfigurationSettingsElement,
     67                                          CXmlDomainImportContext &context)
     68 {
     69     // Parse configurable element's configuration settings
     70     CXmlElement::CChildIterator it(xmlConfigurationSettingsElement);
     71 
     72     CXmlElement xmlConfigurableElementSettingsElement;
     73     auto insertLocation = begin(mAreaConfigurationList);
     74 
     75     while (it.next(xmlConfigurableElementSettingsElement)) {
     76 
     77         // Retrieve area configuration
     78         string configurableElementPath;
     79         xmlConfigurableElementSettingsElement.getAttribute("Path", configurableElementPath);
     80 
     81         auto areaConfiguration = findAreaConfigurationByPath(configurableElementPath);
     82         if (areaConfiguration == end(mAreaConfigurationList)) {
     83 
     84             context.setError("Configurable Element " + configurableElementPath +
     85                              " referred to by Configuration " + getPath() +
     86                              " not associated to Domain");
     87 
     88             return false;
     89         }
     90         // Parse
     91         if (!importOneConfigurableElementSettings(areaConfiguration->get(),
     92                                                   xmlConfigurableElementSettingsElement, context)) {
     93 
     94             return false;
     95         }
     96         // Take into account the new configuration order by moving the configuration associated to
     97         // the element to the n-th position of the configuration list.
     98         // It will result in prepending to the configuration list wit the configuration of all
     99         // elements found in XML, keeping the order of the processing of the XML file.
    100         mAreaConfigurationList.splice(insertLocation, mAreaConfigurationList, areaConfiguration);
    101         // areaConfiguration is still valid, but now refer to the reorderer list
    102         insertLocation = std::next(areaConfiguration);
    103     }
    104     return true;
    105 }
    106 
    107 // XML configuration settings composing
    108 void CDomainConfiguration::composeSettings(CXmlElement &xmlConfigurationSettingsElement,
    109                                            CXmlDomainExportContext &context) const
    110 {
    111     // Go through all are configurations
    112     for (auto &areaConfiguration : mAreaConfigurationList) {
    113 
    114         // Retrieve configurable element
    115         const CConfigurableElement *pConfigurableElement =
    116             areaConfiguration->getConfigurableElement();
    117 
    118         // Create configurable element child element
    119         CXmlElement xmlConfigurableElementSettingsElement;
    120 
    121         xmlConfigurationSettingsElement.createChild(xmlConfigurableElementSettingsElement,
    122                                                     "ConfigurableElement");
    123 
    124         // Set Path attribute
    125         xmlConfigurableElementSettingsElement.setAttribute("Path", pConfigurableElement->getPath());
    126 
    127         // Delegate composing to area configuration
    128         exportOneConfigurableElementSettings(areaConfiguration.get(),
    129                                              xmlConfigurableElementSettingsElement, context);
    130     }
    131 }
    132 
    133 // Serialize one configuration for one configurable element
    134 bool CDomainConfiguration::importOneConfigurableElementSettings(
    135     CAreaConfiguration *areaConfiguration, CXmlElement &xmlConfigurableElementSettingsElement,
    136     CXmlDomainImportContext &context)
    137 {
    138     const CConfigurableElement *destination = areaConfiguration->getConfigurableElement();
    139 
    140     // Check structure
    141     if (xmlConfigurableElementSettingsElement.getNbChildElements() != 1) {
    142 
    143         // Structure error
    144         context.setError("Struture error encountered while parsing settings of " +
    145                          destination->getKind() + " " + destination->getName() +
    146                          " in Configuration " + getPath());
    147 
    148         return false;
    149     }
    150 
    151     // Element content
    152     CXmlElement xmlConfigurableElementSettingsElementContent;
    153     // Check name and kind
    154     if (!xmlConfigurableElementSettingsElement.getChildElement(
    155             destination->getXmlElementName(), destination->getName(),
    156             xmlConfigurableElementSettingsElementContent)) {
    157 
    158         // "Component" tag has been renamed to "ParameterBlock", but retro-compatibility shall
    159         // be ensured.
    160         //
    161         // So checking if this case occurs, i.e. element name is "ParameterBlock"
    162         // but found xml setting name is "Component".
    163         bool compatibilityCase =
    164             (destination->getXmlElementName() == "ParameterBlock") &&
    165             xmlConfigurableElementSettingsElement.getChildElement(
    166                 "Component", destination->getName(), xmlConfigurableElementSettingsElementContent);
    167 
    168         // Error if the compatibility case does not occur.
    169         if (!compatibilityCase) {
    170             context.setError("Couldn't find settings for " + destination->getXmlElementName() +
    171                              " " + destination->getName() + " for Configuration " + getPath());
    172 
    173             return false;
    174         }
    175     }
    176 
    177     // Create configuration access context
    178     string error;
    179     CConfigurationAccessContext configurationAccessContext(error, false);
    180 
    181     // Have domain configuration parse settings for configurable element
    182     bool success = areaConfiguration->serializeXmlSettings(
    183         xmlConfigurableElementSettingsElementContent, configurationAccessContext);
    184 
    185     context.appendToError(error);
    186     return success;
    187 }
    188 
    189 bool CDomainConfiguration::exportOneConfigurableElementSettings(
    190     CAreaConfiguration *areaConfiguration, CXmlElement &xmlConfigurableElementSettingsElement,
    191     CXmlDomainExportContext &context) const
    192 {
    193     const CConfigurableElement *source = areaConfiguration->getConfigurableElement();
    194 
    195     // Create child XML element
    196     CXmlElement xmlConfigurableElementSettingsElementContent;
    197     xmlConfigurableElementSettingsElement.createChild(xmlConfigurableElementSettingsElementContent,
    198                                                       source->getXmlElementName());
    199 
    200     // Create configuration access context
    201     string error;
    202     CConfigurationAccessContext configurationAccessContext(error, true);
    203     configurationAccessContext.setValueSpaceRaw(context.valueSpaceIsRaw());
    204     configurationAccessContext.setOutputRawFormat(context.outputRawFormatIsHex());
    205 
    206     // Have domain configuration parse settings for configurable element
    207     bool success = areaConfiguration->serializeXmlSettings(
    208         xmlConfigurableElementSettingsElementContent, configurationAccessContext);
    209 
    210     context.appendToError(error);
    211     return success;
    212 }
    213 
    214 void CDomainConfiguration::addConfigurableElement(const CConfigurableElement *configurableElement,
    215                                                   const CSyncerSet *syncerSet)
    216 {
    217     mAreaConfigurationList.emplace_back(configurableElement->createAreaConfiguration(syncerSet));
    218 }
    219 
    220 void CDomainConfiguration::removeConfigurableElement(
    221     const CConfigurableElement *pConfigurableElement)
    222 {
    223     auto &areaConfigurationToRemove = getAreaConfiguration(pConfigurableElement);
    224 
    225     mAreaConfigurationList.remove(areaConfigurationToRemove);
    226 }
    227 
    228 bool CDomainConfiguration::setElementSequence(const std::vector<string> &newElementSequence,
    229                                               string &error)
    230 {
    231     std::vector<string> elementSequenceSet;
    232     auto insertLocation = begin(mAreaConfigurationList);
    233 
    234     for (const std::string &elementPath : newElementSequence) {
    235 
    236         auto areaConfiguration = findAreaConfigurationByPath(elementPath);
    237         if (areaConfiguration == end(mAreaConfigurationList)) {
    238 
    239             error = "Element " + elementPath + " not found in domain";
    240 
    241             return false;
    242         }
    243         auto it = find(begin(elementSequenceSet), end(elementSequenceSet), elementPath);
    244         if (it != end(elementSequenceSet)) {
    245             error = "Element " + elementPath + " provided more than once";
    246             return false;
    247         }
    248         elementSequenceSet.push_back(elementPath);
    249         // Take into account the new configuration order by moving the configuration associated to
    250         // the element to the n-th position of the configuration list.
    251         // It will result in prepending to the configuration list wit the configuration of all
    252         // elements found in XML, keeping the order of the processing of the XML file.
    253         mAreaConfigurationList.splice(insertLocation, mAreaConfigurationList, areaConfiguration);
    254         // areaConfiguration is still valid, but now refer to the reorderer list
    255         insertLocation = std::next(areaConfiguration);
    256     }
    257     return true;
    258 }
    259 
    260 void CDomainConfiguration::getElementSequence(string &strResult) const
    261 {
    262     // List configurable element paths out of ordered area configuration list
    263     strResult = accumulate(begin(mAreaConfigurationList), end(mAreaConfigurationList), string("\n"),
    264                            [](const string &a, const AreaConfiguration &conf) {
    265                                return a + conf->getConfigurableElement()->getPath() + "\n";
    266                            });
    267 }
    268 
    269 // Application rule
    270 bool CDomainConfiguration::setApplicationRule(
    271     const string &strApplicationRule,
    272     const CSelectionCriteriaDefinition *pSelectionCriteriaDefinition, string &strError)
    273 {
    274     // Parser
    275     CRuleParser ruleParser(strApplicationRule, pSelectionCriteriaDefinition);
    276 
    277     // Attempt to parse it
    278     if (!ruleParser.parse(NULL, strError)) {
    279 
    280         return false;
    281     }
    282     // Replace compound rule
    283     setRule(ruleParser.grabRootRule());
    284 
    285     return true;
    286 }
    287 
    288 void CDomainConfiguration::clearApplicationRule()
    289 {
    290     // Replace compound rule
    291     setRule(NULL);
    292 }
    293 
    294 string CDomainConfiguration::getApplicationRule() const
    295 {
    296     const CCompoundRule *pRule = getRule();
    297     return pRule ? pRule->dump() : "<none>";
    298 }
    299 
    300 /**
    301  * Get the Configuration Blackboard.
    302  *
    303  * Fetch the Configuration Blackboard related to the ConfigurableElement given in parameter. This
    304  * Element is used to retrieve the correct AreaConfiguration where the Blackboard is stored.
    305  *
    306  * @param[in] pConfigurableElement      A pointer to a ConfigurableElement that is part of the
    307  *                                      Domain. This must have been checked previously, as an
    308  *                                      assertion is performed.
    309  *
    310  * return Pointer to the Blackboard of the Configuration.
    311  */
    312 CParameterBlackboard *CDomainConfiguration::getBlackboard(
    313     const CConfigurableElement *pConfigurableElement) const
    314 {
    315     const auto &it = find_if(begin(mAreaConfigurationList), end(mAreaConfigurationList),
    316                              [&](const AreaConfiguration &conf) {
    317                                  return conf != nullptr &&
    318                                         conf->getConfigurableElement() == pConfigurableElement;
    319                              });
    320     ALWAYS_ASSERT(it != end(mAreaConfigurationList), "Configurable Element "
    321                                                          << pConfigurableElement->getName()
    322                                                          << " not found in any area Configuration");
    323     return &(*it)->getBlackboard();
    324 }
    325 
    326 // Save data from current
    327 void CDomainConfiguration::save(const CParameterBlackboard *pMainBlackboard)
    328 {
    329     // Just propagate to areas
    330     for (auto &areaConfiguration : mAreaConfigurationList) {
    331         areaConfiguration->save(pMainBlackboard);
    332     }
    333 }
    334 
    335 // Apply data to current
    336 bool CDomainConfiguration::restore(CParameterBlackboard *pMainBlackboard, bool bSync,
    337                                    core::Results *errors) const
    338 {
    339     return std::accumulate(begin(mAreaConfigurationList), end(mAreaConfigurationList), true,
    340                            [&](bool accumulator, const AreaConfiguration &conf) {
    341                                return conf->restore(pMainBlackboard, bSync, errors) && accumulator;
    342                            });
    343 }
    344 
    345 // Ensure validity for configurable element area configuration
    346 void CDomainConfiguration::validate(const CConfigurableElement *pConfigurableElement,
    347                                     const CParameterBlackboard *pMainBlackboard)
    348 {
    349     auto &areaConfigurationToValidate = getAreaConfiguration(pConfigurableElement);
    350 
    351     // Delegate
    352     areaConfigurationToValidate->validate(pMainBlackboard);
    353 }
    354 
    355 // Ensure validity of all area configurations
    356 void CDomainConfiguration::validate(const CParameterBlackboard *pMainBlackboard)
    357 {
    358     for (auto &areaConfiguration : mAreaConfigurationList) {
    359         areaConfiguration->validate(pMainBlackboard);
    360     }
    361 }
    362 
    363 // Return configuration validity for given configurable element
    364 bool CDomainConfiguration::isValid(const CConfigurableElement *pConfigurableElement) const
    365 {
    366     // Get child configurable elemnt's area configuration
    367     auto &areaConfiguration = getAreaConfiguration(pConfigurableElement);
    368 
    369     ALWAYS_ASSERT(areaConfiguration != nullptr, "Configurable Element "
    370                                                     << pConfigurableElement->getName()
    371                                                     << " not found in any area Configuration");
    372 
    373     return areaConfiguration->isValid();
    374 }
    375 
    376 // Ensure validity of configurable element's area configuration by copying in from a valid one
    377 void CDomainConfiguration::validateAgainst(const CDomainConfiguration *pValidDomainConfiguration,
    378                                            const CConfigurableElement *pConfigurableElement)
    379 {
    380     // Retrieve related area configurations
    381     auto &areaConfigurationToValidate = getAreaConfiguration(pConfigurableElement);
    382     const auto &areaConfigurationToValidateAgainst =
    383         pValidDomainConfiguration->getAreaConfiguration(pConfigurableElement);
    384 
    385     // Delegate to area
    386     areaConfigurationToValidate->validateAgainst(areaConfigurationToValidateAgainst.get());
    387 }
    388 
    389 void CDomainConfiguration::validateAgainst(const CDomainConfiguration *validDomainConfiguration)
    390 {
    391     ALWAYS_ASSERT(mAreaConfigurationList.size() ==
    392                       validDomainConfiguration->mAreaConfigurationList.size(),
    393                   "Cannot validate domain configuration "
    394                       << getPath() << " since area configuration list does not have the same size"
    395                                       "than the configuration list to check against");
    396     for (const auto &configurationToValidateAgainst :
    397          validDomainConfiguration->mAreaConfigurationList) {
    398         // Get the area configuration associated to the configurable element of the
    399         // valid area configuration, it will assert if none found.
    400         auto configurableElement = configurationToValidateAgainst->getConfigurableElement();
    401         auto &configurationToValidate = getAreaConfiguration(configurableElement);
    402         // Delegate to area
    403         configurationToValidate->validateAgainst(configurationToValidateAgainst.get());
    404     }
    405 }
    406 
    407 // Dynamic data application
    408 bool CDomainConfiguration::isApplicable() const
    409 {
    410     const CCompoundRule *pRule = getRule();
    411 
    412     return pRule && pRule->matches();
    413 }
    414 
    415 // Merge existing configurations to given configurable element ones
    416 void CDomainConfiguration::merge(CConfigurableElement *pToConfigurableElement,
    417                                  CConfigurableElement *pFromConfigurableElement)
    418 {
    419     // Retrieve related area configurations
    420     auto &areaConfigurationToMergeTo = getAreaConfiguration(pToConfigurableElement);
    421     const auto &areaConfigurationToMergeFrom = getAreaConfiguration(pFromConfigurableElement);
    422 
    423     // Do the merge
    424     areaConfigurationToMergeFrom->copyToOuter(areaConfigurationToMergeTo.get());
    425 }
    426 
    427 // Domain splitting
    428 void CDomainConfiguration::split(CConfigurableElement *pFromConfigurableElement)
    429 {
    430     // Retrieve related area configuration
    431     const auto &areaConfigurationToSplitFrom = getAreaConfiguration(pFromConfigurableElement);
    432 
    433     // Go through children areas to copy configuration data to them
    434     size_t uiNbConfigurableElementChildren = pFromConfigurableElement->getNbChildren();
    435     size_t uiChild;
    436 
    437     for (uiChild = 0; uiChild < uiNbConfigurableElementChildren; uiChild++) {
    438 
    439         CConfigurableElement *pToChildConfigurableElement =
    440             static_cast<CConfigurableElement *>(pFromConfigurableElement->getChild(uiChild));
    441 
    442         // Get child configurable elemnt's area configuration
    443         auto &childAreaConfiguration = getAreaConfiguration(pToChildConfigurableElement);
    444 
    445         // Do the copy
    446         childAreaConfiguration->copyFromOuter(areaConfigurationToSplitFrom.get());
    447     }
    448 }
    449 
    450 const CDomainConfiguration::AreaConfiguration &CDomainConfiguration::getAreaConfiguration(
    451     const CConfigurableElement *pConfigurableElement) const
    452 {
    453     const auto &it = find_if(begin(mAreaConfigurationList), end(mAreaConfigurationList),
    454                              [&](const AreaConfiguration &conf) {
    455                                  return conf->getConfigurableElement() == pConfigurableElement;
    456                              });
    457     ALWAYS_ASSERT(it != end(mAreaConfigurationList),
    458                   "Configurable Element " << pConfigurableElement->getName()
    459                                           << " not found in Domain Configuration list");
    460     return *it;
    461 }
    462 
    463 CDomainConfiguration::AreaConfigurations::iterator CDomainConfiguration::
    464     findAreaConfigurationByPath(const std::string &configurableElementPath)
    465 {
    466     auto areaConfiguration =
    467         find_if(begin(mAreaConfigurationList), end(mAreaConfigurationList),
    468                 [&](const AreaConfiguration &conf) {
    469                     return conf->getConfigurableElement()->getPath() == configurableElementPath;
    470                 });
    471     return areaConfiguration;
    472 }
    473 
    474 // Rule
    475 const CCompoundRule *CDomainConfiguration::getRule() const
    476 {
    477     if (getNbChildren()) {
    478         // Rule created
    479         return static_cast<const CCompoundRule *>(getChild(ECompoundRule));
    480     }
    481     return NULL;
    482 }
    483 
    484 CCompoundRule *CDomainConfiguration::getRule()
    485 {
    486     if (getNbChildren()) {
    487         // Rule created
    488         return static_cast<CCompoundRule *>(getChild(ECompoundRule));
    489     }
    490     return NULL;
    491 }
    492 
    493 void CDomainConfiguration::setRule(CCompoundRule *pRule)
    494 {
    495     CCompoundRule *pOldRule = getRule();
    496 
    497     if (pOldRule) {
    498         // Remove previous rule
    499         removeChild(pOldRule);
    500 
    501         delete pOldRule;
    502     }
    503 
    504     // Set new one
    505     if (pRule) {
    506         // Chain
    507         addChild(pRule);
    508     }
    509 }
    510