| /* |
| * 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(NULL, strError)) { |
| |
| return false; |
| } |
| // Replace compound rule |
| setRule(ruleParser.grabRootRule()); |
| |
| return true; |
| } |
| |
| void CDomainConfiguration::clearApplicationRule() |
| { |
| // Replace compound rule |
| setRule(NULL); |
| } |
| |
| 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 NULL; |
| } |
| |
| CCompoundRule *CDomainConfiguration::getRule() |
| { |
| if (getNbChildren()) { |
| // Rule created |
| return static_cast<CCompoundRule *>(getChild(ECompoundRule)); |
| } |
| return NULL; |
| } |
| |
| 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); |
| } |
| } |