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