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