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 47using std::string; 48 49CDomainConfiguration::CDomainConfiguration(const string &strName) : base(strName) 50{ 51} 52 53// Class kind 54string CDomainConfiguration::getKind() const 55{ 56 return "Configuration"; 57} 58 59// Child dynamic creation 60bool CDomainConfiguration::childrenAreDynamic() const 61{ 62 return true; 63} 64 65// XML configuration settings parsing 66bool 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 108void 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 134bool 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 189bool 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 214void CDomainConfiguration::addConfigurableElement(const CConfigurableElement *configurableElement, 215 const CSyncerSet *syncerSet) 216{ 217 mAreaConfigurationList.emplace_back(configurableElement->createAreaConfiguration(syncerSet)); 218} 219 220void CDomainConfiguration::removeConfigurableElement( 221 const CConfigurableElement *pConfigurableElement) 222{ 223 auto &areaConfigurationToRemove = getAreaConfiguration(pConfigurableElement); 224 225 mAreaConfigurationList.remove(areaConfigurationToRemove); 226} 227 228bool 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 260void 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 270bool 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 288void CDomainConfiguration::clearApplicationRule() 289{ 290 // Replace compound rule 291 setRule(NULL); 292} 293 294string 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 */ 312CParameterBlackboard *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 327void 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 336bool 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 346void 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 356void 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 364bool 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 377void 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 389void 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 408bool 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 416void 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 428void 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 450const 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 463CDomainConfiguration::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 475const 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 484CCompoundRule *CDomainConfiguration::getRule() 485{ 486 if (getNbChildren()) { 487 // Rule created 488 return static_cast<CCompoundRule *>(getChild(ECompoundRule)); 489 } 490 return NULL; 491} 492 493void 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