/* * 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); } }