• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "ConfigurableElement.h"
31 #include "MappingData.h"
32 #include "SyncerSet.h"
33 #include "ConfigurableDomain.h"
34 #include "ConfigurationAccessContext.h"
35 #include "ConfigurableElementAggregator.h"
36 #include "AreaConfiguration.h"
37 #include "Iterator.hpp"
38 #include "Utility.h"
39 #include "XmlParameterSerializingContext.h"
40 #include <assert.h>
41 
42 #define base CElement
43 
CConfigurableElement(const std::string & strName)44 CConfigurableElement::CConfigurableElement(const std::string &strName) : base(strName)
45 {
46 }
47 
fromXml(const CXmlElement & xmlElement,CXmlSerializingContext & serializingContext)48 bool CConfigurableElement::fromXml(const CXmlElement &xmlElement,
49                                    CXmlSerializingContext &serializingContext)
50 {
51     auto &context = static_cast<CXmlParameterSerializingContext &>(serializingContext);
52     auto &accessContext = context.getAccessContext();
53 
54     if (accessContext.serializeSettings()) {
55         // As serialization and deserialisation are handled through the *same* function
56         // the (de)serialize object can not be const in `serializeXmlSettings` signature.
57         // As a result a const_cast is unavoidable :(.
58         // Fixme: split serializeXmlSettings in two functions (in and out) to avoid the `const_cast`
59         return serializeXmlSettings(const_cast<CXmlElement &>(xmlElement),
60                                     static_cast<CConfigurationAccessContext &>(accessContext));
61     }
62     return structureFromXml(xmlElement, serializingContext);
63 }
64 
toXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const65 void CConfigurableElement::toXml(CXmlElement &xmlElement,
66                                  CXmlSerializingContext &serializingContext) const
67 {
68     auto &context = static_cast<CXmlParameterSerializingContext &>(serializingContext);
69     auto &accessContext = context.getAccessContext();
70     if (accessContext.serializeSettings()) {
71 
72         serializeXmlSettings(xmlElement, static_cast<CConfigurationAccessContext &>(accessContext));
73     } else {
74 
75         structureToXml(xmlElement, serializingContext);
76     }
77 }
78 
79 // XML configuration settings parsing
serializeXmlSettings(CXmlElement & xmlConfigurationSettingsElementContent,CConfigurationAccessContext & configurationAccessContext) const80 bool CConfigurableElement::serializeXmlSettings(
81     CXmlElement &xmlConfigurationSettingsElementContent,
82     CConfigurationAccessContext &configurationAccessContext) const
83 {
84     size_t uiNbChildren = getNbChildren();
85 
86     if (!configurationAccessContext.serializeOut()) {
87         // Just do basic checks and propagate to children
88         CXmlElement::CChildIterator it(xmlConfigurationSettingsElementContent);
89 
90         CXmlElement xmlChildConfigurableElementSettingsElement;
91 
92         // Propagate to children
93         for (size_t index = 0; index < uiNbChildren; index++) {
94 
95             // Get child
96             const CConfigurableElement *pChildConfigurableElement =
97                 static_cast<const CConfigurableElement *>(getChild(index));
98 
99             if (!it.next(xmlChildConfigurableElementSettingsElement)) {
100 
101                 // Structure error
102                 configurationAccessContext.setError(
103                     "Configuration settings parsing: missing child node " +
104                     pChildConfigurableElement->getXmlElementName() + " (name:" +
105                     pChildConfigurableElement->getName() + ") in " + getName());
106 
107                 return false;
108             }
109 
110             // Check element type matches in type
111             if (xmlChildConfigurableElementSettingsElement.getType() !=
112                 pChildConfigurableElement->getXmlElementName()) {
113 
114                 // "Component" tag has been renamed to "ParameterBlock", but retro-compatibility
115                 // shall be ensured.
116                 //
117                 // So checking if this case occurs, i.e. element name is "ParameterBlock"
118                 // but xml setting name is "Component".
119                 bool compatibilityCase =
120                     (pChildConfigurableElement->getXmlElementName() == "ParameterBlock") &&
121                     (xmlChildConfigurableElementSettingsElement.getType() == "Component");
122 
123                 // Error if the compatibility case does not occur.
124                 if (!compatibilityCase) {
125 
126                     // Type error
127                     configurationAccessContext.setError(
128                         "Configuration settings parsing: Settings "
129                         "for configurable element " +
130                         pChildConfigurableElement->getQualifiedPath() +
131                         " does not match expected type: " +
132                         xmlChildConfigurableElementSettingsElement.getType() + " instead of " +
133                         pChildConfigurableElement->getKind());
134                     return false;
135                 }
136             }
137 
138             // Check element type matches in name
139             if (xmlChildConfigurableElementSettingsElement.getNameAttribute() !=
140                 pChildConfigurableElement->getName()) {
141 
142                 // Name error
143                 configurationAccessContext.setError(
144                     "Configuration settings parsing: Under configurable element " +
145                     getQualifiedPath() + ", expected element name " +
146                     pChildConfigurableElement->getName() + " but found " +
147                     xmlChildConfigurableElementSettingsElement.getNameAttribute() + " instead");
148 
149                 return false;
150             }
151 
152             // Parse child configurable element's settings
153             if (!pChildConfigurableElement->serializeXmlSettings(
154                     xmlChildConfigurableElementSettingsElement, configurationAccessContext)) {
155 
156                 return false;
157             }
158         }
159         // There should remain no configurable element to parse
160         if (it.next(xmlChildConfigurableElementSettingsElement)) {
161 
162             // Structure error
163             configurationAccessContext.setError(
164                 "Configuration settings parsing: Unexpected xml element node " +
165                 xmlChildConfigurableElementSettingsElement.getType() + " in " + getQualifiedPath());
166 
167             return false;
168         }
169     } else {
170         // Handle element name attribute
171         xmlConfigurationSettingsElementContent.setNameAttribute(getName());
172 
173         // Propagate to children
174         for (size_t index = 0; index < uiNbChildren; index++) {
175 
176             const CConfigurableElement *pChildConfigurableElement =
177                 static_cast<const CConfigurableElement *>(getChild(index));
178 
179             // Create corresponding child element
180             CXmlElement xmlChildConfigurableElementSettingsElement;
181 
182             xmlConfigurationSettingsElementContent.createChild(
183                 xmlChildConfigurableElementSettingsElement,
184                 pChildConfigurableElement->getXmlElementName());
185 
186             // Propagate
187             pChildConfigurableElement->serializeXmlSettings(
188                 xmlChildConfigurableElementSettingsElement, configurationAccessContext);
189         }
190     }
191     // Done
192     return true;
193 }
194 
195 // AreaConfiguration creation
createAreaConfiguration(const CSyncerSet * pSyncerSet) const196 CAreaConfiguration *CConfigurableElement::createAreaConfiguration(
197     const CSyncerSet *pSyncerSet) const
198 {
199     return new CAreaConfiguration(this, pSyncerSet);
200 }
201 
202 // Parameter access
accessValue(CPathNavigator & pathNavigator,std::string & strValue,bool bSet,CParameterAccessContext & parameterAccessContext) const203 bool CConfigurableElement::accessValue(CPathNavigator &pathNavigator, std::string &strValue,
204                                        bool bSet,
205                                        CParameterAccessContext &parameterAccessContext) const
206 {
207     std::string *pStrChildName = pathNavigator.next();
208 
209     if (!pStrChildName) {
210 
211         parameterAccessContext.setError((bSet ? "Can't set " : "Can't get ") +
212                                         pathNavigator.getCurrentPath() +
213                                         " because it is not a parameter");
214 
215         return false;
216     }
217 
218     const CConfigurableElement *pChild =
219         static_cast<const CConfigurableElement *>(findChild(*pStrChildName));
220 
221     if (!pChild) {
222 
223         parameterAccessContext.setError("Path not found: " + pathNavigator.getCurrentPath());
224 
225         return false;
226     }
227 
228     return pChild->accessValue(pathNavigator, strValue, bSet, parameterAccessContext);
229 }
230 
231 // Whole element access
getSettingsAsBytes(std::vector<uint8_t> & bytes,CParameterAccessContext & parameterAccessContext) const232 void CConfigurableElement::getSettingsAsBytes(std::vector<uint8_t> &bytes,
233                                               CParameterAccessContext &parameterAccessContext) const
234 {
235     bytes.resize(getFootPrint());
236 
237     parameterAccessContext.getParameterBlackboard()->readBytes(
238         bytes, getOffset() - parameterAccessContext.getBaseOffset());
239 }
240 
setSettingsAsBytes(const std::vector<uint8_t> & bytes,CParameterAccessContext & parameterAccessContext) const241 bool CConfigurableElement::setSettingsAsBytes(const std::vector<uint8_t> &bytes,
242                                               CParameterAccessContext &parameterAccessContext) const
243 {
244     CParameterBlackboard *pParameterBlackboard = parameterAccessContext.getParameterBlackboard();
245 
246     // Size
247     size_t size = getFootPrint();
248 
249     // Check sizes match
250     if (size != bytes.size()) {
251 
252         parameterAccessContext.setError(std::string("Wrong size: Expected: ") +
253                                         std::to_string(size) + " Provided: " +
254                                         std::to_string(bytes.size()));
255 
256         return false;
257     }
258 
259     // Write bytes
260     pParameterBlackboard->writeBytes(bytes, getOffset() - parameterAccessContext.getBaseOffset());
261 
262     if (not parameterAccessContext.getAutoSync()) {
263         // Auto sync is not activated, sync will be defered until an explicit request
264         return true;
265     }
266 
267     CSyncerSet syncerSet;
268     fillSyncerSet(syncerSet);
269     core::Results res;
270     if (not syncerSet.sync(*parameterAccessContext.getParameterBlackboard(), false, &res)) {
271 
272         parameterAccessContext.setError(utility::asString(res));
273         return false;
274     }
275     return true;
276 }
277 
getConfigurableElementContext() const278 std::list<const CConfigurableElement *> CConfigurableElement::getConfigurableElementContext() const
279 {
280     std::list<const CConfigurableElement *> configurableElementPath;
281 
282     const CElement *element = this;
283     while (element != nullptr and isOfConfigurableElementType(element)) {
284         auto configurableElement = static_cast<const CConfigurableElement *>(element);
285 
286         configurableElementPath.push_back(configurableElement);
287         element = element->getParent();
288     }
289 
290     return configurableElementPath;
291 }
292 
293 // Used for simulation and virtual subsystems
setDefaultValues(CParameterAccessContext & parameterAccessContext) const294 void CConfigurableElement::setDefaultValues(CParameterAccessContext &parameterAccessContext) const
295 {
296     // Propagate to children
297     size_t uiNbChildren = getNbChildren();
298 
299     for (size_t index = 0; index < uiNbChildren; index++) {
300 
301         const CConfigurableElement *pConfigurableElement =
302             static_cast<const CConfigurableElement *>(getChild(index));
303 
304         pConfigurableElement->setDefaultValues(parameterAccessContext);
305     }
306 }
307 
308 // Element properties
showProperties(std::string & strResult) const309 void CConfigurableElement::showProperties(std::string &strResult) const
310 {
311     base::showProperties(strResult);
312 
313     strResult += "Total size: " + getFootprintAsString() + "\n";
314 }
315 
logValue(utility::ErrorContext & context) const316 std::string CConfigurableElement::logValue(utility::ErrorContext &context) const
317 {
318     return logValue(static_cast<CParameterAccessContext &>(context));
319 }
320 
logValue(CParameterAccessContext &) const321 std::string CConfigurableElement::logValue(CParameterAccessContext & /*ctx*/) const
322 {
323     // By default, an element does not have a value. Only leaf elements have
324     // one. This method could be pure virtual but then, several derived classes
325     // would need to implement it in order to simply return an empty string.
326     return "";
327 }
328 
329 // Offset
setOffset(size_t offset)330 void CConfigurableElement::setOffset(size_t offset)
331 {
332     // Assign offset locally
333     _offset = offset;
334 
335     // Propagate to children
336     size_t uiNbChildren = getNbChildren();
337 
338     for (size_t index = 0; index < uiNbChildren; index++) {
339 
340         CConfigurableElement *pConfigurableElement =
341             static_cast<CConfigurableElement *>(getChild(index));
342 
343         pConfigurableElement->setOffset(offset);
344 
345         offset += pConfigurableElement->getFootPrint();
346     }
347 }
348 
getOffset() const349 size_t CConfigurableElement::getOffset() const
350 {
351     return _offset;
352 }
353 
354 // Memory
getFootPrint() const355 size_t CConfigurableElement::getFootPrint() const
356 {
357     size_t uiSize = 0;
358     size_t uiNbChildren = getNbChildren();
359 
360     for (size_t index = 0; index < uiNbChildren; index++) {
361 
362         const CConfigurableElement *pConfigurableElement =
363             static_cast<const CConfigurableElement *>(getChild(index));
364 
365         uiSize += pConfigurableElement->getFootPrint();
366     }
367 
368     return uiSize;
369 }
370 
371 // Browse parent path to find syncer
getSyncer() const372 ISyncer *CConfigurableElement::getSyncer() const
373 {
374     // Check parent
375     const CElement *pParent = getParent();
376 
377     if (isOfConfigurableElementType(pParent)) {
378 
379         return static_cast<const CConfigurableElement *>(pParent)->getSyncer();
380     }
381     return nullptr;
382 }
383 
384 // Syncer set (me, ascendant or descendant ones)
fillSyncerSet(CSyncerSet & syncerSet) const385 void CConfigurableElement::fillSyncerSet(CSyncerSet &syncerSet) const
386 {
387     //  Try me or ascendants
388     ISyncer *pMineOrAscendantSyncer = getSyncer();
389 
390     if (pMineOrAscendantSyncer) {
391 
392         // Provide found syncer object
393         syncerSet += pMineOrAscendantSyncer;
394 
395         // Done
396         return;
397     }
398     // Fetch descendant ones
399     fillSyncerSetFromDescendant(syncerSet);
400 }
401 
402 // Syncer set (descendant)
fillSyncerSetFromDescendant(CSyncerSet & syncerSet) const403 void CConfigurableElement::fillSyncerSetFromDescendant(CSyncerSet &syncerSet) const
404 {
405     // Dig
406     size_t uiNbChildren = getNbChildren();
407 
408     for (size_t index = 0; index < uiNbChildren; index++) {
409 
410         const CConfigurableElement *pConfigurableElement =
411             static_cast<const CConfigurableElement *>(getChild(index));
412 
413         pConfigurableElement->fillSyncerSetFromDescendant(syncerSet);
414     }
415 }
416 
417 // Configurable domain association
addAttachedConfigurableDomain(const CConfigurableDomain * pConfigurableDomain)418 void CConfigurableElement::addAttachedConfigurableDomain(
419     const CConfigurableDomain *pConfigurableDomain)
420 {
421     _configurableDomainList.push_back(pConfigurableDomain);
422 }
423 
removeAttachedConfigurableDomain(const CConfigurableDomain * pConfigurableDomain)424 void CConfigurableElement::removeAttachedConfigurableDomain(
425     const CConfigurableDomain *pConfigurableDomain)
426 {
427     _configurableDomainList.remove(pConfigurableDomain);
428 }
429 
430 // Belonging domain
belongsTo(const CConfigurableDomain * pConfigurableDomain) const431 bool CConfigurableElement::belongsTo(const CConfigurableDomain *pConfigurableDomain) const
432 {
433     if (containsConfigurableDomain(pConfigurableDomain)) {
434 
435         return true;
436     }
437     return belongsToDomainAscending(pConfigurableDomain);
438 }
439 
440 // Belonging domains
getBelongingDomains(std::list<const CConfigurableDomain * > & configurableDomainList) const441 void CConfigurableElement::getBelongingDomains(
442     std::list<const CConfigurableDomain *> &configurableDomainList) const
443 {
444     configurableDomainList.insert(configurableDomainList.end(), _configurableDomainList.begin(),
445                                   _configurableDomainList.end());
446 
447     // Check parent
448     const CElement *pParent = getParent();
449 
450     if (isOfConfigurableElementType(pParent)) {
451 
452         static_cast<const CConfigurableElement *>(pParent)->getBelongingDomains(
453             configurableDomainList);
454     }
455 }
456 
listBelongingDomains(std::string & strResult,bool bVertical) const457 void CConfigurableElement::listBelongingDomains(std::string &strResult, bool bVertical) const
458 {
459     // Get belonging domain list
460     std::list<const CConfigurableDomain *> configurableDomainList;
461 
462     getBelongingDomains(configurableDomainList);
463 
464     // Fill list
465     listDomains(configurableDomainList, strResult, bVertical);
466 }
467 
468 // Elements with no domains
listRogueElements(std::string & strResult) const469 void CConfigurableElement::listRogueElements(std::string &strResult) const
470 {
471     // Get rogue element aggregate list (no associated domain)
472     std::list<const CConfigurableElement *> rogueElementList;
473 
474     CConfigurableElementAggregator configurableElementAggregator(
475         rogueElementList, &CConfigurableElement::hasNoDomainAssociated);
476 
477     configurableElementAggregator.aggegate(this);
478 
479     // Build list as std::string
480     std::list<const CConfigurableElement *>::const_iterator it;
481 
482     for (it = rogueElementList.begin(); it != rogueElementList.end(); ++it) {
483 
484         const CConfigurableElement *pConfigurableElement = *it;
485 
486         strResult += pConfigurableElement->getPath() + "\n";
487     }
488 }
489 
isRogue() const490 bool CConfigurableElement::isRogue() const
491 {
492     // Check not belonging to any domin from current level and towards ascendents
493     if (getBelongingDomainCount() != 0) {
494 
495         return false;
496     }
497 
498     // Get a list of elements (current + descendants) with no domains associated
499     std::list<const CConfigurableElement *> rogueElementList;
500 
501     CConfigurableElementAggregator agregator(rogueElementList,
502                                              &CConfigurableElement::hasNoDomainAssociated);
503 
504     agregator.aggegate(this);
505 
506     // Check only one element found which ought to be current one
507     return (rogueElementList.size() == 1) && (rogueElementList.front() == this);
508 }
509 
510 // Footprint as string
getFootprintAsString() const511 std::string CConfigurableElement::getFootprintAsString() const
512 {
513     // Get size as string
514     return std::to_string(getFootPrint()) + " byte(s)";
515 }
516 
517 // Matching check for no domain association
hasNoDomainAssociated() const518 bool CConfigurableElement::hasNoDomainAssociated() const
519 {
520     return _configurableDomainList.empty();
521 }
522 
523 // Matching check for no valid associated domains
hasNoValidDomainAssociated() const524 bool CConfigurableElement::hasNoValidDomainAssociated() const
525 {
526     if (_configurableDomainList.empty()) {
527 
528         // No domains associated
529         return true;
530     }
531 
532     ConfigurableDomainListConstIterator it;
533 
534     // Browse all configurable domains for validity checking
535     for (it = _configurableDomainList.begin(); it != _configurableDomainList.end(); ++it) {
536 
537         const CConfigurableDomain *pConfigurableDomain = *it;
538 
539         if (pConfigurableDomain->isApplicableConfigurationValid(this)) {
540 
541             return false;
542         }
543     }
544 
545     return true;
546 }
547 
548 // Owning domains
listAssociatedDomains(std::string & strResult,bool bVertical) const549 void CConfigurableElement::listAssociatedDomains(std::string &strResult, bool bVertical) const
550 {
551     // Fill list
552     listDomains(_configurableDomainList, strResult, bVertical);
553 }
554 
getBelongingDomainCount() const555 size_t CConfigurableElement::getBelongingDomainCount() const
556 {
557     // Get belonging domain list
558     std::list<const CConfigurableDomain *> configurableDomainList;
559 
560     getBelongingDomains(configurableDomainList);
561 
562     return configurableDomainList.size();
563 }
564 
listDomains(const std::list<const CConfigurableDomain * > & configurableDomainList,std::string & strResult,bool bVertical) const565 void CConfigurableElement::listDomains(
566     const std::list<const CConfigurableDomain *> &configurableDomainList, std::string &strResult,
567     bool bVertical) const
568 {
569     // Fill list
570     ConfigurableDomainListConstIterator it;
571     bool bFirst = true;
572 
573     // Browse all configurable domains for comparison
574     for (it = configurableDomainList.begin(); it != configurableDomainList.end(); ++it) {
575 
576         const CConfigurableDomain *pConfigurableDomain = *it;
577 
578         if (!bVertical && !bFirst) {
579 
580             strResult += ", ";
581         }
582 
583         strResult += pConfigurableDomain->getName();
584 
585         if (bVertical) {
586 
587             strResult += "\n";
588         } else {
589 
590             bFirst = false;
591         }
592     }
593 }
594 
containsConfigurableDomain(const CConfigurableDomain * pConfigurableDomain) const595 bool CConfigurableElement::containsConfigurableDomain(
596     const CConfigurableDomain *pConfigurableDomain) const
597 {
598     ConfigurableDomainListConstIterator it;
599 
600     // Browse all configurable domains for comparison
601     for (it = _configurableDomainList.begin(); it != _configurableDomainList.end(); ++it) {
602 
603         if (pConfigurableDomain == *it) {
604 
605             return true;
606         }
607     }
608     return false;
609 }
610 
611 // Belonging domain ascending search
belongsToDomainAscending(const CConfigurableDomain * pConfigurableDomain) const612 bool CConfigurableElement::belongsToDomainAscending(
613     const CConfigurableDomain *pConfigurableDomain) const
614 {
615     // Check parent
616     const CElement *pParent = getParent();
617 
618     if (isOfConfigurableElementType(pParent)) {
619 
620         return static_cast<const CConfigurableElement *>(pParent)->belongsTo(pConfigurableDomain);
621     }
622     return false;
623 }
624 
625 // Belonging subsystem
getBelongingSubsystem() const626 const CSubsystem *CConfigurableElement::getBelongingSubsystem() const
627 {
628     const CElement *pParent = getParent();
629 
630     // Stop at system class
631     if (!pParent->getParent()) {
632 
633         return nullptr;
634     }
635 
636     return static_cast<const CConfigurableElement *>(pParent)->getBelongingSubsystem();
637 }
638 
639 // Check element is a parameter
isParameter() const640 bool CConfigurableElement::isParameter() const
641 {
642     return false;
643 }
644 
645 // Check parent is still of current type (by structure knowledge)
isOfConfigurableElementType(const CElement * pParent) const646 bool CConfigurableElement::isOfConfigurableElementType(const CElement *pParent) const
647 {
648     assert(pParent);
649 
650     // Up to system class
651     return !!pParent->getParent();
652 }
653