1 /*
2 * Copyright (c) 2011-2014, 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 <cassert>
31 #include "ConfigurableDomains.h"
32 #include "ConfigurableDomain.h"
33 #include "ConfigurableElement.h"
34 #include "BinaryStream.h"
35 #include "AutoLog.h"
36
37 #define base CBinarySerializableElement
38
39 using std::string;
40
CConfigurableDomains()41 CConfigurableDomains::CConfigurableDomains()
42 {
43 }
44
getKind() const45 string CConfigurableDomains::getKind() const
46 {
47 return "ConfigurableDomains";
48 }
49
childrenAreDynamic() const50 bool CConfigurableDomains::childrenAreDynamic() const
51 {
52 return true;
53 }
54
55 // Ensure validity on whole domains from main blackboard
validate(const CParameterBlackboard * pMainBlackboard)56 void CConfigurableDomains::validate(const CParameterBlackboard* pMainBlackboard)
57 {
58 // Delegate to domains
59 size_t uiChild;
60 size_t uiNbConfigurableDomains = getNbChildren();
61
62 for (uiChild = 0; uiChild < uiNbConfigurableDomains; uiChild++) {
63
64 CConfigurableDomain* pChildConfigurableDomain = static_cast<CConfigurableDomain*>(getChild(uiChild));
65
66 pChildConfigurableDomain->validate(pMainBlackboard);
67 }
68 }
69
70 // Configuration application if required
apply(CParameterBlackboard * pParameterBlackboard,CSyncerSet & syncerSet,bool bForce) const71 void CConfigurableDomains::apply(CParameterBlackboard* pParameterBlackboard, CSyncerSet& syncerSet, bool bForce) const
72 {
73 CAutoLog autoLog(this, "Applying configurations");
74
75 /// Delegate to domains
76
77 // Start with domains that can be synchronized all at once (with passed syncer set)
78 size_t uiChild;
79 size_t uiNbConfigurableDomains = getNbChildren();
80
81 for (uiChild = 0; uiChild < uiNbConfigurableDomains; uiChild++) {
82
83 const CConfigurableDomain* pChildConfigurableDomain = static_cast<const CConfigurableDomain*>(getChild(uiChild));
84
85 // Apply and collect syncers when relevant
86 pChildConfigurableDomain->apply(pParameterBlackboard, &syncerSet, bForce);
87 }
88 // Synchronize those collected syncers
89 syncerSet.sync(*pParameterBlackboard, false, NULL);
90
91 // Then deal with domains that need to synchronize along apply
92 for (uiChild = 0; uiChild < uiNbConfigurableDomains; uiChild++) {
93
94 const CConfigurableDomain* pChildConfigurableDomain = static_cast<const CConfigurableDomain*>(getChild(uiChild));
95
96 // Apply and synchronize when relevant
97 pChildConfigurableDomain->apply(pParameterBlackboard, NULL, bForce);
98 }
99 }
100
101 // From IXmlSource
toXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const102 void CConfigurableDomains::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
103 {
104 // Set attribute
105 xmlElement.setAttributeString("SystemClassName", getName());
106
107 base::childrenToXml(xmlElement, serializingContext);
108 }
109
110 // Configuration/Domains handling
111 /// Domains
createDomain(const string & strName,string & strError)112 bool CConfigurableDomains::createDomain(const string& strName, string& strError)
113 {
114 // Already exists?
115 if (findChild(strName)) {
116
117 strError = "Already existing configurable domain";
118
119 return false;
120 }
121
122 log_info("Creating configurable domain \"%s\"", strName.c_str());
123
124 // Creation/Hierarchy
125 addChild(new CConfigurableDomain(strName));
126
127 return true;
128 }
129
addDomain(CConfigurableDomain & domain,bool bOverwrite,string & strError)130 bool CConfigurableDomains::addDomain(CConfigurableDomain& domain, bool bOverwrite,
131 string& strError)
132 {
133 string strErrorDrop;
134
135 string strDomainName(domain.getName());
136 CConfigurableDomain* pExistingDomain = findConfigurableDomain(strDomainName, strErrorDrop);
137
138 if (pExistingDomain) {
139 if (!bOverwrite) {
140 strError = "Can't add domain \"" + strDomainName +
141 "\" because it already exists and overwrite was not requested.";
142 return false;
143 }
144
145 deleteDomain(*pExistingDomain);
146 }
147
148 log_info("Adding configurable domain \"%s\"", strDomainName.c_str());
149
150 addChild(&domain);
151
152 return true;
153 }
154
deleteDomain(CConfigurableDomain & configurableDomain)155 void CConfigurableDomains::deleteDomain(CConfigurableDomain& configurableDomain)
156 {
157 log_info("Deleting configurable domain \"%s\"", configurableDomain.getName().c_str() );
158
159 removeChild(&configurableDomain);
160
161 delete &configurableDomain;
162 }
163
deleteDomain(const string & strName,string & strError)164 bool CConfigurableDomains::deleteDomain(const string& strName, string& strError)
165 {
166 CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strName, strError);
167
168 if (pConfigurableDomain) {
169 deleteDomain(*pConfigurableDomain);
170 return true;
171 }
172
173 return false;
174 }
175
deleteAllDomains()176 void CConfigurableDomains::deleteAllDomains()
177 {
178 log_info("Deleting all configurable domains");
179
180 //remove Children
181 clean();
182 }
183
renameDomain(const string & strName,const string & strNewName,string & strError)184 bool CConfigurableDomains::renameDomain(const string& strName, const string& strNewName, string& strError)
185 {
186 CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strName, strError);
187
188 if (!pConfigurableDomain) {
189
190 return false;
191 }
192
193 log_info("Renaming configurable domain \"%s\" to \"%s\"", strName.c_str(), strNewName.c_str());
194
195 // Rename
196 return pConfigurableDomain->rename(strNewName, strError);
197 }
198
setSequenceAwareness(const string & strDomain,bool bSequenceAware,string & strError)199 bool CConfigurableDomains::setSequenceAwareness(const string& strDomain, bool bSequenceAware, string& strError)
200 {
201 CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strError);
202
203 if (!pConfigurableDomain) {
204
205 return false;
206 }
207
208 pConfigurableDomain->setSequenceAwareness(bSequenceAware);
209
210 return true;
211 }
212
getSequenceAwareness(const string & strDomain,bool & bSequenceAware,string & strError) const213 bool CConfigurableDomains::getSequenceAwareness(const string& strDomain, bool& bSequenceAware, string& strError) const
214 {
215 const CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strError);
216
217 if (!pConfigurableDomain) {
218
219 return false;
220 }
221
222 bSequenceAware = pConfigurableDomain->getSequenceAwareness();
223
224 return true;
225 }
226
227 /// Configurations
listConfigurations(const string & strDomain,string & strResult) const228 bool CConfigurableDomains::listConfigurations(const string& strDomain, string& strResult) const
229 {
230 const CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strResult);
231
232 if (!pConfigurableDomain) {
233
234 return false;
235 }
236 // delegate
237 pConfigurableDomain->listChildren(strResult);
238
239 return true;
240 }
241
createConfiguration(const string & strDomain,const string & strConfiguration,const CParameterBlackboard * pMainBlackboard,string & strError)242 bool CConfigurableDomains::createConfiguration(const string& strDomain, const string& strConfiguration, const CParameterBlackboard* pMainBlackboard, string& strError)
243 {
244 // Find domain
245 CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strError);
246
247 if (!pConfigurableDomain) {
248
249 return false;
250 }
251 // Delegate
252 return pConfigurableDomain->createConfiguration(strConfiguration, pMainBlackboard, strError);
253 }
254
deleteConfiguration(const string & strDomain,const string & strConfiguration,string & strError)255 bool CConfigurableDomains::deleteConfiguration(const string& strDomain, const string& strConfiguration, string& strError)
256 {
257 // Find domain
258 CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strError);
259
260 if (!pConfigurableDomain) {
261
262 return false;
263 }
264 // Delegate
265 return pConfigurableDomain->deleteConfiguration(strConfiguration, strError);
266 }
267
renameConfiguration(const string & strDomain,const string & strConfigurationName,const string & strNewConfigurationName,string & strError)268 bool CConfigurableDomains::renameConfiguration(const string& strDomain, const string& strConfigurationName, const string& strNewConfigurationName, string& strError)
269 {
270 // Find domain
271 CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strError);
272
273 if (!pConfigurableDomain) {
274
275 return false;
276 }
277 // Delegate
278 return pConfigurableDomain->renameConfiguration(strConfigurationName, strNewConfigurationName, strError);
279 }
280
listDomainElements(const string & strDomain,string & strResult) const281 bool CConfigurableDomains::listDomainElements(const string& strDomain, string& strResult) const
282 {
283 // Find domain
284 const CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strResult);
285
286 if (!pConfigurableDomain) {
287
288 return false;
289 }
290 // Delegate
291 pConfigurableDomain->listAssociatedToElements(strResult);
292
293 return true;
294 }
295
split(const string & strDomain,CConfigurableElement * pConfigurableElement,string & strError)296 bool CConfigurableDomains::split(const string& strDomain, CConfigurableElement* pConfigurableElement, string& strError)
297 {
298 // Find domain
299 CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strError);
300
301 if (!pConfigurableDomain) {
302
303 return false;
304 }
305 // Delegate
306 pConfigurableDomain->split(pConfigurableElement, strError);
307
308 return true;
309 }
310
listAssociatedElements(string & strResult) const311 void CConfigurableDomains::listAssociatedElements(string& strResult) const
312 {
313 strResult = "\n";
314
315 std::set<const CConfigurableElement*> configurableElementSet;
316
317 // Get all owned configurable elements
318 gatherAllOwnedConfigurableElements(configurableElementSet);
319
320 // Fill result
321 std::set<const CConfigurableElement*>::const_iterator it;
322
323 for (it = configurableElementSet.begin(); it != configurableElementSet.end(); ++it) {
324
325 const CConfigurableElement* pConfigurableElement = *it;
326
327 string strAssociatedDomainList;
328
329 pConfigurableElement->listAssociatedDomains(strAssociatedDomainList, false);
330
331 strResult += pConfigurableElement->getPath() + " [" + strAssociatedDomainList + "]\n";
332 }
333 }
334
listConflictingElements(string & strResult) const335 void CConfigurableDomains::listConflictingElements(string& strResult) const
336 {
337 strResult = "\n";
338
339 std::set<const CConfigurableElement*> configurableElementSet;
340
341 // Get all owned configurable elements
342 gatherAllOwnedConfigurableElements(configurableElementSet);
343
344 // Fill result
345 std::set<const CConfigurableElement*>::const_iterator it;
346
347 for (it = configurableElementSet.begin(); it != configurableElementSet.end(); ++it) {
348
349 const CConfigurableElement* pConfigurableElement = *it;
350
351 if (pConfigurableElement->getBelongingDomainCount() > 1) {
352
353 string strBelongingDomainList;
354
355 pConfigurableElement->listBelongingDomains(strBelongingDomainList, false);
356
357 strResult += pConfigurableElement->getPath() + " contained in multiple domains: " + strBelongingDomainList + "\n";
358 }
359 }
360 }
361
listDomains(string & strResult) const362 void CConfigurableDomains::listDomains(string& strResult) const
363 {
364 strResult = "\n";
365
366 // List domains
367 size_t uiChild;
368 size_t uiNbConfigurableDomains = getNbChildren();
369
370 for (uiChild = 0; uiChild < uiNbConfigurableDomains; uiChild++) {
371
372 const CConfigurableDomain* pChildConfigurableDomain = static_cast<const CConfigurableDomain*>(getChild(uiChild));
373
374 // Name
375 strResult += pChildConfigurableDomain->getName();
376
377 // Sequence awareness
378 if (pChildConfigurableDomain->getSequenceAwareness()) {
379
380 strResult += " [sequence aware]";
381 }
382 strResult += "\n";
383 }
384 }
385
386 // Gather configurable elements owned by any domain
gatherAllOwnedConfigurableElements(std::set<const CConfigurableElement * > & configurableElementSet) const387 void CConfigurableDomains::gatherAllOwnedConfigurableElements(std::set<const CConfigurableElement*>& configurableElementSet) const
388 {
389 // Delegate to domains
390 size_t uiChild;
391 size_t uiNbConfigurableDomains = getNbChildren();
392
393 for (uiChild = 0; uiChild < uiNbConfigurableDomains; uiChild++) {
394
395 const CConfigurableDomain* pChildConfigurableDomain = static_cast<const CConfigurableDomain*>(getChild(uiChild));
396
397 pChildConfigurableDomain->gatherConfigurableElements(configurableElementSet);
398 }
399 }
400
401 // Config restore
restoreConfiguration(const string & strDomain,const string & strConfiguration,CParameterBlackboard * pMainBlackboard,bool bAutoSync,std::list<string> & lstrError) const402 bool CConfigurableDomains::restoreConfiguration(const string& strDomain, const string& strConfiguration, CParameterBlackboard* pMainBlackboard, bool bAutoSync, std::list<string>& lstrError) const
403 {
404 string strError;
405 // Find domain
406 const CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strError);
407
408 if (!pConfigurableDomain) {
409
410 lstrError.push_back(strError);
411 return false;
412 }
413 // Delegate
414 return pConfigurableDomain->restoreConfiguration(strConfiguration, pMainBlackboard, bAutoSync, lstrError);
415 }
416
417 // Config save
saveConfiguration(const string & strDomain,const string & strConfiguration,const CParameterBlackboard * pMainBlackboard,string & strError)418 bool CConfigurableDomains::saveConfiguration(const string& strDomain, const string& strConfiguration, const CParameterBlackboard* pMainBlackboard, string& strError)
419 {
420 // Find domain
421 CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strError);
422
423 if (!pConfigurableDomain) {
424
425 return false;
426 }
427 // Delegate
428 return pConfigurableDomain->saveConfiguration(strConfiguration, pMainBlackboard, strError);
429 }
430
setElementSequence(const string & strDomain,const string & strConfiguration,const std::vector<string> & astrNewElementSequence,string & strError)431 bool CConfigurableDomains::setElementSequence(const string& strDomain, const string& strConfiguration, const std::vector<string>& astrNewElementSequence, string& strError)
432 {
433 // Find domain
434 CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strError);
435
436 if (!pConfigurableDomain) {
437
438 return false;
439 }
440
441 // Delegate to domain
442 return pConfigurableDomain->setElementSequence(strConfiguration, astrNewElementSequence, strError);
443 }
444
getElementSequence(const string & strDomain,const string & strConfiguration,string & strResult) const445 bool CConfigurableDomains::getElementSequence(const string& strDomain, const string& strConfiguration, string& strResult) const
446 {
447 // Find domain
448 const CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strResult);
449
450 if (!pConfigurableDomain) {
451
452 return false;
453 }
454 // Delegate to domain
455 return pConfigurableDomain->getElementSequence(strConfiguration, strResult);
456 }
457
setApplicationRule(const string & strDomain,const string & strConfiguration,const string & strApplicationRule,const CSelectionCriteriaDefinition * pSelectionCriteriaDefinition,string & strError)458 bool CConfigurableDomains::setApplicationRule(const string& strDomain, const string& strConfiguration, const string& strApplicationRule, const CSelectionCriteriaDefinition* pSelectionCriteriaDefinition, string& strError)
459 {
460 CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strError);
461
462 if (!pConfigurableDomain) {
463
464 return false;
465 }
466
467 // Delegate to domain
468 return pConfigurableDomain->setApplicationRule(strConfiguration, strApplicationRule, pSelectionCriteriaDefinition, strError);
469 }
470
clearApplicationRule(const string & strDomain,const string & strConfiguration,string & strError)471 bool CConfigurableDomains::clearApplicationRule(const string& strDomain, const string& strConfiguration, string& strError)
472 {
473 CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strError);
474
475 if (!pConfigurableDomain) {
476
477 return false;
478 }
479
480 // Delegate to domain
481 return pConfigurableDomain->clearApplicationRule(strConfiguration, strError);
482 }
483
getApplicationRule(const string & strDomain,const string & strConfiguration,string & strResult) const484 bool CConfigurableDomains::getApplicationRule(const string& strDomain, const string& strConfiguration, string& strResult) const
485 {
486 const CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strResult);
487
488 if (!pConfigurableDomain) {
489
490 return false;
491 }
492
493 // Delegate to domain
494 return pConfigurableDomain->getApplicationRule(strConfiguration, strResult);
495 }
496
497 // Last applied configurations
listLastAppliedConfigurations(string & strResult) const498 void CConfigurableDomains::listLastAppliedConfigurations(string& strResult) const
499 {
500 // Browse domains
501 size_t uiChild;
502 size_t uiNbConfigurableDomains = getNbChildren();
503
504 for (uiChild = 0; uiChild < uiNbConfigurableDomains; uiChild++) {
505
506 const CConfigurableDomain* pChildConfigurableDomain = static_cast<const CConfigurableDomain*>(getChild(uiChild));
507
508 strResult += pChildConfigurableDomain->getName() + ": " + pChildConfigurableDomain->getLastAppliedConfigurationName() + " [" + pChildConfigurableDomain->getPendingConfigurationName() + "]\n";
509 }
510 }
511
512 // Configurable element - domain association
addConfigurableElementToDomain(const string & strDomain,CConfigurableElement * pConfigurableElement,const CParameterBlackboard * pMainBlackboard,string & strError)513 bool CConfigurableDomains::addConfigurableElementToDomain(const string& strDomain, CConfigurableElement* pConfigurableElement, const CParameterBlackboard* pMainBlackboard, string& strError)
514 {
515 // Find domain
516 CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strError);
517
518 if (!pConfigurableDomain) {
519
520 return false;
521 }
522 // Delegate
523 return pConfigurableDomain->addConfigurableElement(pConfigurableElement, pMainBlackboard, strError);
524 }
525
removeConfigurableElementFromDomain(const string & strDomain,CConfigurableElement * pConfigurableElement,string & strError)526 bool CConfigurableDomains::removeConfigurableElementFromDomain(const string& strDomain, CConfigurableElement* pConfigurableElement, string& strError)
527 {
528 // Find domain
529 CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strError);
530
531 if (!pConfigurableDomain) {
532
533 return false;
534 }
535 // Delegate
536 return pConfigurableDomain->removeConfigurableElement(pConfigurableElement, strError);
537 }
538
findConfigurationBlackboard(const string & strDomain,const string & strConfiguration,const CConfigurableElement * pConfigurableElement,uint32_t & uiBaseOffset,bool & bIsLastApplied,string & strError) const539 CParameterBlackboard* CConfigurableDomains::findConfigurationBlackboard(const string& strDomain,
540 const string& strConfiguration,
541 const CConfigurableElement* pConfigurableElement,
542 uint32_t& uiBaseOffset,
543 bool& bIsLastApplied,
544 string& strError) const
545 {
546 log_info("Find configuration blackboard for Domain:%s, Configuration:%s, Element:%s",
547 strDomain.c_str(), strConfiguration.c_str(), pConfigurableElement->getPath().c_str());
548
549 // Find domain
550 const CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strDomain, strError);
551
552 if (!pConfigurableDomain) {
553
554 return NULL;
555 }
556
557 // Check that element belongs to the domain
558 if (!pConfigurableElement->belongsTo(pConfigurableDomain)) {
559
560 strError = "Element \"" + pConfigurableElement->getPath() + "\" does not belong to domain \"" + strDomain + "\"";
561
562 return NULL;
563 }
564
565 // Find Configuration Blackboard and Base Offset
566 return pConfigurableDomain->findConfigurationBlackboard(strConfiguration, pConfigurableElement, uiBaseOffset, bIsLastApplied, strError);
567 }
568
569 // Binary settings load/store
serializeSettings(const string & strBinarySettingsFilePath,bool bOut,uint8_t uiStructureChecksum,string & strError)570 bool CConfigurableDomains::serializeSettings(const string& strBinarySettingsFilePath, bool bOut, uint8_t uiStructureChecksum, string& strError)
571 {
572 // Instantiate byte stream
573 CBinaryStream binarySettingsStream(strBinarySettingsFilePath, bOut, getDataSize(), uiStructureChecksum);
574
575 // Open file
576 if (!binarySettingsStream.open(strError)) {
577
578 strError = "Unable to open binary settings file " + strBinarySettingsFilePath + ": " + strError;
579
580 return false;
581 }
582
583 // Serialize
584 binarySerialize(binarySettingsStream);
585
586 // Close stream
587 binarySettingsStream.close();
588
589 return true;
590 }
591
592 // Domain retrieval
findConfigurableDomain(const string & strDomain,string & strError)593 CConfigurableDomain* CConfigurableDomains::findConfigurableDomain(const string& strDomain, string& strError)
594 {
595 // Call the const equivalent
596 return const_cast<CConfigurableDomain*>(
597 static_cast<const CConfigurableDomains*>(this)->findConfigurableDomain(strDomain, strError)
598 );
599 }
600
findConfigurableDomain(const string & strDomain,string & strError) const601 const CConfigurableDomain* CConfigurableDomains::findConfigurableDomain(const string& strDomain, string& strError) const
602 {
603 // Find domain
604 const CConfigurableDomain* pConfigurableDomain = static_cast<const CConfigurableDomain*>(findChild(strDomain));
605
606 if (!pConfigurableDomain) {
607
608 strError = "Configurable domain " + strDomain + " not found";
609
610 return NULL;
611 }
612
613 return pConfigurableDomain;
614 }
615