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