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