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