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() :
44    _bSequenceAware(false), _pLastAppliedConfiguration(NULL)
45{
46}
47
48CConfigurableDomain::CConfigurableDomain(const string& strName) : base(strName), _bSequenceAware(false), _pLastAppliedConfiguration(NULL)
49{
50}
51
52CConfigurableDomain::~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
74string CConfigurableDomain::getKind() const
75{
76    return "ConfigurableDomain";
77}
78
79bool CConfigurableDomain::childrenAreDynamic() const
80{
81    return true;
82}
83
84// Content dumping
85void 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
103void 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
113bool CConfigurableDomain::getSequenceAwareness() const
114{
115    return _bSequenceAware;
116}
117
118// From IXmlSource
119void CConfigurableDomain::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
120{
121    base::toXml(xmlElement, serializingContext);
122
123    // Sequence awareness
124    xmlElement.setAttributeBoolean("SequenceAware", _bSequenceAware);
125}
126
127void 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
141void 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
152void 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
176void 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
214bool 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
244bool 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
260bool 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
312bool 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
357bool 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
381bool 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*/
417CParameterBlackboard* 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
457bool 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
505const 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
522void 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
566bool 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
574void 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
591bool 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
633bool 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
660void 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
675bool 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
689bool 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
716bool 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
733bool 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
747bool 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
763bool 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
777bool 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
793bool 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
810string CConfigurableDomain::getLastAppliedConfigurationName() const
811{
812    if (_pLastAppliedConfiguration) {
813
814        return _pLastAppliedConfiguration->getName();
815    }
816    return "<none>";
817}
818
819// Pending configuration
820string 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
832void 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
848void 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
865void 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
881void 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
908bool 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
930const 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
948const 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
966void 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
973bool 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
989void 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
1023void 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
1039void 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
1081void 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
1114CSyncerSet* 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
1124CDomainConfiguration* 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
1137const 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