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 "Subsystem.h"
31 #include "ComponentLibrary.h"
32 #include "InstanceDefinition.h"
33 #include "XmlParameterSerializingContext.h"
34 #include "ParameterAccessContext.h"
35 #include "ConfigurationAccessContext.h"
36 #include "SubsystemObjectCreator.h"
37 #include "MappingData.h"
38 #include <assert.h>
39 #include <sstream>
40
41 #define base CConfigurableElement
42
43 using std::string;
44 using std::list;
45
CSubsystem(const string & strName,core::log::Logger & logger)46 CSubsystem::CSubsystem(const string &strName, core::log::Logger &logger)
47 : base(strName), _pComponentLibrary(new CComponentLibrary),
48 _pInstanceDefinition(new CInstanceDefinition), _logger(logger)
49 {
50 // Note: A subsystem contains instance components
51 // InstanceDefintion and ComponentLibrary objects are then not chosen to be children
52 // They'll be delt with locally
53 }
54
~CSubsystem()55 CSubsystem::~CSubsystem()
56 {
57 // FIXME use unique_ptr, would make this method empty
58
59 for (auto *subsystemObject : _subsystemObjectList) {
60
61 delete subsystemObject;
62 }
63
64 // Remove susbsystem creators
65 for (auto *subsystemObjectCreator : _subsystemObjectCreatorArray) {
66
67 delete subsystemObjectCreator;
68 }
69
70 // Order matters!
71 delete _pInstanceDefinition;
72 delete _pComponentLibrary;
73
74 delete _pMappingData;
75 }
76
getKind() const77 string CSubsystem::getKind() const
78 {
79 return "Subsystem";
80 }
81
82 // Susbsystem sanity
isAlive() const83 bool CSubsystem::isAlive() const
84 {
85 return true;
86 }
87
88 // Resynchronization after subsystem restart needed
needResync(bool)89 bool CSubsystem::needResync(bool /*bClear*/)
90 {
91 return false;
92 }
93
structureFromXml(const CXmlElement & xmlElement,CXmlSerializingContext & serializingContext)94 bool CSubsystem::structureFromXml(const CXmlElement &xmlElement,
95 CXmlSerializingContext &serializingContext)
96 {
97 // Subsystem class does not rely on generic fromXml algorithm of Element class.
98 // So, setting here the description if found as XML attribute.
99 string description;
100 xmlElement.getAttribute(gDescriptionPropertyName, description);
101 setDescription(description);
102
103 // Context
104 CXmlParameterSerializingContext ¶meterBuildContext =
105 static_cast<CXmlParameterSerializingContext &>(serializingContext);
106
107 // Install temporary component library for further component creation
108 parameterBuildContext.setComponentLibrary(_pComponentLibrary);
109
110 CXmlElement childElement;
111
112 // Manage mapping attribute
113 string rawMapping;
114 xmlElement.getAttribute("Mapping", rawMapping);
115 if (!rawMapping.empty()) {
116
117 std::string error;
118 _pMappingData = new CMappingData;
119 if (!_pMappingData->init(rawMapping, error)) {
120
121 serializingContext.setError("Invalid Mapping data from XML element '" +
122 xmlElement.getPath() + "': " + error);
123 return false;
124 }
125 }
126
127 // XML populate ComponentLibrary
128 xmlElement.getChildElement("ComponentLibrary", childElement);
129
130 if (!_pComponentLibrary->fromXml(childElement, serializingContext)) {
131
132 return false;
133 }
134
135 // XML populate InstanceDefintion
136 xmlElement.getChildElement("InstanceDefintion", childElement);
137 if (!_pInstanceDefinition->fromXml(childElement, serializingContext)) {
138
139 return false;
140 }
141
142 // Create components
143 _pInstanceDefinition->createInstances(this);
144
145 // Execute mapping to create subsystem mapping entities
146 string strError;
147 if (!mapSubsystemElements(strError)) {
148
149 serializingContext.setError(strError);
150
151 return false;
152 }
153
154 return true;
155 }
156
mapSubsystemElements(string & strError)157 bool CSubsystem::mapSubsystemElements(string &strError)
158 {
159 // Default mapping context
160 CMappingContext context(_contextMappingKeyArray.size());
161 // Add Subsystem-level mapping data, which will be propagated to all children
162 handleMappingContext(this, context, strError);
163
164 _contextStack.push(context);
165
166 // Map all instantiated subelements in subsystem
167 size_t nbChildren = getNbChildren();
168
169 for (size_t child = 0; child < nbChildren; child++) {
170
171 CInstanceConfigurableElement *pInstanceConfigurableChildElement =
172 static_cast<CInstanceConfigurableElement *>(getChild(child));
173
174 if (!pInstanceConfigurableChildElement->map(*this, strError)) {
175
176 return false;
177 }
178 }
179 return true;
180 }
181
182 // Formats the mapping of the ConfigurableElements
formatMappingDataList(const list<const CConfigurableElement * > & configurableElementPath) const183 string CSubsystem::formatMappingDataList(
184 const list<const CConfigurableElement *> &configurableElementPath) const
185 {
186 // The list is parsed in reverse order because it has been filled from the leaf to the trunk
187 // of the tree. When formatting the mapping, we want to start from the subsystem level
188 std::list<string> mappings;
189 list<const CConfigurableElement *>::const_reverse_iterator it;
190 for (it = configurableElementPath.rbegin(); it != configurableElementPath.rend(); ++it) {
191
192 auto maybeMapping = (*it)->getFormattedMapping();
193 if (not maybeMapping.empty()) {
194 mappings.push_back(maybeMapping);
195 }
196 }
197
198 return utility::asString(mappings, ", ");
199 }
200
201 // Find the CSubystemObject containing a specific CInstanceConfigurableElement
findSubsystemObjectFromConfigurableElement(const CInstanceConfigurableElement * pInstanceConfigurableElement) const202 const CSubsystemObject *CSubsystem::findSubsystemObjectFromConfigurableElement(
203 const CInstanceConfigurableElement *pInstanceConfigurableElement) const
204 {
205
206 list<CSubsystemObject *>::const_iterator it;
207 for (it = _subsystemObjectList.begin(); it != _subsystemObjectList.end(); ++it) {
208
209 // Check if one of the SubsystemObjects is associated with a ConfigurableElement
210 // corresponding to the expected one
211 const CSubsystemObject *pSubsystemObject = *it;
212
213 if (pSubsystemObject->getConfigurableElement() == pInstanceConfigurableElement) {
214
215 return pSubsystemObject;
216 }
217 }
218
219 return nullptr;
220 }
221
findSubsystemLevelMappingKeyValue(const CInstanceConfigurableElement * pInstanceConfigurableElement,string & strMappingKey,string & strMappingValue) const222 void CSubsystem::findSubsystemLevelMappingKeyValue(
223 const CInstanceConfigurableElement *pInstanceConfigurableElement, string &strMappingKey,
224 string &strMappingValue) const
225 {
226 // Find creator to get key name
227 std::vector<CSubsystemObjectCreator *>::const_iterator it;
228 for (it = _subsystemObjectCreatorArray.begin(); it != _subsystemObjectCreatorArray.end();
229 ++it) {
230
231 const CSubsystemObjectCreator *pSubsystemObjectCreator = *it;
232
233 strMappingKey = pSubsystemObjectCreator->getMappingKey();
234
235 // Check if the ObjectCreator MappingKey corresponds to the element mapping data
236 const string *pStrValue;
237 if (pInstanceConfigurableElement->getMappingData(strMappingKey, pStrValue)) {
238
239 strMappingValue = *pStrValue;
240 return;
241 }
242 }
243 assert(0);
244 }
245
246 // Formats the mapping data as a comma separated list of key value pairs
getFormattedSubsystemMappingData(const CInstanceConfigurableElement * pInstanceConfigurableElement) const247 string CSubsystem::getFormattedSubsystemMappingData(
248 const CInstanceConfigurableElement *pInstanceConfigurableElement) const
249 {
250 // Find the SubsystemObject related to pInstanceConfigurableElement
251 const CSubsystemObject *pSubsystemObject =
252 findSubsystemObjectFromConfigurableElement(pInstanceConfigurableElement);
253
254 // Exit if node does not correspond to a SubsystemObject
255 if (pSubsystemObject == nullptr) {
256
257 return "";
258 }
259
260 // Find SubsystemCreator mapping key
261 string strMappingKey;
262 string strMappingValue; // mapping value where amends are not replaced by their value
263 findSubsystemLevelMappingKeyValue(pInstanceConfigurableElement, strMappingKey, strMappingValue);
264
265 // Find SubSystemObject mapping value (with amends replaced by their value)
266 return strMappingKey + ":" + pSubsystemObject->getFormattedMappingValue();
267 }
268
getMapping(list<const CConfigurableElement * > & configurableElementPath) const269 string CSubsystem::getMapping(list<const CConfigurableElement *> &configurableElementPath) const
270 {
271 if (configurableElementPath.empty()) {
272
273 return "";
274 }
275
276 // Get the first element, which is the element containing the amended mapping
277 const CInstanceConfigurableElement *pInstanceConfigurableElement =
278 static_cast<const CInstanceConfigurableElement *>(configurableElementPath.front());
279
280 // Format context mapping data
281 string strValue = formatMappingDataList(configurableElementPath);
282
283 // Print the mapping of the first node, which corresponds to a SubsystemObject
284 auto subsystemObjectAmendedMapping =
285 getFormattedSubsystemMappingData(pInstanceConfigurableElement);
286 if (not subsystemObjectAmendedMapping.empty()) {
287 strValue += ", " + subsystemObjectAmendedMapping;
288 }
289
290 return strValue;
291 }
292
293 // Used for simulation and virtual subsystems
setDefaultValues(CParameterAccessContext & parameterAccessContext) const294 void CSubsystem::setDefaultValues(CParameterAccessContext ¶meterAccessContext) const
295 {
296 base::setDefaultValues(parameterAccessContext);
297 }
298
299 // Belonging subsystem
getBelongingSubsystem() const300 const CSubsystem *CSubsystem::getBelongingSubsystem() const
301 {
302 return this;
303 }
304
305 // Subsystem context mapping keys publication
addContextMappingKey(const string & strMappingKey)306 void CSubsystem::addContextMappingKey(const string &strMappingKey)
307 {
308 _contextMappingKeyArray.push_back(strMappingKey);
309 }
310
311 // Subsystem object creator publication (strong reference)
addSubsystemObjectFactory(CSubsystemObjectCreator * pSubsystemObjectCreator)312 void CSubsystem::addSubsystemObjectFactory(CSubsystemObjectCreator *pSubsystemObjectCreator)
313 {
314 _subsystemObjectCreatorArray.push_back(pSubsystemObjectCreator);
315 }
316
317 // Generic error handling from derived subsystem classes
getMappingError(const string & strKey,const string & strMessage,const CConfigurableElement * pConfigurableElement) const318 string CSubsystem::getMappingError(const string &strKey, const string &strMessage,
319 const CConfigurableElement *pConfigurableElement) const
320 {
321 return getName() + " " + getKind() + " " + "mapping:\n" + strKey + " " + "error: \"" +
322 strMessage + "\" " + "for element " + pConfigurableElement->getPath();
323 }
324
getMappingData(const std::string & strKey,const std::string * & pStrValue) const325 bool CSubsystem::getMappingData(const std::string &strKey, const std::string *&pStrValue) const
326 {
327 if (_pMappingData) {
328
329 return _pMappingData->getValue(strKey, pStrValue);
330 }
331 return false;
332 }
333
334 // Returns the formatted mapping
getFormattedMapping() const335 std::string CSubsystem::getFormattedMapping() const
336 {
337 if (!_pMappingData) {
338 return "";
339 }
340 return _pMappingData->asString();
341 }
342
343 // Mapping generic context handling
handleMappingContext(const CConfigurableElement * pConfigurableElement,CMappingContext & context,string & strError) const344 bool CSubsystem::handleMappingContext(const CConfigurableElement *pConfigurableElement,
345 CMappingContext &context, string &strError) const
346 {
347 // Feed context with found mapping data
348 for (size_t item = 0; item < _contextMappingKeyArray.size(); item++) {
349
350 const string &strKey = _contextMappingKeyArray[item];
351 const string *pStrValue;
352
353 if (pConfigurableElement->getMappingData(strKey, pStrValue)) {
354 // Assign item to context
355 if (!context.setItem(item, &strKey, pStrValue)) {
356
357 strError = getMappingError(strKey, "Already set", pConfigurableElement);
358
359 return false;
360 }
361 }
362 }
363 return true;
364 }
365
366 // Subsystem object creation handling
handleSubsystemObjectCreation(CInstanceConfigurableElement * pInstanceConfigurableElement,CMappingContext & context,bool & bHasCreatedSubsystemObject,string & strError)367 bool CSubsystem::handleSubsystemObjectCreation(
368 CInstanceConfigurableElement *pInstanceConfigurableElement, CMappingContext &context,
369 bool &bHasCreatedSubsystemObject, string &strError)
370 {
371 bHasCreatedSubsystemObject = false;
372
373 for (const auto *pSubsystemObjectCreator : _subsystemObjectCreatorArray) {
374
375 // Mapping key
376 string strKey = pSubsystemObjectCreator->getMappingKey();
377 // Object id
378 const string *pStrValue;
379
380 if (pInstanceConfigurableElement->getMappingData(strKey, pStrValue)) {
381
382 // First check context consistency
383 // (required ancestors must have been set prior to object creation)
384 uint32_t uiAncestorMask = pSubsystemObjectCreator->getAncestorMask();
385
386 for (size_t uiAncestorKey = 0; uiAncestorKey < _contextMappingKeyArray.size();
387 uiAncestorKey++) {
388
389 if (!((1 << uiAncestorKey) & uiAncestorMask)) {
390 // Ancestor not required
391 continue;
392 }
393 // Check ancestor was provided
394 if (!context.iSet(uiAncestorKey)) {
395
396 strError =
397 getMappingError(strKey, _contextMappingKeyArray[uiAncestorKey] + " not set",
398 pInstanceConfigurableElement);
399
400 return false;
401 }
402 }
403
404 // Then check configurable element size is correct
405 if (pInstanceConfigurableElement->getFootPrint() >
406 pSubsystemObjectCreator->getMaxConfigurableElementSize()) {
407
408 string strSizeError =
409 "Size should not exceed " +
410 std::to_string(pSubsystemObjectCreator->getMaxConfigurableElementSize());
411
412 strError = getMappingError(strKey, strSizeError, pInstanceConfigurableElement);
413
414 return false;
415 }
416
417 // Do create object and keep its track
418 _subsystemObjectList.push_back(pSubsystemObjectCreator->objectCreate(
419 *pStrValue, pInstanceConfigurableElement, context, _logger));
420
421 // Indicate subsytem creation to caller
422 bHasCreatedSubsystemObject = true;
423
424 // The subsystem Object has been instantiated, no need to continue looking for an
425 // instantiation mapping
426 break;
427 }
428 }
429
430 return true;
431 }
432
433 // From IMapper
434 // Handle a configurable element mapping
mapBegin(CInstanceConfigurableElement * pInstanceConfigurableElement,bool & bKeepDiving,string & strError)435 bool CSubsystem::mapBegin(CInstanceConfigurableElement *pInstanceConfigurableElement,
436 bool &bKeepDiving, string &strError)
437 {
438 // Get current context
439 CMappingContext context = _contextStack.top();
440
441 // Add mapping in context
442 if (!handleMappingContext(pInstanceConfigurableElement, context, strError)) {
443
444 return false;
445 }
446
447 // Push context
448 _contextStack.push(context);
449
450 // Assume diving by default
451 bKeepDiving = true;
452
453 // Deal with ambiguous usage of parameter blocks
454 bool bShouldCreateSubsystemObject = true;
455
456 switch (pInstanceConfigurableElement->getType()) {
457
458 case CInstanceConfigurableElement::EComponent:
459 case CInstanceConfigurableElement::EParameterBlock:
460 // Subsystem object creation is optional in parameter blocks
461 bShouldCreateSubsystemObject = false;
462 // No break
463 case CInstanceConfigurableElement::EBitParameterBlock:
464 case CInstanceConfigurableElement::EParameter:
465 case CInstanceConfigurableElement::EStringParameter:
466
467 bool bHasCreatedSubsystemObject;
468
469 if (!handleSubsystemObjectCreation(pInstanceConfigurableElement, context,
470 bHasCreatedSubsystemObject, strError)) {
471
472 return false;
473 }
474 // Check for creation error
475 if (bShouldCreateSubsystemObject && !bHasCreatedSubsystemObject) {
476
477 strError = getMappingError("Not found", "Subsystem object mapping key is missing",
478 pInstanceConfigurableElement);
479 return false;
480 }
481 // Not created and no error, keep diving
482 bKeepDiving = !bHasCreatedSubsystemObject;
483
484 return true;
485
486 default:
487 assert(0);
488 return false;
489 }
490 }
491
mapEnd()492 void CSubsystem::mapEnd()
493 {
494 // Unstack context
495 _contextStack.pop();
496 }
497