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