Home | History | Annotate | Download | only in parameter
      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