ParameterMapping.cpp
Go to the documentation of this file.
1/*
2* This file is part of ArmarX.
3*
4* Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5*
6* ArmarX is free software; you can redistribute it and/or modify
7* it under the terms of the GNU General Public License version 2 as
8* published by the Free Software Foundation.
9*
10* ArmarX is distributed in the hope that it will be useful, but
11* WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU General Public License
16* along with this program. If not, see <http://www.gnu.org/licenses/>.
17*
18* @package ArmarXCore::Statechart
19* @author Mirko Waechter( mirko.waechter at kit dot edu)
20* @date 2012
21* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22* GNU General Public License
23*/
24#include "ParameterMapping.h"
25
27
28#include "Exception.h"
29#include "StateParameter.h"
30#include "StateUtilFunctions.h"
31#include "StatechartContext.h"
32
33namespace armarx
34{
35
36 StatechartContext* ParameterMapping::__context = nullptr;
37
38 ParameterMapping::ParameterMapping(const ParameterMapping& source) :
39 IceUtil::Shared(source),
40 Ice::Object(source),
41 ParameterMappingIceBase(source),
43 {
44 *this = source;
45 }
46
47 void
48 ParameterMapping::_applyMapping(StateParameterMap& targetDictionary)
49 {
50 if (priorities.size() == 0)
51 {
52 _addMissingSources(priorities);
53 }
54
55 if (__greedyInput)
56 {
57 PriorityMap::reverse_iterator it = priorities.rbegin();
58
59 for (; it != priorities.rend(); ++it)
60 {
61 SourceDictionaryMap::iterator itSourceDict = sourceDictionaries.find(it->second);
62
63 if (itSourceDict != sourceDictionaries.end())
64 {
65 _greedyMapping(targetDictionary, itSourceDict->second);
66 }
67 }
68 }
69
70 PriorityMap::iterator it = priorities.begin();
71
72 // iterate from start (low priority) and overwrite values later if found in higher
73 // priority dictionaries as well
74 for (; it != priorities.end(); ++it)
75 {
76 __fillFromMappingSource(it->second, targetDictionary);
77 }
78 }
79
80 void
81 ParameterMapping::__fillFromMappingSource(MappingSource mappingSource,
82 StateParameterMap& targetDictionary)
83 {
84 if (mappingSource == eDataField)
85 {
86 // get data directly from the observer
87 _fillFromDataField(targetDictionary);
88 }
89 else if (mappingSource == eValue)
90 {
91 // get direct value mappings
92 _fillFromValues(targetDictionary);
93 }
94 else
95 {
96 // get data from source dictionaries
97
98 // select which source dict to use
99 SourceDictionaryMap::iterator itSourceDict = sourceDictionaries.find(mappingSource);
100
101 if (itSourceDict != sourceDictionaries.end())
102 {
103 for (StateParameterMap::iterator itTargetDict = targetDictionary.begin();
104 itTargetDict != targetDictionary.end();
105 itTargetDict++)
106 {
107 // get the specific entry (if existing) in the source dict for the selected target dict entry
108 StringVariantContainerBaseMap::const_iterator itSourceEntry = _hasMappingEntry(
109 itTargetDict->first, itSourceDict->second, itSourceDict->first);
110
111 if (itSourceEntry != itSourceDict->second.end())
112 {
113 __copyDataFromSourceDict(itSourceEntry, itTargetDict);
114 }
115 }
116 }
117 }
118 }
119
120 void
121 ParameterMapping::__copyDataFromSourceDict(
122 StringVariantContainerBaseMap::const_iterator& itSourceEntry,
123 StateParameterMap::iterator itTargetEntry)
124 {
125 if (itSourceEntry->second->getSize() > 0)
126 {
127 if (!VariantContainerType::compare(itTargetEntry->second->value->getContainerType(),
128 itSourceEntry->second->getContainerType()))
129 {
130 throw exceptions::local::eStatechartLogicError(
131 "Cannot map different types: " +
132 VariantContainerType::allTypesToString(
133 itTargetEntry->second->value->getContainerType()) +
134 " (" + itTargetEntry->first + ") vs. " +
135 VariantContainerType::allTypesToString(
136 itSourceEntry->second->getContainerType()) +
137 " (" + itSourceEntry->first + ")");
138 }
139 }
140
141 {
142 // // copy data from source dictionary
143 // if (!VariantContainerType::compare(itTargetEntry->second->value->getContainerType(), itSourceEntry->second->getContainerType()))
144 // throw exceptions::local::eStatechartLogicError("Cannot map parameter! The variant type of targetkey '" + itTargetEntry->first + "' does not match sourcekey '" + itSourceEntry->first + "' ("
145 // + VariantContainerType::allTypesToString(itTargetEntry->second->value->getContainerType()) + " vs. " + VariantContainerType::allTypesToString(itSourceEntry->second->getContainerType()) + ")");
146
147 itTargetEntry->second->value = itSourceEntry->second; //->cloneContainer();
148 }
149
150
151 itTargetEntry->second->set = true;
152 }
153
154 void
155 ParameterMapping::_greedyMapping(StateParameterMap& targetDictionary,
156 StringVariantContainerBaseMap& sourceDictionary)
157 {
158 for (StringVariantContainerBaseMap::const_iterator it = sourceDictionary.begin();
159 it != sourceDictionary.end();
160 it++)
161 {
163 param->value = it->second->cloneContainer();
164 param->optionalParam = false;
165 param->set = true;
166
167 targetDictionary[it->first] = param;
168 }
169 }
170
171 void
172 ParameterMapping::_fillFromDataField(StateParameterMap& targetDictionary)
173 {
174 std::map<std::string,
175 std::pair<DataFieldIdentifierBaseList, std::vector<StateParameterPtr>>>
176 observerSplittedMap;
177
178 //first split required parameters by observer
179 MappingList::const_iterator itMapping;
180
181 for (itMapping = mappings.begin(); itMapping != mappings.end(); ++itMapping)
182 {
183 if (itMapping->mappingSrc == eDataField)
184 {
185 StateParameterMap::iterator itTargetDict =
186 targetDictionary.find(itMapping->targetKey);
187
188 if (itTargetDict != targetDictionary.end())
189 {
190 DataFieldIdentifierBasePtr id = new DataFieldIdentifier(itMapping->sourceKey);
191
192 observerSplittedMap[id->observerName].first.push_back(id);
193 observerSplittedMap[id->observerName].second.push_back(
194 StateParameterPtr::dynamicCast(itTargetDict->second));
195 }
196 }
197 }
198
199 //now get all the data from each observer in a bulk and set the stateparameterpointers
200 if (!__context && observerSplittedMap.size() != 0)
201 {
202 throw LocalException("StatechartContext Pointer is NULL");
203 }
204
205 std::map<std::string,
206 std::pair<DataFieldIdentifierBaseList, std::vector<StateParameterPtr>>>::iterator
207 itObservers = observerSplittedMap.begin();
208
209 for (; itObservers != observerSplittedMap.end(); ++itObservers)
210 {
211 std::string observerName = itObservers->first;
212 std::vector<StateParameterPtr>& paramList = itObservers->second.second;
213 TimedVariantBaseList variants =
214 __context->getDataListFromObserver(observerName, itObservers->second.first);
215
216 for (unsigned int i = 0; i < variants.size() && i < paramList.size(); ++i)
217 {
218 if (!variants.at(i)->getInitialized())
219 {
220 continue;
221 }
222 const Variant& data = *VariantPtr::dynamicCast(variants.at(i));
223 paramList.at(i)->value = new SingleVariant(data);
224 paramList.at(i)->set = true;
225 }
226 }
227 }
228
229 void
230 ParameterMapping::_fillFromValues(StateParameterMap& targetDictionary)
231 {
232 MappingList::const_iterator itMapping;
233
234 for (itMapping = mappings.begin(); itMapping != mappings.end(); ++itMapping)
235 {
236 if (itMapping->mappingSrc == eValue)
237 {
238 StateParameterMap::iterator itTargetDict =
239 targetDictionary.find(itMapping->targetKey);
240
241 if (itTargetDict != targetDictionary.end())
242 {
243 itTargetDict->second->value = itMapping->value;
244 itTargetDict->second->set = true;
245 }
246 }
247 }
248 }
249
252 {
253 return PM::createMapping();
254 }
255
256 Ice::ObjectPtr
258 {
259 Ice::ObjectPtr ptr = new ParameterMapping(*this);
260 return ptr;
261 }
262
265 {
266 return ParameterMappingPtr::dynamicCast(ice_clone());
267 // ParameterMappingPtr ptr = new ParameterMapping(*this);
268 // return ptr;
269 }
270
272 ParameterMapping::operator=(const ParameterMapping& rhs)
273 {
274 useParentsInput = rhs.useParentsInput;
275 __greedyInput = rhs.__greedyInput;
276 priorities = rhs.priorities;
277 mappings = rhs.mappings;
278 sourceDictionaries.clear();
279
280 for (SourceDictionaryMap::const_iterator it = rhs.sourceDictionaries.begin();
281 it != rhs.sourceDictionaries.end();
282 ++it)
283 {
284 StateUtilFunctions::copyDictionary(it->second, sourceDictionaries[it->first]);
285 }
286
287 return *this;
288 }
289
290 std::string
291 ParameterMapping::MappingSourceToString(MappingSource mappingSource)
292 {
293 switch (mappingSource)
294 {
295 case eParent:
296 return "Parent";
297
298 case eOutput:
299 return "Output";
300
301 case eDataField:
302 return "DataField";
303
304 case eEvent:
305 return "Event";
306
307 case eValue:
308 return "Value";
309
310 default:
311 return "Undefined";
312 }
313 }
314
315 MappingSource
316 ParameterMapping::StringToMappingSource(const std::string& mappingSourceString)
317 {
318 if (mappingSourceString == "Parent")
319 {
320 return eParent;
321 }
322 else if (mappingSourceString == "Output")
323 {
324 return eOutput;
325 }
326 else if (mappingSourceString == "DataField")
327 {
328 return eDataField;
329 }
330 else if (mappingSourceString == "Event")
331 {
332 return eEvent;
333 }
334 else if (mappingSourceString == "Value")
335 {
336 return eValue;
337 }
338 else
339 {
340 return eMappingSourcesCount;
341 }
342 }
343
344 StringVariantContainerBaseMap::const_iterator
345 ParameterMapping::_hasMappingEntry(const std::string& keyDestination,
346 const StringVariantContainerBaseMap& sourceDict,
347 MappingSource allowedMappingSource)
348 {
349 StringVariantContainerBaseMap::const_iterator result;
350 Ice::StringSeq fieldsDest = _getFields(keyDestination);
351
352
353 // first: find entry in mapping that fits somehow to keyDestination
354 // e.g. 'State1.*' fits to 'State1.angle', '*' fits to 'State1.angle', 'angle' does NOT fit to 'State1.angle'
355 // Note: '*.*' is same as '*'
356 int destWildcardIndex = -1;
357 MappingList::const_iterator it;
358
359 for (it = mappings.begin(); it != mappings.end(); ++it)
360 {
361 if (it->mappingSrc != allowedMappingSource)
362 {
363 continue;
364 }
365
366 bool found = true;
367 Ice::StringSeq mappingFields = _getFields(it->targetKey);
368
369 for (unsigned int i = 0; i < fieldsDest.size(); ++i)
370 {
371 if (i >= mappingFields.size())
372 {
373 break;
374 }
375
376 if (mappingFields.at(i) == "*")
377 {
378 destWildcardIndex = i;
379 }
380
381 // check if mapping fields fit to fields of key of destination map
382 if (!(mappingFields.at(i) == "*" || mappingFields.at(i) == fieldsDest.at(i)))
383 {
384 found = false;
385 break;
386 }
387 }
388
389 if (found)
390 {
391 // second: find key in SourceDict that fits to the 2nd parameter of the selected mapping entry
392 result = _findSourceEntry(it->sourceKey, sourceDict, destWildcardIndex, fieldsDest);
393
394 if (result != sourceDict.end())
395 {
396 return result;
397 }
398 }
399 }
400
401 if (it == mappings.end())
402 {
403 result = sourceDict.end(); // not found
404 }
405
406 return result;
407 }
408
409 StringVariantContainerBaseMap::const_iterator
410 ParameterMapping::_findSourceEntry(const std::string sourceKey,
411 const StringVariantContainerBaseMap& sourceDict,
412 int destWildcardIndex,
413 const Ice::StringSeq& fieldsDest)
414 {
415 StringVariantContainerBaseMap::const_iterator result = sourceDict.end();
416 Ice::StringSeq mappingFields = _getFields(sourceKey);
417
418 for (result = sourceDict.begin(); result != sourceDict.end(); ++result)
419 {
420 Ice::StringSeq fieldsSrcDict = _getFields(result->first);
421 bool found = true;
422
423 for (unsigned int i = 0; i < fieldsSrcDict.size(); ++i)
424 {
425 if (i >= mappingFields.size())
426 {
427 break;
428 }
429
430 assert(i < fieldsSrcDict.size());
431
432 if (mappingFields.at(i) == "*")
433 {
434 // check if all fields match after the wildcard
435 for (int j = 0; j < int(fieldsSrcDict.size()) - int(i); ++j)
436 {
437 assert(i + j < fieldsSrcDict.size());
438 assert(destWildcardIndex + j < (int)fieldsDest.size());
439
440 if (fieldsSrcDict.at(i + j) != fieldsDest.at(destWildcardIndex + j))
441 {
442 found = false;
443 break;
444 }
445 }
446
447 if (!found)
448 {
449 break;
450 }
451 }
452 // check if the fields do match exactly
453 else if (mappingFields.at(i) != fieldsSrcDict.at(i))
454 {
455 found = false;
456 break;
457 }
458 }
459
460 if (found)
461 {
462 return result;
463 }
464 }
465
466 return result;
467 }
468
469 Ice::StringSeq
470 ParameterMapping::_getFields(std::string source, char seperator)
471 {
472 std::vector<std::string> result;
473 size_t pos;
474
475 while ((pos = source.find(seperator)) != std::string::npos)
476 {
477 result.push_back(source.substr(0, pos));
478 source = source.substr(pos + 1);
479 }
480
481 result.push_back(source);
482 return result;
483 }
484
485 void
486 ParameterMapping::_addMissingSources(PriorityMap& priorityMap)
487 {
488 int lowestPriority = 0;
489
490 if (priorityMap.begin() != priorityMap.end())
491 {
492 lowestPriority = priorityMap.begin()->first;
493 }
494
495 bool found = false;
496
497 for (int i = 0; i < (int)eMappingSourcesCount; ++i)
498 {
499 PriorityMap::iterator it = priorityMap.begin();
500
501 for (; it != priorityMap.end(); ++it)
502 {
503 if (int(it->second) == i)
504 {
505 found = true;
506 }
507 }
508
509 if (!found)
510 {
511 priorityMap[--lowestPriority] = MappingSource(i);
512 }
513 }
514 }
515
516 // ParameterMappingPtr
517 // ParameterMapping::addTuple(const std::string & sourceKey,
518 // const std::string & targetKey){
519 // Ice::StringSeq sourceKeySeq = getFields(sourceKey);
520 // Ice::StringSeq targetKeySeq = getFields(targetKey);
521 // if((*sourceKeySeq.rbegin()=="*" && *targetKeySeq.rbegin() != "*")
522 // || (*sourceKeySeq.rbegin()!="*" && *targetKeySeq.rbegin() == "*"))
523 // throw exceptions::local::eLogicError("A parameter mapping cannot map from a wildcard to a specific key or vice versa. Either both keys must be wildcards or none.");
524 // paramMapping[targetKey] = sourceKey;
525 // return this;
526 // }
527
530 MappingSource mappingSrc,
531 const Ice::Current& c)
532 {
533 if (priorities.find(priorityLevel) != priorities.end())
534 {
535 std::stringstream stream;
536 stream << "Priority level " << priorityLevel << " already exists!";
538 }
539
540 priorities[priorityLevel] = mappingSrc;
541 return this;
542 }
543
546 const StringVariantContainerBaseMap& sourceDict,
547 const Ice::Current& c)
548 {
549 // StateUtilFunctions::copyDictionary(sourceDict, sourceDictionaries[mappingSrc]);
550 sourceDictionaries[mappingSrc] = sourceDict;
551 return this;
552 }
553
554 void
555 ParameterMapping::addMappingEntry(MappingSource mappingSource,
556 const std::string& sourceKey,
557 const std::string& targetKey,
558 VariantContainerBasePtr value)
559 {
560 if (!value && mappingSource == eValue)
561 {
562 return;
563 }
564 MappingEntry entry;
565 entry.mappingSrc = mappingSource;
566 entry.targetKey = targetKey;
567 entry.sourceKey = sourceKey;
568 entry.value = value;
569 mappings.push_back(entry);
570 }
571
574 {
575 ParameterMappingPtr ptr = new ParameterMapping();
576 return ptr;
577 }
578
580 ParameterMapping::mapFromOutput(const std::string& sourceKey,
581 const std::string& targetKey,
582 const Ice::Current& c)
583 {
584 addMappingEntry(eOutput, sourceKey, targetKey);
585 return this;
586 }
587
589 ParameterMapping::mapFromOutput(const std::string& bothKeys, const Ice::Current& c)
590 {
591 addMappingEntry(eOutput, bothKeys, bothKeys);
592 return this;
593 }
594
596 ParameterMapping::mapFromParent(const std::string& parentKey,
597 const std::string& targetKey,
598 const Ice::Current& c)
599 {
600 addMappingEntry(eParent, parentKey, targetKey);
601 return this;
602 }
603
605 ParameterMapping::mapFromParent(const std::string& bothKeys, const Ice::Current& c)
606 {
607 addMappingEntry(eParent, bothKeys, bothKeys);
608 return this;
609 }
610
612 ParameterMapping::mapFromEvent(const std::string& eventKey,
613 const std::string& targetKey,
614 const Ice::Current& c)
615 {
616 addMappingEntry(eEvent, eventKey, targetKey);
617 return this;
618 }
619
621 ParameterMapping::mapFromEvent(const std::string& bothKeys, const Ice::Current& c)
622 {
623 addMappingEntry(eEvent, bothKeys, bothKeys);
624 return this;
625 }
626
629 const std::string& targetKey,
630 const Ice::Current& c)
631 {
632 DataFieldIdentifierPtr id = DataFieldIdentifierPtr::dynamicCast(dataFieldIdentifier);
633 addMappingEntry(eDataField, id->getIdentifierStr(), targetKey);
634 return this;
635 }
636
639 {
640 __greedyInput = on;
641 return this;
642 }
643
644 void
646 {
647 ParameterMapping::__context = context;
648 }
649} // namespace armarx
650
651std::ostream&
652std::operator<<(std::ostream& stream, const armarx::ParameterMapping& mapping)
653{
654 for (const ::armarx::MappingEntry& elem : mapping.mappings)
655 {
656 stream << armarx::ParameterMapping::MappingSourceToString(elem.mappingSrc) << ": "
657 << elem.sourceKey << " -> " << elem.targetKey << "\n";
658 }
659
660 return stream;
661}
constexpr T c
DataFieldIdentifier provide the basis to identify data field within a distributed ArmarX scenario.
Base Class for all Logging classes.
Definition Logging.h:240
This class maps parameters from several source dictionaries to one input dictionary.
void _fillFromValues(StateParameterMap &targetDictionary)
void _greedyMapping(StateParameterMap &targetDictionary, StringVariantContainerBaseMap &sourceDictionary)
ParameterMappingPtr mapFromParent(const std::string &parentKey, const std::string &targetKey, const Ice::Current &c=Ice::emptyCurrent)
Adds an entry to the ParameterMapping, that maps the sourceKey's value from the parent's input parame...
static void _setStatechartContext(StatechartContext *__context)
ParameterMappingPtr setTargetDictToGreedy(bool on=true)
Sets the behaviour of the mapping into the target dictionary to greedy.
virtual ParameterMappingPtr clone() const
Returns a new instance of ParameterMapping with the contents of this instance.
void _applyMapping(StateParameterMap &targetDictionary)
This function applies a given mapping to the given inputdictionary.
void _fillFromDataField(StateParameterMap &targetDictionary)
ParameterMapping & operator=(const ParameterMapping &rhs)
ParameterMappingPtr mapFromOutput(const std::string &sourceKey, const std::string &targetKey, const Ice::Current &c=Ice::emptyCurrent)
Adds an entry to the ParameterMapping, that maps the sourceKey's value from the output parameters of ...
static void _addMissingSources(PriorityMap &priorityMap)
ParameterMappingPtr setSourcePriority(int priorityLevel, MappingSource mappingSrc, const Ice::Current &c=Ice::emptyCurrent)
Adds a priority for a specific source dictionary to the mapping.
StringVariantContainerBaseMap::const_iterator _findSourceEntry(const std::string sourceKey, const StringVariantContainerBaseMap &sourceDict, int destWildcardIndex, const Ice::StringSeq &fieldsDest)
StringVariantContainerBaseMap::const_iterator _hasMappingEntry(const std::string &keyDestination, const StringVariantContainerBaseMap &sourceDict, MappingSource allowedMappingSource)
Checks wether the mapping has an entry like keyDestination that maps onto a parameter of mapSource.
void addMappingEntry(MappingSource mappingSource, const std::string &sourceKey, const std::string &targetKey, VariantContainerBasePtr value=nullptr)
static Ice::StringSeq _getFields(std::string source, char seperator='.')
Takes a string and seperates the string by the seperator-char.
static std::string MappingSourceToString(MappingSource mappingSource)
ParameterMappingPtr mapFromEvent(const std::string &eventKey, const std::string &targetKey, const Ice::Current &c=Ice::emptyCurrent)
Adds an entry to the ParameterMapping, that maps the sourceKey's value from the event parameters of t...
::Ice::ObjectPtr ice_clone() const override
Returns a new instance of ParameterMapping with the contents of this instance.
ParameterMappingPtr _addSourceDictionary(MappingSource mappingSrc, const StringVariantContainerBaseMap &sourceDict, const Ice::Current &c=Ice::emptyCurrent)
ParameterMappingPtr mapFromDataField(const DataFieldIdentifierBasePtr &dataFieldIdentifier, const std::string &targetKey, const Ice::Current &c=Ice::emptyCurrent)
Adds an entry to the ParameterMapping, that maps the value of the datafield entry to the targetKey's ...
static ParameterMappingPtr createMapping()
Creates a new instance of a ParameterMapping. Since the constructors are private, this method must be...
static MappingSource StringToMappingSource(const std::string &mappingSourceString)
The SingleVariant class is required to store single Variant instances in VariantContainer subclasses.
static StateParameterPtr create()
This class contains a statechart and provides the interfaces to distributed components.
The Variant class is described here: Variants.
Definition Variant.h:224
void copyDictionary(const StringVariantContainerBaseMap &source, StringVariantContainerBaseMap &destination)
Clears the destination map and copies the parameters of the source in it.
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceInternal::Handle< StateParameter > StateParameterPtr
IceInternal::Handle< DataFieldIdentifierBase > DataFieldIdentifierBasePtr
IceInternal::Handle< DataFieldIdentifier > DataFieldIdentifierPtr
Typedef of DataFieldIdentifierPtr as IceInternal::Handle<DataFieldIdentifier> for convenience.
IceInternal::Handle< ParameterMapping > ParameterMappingPtr
ParameterMappingPtr createMapping()
Returns a new and empty instance of ParameterMapping.
Vertex source(const detail::edge_base< Directed, Vertex > &e, const PCG &)
ARMARXCORE_IMPORT_EXPORT ostream & operator<<(ostream &stream, const armarx::RunningTaskIceBase &task)