• 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 "DomainConfiguration.h"
31 #include "ConfigurableElement.h"
32 #include "CompoundRule.h"
33 #include "Subsystem.h"
34 #include "XmlDomainSerializingContext.h"
35 #include "XmlDomainImportContext.h"
36 #include "XmlDomainExportContext.h"
37 #include "ConfigurationAccessContext.h"
38 #include "AlwaysAssert.hpp"
39 #include <assert.h>
40 #include <cstdlib>
41 #include <algorithm>
42 #include <numeric>
43 #include "RuleParser.h"
44 
45 #define base CElement
46 
47 using std::string;
48 
CDomainConfiguration(const string & strName)49 CDomainConfiguration::CDomainConfiguration(const string &strName) : base(strName)
50 {
51 }
52 
53 // Class kind
getKind() const54 string CDomainConfiguration::getKind() const
55 {
56     return "Configuration";
57 }
58 
59 // Child dynamic creation
childrenAreDynamic() const60 bool CDomainConfiguration::childrenAreDynamic() const
61 {
62     return true;
63 }
64 
65 // XML configuration settings parsing
parseSettings(CXmlElement & xmlConfigurationSettingsElement,CXmlDomainImportContext & context)66 bool CDomainConfiguration::parseSettings(CXmlElement &xmlConfigurationSettingsElement,
67                                          CXmlDomainImportContext &context)
68 {
69     // Parse configurable element's configuration settings
70     CXmlElement::CChildIterator it(xmlConfigurationSettingsElement);
71 
72     CXmlElement xmlConfigurableElementSettingsElement;
73     auto insertLocation = begin(mAreaConfigurationList);
74 
75     while (it.next(xmlConfigurableElementSettingsElement)) {
76 
77         // Retrieve area configuration
78         string configurableElementPath;
79         xmlConfigurableElementSettingsElement.getAttribute("Path", configurableElementPath);
80 
81         auto areaConfiguration = findAreaConfigurationByPath(configurableElementPath);
82         if (areaConfiguration == end(mAreaConfigurationList)) {
83 
84             context.setError("Configurable Element " + configurableElementPath +
85                              " referred to by Configuration " + getPath() +
86                              " not associated to Domain");
87 
88             return false;
89         }
90         // Parse
91         if (!importOneConfigurableElementSettings(areaConfiguration->get(),
92                                                   xmlConfigurableElementSettingsElement, context)) {
93 
94             return false;
95         }
96         // Take into account the new configuration order by moving the configuration associated to
97         // the element to the n-th position of the configuration list.
98         // It will result in prepending to the configuration list wit the configuration of all
99         // elements found in XML, keeping the order of the processing of the XML file.
100         mAreaConfigurationList.splice(insertLocation, mAreaConfigurationList, areaConfiguration);
101         // areaConfiguration is still valid, but now refer to the reorderer list
102         insertLocation = std::next(areaConfiguration);
103     }
104     return true;
105 }
106 
107 // XML configuration settings composing
composeSettings(CXmlElement & xmlConfigurationSettingsElement,CXmlDomainExportContext & context) const108 void CDomainConfiguration::composeSettings(CXmlElement &xmlConfigurationSettingsElement,
109                                            CXmlDomainExportContext &context) const
110 {
111     // Go through all are configurations
112     for (auto &areaConfiguration : mAreaConfigurationList) {
113 
114         // Retrieve configurable element
115         const CConfigurableElement *pConfigurableElement =
116             areaConfiguration->getConfigurableElement();
117 
118         // Create configurable element child element
119         CXmlElement xmlConfigurableElementSettingsElement;
120 
121         xmlConfigurationSettingsElement.createChild(xmlConfigurableElementSettingsElement,
122                                                     "ConfigurableElement");
123 
124         // Set Path attribute
125         xmlConfigurableElementSettingsElement.setAttribute("Path", pConfigurableElement->getPath());
126 
127         // Delegate composing to area configuration
128         exportOneConfigurableElementSettings(areaConfiguration.get(),
129                                              xmlConfigurableElementSettingsElement, context);
130     }
131 }
132 
133 // Serialize one configuration for one configurable element
importOneConfigurableElementSettings(CAreaConfiguration * areaConfiguration,CXmlElement & xmlConfigurableElementSettingsElement,CXmlDomainImportContext & context)134 bool CDomainConfiguration::importOneConfigurableElementSettings(
135     CAreaConfiguration *areaConfiguration, CXmlElement &xmlConfigurableElementSettingsElement,
136     CXmlDomainImportContext &context)
137 {
138     const CConfigurableElement *destination = areaConfiguration->getConfigurableElement();
139 
140     // Check structure
141     if (xmlConfigurableElementSettingsElement.getNbChildElements() != 1) {
142 
143         // Structure error
144         context.setError("Struture error encountered while parsing settings of " +
145                          destination->getKind() + " " + destination->getName() +
146                          " in Configuration " + getPath());
147 
148         return false;
149     }
150 
151     // Element content
152     CXmlElement xmlConfigurableElementSettingsElementContent;
153     // Check name and kind
154     if (!xmlConfigurableElementSettingsElement.getChildElement(
155             destination->getXmlElementName(), destination->getName(),
156             xmlConfigurableElementSettingsElementContent)) {
157 
158         // "Component" tag has been renamed to "ParameterBlock", but retro-compatibility shall
159         // be ensured.
160         //
161         // So checking if this case occurs, i.e. element name is "ParameterBlock"
162         // but found xml setting name is "Component".
163         bool compatibilityCase =
164             (destination->getXmlElementName() == "ParameterBlock") &&
165             xmlConfigurableElementSettingsElement.getChildElement(
166                 "Component", destination->getName(), xmlConfigurableElementSettingsElementContent);
167 
168         // Error if the compatibility case does not occur.
169         if (!compatibilityCase) {
170             context.setError("Couldn't find settings for " + destination->getXmlElementName() +
171                              " " + destination->getName() + " for Configuration " + getPath());
172 
173             return false;
174         }
175     }
176 
177     // Create configuration access context
178     string error;
179     CConfigurationAccessContext configurationAccessContext(error, false);
180 
181     // Have domain configuration parse settings for configurable element
182     bool success = areaConfiguration->serializeXmlSettings(
183         xmlConfigurableElementSettingsElementContent, configurationAccessContext);
184 
185     context.appendToError(error);
186     return success;
187 }
188 
exportOneConfigurableElementSettings(CAreaConfiguration * areaConfiguration,CXmlElement & xmlConfigurableElementSettingsElement,CXmlDomainExportContext & context) const189 bool CDomainConfiguration::exportOneConfigurableElementSettings(
190     CAreaConfiguration *areaConfiguration, CXmlElement &xmlConfigurableElementSettingsElement,
191     CXmlDomainExportContext &context) const
192 {
193     const CConfigurableElement *source = areaConfiguration->getConfigurableElement();
194 
195     // Create child XML element
196     CXmlElement xmlConfigurableElementSettingsElementContent;
197     xmlConfigurableElementSettingsElement.createChild(xmlConfigurableElementSettingsElementContent,
198                                                       source->getXmlElementName());
199 
200     // Create configuration access context
201     string error;
202     CConfigurationAccessContext configurationAccessContext(error, true);
203     configurationAccessContext.setValueSpaceRaw(context.valueSpaceIsRaw());
204     configurationAccessContext.setOutputRawFormat(context.outputRawFormatIsHex());
205 
206     // Have domain configuration parse settings for configurable element
207     bool success = areaConfiguration->serializeXmlSettings(
208         xmlConfigurableElementSettingsElementContent, configurationAccessContext);
209 
210     context.appendToError(error);
211     return success;
212 }
213 
addConfigurableElement(const CConfigurableElement * configurableElement,const CSyncerSet * syncerSet)214 void CDomainConfiguration::addConfigurableElement(const CConfigurableElement *configurableElement,
215                                                   const CSyncerSet *syncerSet)
216 {
217     mAreaConfigurationList.emplace_back(configurableElement->createAreaConfiguration(syncerSet));
218 }
219 
removeConfigurableElement(const CConfigurableElement * pConfigurableElement)220 void CDomainConfiguration::removeConfigurableElement(
221     const CConfigurableElement *pConfigurableElement)
222 {
223     auto &areaConfigurationToRemove = getAreaConfiguration(pConfigurableElement);
224 
225     mAreaConfigurationList.remove(areaConfigurationToRemove);
226 }
227 
setElementSequence(const std::vector<string> & newElementSequence,string & error)228 bool CDomainConfiguration::setElementSequence(const std::vector<string> &newElementSequence,
229                                               string &error)
230 {
231     std::vector<string> elementSequenceSet;
232     auto insertLocation = begin(mAreaConfigurationList);
233 
234     for (const std::string &elementPath : newElementSequence) {
235 
236         auto areaConfiguration = findAreaConfigurationByPath(elementPath);
237         if (areaConfiguration == end(mAreaConfigurationList)) {
238 
239             error = "Element " + elementPath + " not found in domain";
240 
241             return false;
242         }
243         auto it = find(begin(elementSequenceSet), end(elementSequenceSet), elementPath);
244         if (it != end(elementSequenceSet)) {
245             error = "Element " + elementPath + " provided more than once";
246             return false;
247         }
248         elementSequenceSet.push_back(elementPath);
249         // Take into account the new configuration order by moving the configuration associated to
250         // the element to the n-th position of the configuration list.
251         // It will result in prepending to the configuration list wit the configuration of all
252         // elements found in XML, keeping the order of the processing of the XML file.
253         mAreaConfigurationList.splice(insertLocation, mAreaConfigurationList, areaConfiguration);
254         // areaConfiguration is still valid, but now refer to the reorderer list
255         insertLocation = std::next(areaConfiguration);
256     }
257     return true;
258 }
259 
getElementSequence(string & strResult) const260 void CDomainConfiguration::getElementSequence(string &strResult) const
261 {
262     // List configurable element paths out of ordered area configuration list
263     strResult = accumulate(begin(mAreaConfigurationList), end(mAreaConfigurationList), string("\n"),
264                            [](const string &a, const AreaConfiguration &conf) {
265                                return a + conf->getConfigurableElement()->getPath() + "\n";
266                            });
267 }
268 
269 // Application rule
setApplicationRule(const string & strApplicationRule,const CSelectionCriteriaDefinition * pSelectionCriteriaDefinition,string & strError)270 bool CDomainConfiguration::setApplicationRule(
271     const string &strApplicationRule,
272     const CSelectionCriteriaDefinition *pSelectionCriteriaDefinition, string &strError)
273 {
274     // Parser
275     CRuleParser ruleParser(strApplicationRule, pSelectionCriteriaDefinition);
276 
277     // Attempt to parse it
278     if (!ruleParser.parse(NULL, strError)) {
279 
280         return false;
281     }
282     // Replace compound rule
283     setRule(ruleParser.grabRootRule());
284 
285     return true;
286 }
287 
clearApplicationRule()288 void CDomainConfiguration::clearApplicationRule()
289 {
290     // Replace compound rule
291     setRule(NULL);
292 }
293 
getApplicationRule() const294 string CDomainConfiguration::getApplicationRule() const
295 {
296     const CCompoundRule *pRule = getRule();
297     return pRule ? pRule->dump() : "<none>";
298 }
299 
300 /**
301  * Get the Configuration Blackboard.
302  *
303  * Fetch the Configuration Blackboard related to the ConfigurableElement given in parameter. This
304  * Element is used to retrieve the correct AreaConfiguration where the Blackboard is stored.
305  *
306  * @param[in] pConfigurableElement      A pointer to a ConfigurableElement that is part of the
307  *                                      Domain. This must have been checked previously, as an
308  *                                      assertion is performed.
309  *
310  * return Pointer to the Blackboard of the Configuration.
311  */
getBlackboard(const CConfigurableElement * pConfigurableElement) const312 CParameterBlackboard *CDomainConfiguration::getBlackboard(
313     const CConfigurableElement *pConfigurableElement) const
314 {
315     const auto &it = find_if(begin(mAreaConfigurationList), end(mAreaConfigurationList),
316                              [&](const AreaConfiguration &conf) {
317                                  return conf != nullptr &&
318                                         conf->getConfigurableElement() == pConfigurableElement;
319                              });
320     ALWAYS_ASSERT(it != end(mAreaConfigurationList), "Configurable Element "
321                                                          << pConfigurableElement->getName()
322                                                          << " not found in any area Configuration");
323     return &(*it)->getBlackboard();
324 }
325 
326 // Save data from current
save(const CParameterBlackboard * pMainBlackboard)327 void CDomainConfiguration::save(const CParameterBlackboard *pMainBlackboard)
328 {
329     // Just propagate to areas
330     for (auto &areaConfiguration : mAreaConfigurationList) {
331         areaConfiguration->save(pMainBlackboard);
332     }
333 }
334 
335 // Apply data to current
restore(CParameterBlackboard * pMainBlackboard,bool bSync,core::Results * errors) const336 bool CDomainConfiguration::restore(CParameterBlackboard *pMainBlackboard, bool bSync,
337                                    core::Results *errors) const
338 {
339     return std::accumulate(begin(mAreaConfigurationList), end(mAreaConfigurationList), true,
340                            [&](bool accumulator, const AreaConfiguration &conf) {
341                                return conf->restore(pMainBlackboard, bSync, errors) && accumulator;
342                            });
343 }
344 
345 // Ensure validity for configurable element area configuration
validate(const CConfigurableElement * pConfigurableElement,const CParameterBlackboard * pMainBlackboard)346 void CDomainConfiguration::validate(const CConfigurableElement *pConfigurableElement,
347                                     const CParameterBlackboard *pMainBlackboard)
348 {
349     auto &areaConfigurationToValidate = getAreaConfiguration(pConfigurableElement);
350 
351     // Delegate
352     areaConfigurationToValidate->validate(pMainBlackboard);
353 }
354 
355 // Ensure validity of all area configurations
validate(const CParameterBlackboard * pMainBlackboard)356 void CDomainConfiguration::validate(const CParameterBlackboard *pMainBlackboard)
357 {
358     for (auto &areaConfiguration : mAreaConfigurationList) {
359         areaConfiguration->validate(pMainBlackboard);
360     }
361 }
362 
363 // Return configuration validity for given configurable element
isValid(const CConfigurableElement * pConfigurableElement) const364 bool CDomainConfiguration::isValid(const CConfigurableElement *pConfigurableElement) const
365 {
366     // Get child configurable elemnt's area configuration
367     auto &areaConfiguration = getAreaConfiguration(pConfigurableElement);
368 
369     ALWAYS_ASSERT(areaConfiguration != nullptr, "Configurable Element "
370                                                     << pConfigurableElement->getName()
371                                                     << " not found in any area Configuration");
372 
373     return areaConfiguration->isValid();
374 }
375 
376 // Ensure validity of configurable element's area configuration by copying in from a valid one
validateAgainst(const CDomainConfiguration * pValidDomainConfiguration,const CConfigurableElement * pConfigurableElement)377 void CDomainConfiguration::validateAgainst(const CDomainConfiguration *pValidDomainConfiguration,
378                                            const CConfigurableElement *pConfigurableElement)
379 {
380     // Retrieve related area configurations
381     auto &areaConfigurationToValidate = getAreaConfiguration(pConfigurableElement);
382     const auto &areaConfigurationToValidateAgainst =
383         pValidDomainConfiguration->getAreaConfiguration(pConfigurableElement);
384 
385     // Delegate to area
386     areaConfigurationToValidate->validateAgainst(areaConfigurationToValidateAgainst.get());
387 }
388 
validateAgainst(const CDomainConfiguration * validDomainConfiguration)389 void CDomainConfiguration::validateAgainst(const CDomainConfiguration *validDomainConfiguration)
390 {
391     ALWAYS_ASSERT(mAreaConfigurationList.size() ==
392                       validDomainConfiguration->mAreaConfigurationList.size(),
393                   "Cannot validate domain configuration "
394                       << getPath() << " since area configuration list does not have the same size"
395                                       "than the configuration list to check against");
396     for (const auto &configurationToValidateAgainst :
397          validDomainConfiguration->mAreaConfigurationList) {
398         // Get the area configuration associated to the configurable element of the
399         // valid area configuration, it will assert if none found.
400         auto configurableElement = configurationToValidateAgainst->getConfigurableElement();
401         auto &configurationToValidate = getAreaConfiguration(configurableElement);
402         // Delegate to area
403         configurationToValidate->validateAgainst(configurationToValidateAgainst.get());
404     }
405 }
406 
407 // Dynamic data application
isApplicable() const408 bool CDomainConfiguration::isApplicable() const
409 {
410     const CCompoundRule *pRule = getRule();
411 
412     return pRule && pRule->matches();
413 }
414 
415 // Merge existing configurations to given configurable element ones
merge(CConfigurableElement * pToConfigurableElement,CConfigurableElement * pFromConfigurableElement)416 void CDomainConfiguration::merge(CConfigurableElement *pToConfigurableElement,
417                                  CConfigurableElement *pFromConfigurableElement)
418 {
419     // Retrieve related area configurations
420     auto &areaConfigurationToMergeTo = getAreaConfiguration(pToConfigurableElement);
421     const auto &areaConfigurationToMergeFrom = getAreaConfiguration(pFromConfigurableElement);
422 
423     // Do the merge
424     areaConfigurationToMergeFrom->copyToOuter(areaConfigurationToMergeTo.get());
425 }
426 
427 // Domain splitting
split(CConfigurableElement * pFromConfigurableElement)428 void CDomainConfiguration::split(CConfigurableElement *pFromConfigurableElement)
429 {
430     // Retrieve related area configuration
431     const auto &areaConfigurationToSplitFrom = getAreaConfiguration(pFromConfigurableElement);
432 
433     // Go through children areas to copy configuration data to them
434     size_t uiNbConfigurableElementChildren = pFromConfigurableElement->getNbChildren();
435     size_t uiChild;
436 
437     for (uiChild = 0; uiChild < uiNbConfigurableElementChildren; uiChild++) {
438 
439         CConfigurableElement *pToChildConfigurableElement =
440             static_cast<CConfigurableElement *>(pFromConfigurableElement->getChild(uiChild));
441 
442         // Get child configurable elemnt's area configuration
443         auto &childAreaConfiguration = getAreaConfiguration(pToChildConfigurableElement);
444 
445         // Do the copy
446         childAreaConfiguration->copyFromOuter(areaConfigurationToSplitFrom.get());
447     }
448 }
449 
getAreaConfiguration(const CConfigurableElement * pConfigurableElement) const450 const CDomainConfiguration::AreaConfiguration &CDomainConfiguration::getAreaConfiguration(
451     const CConfigurableElement *pConfigurableElement) const
452 {
453     const auto &it = find_if(begin(mAreaConfigurationList), end(mAreaConfigurationList),
454                              [&](const AreaConfiguration &conf) {
455                                  return conf->getConfigurableElement() == pConfigurableElement;
456                              });
457     ALWAYS_ASSERT(it != end(mAreaConfigurationList),
458                   "Configurable Element " << pConfigurableElement->getName()
459                                           << " not found in Domain Configuration list");
460     return *it;
461 }
462 
463 CDomainConfiguration::AreaConfigurations::iterator CDomainConfiguration::
findAreaConfigurationByPath(const std::string & configurableElementPath)464     findAreaConfigurationByPath(const std::string &configurableElementPath)
465 {
466     auto areaConfiguration =
467         find_if(begin(mAreaConfigurationList), end(mAreaConfigurationList),
468                 [&](const AreaConfiguration &conf) {
469                     return conf->getConfigurableElement()->getPath() == configurableElementPath;
470                 });
471     return areaConfiguration;
472 }
473 
474 // Rule
getRule() const475 const CCompoundRule *CDomainConfiguration::getRule() const
476 {
477     if (getNbChildren()) {
478         // Rule created
479         return static_cast<const CCompoundRule *>(getChild(ECompoundRule));
480     }
481     return NULL;
482 }
483 
getRule()484 CCompoundRule *CDomainConfiguration::getRule()
485 {
486     if (getNbChildren()) {
487         // Rule created
488         return static_cast<CCompoundRule *>(getChild(ECompoundRule));
489     }
490     return NULL;
491 }
492 
setRule(CCompoundRule * pRule)493 void CDomainConfiguration::setRule(CCompoundRule *pRule)
494 {
495     CCompoundRule *pOldRule = getRule();
496 
497     if (pOldRule) {
498         // Remove previous rule
499         removeChild(pOldRule);
500 
501         delete pOldRule;
502     }
503 
504     // Set new one
505     if (pRule) {
506         // Chain
507         addChild(pRule);
508     }
509 }
510