| /* | |
| * 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 "DomainConfiguration.h" | |
| #include "ConfigurableElement.h" | |
| #include "CompoundRule.h" | |
| #include "Subsystem.h" | |
| #include "XmlDomainSerializingContext.h" | |
| #include "XmlDomainImportContext.h" | |
| #include "XmlDomainExportContext.h" | |
| #include "ConfigurationAccessContext.h" | |
| #include "AlwaysAssert.hpp" | |
| #include <assert.h> | |
| #include <cstdlib> | |
| #include <algorithm> | |
| #include <numeric> | |
| #include "RuleParser.h" | |
| #define base CElement | |
| using std::string; | |
| CDomainConfiguration::CDomainConfiguration(const string &strName) : base(strName) | |
| { | |
| } | |
| // Class kind | |
| string CDomainConfiguration::getKind() const | |
| { | |
| return "Configuration"; | |
| } | |
| // Child dynamic creation | |
| bool CDomainConfiguration::childrenAreDynamic() const | |
| { | |
| return true; | |
| } | |
| // XML configuration settings parsing | |
| bool CDomainConfiguration::parseSettings(CXmlElement &xmlConfigurationSettingsElement, | |
| CXmlDomainImportContext &context) | |
| { | |
| // Parse configurable element's configuration settings | |
| CXmlElement::CChildIterator it(xmlConfigurationSettingsElement); | |
| CXmlElement xmlConfigurableElementSettingsElement; | |
| auto insertLocation = begin(mAreaConfigurationList); | |
| while (it.next(xmlConfigurableElementSettingsElement)) { | |
| // Retrieve area configuration | |
| string configurableElementPath; | |
| xmlConfigurableElementSettingsElement.getAttribute("Path", configurableElementPath); | |
| auto areaConfiguration = findAreaConfigurationByPath(configurableElementPath); | |
| if (areaConfiguration == end(mAreaConfigurationList)) { | |
| context.setError("Configurable Element " + configurableElementPath + | |
| " referred to by Configuration " + getPath() + | |
| " not associated to Domain"); | |
| return false; | |
| } | |
| // Parse | |
| if (!importOneConfigurableElementSettings(areaConfiguration->get(), | |
| xmlConfigurableElementSettingsElement, context)) { | |
| return false; | |
| } | |
| // Take into account the new configuration order by moving the configuration associated to | |
| // the element to the n-th position of the configuration list. | |
| // It will result in prepending to the configuration list wit the configuration of all | |
| // elements found in XML, keeping the order of the processing of the XML file. | |
| mAreaConfigurationList.splice(insertLocation, mAreaConfigurationList, areaConfiguration); | |
| // areaConfiguration is still valid, but now refer to the reorderer list | |
| insertLocation = std::next(areaConfiguration); | |
| } | |
| return true; | |
| } | |
| // XML configuration settings composing | |
| void CDomainConfiguration::composeSettings(CXmlElement &xmlConfigurationSettingsElement, | |
| CXmlDomainExportContext &context) const | |
| { | |
| // Go through all are configurations | |
| for (auto &areaConfiguration : mAreaConfigurationList) { | |
| // Retrieve configurable element | |
| const CConfigurableElement *pConfigurableElement = | |
| areaConfiguration->getConfigurableElement(); | |
| // Create configurable element child element | |
| CXmlElement xmlConfigurableElementSettingsElement; | |
| xmlConfigurationSettingsElement.createChild(xmlConfigurableElementSettingsElement, | |
| "ConfigurableElement"); | |
| // Set Path attribute | |
| xmlConfigurableElementSettingsElement.setAttribute("Path", pConfigurableElement->getPath()); | |
| // Delegate composing to area configuration | |
| exportOneConfigurableElementSettings(areaConfiguration.get(), | |
| xmlConfigurableElementSettingsElement, context); | |
| } | |
| } | |
| // Serialize one configuration for one configurable element | |
| bool CDomainConfiguration::importOneConfigurableElementSettings( | |
| CAreaConfiguration *areaConfiguration, CXmlElement &xmlConfigurableElementSettingsElement, | |
| CXmlDomainImportContext &context) | |
| { | |
| const CConfigurableElement *destination = areaConfiguration->getConfigurableElement(); | |
| // Check structure | |
| if (xmlConfigurableElementSettingsElement.getNbChildElements() != 1) { | |
| // Structure error | |
| context.setError("Struture error encountered while parsing settings of " + | |
| destination->getKind() + " " + destination->getName() + | |
| " in Configuration " + getPath()); | |
| return false; | |
| } | |
| // Element content | |
| CXmlElement xmlConfigurableElementSettingsElementContent; | |
| // Check name and kind | |
| if (!xmlConfigurableElementSettingsElement.getChildElement( | |
| destination->getXmlElementName(), destination->getName(), | |
| xmlConfigurableElementSettingsElementContent)) { | |
| // "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 found xml setting name is "Component". | |
| bool compatibilityCase = | |
| (destination->getXmlElementName() == "ParameterBlock") && | |
| xmlConfigurableElementSettingsElement.getChildElement( | |
| "Component", destination->getName(), xmlConfigurableElementSettingsElementContent); | |
| // Error if the compatibility case does not occur. | |
| if (!compatibilityCase) { | |
| context.setError("Couldn't find settings for " + destination->getXmlElementName() + | |
| " " + destination->getName() + " for Configuration " + getPath()); | |
| return false; | |
| } | |
| } | |
| // Create configuration access context | |
| string error; | |
| CConfigurationAccessContext configurationAccessContext(error, false); | |
| // Have domain configuration parse settings for configurable element | |
| bool success = areaConfiguration->serializeXmlSettings( | |
| xmlConfigurableElementSettingsElementContent, configurationAccessContext); | |
| context.appendToError(error); | |
| return success; | |
| } | |
| bool CDomainConfiguration::exportOneConfigurableElementSettings( | |
| CAreaConfiguration *areaConfiguration, CXmlElement &xmlConfigurableElementSettingsElement, | |
| CXmlDomainExportContext &context) const | |
| { | |
| const CConfigurableElement *source = areaConfiguration->getConfigurableElement(); | |
| // Create child XML element | |
| CXmlElement xmlConfigurableElementSettingsElementContent; | |
| xmlConfigurableElementSettingsElement.createChild(xmlConfigurableElementSettingsElementContent, | |
| source->getXmlElementName()); | |
| // Create configuration access context | |
| string error; | |
| CConfigurationAccessContext configurationAccessContext(error, true); | |
| configurationAccessContext.setValueSpaceRaw(context.valueSpaceIsRaw()); | |
| configurationAccessContext.setOutputRawFormat(context.outputRawFormatIsHex()); | |
| // Have domain configuration parse settings for configurable element | |
| bool success = areaConfiguration->serializeXmlSettings( | |
| xmlConfigurableElementSettingsElementContent, configurationAccessContext); | |
| context.appendToError(error); | |
| return success; | |
| } | |
| void CDomainConfiguration::addConfigurableElement(const CConfigurableElement *configurableElement, | |
| const CSyncerSet *syncerSet) | |
| { | |
| mAreaConfigurationList.emplace_back(configurableElement->createAreaConfiguration(syncerSet)); | |
| } | |
| void CDomainConfiguration::removeConfigurableElement( | |
| const CConfigurableElement *pConfigurableElement) | |
| { | |
| auto &areaConfigurationToRemove = getAreaConfiguration(pConfigurableElement); | |
| mAreaConfigurationList.remove(areaConfigurationToRemove); | |
| } | |
| bool CDomainConfiguration::setElementSequence(const std::vector<string> &newElementSequence, | |
| string &error) | |
| { | |
| std::vector<string> elementSequenceSet; | |
| auto insertLocation = begin(mAreaConfigurationList); | |
| for (const std::string &elementPath : newElementSequence) { | |
| auto areaConfiguration = findAreaConfigurationByPath(elementPath); | |
| if (areaConfiguration == end(mAreaConfigurationList)) { | |
| error = "Element " + elementPath + " not found in domain"; | |
| return false; | |
| } | |
| auto it = find(begin(elementSequenceSet), end(elementSequenceSet), elementPath); | |
| if (it != end(elementSequenceSet)) { | |
| error = "Element " + elementPath + " provided more than once"; | |
| return false; | |
| } | |
| elementSequenceSet.push_back(elementPath); | |
| // Take into account the new configuration order by moving the configuration associated to | |
| // the element to the n-th position of the configuration list. | |
| // It will result in prepending to the configuration list wit the configuration of all | |
| // elements found in XML, keeping the order of the processing of the XML file. | |
| mAreaConfigurationList.splice(insertLocation, mAreaConfigurationList, areaConfiguration); | |
| // areaConfiguration is still valid, but now refer to the reorderer list | |
| insertLocation = std::next(areaConfiguration); | |
| } | |
| return true; | |
| } | |
| void CDomainConfiguration::getElementSequence(string &strResult) const | |
| { | |
| // List configurable element paths out of ordered area configuration list | |
| strResult = accumulate(begin(mAreaConfigurationList), end(mAreaConfigurationList), string("\n"), | |
| [](const string &a, const AreaConfiguration &conf) { | |
| return a + conf->getConfigurableElement()->getPath() + "\n"; | |
| }); | |
| } | |
| // Application rule | |
| bool CDomainConfiguration::setApplicationRule( | |
| const string &strApplicationRule, | |
| const CSelectionCriteriaDefinition *pSelectionCriteriaDefinition, string &strError) | |
| { | |
| // Parser | |
| CRuleParser ruleParser(strApplicationRule, pSelectionCriteriaDefinition); | |
| // Attempt to parse it | |
| if (!ruleParser.parse(nullptr, strError)) { | |
| return false; | |
| } | |
| // Replace compound rule | |
| setRule(ruleParser.grabRootRule()); | |
| return true; | |
| } | |
| void CDomainConfiguration::clearApplicationRule() | |
| { | |
| // Replace compound rule | |
| setRule(nullptr); | |
| } | |
| string CDomainConfiguration::getApplicationRule() const | |
| { | |
| const CCompoundRule *pRule = getRule(); | |
| return pRule ? pRule->dump() : "<none>"; | |
| } | |
| /** | |
| * Get the Configuration Blackboard. | |
| * | |
| * Fetch the Configuration Blackboard related to the ConfigurableElement given in parameter. This | |
| * Element is used to retrieve the correct AreaConfiguration where the Blackboard is stored. | |
| * | |
| * @param[in] pConfigurableElement A pointer to a ConfigurableElement that is part of the | |
| * Domain. This must have been checked previously, as an | |
| * assertion is performed. | |
| * | |
| * return Pointer to the Blackboard of the Configuration. | |
| */ | |
| CParameterBlackboard *CDomainConfiguration::getBlackboard( | |
| const CConfigurableElement *pConfigurableElement) const | |
| { | |
| const auto &it = find_if(begin(mAreaConfigurationList), end(mAreaConfigurationList), | |
| [&](const AreaConfiguration &conf) { | |
| return conf != nullptr && | |
| conf->getConfigurableElement() == pConfigurableElement; | |
| }); | |
| ALWAYS_ASSERT(it != end(mAreaConfigurationList), "Configurable Element " | |
| << pConfigurableElement->getName() | |
| << " not found in any area Configuration"); | |
| return &(*it)->getBlackboard(); | |
| } | |
| // Save data from current | |
| void CDomainConfiguration::save(const CParameterBlackboard *pMainBlackboard) | |
| { | |
| // Just propagate to areas | |
| for (auto &areaConfiguration : mAreaConfigurationList) { | |
| areaConfiguration->save(pMainBlackboard); | |
| } | |
| } | |
| // Apply data to current | |
| bool CDomainConfiguration::restore(CParameterBlackboard *pMainBlackboard, bool bSync, | |
| core::Results *errors) const | |
| { | |
| return std::accumulate(begin(mAreaConfigurationList), end(mAreaConfigurationList), true, | |
| [&](bool accumulator, const AreaConfiguration &conf) { | |
| return conf->restore(pMainBlackboard, bSync, errors) && accumulator; | |
| }); | |
| } | |
| // Ensure validity for configurable element area configuration | |
| void CDomainConfiguration::validate(const CConfigurableElement *pConfigurableElement, | |
| const CParameterBlackboard *pMainBlackboard) | |
| { | |
| auto &areaConfigurationToValidate = getAreaConfiguration(pConfigurableElement); | |
| // Delegate | |
| areaConfigurationToValidate->validate(pMainBlackboard); | |
| } | |
| // Ensure validity of all area configurations | |
| void CDomainConfiguration::validate(const CParameterBlackboard *pMainBlackboard) | |
| { | |
| for (auto &areaConfiguration : mAreaConfigurationList) { | |
| areaConfiguration->validate(pMainBlackboard); | |
| } | |
| } | |
| // Return configuration validity for given configurable element | |
| bool CDomainConfiguration::isValid(const CConfigurableElement *pConfigurableElement) const | |
| { | |
| // Get child configurable elemnt's area configuration | |
| auto &areaConfiguration = getAreaConfiguration(pConfigurableElement); | |
| ALWAYS_ASSERT(areaConfiguration != nullptr, "Configurable Element " | |
| << pConfigurableElement->getName() | |
| << " not found in any area Configuration"); | |
| return areaConfiguration->isValid(); | |
| } | |
| // Ensure validity of configurable element's area configuration by copying in from a valid one | |
| void CDomainConfiguration::validateAgainst(const CDomainConfiguration *pValidDomainConfiguration, | |
| const CConfigurableElement *pConfigurableElement) | |
| { | |
| // Retrieve related area configurations | |
| auto &areaConfigurationToValidate = getAreaConfiguration(pConfigurableElement); | |
| const auto &areaConfigurationToValidateAgainst = | |
| pValidDomainConfiguration->getAreaConfiguration(pConfigurableElement); | |
| // Delegate to area | |
| areaConfigurationToValidate->validateAgainst(areaConfigurationToValidateAgainst.get()); | |
| } | |
| void CDomainConfiguration::validateAgainst(const CDomainConfiguration *validDomainConfiguration) | |
| { | |
| ALWAYS_ASSERT(mAreaConfigurationList.size() == | |
| validDomainConfiguration->mAreaConfigurationList.size(), | |
| "Cannot validate domain configuration " | |
| << getPath() << " since area configuration list does not have the same size" | |
| "than the configuration list to check against"); | |
| for (const auto &configurationToValidateAgainst : | |
| validDomainConfiguration->mAreaConfigurationList) { | |
| // Get the area configuration associated to the configurable element of the | |
| // valid area configuration, it will assert if none found. | |
| auto configurableElement = configurationToValidateAgainst->getConfigurableElement(); | |
| auto &configurationToValidate = getAreaConfiguration(configurableElement); | |
| // Delegate to area | |
| configurationToValidate->validateAgainst(configurationToValidateAgainst.get()); | |
| } | |
| } | |
| // Dynamic data application | |
| bool CDomainConfiguration::isApplicable() const | |
| { | |
| const CCompoundRule *pRule = getRule(); | |
| return pRule && pRule->matches(); | |
| } | |
| // Merge existing configurations to given configurable element ones | |
| void CDomainConfiguration::merge(CConfigurableElement *pToConfigurableElement, | |
| CConfigurableElement *pFromConfigurableElement) | |
| { | |
| // Retrieve related area configurations | |
| auto &areaConfigurationToMergeTo = getAreaConfiguration(pToConfigurableElement); | |
| const auto &areaConfigurationToMergeFrom = getAreaConfiguration(pFromConfigurableElement); | |
| // Do the merge | |
| areaConfigurationToMergeFrom->copyToOuter(areaConfigurationToMergeTo.get()); | |
| } | |
| // Domain splitting | |
| void CDomainConfiguration::split(CConfigurableElement *pFromConfigurableElement) | |
| { | |
| // Retrieve related area configuration | |
| const auto &areaConfigurationToSplitFrom = getAreaConfiguration(pFromConfigurableElement); | |
| // Go through children areas to copy configuration data to them | |
| size_t uiNbConfigurableElementChildren = pFromConfigurableElement->getNbChildren(); | |
| size_t uiChild; | |
| for (uiChild = 0; uiChild < uiNbConfigurableElementChildren; uiChild++) { | |
| CConfigurableElement *pToChildConfigurableElement = | |
| static_cast<CConfigurableElement *>(pFromConfigurableElement->getChild(uiChild)); | |
| // Get child configurable elemnt's area configuration | |
| auto &childAreaConfiguration = getAreaConfiguration(pToChildConfigurableElement); | |
| // Do the copy | |
| childAreaConfiguration->copyFromOuter(areaConfigurationToSplitFrom.get()); | |
| } | |
| } | |
| const CDomainConfiguration::AreaConfiguration &CDomainConfiguration::getAreaConfiguration( | |
| const CConfigurableElement *pConfigurableElement) const | |
| { | |
| const auto &it = find_if(begin(mAreaConfigurationList), end(mAreaConfigurationList), | |
| [&](const AreaConfiguration &conf) { | |
| return conf->getConfigurableElement() == pConfigurableElement; | |
| }); | |
| ALWAYS_ASSERT(it != end(mAreaConfigurationList), | |
| "Configurable Element " << pConfigurableElement->getName() | |
| << " not found in Domain Configuration list"); | |
| return *it; | |
| } | |
| CDomainConfiguration::AreaConfigurations::iterator CDomainConfiguration:: | |
| findAreaConfigurationByPath(const std::string &configurableElementPath) | |
| { | |
| auto areaConfiguration = | |
| find_if(begin(mAreaConfigurationList), end(mAreaConfigurationList), | |
| [&](const AreaConfiguration &conf) { | |
| return conf->getConfigurableElement()->getPath() == configurableElementPath; | |
| }); | |
| return areaConfiguration; | |
| } | |
| // Rule | |
| const CCompoundRule *CDomainConfiguration::getRule() const | |
| { | |
| if (getNbChildren()) { | |
| // Rule created | |
| return static_cast<const CCompoundRule *>(getChild(ECompoundRule)); | |
| } | |
| return nullptr; | |
| } | |
| CCompoundRule *CDomainConfiguration::getRule() | |
| { | |
| if (getNbChildren()) { | |
| // Rule created | |
| return static_cast<CCompoundRule *>(getChild(ECompoundRule)); | |
| } | |
| return nullptr; | |
| } | |
| void CDomainConfiguration::setRule(CCompoundRule *pRule) | |
| { | |
| CCompoundRule *pOldRule = getRule(); | |
| if (pOldRule) { | |
| // Remove previous rule | |
| removeChild(pOldRule); | |
| delete pOldRule; | |
| } | |
| // Set new one | |
| if (pRule) { | |
| // Chain | |
| addChild(pRule); | |
| } | |
| } |