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 43using std::string; 44 45CConfigurableDomain::CConfigurableDomain(const string &strName) : base(strName) 46{ 47} 48 49CConfigurableDomain::~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 72string CConfigurableDomain::getKind() const 73{ 74 return "ConfigurableDomain"; 75} 76 77bool CConfigurableDomain::childrenAreDynamic() const 78{ 79 return true; 80} 81 82// Content dumping 83string 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 96void CConfigurableDomain::setSequenceAwareness(bool bSequenceAware) 97{ 98 if (_bSequenceAware != bSequenceAware) { 99 100 _bSequenceAware = bSequenceAware; 101 } 102} 103 104bool CConfigurableDomain::getSequenceAwareness() const 105{ 106 return _bSequenceAware; 107} 108 109// From IXmlSource 110void 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 119void 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 133void 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 145void 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 170void 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 208bool 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 242bool 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 258bool 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 317bool 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 364bool 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 392bool 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*/ 429CParameterBlackboard *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 470bool 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 523const 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 542void 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 588bool 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 599void 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 617bool 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 662bool 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 687void 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 700bool 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 714bool 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 742bool 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 760bool 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 776bool 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 794bool 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 811bool 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 827bool 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 846string CConfigurableDomain::getLastAppliedConfigurationName() const 847{ 848 if (_pLastAppliedConfiguration) { 849 850 return _pLastAppliedConfiguration->getName(); 851 } 852 return "<none>"; 853} 854 855// Pending configuration 856string 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 880void 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 896void 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 913void 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 930void 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 960bool 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 982const 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 1001const 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 1019void 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 1027bool 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 1044void 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 1084void 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 1101void 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 1148void 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 1182CSyncerSet *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 1195CDomainConfiguration *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 1210const 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