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 "ConfigurableDomain.h" 31 #include "DomainConfiguration.h" 32 #include "ConfigurableElement.h" 33 #include "ConfigurationAccessContext.h" 34 #include "XmlDomainSerializingContext.h" 35 #include "XmlDomainImportContext.h" 36 #include "XmlDomainExportContext.h" 37 #include "Utility.h" 38 #include "AlwaysAssert.hpp" 39 #include <cassert> 40 41 #define base CElement 42 43 using std::string; 44 45 CConfigurableDomain::CConfigurableDomain(const string &strName) : base(strName) 46 { 47 } 48 49 CConfigurableDomain::~CConfigurableDomain() 50 { 51 // Remove all configurable elements 52 ConfigurableElementListIterator it; 53 54 for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) { 55 56 CConfigurableElement *pConfigurableElement = *it; 57 58 // Remove from configurable element 59 pConfigurableElement->removeAttachedConfigurableDomain(this); 60 } 61 62 // Remove all associated syncer sets 63 ConfigurableElementToSyncerSetMapIterator mapIt; 64 65 for (mapIt = _configurableElementToSyncerSetMap.begin(); 66 mapIt != _configurableElementToSyncerSetMap.end(); ++mapIt) { 67 68 delete mapIt->second; 69 } 70 } 71 72 string CConfigurableDomain::getKind() const 73 { 74 return "ConfigurableDomain"; 75 } 76 77 bool CConfigurableDomain::childrenAreDynamic() const 78 { 79 return true; 80 } 81 82 // Content dumping 83 string CConfigurableDomain::logValue(utility::ErrorContext & /*ctx*/) const 84 { 85 return string("{") + 86 87 "Sequence aware: " + (_bSequenceAware ? "yes" : "no") + 88 89 ", Last applied configuration: " + 90 (_pLastAppliedConfiguration ? _pLastAppliedConfiguration->getName() : "<none>") + 91 92 "}"; 93 } 94 95 // Sequence awareness 96 void CConfigurableDomain::setSequenceAwareness(bool bSequenceAware) 97 { 98 if (_bSequenceAware != bSequenceAware) { 99 100 _bSequenceAware = bSequenceAware; 101 } 102 } 103 104 bool CConfigurableDomain::getSequenceAwareness() const 105 { 106 return _bSequenceAware; 107 } 108 109 // From IXmlSource 110 void CConfigurableDomain::toXml(CXmlElement &xmlElement, 111 CXmlSerializingContext &serializingContext) const 112 { 113 base::toXml(xmlElement, serializingContext); 114 115 // Sequence awareness 116 xmlElement.setAttribute("SequenceAware", _bSequenceAware); 117 } 118 119 void CConfigurableDomain::childrenToXml(CXmlElement &xmlElement, 120 CXmlSerializingContext &serializingContext) const 121 { 122 // Configurations 123 composeDomainConfigurations(xmlElement, serializingContext); 124 125 // Configurable Elements 126 composeConfigurableElements(xmlElement); 127 128 // Settings 129 composeSettings(xmlElement, static_cast<CXmlDomainExportContext &>(serializingContext)); 130 } 131 132 // XML composing 133 void CConfigurableDomain::composeDomainConfigurations( 134 CXmlElement &xmlElement, CXmlSerializingContext &serializingContext) const 135 { 136 // Create Configurations element 137 CXmlElement xmlConfigurationsElement; 138 139 xmlElement.createChild(xmlConfigurationsElement, "Configurations"); 140 141 // Delegate to base 142 base::childrenToXml(xmlConfigurationsElement, serializingContext); 143 } 144 145 void CConfigurableDomain::composeConfigurableElements(CXmlElement &xmlElement) const 146 { 147 // Create ConfigurableElements element 148 CXmlElement xmlConfigurableElementsElement; 149 150 xmlElement.createChild(xmlConfigurableElementsElement, "ConfigurableElements"); 151 152 // Serialize out all configurable elements settings 153 ConfigurableElementListIterator it; 154 155 for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) { 156 157 const CConfigurableElement *pConfigurableElement = *it; 158 159 // Create corresponding XML child element 160 CXmlElement xmlChildConfigurableElement; 161 162 xmlConfigurableElementsElement.createChild(xmlChildConfigurableElement, 163 "ConfigurableElement"); 164 165 // Set Path attribute 166 xmlChildConfigurableElement.setAttribute("Path", pConfigurableElement->getPath()); 167 } 168 } 169 170 void CConfigurableDomain::composeSettings(CXmlElement &xmlElement, 171 CXmlDomainExportContext &context) const 172 { 173 if (!context.withSettings()) { 174 175 return; 176 } 177 178 // Create Settings element 179 CXmlElement xmlSettingsElement; 180 181 xmlElement.createChild(xmlSettingsElement, "Settings"); 182 183 // Serialize out all configurations settings 184 size_t uiNbConfigurations = getNbChildren(); 185 size_t uiChildConfiguration; 186 187 for (uiChildConfiguration = 0; uiChildConfiguration < uiNbConfigurations; 188 uiChildConfiguration++) { 189 190 const CDomainConfiguration *pDomainConfiguration = 191 static_cast<const CDomainConfiguration *>(getChild(uiChildConfiguration)); 192 193 // Create child xml element for that configuration 194 CXmlElement xmlConfigurationSettingsElement; 195 196 xmlSettingsElement.createChild(xmlConfigurationSettingsElement, 197 pDomainConfiguration->getXmlElementName()); 198 199 // Set its name attribute 200 xmlConfigurationSettingsElement.setNameAttribute(pDomainConfiguration->getName()); 201 202 // Serialize out configuration settings 203 pDomainConfiguration->composeSettings(xmlConfigurationSettingsElement, context); 204 } 205 } 206 207 // From IXmlSink 208 bool CConfigurableDomain::fromXml(const CXmlElement &xmlElement, 209 CXmlSerializingContext &serializingContext) 210 { 211 // Context 212 CXmlDomainImportContext &xmlDomainImportContext = 213 static_cast<CXmlDomainImportContext &>(serializingContext); 214 215 // Sequence awareness (optional) 216 xmlElement.getAttribute("SequenceAware", _bSequenceAware); 217 218 std::string name; 219 xmlElement.getAttribute("Name", name); 220 setName(name); 221 222 // Local parsing. Do not dig 223 if (!parseDomainConfigurations(xmlElement, xmlDomainImportContext) || 224 !parseConfigurableElements(xmlElement, xmlDomainImportContext) || 225 !parseSettings(xmlElement, xmlDomainImportContext)) { 226 227 return false; 228 } 229 230 // All provided configurations are parsed 231 // Attempt validation on areas of non provided configurations for all configurable elements if 232 // required 233 if (xmlDomainImportContext.autoValidationRequired()) { 234 235 autoValidateAll(); 236 } 237 238 return true; 239 } 240 241 // XML parsing 242 bool CConfigurableDomain::parseDomainConfigurations(const CXmlElement &xmlElement, 243 CXmlDomainImportContext &serializingContext) 244 { 245 // We're supposedly clean 246 assert(_configurableElementList.empty()); 247 248 // Get Configurations element 249 CXmlElement xmlConfigurationsElement; 250 251 xmlElement.getChildElement("Configurations", xmlConfigurationsElement); 252 253 // Parse it and create domain configuration objects 254 return base::fromXml(xmlConfigurationsElement, serializingContext); 255 } 256 257 // Parse configurable elements 258 bool CConfigurableDomain::parseConfigurableElements(const CXmlElement &xmlElement, 259 CXmlDomainImportContext &serializingContext) 260 { 261 CSystemClass &systemClass = serializingContext.getSystemClass(); 262 263 // Get ConfigurableElements element 264 CXmlElement xmlConfigurableElementsElement; 265 xmlElement.getChildElement("ConfigurableElements", xmlConfigurableElementsElement); 266 267 // Parse it and associate found configurable elements to it 268 CXmlElement::CChildIterator it(xmlConfigurableElementsElement); 269 270 CXmlElement xmlConfigurableElementElement; 271 272 while (it.next(xmlConfigurableElementElement)) { 273 274 // Locate configurable element 275 string strConfigurableElementPath; 276 xmlConfigurableElementElement.getAttribute("Path", strConfigurableElementPath); 277 278 CPathNavigator pathNavigator(strConfigurableElementPath); 279 string strError; 280 281 // Is there an element and does it match system class name? 282 if (!pathNavigator.navigateThrough(systemClass.getName(), strError)) { 283 284 serializingContext.setError( 285 "Could not find configurable element of path " + strConfigurableElementPath + 286 " from ConfigurableDomain description " + getName() + " (" + strError + ")"); 287 288 return false; 289 } 290 // Browse system class for configurable element 291 CConfigurableElement *pConfigurableElement = 292 static_cast<CConfigurableElement *>(systemClass.findDescendant(pathNavigator)); 293 294 if (!pConfigurableElement) { 295 296 serializingContext.setError("Could not find configurable element of path " + 297 strConfigurableElementPath + 298 " from ConfigurableDomain description " + getName()); 299 300 return false; 301 } 302 // Add found element to domain 303 core::Results infos; 304 if (!addConfigurableElement(pConfigurableElement, NULL, infos)) { 305 306 strError = utility::asString(infos); 307 serializingContext.setError(strError); 308 309 return false; 310 } 311 } 312 313 return true; 314 } 315 316 // Parse settings 317 bool CConfigurableDomain::parseSettings(const CXmlElement &xmlElement, 318 CXmlDomainImportContext &serializingContext) 319 { 320 // Check we actually need to parse configuration settings 321 if (!serializingContext.withSettings()) { 322 323 // No parsing required 324 return true; 325 } 326 327 // Get Settings element 328 CXmlElement xmlSettingsElement; 329 if (!xmlElement.getChildElement("Settings", xmlSettingsElement)) { 330 331 // No settings, bail out successfully 332 return true; 333 } 334 335 // Parse configuration settings 336 CXmlElement::CChildIterator it(xmlSettingsElement); 337 338 CXmlElement xmlConfigurationSettingsElement; 339 340 while (it.next(xmlConfigurationSettingsElement)) { 341 // Get domain configuration 342 CDomainConfiguration *pDomainConfiguration = static_cast<CDomainConfiguration *>( 343 findChild(xmlConfigurationSettingsElement.getNameAttribute())); 344 345 if (!pDomainConfiguration) { 346 347 serializingContext.setError("Could not find domain configuration referred to by" 348 " configurable domain \"" + 349 getName() + "\"."); 350 351 return false; 352 } 353 // Have domain configuration parse settings for all configurable elements 354 if (!pDomainConfiguration->parseSettings(xmlConfigurationSettingsElement, 355 serializingContext)) { 356 357 return false; 358 } 359 } 360 361 return true; 362 } 363 // Configurable elements association 364 bool CConfigurableDomain::addConfigurableElement(CConfigurableElement *pConfigurableElement, 365 const CParameterBlackboard *pMainBlackboard, 366 core::Results &infos) 367 { 368 // Already associated? 369 if (containsConfigurableElement(pConfigurableElement)) { 370 371 infos.push_back("Configurable element " + pConfigurableElement->getPath() + 372 " already associated to configuration domain " + getName()); 373 374 return false; 375 } 376 377 // Already owned? 378 if (pConfigurableElement->belongsTo(this)) { 379 380 infos.push_back("Configurable element " + pConfigurableElement->getPath() + 381 " already owned by configuration domain " + getName()); 382 383 return false; 384 } 385 386 // Do add 387 doAddConfigurableElement(pConfigurableElement, infos, pMainBlackboard); 388 389 return true; 390 } 391 392 bool CConfigurableDomain::removeConfigurableElement(CConfigurableElement *pConfigurableElement, 393 string &strError) 394 { 395 // Not associated? 396 if (!containsConfigurableElement(pConfigurableElement)) { 397 398 strError = "Configurable element " + pConfigurableElement->getPath() + 399 " not associated to configuration domain " + getName(); 400 401 return false; 402 } 403 404 // Do remove 405 doRemoveConfigurableElement(pConfigurableElement, true); 406 407 return true; 408 } 409 410 /** 411 * Blackboard Configuration and Base Offset retrieval. 412 * 413 * This method fetches the Blackboard associated to the ConfigurableElement 414 * given in parameter, for a specific Configuration. The ConfigurableElement 415 * must belong to the Domain. If a Blackboard is found, the base offset of 416 * the ConfigurableElement is returned as well. This base offset corresponds to 417 * the offset of the ancestor of the ConfigurableElement associated to the Configuration. 418 * 419 * @param[in] strConfiguration Name of the Configuration. 420 * @param[in] pCandidateDescendantConfigurableElement Pointer to a CConfigurableElement that 421 * belongs to the Domain. 422 * @param[out] baseOffset The base offset of the CConfigurableElement. 423 * @param[out] bIsLastApplied Boolean indicating that the Configuration is 424 * the last one applied of the Domain. 425 * @param[out] strError Error message 426 * 427 * return Pointer to the Blackboard of the Configuration. 428 */ 429 CParameterBlackboard *CConfigurableDomain::findConfigurationBlackboard( 430 const string &strConfiguration, 431 const CConfigurableElement *pCandidateDescendantConfigurableElement, size_t &baseOffset, 432 bool &bIsLastApplied, string &strError) const 433 { 434 // Find Configuration 435 const CDomainConfiguration *pDomainConfiguration = 436 static_cast<const CDomainConfiguration *>(findChild(strConfiguration)); 437 438 if (!pDomainConfiguration) { 439 440 strError = "Domain configuration " + strConfiguration + " not found"; 441 442 return NULL; 443 } 444 445 // Parse all configurable elements 446 ConfigurableElementListIterator it; 447 448 for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) { 449 450 const CConfigurableElement *pAssociatedConfigurableElement = *it; 451 452 // Check if the the associated element is the configurable element or one of its ancestors 453 if ((pCandidateDescendantConfigurableElement == pAssociatedConfigurableElement) || 454 (pCandidateDescendantConfigurableElement->isDescendantOf( 455 pAssociatedConfigurableElement))) { 456 457 baseOffset = pAssociatedConfigurableElement->getOffset(); 458 bIsLastApplied = (pDomainConfiguration == _pLastAppliedConfiguration); 459 460 return pDomainConfiguration->getBlackboard(pAssociatedConfigurableElement); 461 } 462 } 463 464 strError = "Element not associated to the Domain"; 465 466 return NULL; 467 } 468 469 // Domain splitting 470 bool CConfigurableDomain::split(CConfigurableElement *pConfigurableElement, core::Results &infos) 471 { 472 // Not associated? 473 if (!containsConfigurableElement(pConfigurableElement)) { 474 475 std::string strError = "Configurable element " + pConfigurableElement->getPath() + 476 " not associated to configuration domain " + getName(); 477 infos.push_back(strError); 478 479 return false; 480 } 481 482 // Create sub domain areas for all configurable element's children 483 size_t uiNbConfigurableElementChildren = pConfigurableElement->getNbChildren(); 484 485 if (!uiNbConfigurableElementChildren) { 486 487 std::string strError = "Configurable element " + pConfigurableElement->getPath() + 488 " has no children to split configurable domain to"; 489 infos.push_back(strError); 490 491 return false; 492 } 493 494 for (size_t uiChild = 0; uiChild < uiNbConfigurableElementChildren; uiChild++) { 495 496 CConfigurableElement *pChildConfigurableElement = 497 static_cast<CConfigurableElement *>(pConfigurableElement->getChild(uiChild)); 498 499 doAddConfigurableElement(pChildConfigurableElement, infos); 500 } 501 502 // Delegate to configurations 503 size_t uiNbConfigurations = getNbChildren(); 504 505 for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) { 506 507 CDomainConfiguration *pDomainConfiguration = 508 static_cast<CDomainConfiguration *>(getChild(uiChild)); 509 510 pDomainConfiguration->split(pConfigurableElement); 511 } 512 513 // Remove given configurable element from this domain 514 // Note: we shouldn't need to recompute the sync set in that case, as the splitted element 515 // should include the syncers of its children elements 516 doRemoveConfigurableElement(pConfigurableElement, false); 517 518 return true; 519 } 520 521 // Check if there is a pending configuration for this domain: i.e. an applicable configuration 522 // different from the last applied configuration 523 const CDomainConfiguration *CConfigurableDomain::getPendingConfiguration() const 524 { 525 const CDomainConfiguration *pApplicableDomainConfiguration = 526 findApplicableDomainConfiguration(); 527 528 if (pApplicableDomainConfiguration) { 529 530 // Check not the last one before applying 531 if (!_pLastAppliedConfiguration || 532 (_pLastAppliedConfiguration != pApplicableDomainConfiguration)) { 533 534 return pApplicableDomainConfiguration; 535 } 536 } 537 538 return NULL; 539 } 540 541 // Configuration application if required 542 void CConfigurableDomain::apply(CParameterBlackboard *pParameterBlackboard, CSyncerSet *pSyncerSet, 543 bool bForce, std::string &strInfo) const 544 { 545 // Apply configuration only if the blackboard will 546 // be synchronized either now or by syncerSet. 547 if (!pSyncerSet ^ _bSequenceAware) { 548 // The configuration can not be syncronised 549 return; 550 } 551 552 if (bForce) { 553 // Force a configuration restore by forgetting about last applied configuration 554 _pLastAppliedConfiguration = NULL; 555 } 556 const CDomainConfiguration *pApplicableDomainConfiguration = 557 findApplicableDomainConfiguration(); 558 559 if (pApplicableDomainConfiguration) { 560 561 // Check not the last one before applying 562 if (!_pLastAppliedConfiguration || 563 _pLastAppliedConfiguration != pApplicableDomainConfiguration) { 564 565 strInfo = "Applying configuration '" + pApplicableDomainConfiguration->getName() + 566 "' from domain '" + getName() + "'"; 567 568 // Check if we need to synchronize during restore 569 bool bSync = !pSyncerSet && _bSequenceAware; 570 571 // Do the restore 572 pApplicableDomainConfiguration->restore(pParameterBlackboard, bSync, NULL); 573 574 // Record last applied configuration 575 _pLastAppliedConfiguration = pApplicableDomainConfiguration; 576 577 // Check we need to provide syncer set to caller 578 if (pSyncerSet && !_bSequenceAware) { 579 580 // Since we applied changes, add our own sync set to the given one 581 *pSyncerSet += _syncerSet; 582 } 583 } 584 } 585 } 586 587 // Return applicable configuration validity for given configurable element 588 bool CConfigurableDomain::isApplicableConfigurationValid( 589 const CConfigurableElement *pConfigurableElement) const 590 { 591 const CDomainConfiguration *pApplicableDomainConfiguration = 592 findApplicableDomainConfiguration(); 593 594 return pApplicableDomainConfiguration && 595 pApplicableDomainConfiguration->isValid(pConfigurableElement); 596 } 597 598 // In case configurable element was removed 599 void CConfigurableDomain::computeSyncSet() 600 { 601 // Clean sync set first 602 _syncerSet.clear(); 603 604 // Add syncer sets for all associated configurable elements 605 ConfigurableElementToSyncerSetMapIterator mapIt; 606 607 for (mapIt = _configurableElementToSyncerSetMap.begin(); 608 mapIt != _configurableElementToSyncerSetMap.end(); ++mapIt) { 609 610 const CSyncerSet *pSyncerSet = mapIt->second; 611 612 _syncerSet += *pSyncerSet; 613 } 614 } 615 616 // Configuration Management 617 bool CConfigurableDomain::createConfiguration(const string &strName, 618 const CParameterBlackboard *pMainBlackboard, 619 string &strError) 620 { 621 // Already exists? 622 if (findChild(strName)) { 623 624 strError = "Already existing configuration"; 625 626 return false; 627 } 628 629 // Creation 630 CDomainConfiguration *pDomainConfiguration = new CDomainConfiguration(strName); 631 632 // Configurable elements association 633 ConfigurableElementListIterator it; 634 635 for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) { 636 637 const CConfigurableElement *pConfigurableElement = *it; 638 ; 639 640 // Retrieve associated syncer set 641 CSyncerSet *pSyncerSet = getSyncerSet(pConfigurableElement); 642 643 // Associate to configuration 644 pDomainConfiguration->addConfigurableElement(pConfigurableElement, pSyncerSet); 645 } 646 647 // Hierarchy 648 addChild(pDomainConfiguration); 649 650 // Ensure validity of fresh new domain configuration 651 // Attempt auto validation, so that the user gets his/her own settings by defaults 652 if (!autoValidateConfiguration(pDomainConfiguration)) { 653 654 // No valid configuration found to copy in from, validate againt main blackboard (will 655 // concerned remaining invalid parts) 656 pDomainConfiguration->validate(pMainBlackboard); 657 } 658 659 return true; 660 } 661 662 bool CConfigurableDomain::deleteConfiguration(const string &strName, string &strError) 663 { 664 CDomainConfiguration *pDomainConfiguration = findConfiguration(strName, strError); 665 666 if (!pDomainConfiguration) { 667 668 return false; 669 } 670 671 // Was the last applied? 672 if (pDomainConfiguration == _pLastAppliedConfiguration) { 673 674 // Forget about it 675 _pLastAppliedConfiguration = NULL; 676 } 677 678 // Hierarchy 679 removeChild(pDomainConfiguration); 680 681 // Destroy 682 delete pDomainConfiguration; 683 684 return true; 685 } 686 687 void CConfigurableDomain::listAssociatedToElements(string &strResult) const 688 { 689 ConfigurableElementListIterator it; 690 691 // Browse all configurable elements 692 for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) { 693 694 const CConfigurableElement *pConfigurableElement = *it; 695 696 strResult += pConfigurableElement->getPath() + "\n"; 697 } 698 } 699 700 bool CConfigurableDomain::renameConfiguration(const string &strName, const string &strNewName, 701 string &strError) 702 { 703 CDomainConfiguration *pDomainConfiguration = findConfiguration(strName, strError); 704 705 if (!pDomainConfiguration) { 706 707 return false; 708 } 709 710 // Rename 711 return pDomainConfiguration->rename(strNewName, strError); 712 } 713 714 bool CConfigurableDomain::restoreConfiguration(const string &configurationName, 715 CParameterBlackboard *mainBlackboard, bool autoSync, 716 core::Results &errors) const 717 { 718 string error; 719 720 const CDomainConfiguration *configuration = findConfiguration(configurationName, error); 721 722 if (configuration == NULL) { 723 724 errors.push_back(error); 725 return false; 726 } 727 728 // Delegate 729 bool bSuccess = configuration->restore(mainBlackboard, autoSync && _bSequenceAware, &errors); 730 731 // Record last applied configuration 732 _pLastAppliedConfiguration = configuration; 733 734 // Synchronize 735 if (autoSync && !_bSequenceAware) { 736 737 bSuccess &= _syncerSet.sync(*mainBlackboard, false, &errors); 738 } 739 return bSuccess; 740 } 741 742 bool CConfigurableDomain::saveConfiguration(const string &strName, 743 const CParameterBlackboard *pMainBlackboard, 744 string &strError) 745 { 746 // Find Domain configuration 747 CDomainConfiguration *pDomainConfiguration = findConfiguration(strName, strError); 748 749 if (!pDomainConfiguration) { 750 751 return false; 752 } 753 754 // Delegate 755 pDomainConfiguration->save(pMainBlackboard); 756 757 return true; 758 } 759 760 bool CConfigurableDomain::setElementSequence(const string &strConfiguration, 761 const std::vector<string> &astrNewElementSequence, 762 string &strError) 763 { 764 // Find Domain configuration 765 CDomainConfiguration *pDomainConfiguration = findConfiguration(strConfiguration, strError); 766 767 if (!pDomainConfiguration) { 768 769 return false; 770 } 771 772 // Delegate to configuration 773 return pDomainConfiguration->setElementSequence(astrNewElementSequence, strError); 774 } 775 776 bool CConfigurableDomain::getElementSequence(const string &strConfiguration, 777 string &strResult) const 778 { 779 // Find Domain configuration 780 const CDomainConfiguration *pDomainConfiguration = 781 findConfiguration(strConfiguration, strResult); 782 783 if (!pDomainConfiguration) { 784 785 return false; 786 } 787 788 // Delegate to configuration 789 pDomainConfiguration->getElementSequence(strResult); 790 791 return true; 792 } 793 794 bool CConfigurableDomain::setApplicationRule( 795 const string &strConfiguration, const string &strApplicationRule, 796 const CSelectionCriteriaDefinition *pSelectionCriteriaDefinition, string &strError) 797 { 798 // Find Domain configuration 799 CDomainConfiguration *pDomainConfiguration = findConfiguration(strConfiguration, strError); 800 801 if (!pDomainConfiguration) { 802 803 return false; 804 } 805 806 // Delegate to configuration 807 return pDomainConfiguration->setApplicationRule(strApplicationRule, 808 pSelectionCriteriaDefinition, strError); 809 } 810 811 bool CConfigurableDomain::clearApplicationRule(const string &strConfiguration, string &strError) 812 { 813 // Find Domain configuration 814 CDomainConfiguration *pDomainConfiguration = findConfiguration(strConfiguration, strError); 815 816 if (!pDomainConfiguration) { 817 818 return false; 819 } 820 821 // Delegate to configuration 822 pDomainConfiguration->clearApplicationRule(); 823 824 return true; 825 } 826 827 bool CConfigurableDomain::getApplicationRule(const string &strConfiguration, 828 string &strResult) const 829 { 830 // Find Domain configuration 831 const CDomainConfiguration *pDomainConfiguration = 832 findConfiguration(strConfiguration, strResult); 833 834 if (!pDomainConfiguration) { 835 836 return false; 837 } 838 839 // Delegate to configuration 840 strResult = pDomainConfiguration->getApplicationRule(); 841 842 return true; 843 } 844 845 // Last applied configuration 846 string CConfigurableDomain::getLastAppliedConfigurationName() const 847 { 848 if (_pLastAppliedConfiguration) { 849 850 return _pLastAppliedConfiguration->getName(); 851 } 852 return "<none>"; 853 } 854 855 // Pending configuration 856 string CConfigurableDomain::getPendingConfigurationName() const 857 { 858 const CDomainConfiguration *pApplicableDomainConfiguration = 859 findApplicableDomainConfiguration(); 860 861 if (!pApplicableDomainConfiguration) { 862 863 // No configuration is pending 864 return "<none>"; 865 } 866 867 // Check it will be applied 868 if (pApplicableDomainConfiguration != _pLastAppliedConfiguration) { 869 870 // Found config will get applied 871 return pApplicableDomainConfiguration->getName(); 872 } else { 873 874 // Same configuration as current 875 return ""; 876 } 877 } 878 879 // Ensure validity on whole domain from main blackboard 880 void CConfigurableDomain::validate(const CParameterBlackboard *pMainBlackboard) 881 { 882 883 // Propagate 884 size_t uiNbConfigurations = getNbChildren(); 885 886 for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) { 887 888 CDomainConfiguration *pDomainConfiguration = 889 static_cast<CDomainConfiguration *>(getChild(uiChild)); 890 891 pDomainConfiguration->validate(pMainBlackboard); 892 } 893 } 894 895 // Ensure validity on areas related to configurable element 896 void CConfigurableDomain::validateAreas(const CConfigurableElement *pConfigurableElement, 897 const CParameterBlackboard *pMainBlackboard) 898 { 899 // Propagate 900 size_t uiNbConfigurations = getNbChildren(); 901 902 for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) { 903 904 CDomainConfiguration *pDomainConfiguration = 905 static_cast<CDomainConfiguration *>(getChild(uiChild)); 906 907 pDomainConfiguration->validate(pConfigurableElement, pMainBlackboard); 908 } 909 } 910 911 // Attempt validation for all configurable element's areas, relying on already existing valid 912 // configuration inside domain 913 void CConfigurableDomain::autoValidateAll() 914 { 915 // Validate 916 ConfigurableElementListIterator it; 917 918 // Browse all configurable elements for configuration validation 919 for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) { 920 921 const CConfigurableElement *pConfigurableElement = *it; 922 923 // Auto validate element 924 autoValidateAreas(pConfigurableElement); 925 } 926 } 927 928 // Attempt validation for configurable element's areas, relying on already existing valid 929 // configuration inside domain 930 void CConfigurableDomain::autoValidateAreas(const CConfigurableElement *pConfigurableElement) 931 { 932 // Find first valid configuration for given configurable element 933 const CDomainConfiguration *pValidDomainConfiguration = 934 findValidDomainConfiguration(pConfigurableElement); 935 936 // No valid configuration found, give up 937 if (!pValidDomainConfiguration) { 938 939 return; 940 } 941 942 // Validate all other configurations against found one, if any 943 size_t uiNbConfigurations = getNbChildren(); 944 945 for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) { 946 947 CDomainConfiguration *pDomainConfiguration = 948 static_cast<CDomainConfiguration *>(getChild(uiChild)); 949 950 if (pDomainConfiguration != pValidDomainConfiguration && 951 !pDomainConfiguration->isValid(pConfigurableElement)) { 952 // Validate 953 pDomainConfiguration->validateAgainst(pValidDomainConfiguration, pConfigurableElement); 954 } 955 } 956 } 957 958 // Attempt configuration validation for all configurable elements' areas, relying on already 959 // existing valid configuration inside domain 960 bool CConfigurableDomain::autoValidateConfiguration(CDomainConfiguration *pDomainConfiguration) 961 { 962 // Find another configuration than this one, that ought to be valid! 963 size_t uiNbConfigurations = getNbChildren(); 964 965 for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) { 966 967 const CDomainConfiguration *pPotententialValidDomainConfiguration = 968 static_cast<const CDomainConfiguration *>(getChild(uiChild)); 969 970 if (pPotententialValidDomainConfiguration != pDomainConfiguration) { 971 972 // Validate against it 973 pDomainConfiguration->validateAgainst(pPotententialValidDomainConfiguration); 974 975 return true; 976 } 977 } 978 return false; 979 } 980 981 // Search for a valid configuration for given configurable element 982 const CDomainConfiguration *CConfigurableDomain::findValidDomainConfiguration( 983 const CConfigurableElement *pConfigurableElement) const 984 { 985 size_t uiNbConfigurations = getNbChildren(); 986 987 for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) { 988 989 const CDomainConfiguration *pDomainConfiguration = 990 static_cast<const CDomainConfiguration *>(getChild(uiChild)); 991 992 if (pDomainConfiguration->isValid(pConfigurableElement)) { 993 994 return pDomainConfiguration; 995 } 996 } 997 return NULL; 998 } 999 1000 // Search for an applicable configuration 1001 const CDomainConfiguration *CConfigurableDomain::findApplicableDomainConfiguration() const 1002 { 1003 size_t uiNbConfigurations = getNbChildren(); 1004 1005 for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) { 1006 1007 const CDomainConfiguration *pDomainConfiguration = 1008 static_cast<const CDomainConfiguration *>(getChild(uiChild)); 1009 1010 if (pDomainConfiguration->isApplicable()) { 1011 1012 return pDomainConfiguration; 1013 } 1014 } 1015 return NULL; 1016 } 1017 1018 // Gather set of configurable elements 1019 void CConfigurableDomain::gatherConfigurableElements( 1020 std::set<const CConfigurableElement *> &configurableElementSet) const 1021 { 1022 // Insert all configurable elements 1023 configurableElementSet.insert(_configurableElementList.begin(), _configurableElementList.end()); 1024 } 1025 1026 // Check configurable element already attached 1027 bool CConfigurableDomain::containsConfigurableElement( 1028 const CConfigurableElement *pConfigurableCandidateElement) const 1029 { 1030 ConfigurableElementListIterator it; 1031 1032 // Browse all configurable elements for comparison 1033 for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) { 1034 1035 if (pConfigurableCandidateElement == *it) { 1036 1037 return true; 1038 } 1039 } 1040 return false; 1041 } 1042 1043 // Merge any descended configurable element to this one with this one 1044 void CConfigurableDomain::mergeAlreadyAssociatedDescendantConfigurableElements( 1045 CConfigurableElement *newElement, core::Results &infos) 1046 { 1047 std::list<CConfigurableElement *> mergedConfigurableElementList; 1048 1049 ConfigurableElementListIterator it; 1050 1051 // Browse all configurable elements (new one not yet in the list!) 1052 for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) { 1053 1054 CConfigurableElement *pConfigurablePotentialDescendantElement = *it; 1055 1056 if (pConfigurablePotentialDescendantElement->isDescendantOf(newElement)) { 1057 1058 infos.push_back("In domain '" + getName() + 1059 "', merging descendant configurable element's configurations '" + 1060 pConfigurablePotentialDescendantElement->getName() + 1061 "' into its ascendant '" + newElement->getName() + "' ones"); 1062 1063 // Merge configuration data 1064 mergeConfigurations(newElement, pConfigurablePotentialDescendantElement); 1065 1066 // Keep track for removal 1067 mergedConfigurableElementList.push_back(pConfigurablePotentialDescendantElement); 1068 } 1069 } 1070 1071 // Remove all merged elements (new one not yet in the list!) 1072 for (it = mergedConfigurableElementList.begin(); it != mergedConfigurableElementList.end(); 1073 ++it) { 1074 1075 CConfigurableElement *pMergedConfigurableElement = *it; 1076 1077 // Remove merged from configurable element from internal tracking list 1078 // Note: we shouldn't need to recompute the sync set in that case, as the merged to element 1079 // should include the syncers of merged from elements 1080 doRemoveConfigurableElement(pMergedConfigurableElement, false); 1081 } 1082 } 1083 1084 void CConfigurableDomain::mergeConfigurations(CConfigurableElement *pToConfigurableElement, 1085 CConfigurableElement *pFromConfigurableElement) 1086 { 1087 // Propagate to domain configurations 1088 size_t uiNbConfigurations = getNbChildren(); 1089 1090 for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) { 1091 1092 CDomainConfiguration *pDomainConfiguration = 1093 static_cast<CDomainConfiguration *>(getChild(uiChild)); 1094 1095 // Do the merge. 1096 pDomainConfiguration->merge(pToConfigurableElement, pFromConfigurableElement); 1097 } 1098 } 1099 1100 // Configurable elements association 1101 void CConfigurableDomain::doAddConfigurableElement(CConfigurableElement *pConfigurableElement, 1102 core::Results &infos, 1103 const CParameterBlackboard *pMainBlackboard) 1104 { 1105 // Inform configurable element 1106 pConfigurableElement->addAttachedConfigurableDomain(this); 1107 1108 // Create associated syncer set 1109 CSyncerSet *pSyncerSet = new CSyncerSet; 1110 1111 // Add to sync set the configurable element one 1112 pConfigurableElement->fillSyncerSet(*pSyncerSet); 1113 1114 // Store it 1115 _configurableElementToSyncerSetMap[pConfigurableElement] = pSyncerSet; 1116 1117 // Add it to global one 1118 _syncerSet += *pSyncerSet; 1119 1120 // Inform configurations 1121 size_t uiNbConfigurations = getNbChildren(); 1122 1123 for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) { 1124 1125 CDomainConfiguration *pDomainConfiguration = 1126 static_cast<CDomainConfiguration *>(getChild(uiChild)); 1127 1128 pDomainConfiguration->addConfigurableElement(pConfigurableElement, pSyncerSet); 1129 } 1130 1131 // Ensure area validity for that configurable element (if main blackboard provided) 1132 if (pMainBlackboard) { 1133 1134 infos.push_back("Validating domain '" + getName() + 1135 "' against main blackboard for configurable element '" + 1136 pConfigurableElement->getPath() + "'"); 1137 // Need to validate against main blackboard 1138 validateAreas(pConfigurableElement, pMainBlackboard); 1139 } 1140 1141 // Already associated descendend configurable elements need a merge of their configuration data 1142 mergeAlreadyAssociatedDescendantConfigurableElements(pConfigurableElement, infos); 1143 1144 // Add to list 1145 _configurableElementList.push_back(pConfigurableElement); 1146 } 1147 1148 void CConfigurableDomain::doRemoveConfigurableElement(CConfigurableElement *pConfigurableElement, 1149 bool bRecomputeSyncSet) 1150 { 1151 // Remove from list 1152 _configurableElementList.remove(pConfigurableElement); 1153 1154 // Remove associated syncer set 1155 CSyncerSet *pSyncerSet = getSyncerSet(pConfigurableElement); 1156 1157 _configurableElementToSyncerSetMap.erase(pConfigurableElement); 1158 1159 delete pSyncerSet; 1160 1161 // Inform configurable element 1162 pConfigurableElement->removeAttachedConfigurableDomain(this); 1163 1164 // Inform configurations 1165 size_t uiNbConfigurations = getNbChildren(); 1166 1167 for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) { 1168 1169 CDomainConfiguration *pDomainConfiguration = 1170 static_cast<CDomainConfiguration *>(getChild(uiChild)); 1171 1172 pDomainConfiguration->removeConfigurableElement(pConfigurableElement); 1173 } 1174 // Recompute our sync set if needed 1175 if (bRecomputeSyncSet) { 1176 1177 computeSyncSet(); 1178 } 1179 } 1180 1181 // Syncer set retrieval from configurable element 1182 CSyncerSet *CConfigurableDomain::getSyncerSet( 1183 const CConfigurableElement *pConfigurableElement) const 1184 { 1185 ConfigurableElementToSyncerSetMapIterator mapIt = 1186 _configurableElementToSyncerSetMap.find(pConfigurableElement); 1187 1188 ALWAYS_ASSERT(mapIt != _configurableElementToSyncerSetMap.end(), 1189 "Could not find syncer set for " << getName() << " configurable domain"); 1190 1191 return mapIt->second; 1192 } 1193 1194 // Configuration retrieval 1195 CDomainConfiguration *CConfigurableDomain::findConfiguration(const string &strConfiguration, 1196 string &strError) 1197 { 1198 CDomainConfiguration *pDomainConfiguration = 1199 static_cast<CDomainConfiguration *>(findChild(strConfiguration)); 1200 1201 if (!pDomainConfiguration) { 1202 1203 strError = "Domain configuration " + strConfiguration + " not found"; 1204 1205 return NULL; 1206 } 1207 return pDomainConfiguration; 1208 } 1209 1210 const CDomainConfiguration *CConfigurableDomain::findConfiguration(const string &strConfiguration, 1211 string &strError) const 1212 { 1213 const CDomainConfiguration *pDomainConfiguration = 1214 static_cast<const CDomainConfiguration *>(findChild(strConfiguration)); 1215 1216 if (!pDomainConfiguration) { 1217 1218 strError = "Domain configuration " + strConfiguration + " not found"; 1219 1220 return NULL; 1221 } 1222 return pDomainConfiguration; 1223 } 1224