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, nullptr, 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 nullptr;
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 nullptr;
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 nullptr;
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 = nullptr;
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, nullptr);
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 auto 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 = nullptr;
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 == nullptr) {
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 nullptr;
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 nullptr;
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 auto 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 auto mapIt = _configurableElementToSyncerSetMap.find(pConfigurableElement);
1186
1187 ALWAYS_ASSERT(mapIt != _configurableElementToSyncerSetMap.end(),
1188 "Could not find syncer set for " << getName() << " configurable domain");
1189
1190 return mapIt->second;
1191 }
1192
1193 // Configuration retrieval
findConfiguration(const string & strConfiguration,string & strError)1194 CDomainConfiguration *CConfigurableDomain::findConfiguration(const string &strConfiguration,
1195 string &strError)
1196 {
1197 CDomainConfiguration *pDomainConfiguration =
1198 static_cast<CDomainConfiguration *>(findChild(strConfiguration));
1199
1200 if (!pDomainConfiguration) {
1201
1202 strError = "Domain configuration " + strConfiguration + " not found";
1203
1204 return nullptr;
1205 }
1206 return pDomainConfiguration;
1207 }
1208
findConfiguration(const string & strConfiguration,string & strError) const1209 const CDomainConfiguration *CConfigurableDomain::findConfiguration(const string &strConfiguration,
1210 string &strError) const
1211 {
1212 const CDomainConfiguration *pDomainConfiguration =
1213 static_cast<const CDomainConfiguration *>(findChild(strConfiguration));
1214
1215 if (!pDomainConfiguration) {
1216
1217 strError = "Domain configuration " + strConfiguration + " not found";
1218
1219 return nullptr;
1220 }
1221 return pDomainConfiguration;
1222 }
1223