MemoryNameSystem.cpp
Go to the documentation of this file.
1#include "MemoryNameSystem.h"
2
3#include <map>
4#include <optional>
5#include <sstream>
6#include <string>
7#include <vector>
8
9#include <Ice/Exception.h>
10#include <Ice/LocalException.h>
11
12#include <SimoxUtility/algorithm/string/string_tools.h>
13
18
24#include <RobotAPI/interface/armem/mns/MemoryNameSystemInterface.h>
27
29{
30
34
35 MemoryNameSystem::MemoryNameSystem(mns::MemoryNameSystemInterfacePrx mns,
36 ManagedIceObject* component) :
37 util::MemoryListener(component), mns(mns), component(component)
38 {
39 }
40
41 void
42 MemoryNameSystem::initialize(mns::MemoryNameSystemInterfacePrx mns, ManagedIceObject* component)
43 {
44 this->mns = mns;
45 setComponent(component);
46 }
47
48 void
50 {
52
53 mns::dto::GetAllRegisteredServersResult result;
54 try
55 {
56 result = mns->getAllRegisteredServers();
57 }
58 catch (const Ice::NotRegisteredException& e)
59 {
61 }
62
63 if (result.success)
64 {
65 for (const auto& [name, server] : result.servers)
66 {
67 auto [it, inserted] = servers.try_emplace(name, server);
68 if (inserted)
69 {
70 // OK
71 }
72 else
73 {
74 // Compare ice identities, update if it changed.
75 auto foo = [](auto& oldProxy, const auto& newProxy)
76 {
77 if (not newProxy)
78 {
79 ARMARX_WARNING << "New proxy is invalid";
80 return;
81 }
82
83 try
84 {
85 newProxy->ice_ping();
86 }
87 catch (const Ice::Exception& e)
88 {
89 // The new proxy must be reachable
91 }
92
93 if (not oldProxy)
94 {
95 ARMARX_WARNING << "Old proxy is invalid";
96 oldProxy = newProxy;
97 return;
98 }
99
100 try
101 {
102 oldProxy->ice_ping();
103
104 if (oldProxy->ice_getIdentity() != newProxy->ice_getIdentity())
105 {
106 // Replace old proxy by new one. This is the case if the identity changed.
107 oldProxy = newProxy;
108 }
109 }
110 catch (const Ice::Exception&)
111 {
112 // if there is any exception, replace the old proxy by the new one
113 oldProxy = newProxy;
114 }
115 };
116 foo(it->second.reading, server.reading);
117 foo(it->second.writing, server.writing);
118 foo(it->second.prediction, server.prediction);
119 foo(it->second.actions, server.actions);
120 foo(it->second.configuration, server.configuration);
121 foo(it->second.loading, server.loading);
122 foo(it->second.readingLtm, server.readingLtm);
123 }
124 }
125 // Remove all entries which are not there anymore.
126 for (auto it = servers.begin(); it != servers.end();)
127 {
128 if (result.servers.count(it->first) == 0)
129 {
130 it = servers.erase(it);
131 }
132 else
133 {
134 ++it;
135 }
136 }
137 }
138 else
139 {
140 throw error::MemoryNameSystemQueryFailed(result.errorMessage);
141 }
142 }
143
144 mns::dto::MemoryServerInterfaces
146 {
147 update();
148 if (auto it = servers.find(memoryID.memoryName); it != servers.end())
149 {
150 return it->second;
151 }
152 else
153 {
155 }
156 }
157
158 mns::dto::MemoryServerInterfaces
159 MemoryNameSystem::waitForServer(const MemoryID& memoryID)
160 {
161 update();
162 if (memoryID.memoryName.empty())
163 {
164 ARMARX_WARNING << "waitForServer called with EMPTY memory name! "
165 << "This will block forever. MemoryID: " << memoryID;
166 }
167 if (auto it = servers.find(memoryID.memoryName); it != servers.end())
168 {
169 return it->second;
170 }
171 else
172 {
173 mns::dto::WaitForServerInput input;
174 input.name = memoryID.memoryName;
175
177 ARMARX_INFO << "Waiting for memory server for " << memoryID << " ...";
178 mns::dto::WaitForServerResult result = mns->waitForServer(input);
179 if (result.success)
180 {
181 ARMARX_INFO << "Resolved memory for " << memoryID << ".";
182 return result.server;
183 }
184 else
185 {
186 throw error::CouldNotResolveMemoryServer(memoryID, result.errorMessage);
187 }
188 }
189 }
190
191 mns::dto::MemoryServerInterfaces
192 MemoryNameSystem::useServer(const MemoryID& memoryID)
193 {
194 ARMARX_CHECK_NOT_NULL(component)
195 << "Owning component not set when using a memory server. \n"
196 << "When calling `armem::mns::MemoryNameSystem::useServer()`, the owning component "
197 "which should "
198 << "receive the dependency to the memory server must be set beforehand. \n\n"
199 << "Use `armem::mns::MemoryNameSystem::setComponent()` or pass the component on "
200 "construction "
201 << "before calling useServer().";
202 return useServer(memoryID, *component);
203 }
204
205 mns::dto::MemoryServerInterfaces
206 MemoryNameSystem::useServer(const MemoryID& memoryID, ManagedIceObject& component)
207 {
208 mns::dto::MemoryServerInterfaces server = waitForServer(memoryID);
209 // Add dependency.
210
211 component.usingProxy(server.reading->ice_getIdentity().name);
212 return server;
213 }
214
215 mns::dto::MemoryServerInterfaces
216 MemoryNameSystem::useServer(const std::string& memoryName)
217 {
218 return useServer(MemoryID().withMemoryName(memoryName));
219 }
220
221 mns::dto::MemoryServerInterfaces
222 MemoryNameSystem::useServer(const std::string& memoryName, ManagedIceObject& component)
223 {
224 return useServer(MemoryID().withMemoryName(memoryName), component);
225 }
226
229 {
230 auto server = resolveServer(memoryID);
231 return Configurator(server.configuration);
232 }
233
236 {
237 auto server = useServer(memoryID);
238 return Configurator(server.configuration);
239 }
240
243 {
244 auto server = useServer(memoryID, component);
245 return Configurator(server.configuration);
246 }
247
249 MemoryNameSystem::useConfigurator(const std::string& memoryName)
250 {
251 return useConfigurator(MemoryID().withMemoryName(memoryName));
252 }
253
255 MemoryNameSystem::useConfigurator(const std::string& memoryName, ManagedIceObject& component)
256 {
257 return useConfigurator(MemoryID().withMemoryName(memoryName), component);
258 }
259
260 Loader
262 {
263 auto server = resolveServer(memoryID);
264 return Loader(server.loading);
265 }
266
267 Loader
269 {
270 auto server = useServer(memoryID);
271 return Loader(server.loading);
272 }
273
274 Loader
276 {
277 auto server = useServer(memoryID, component);
278 return Loader(server.loading);
279 }
280
281 Loader
282 MemoryNameSystem::useLoader(const std::string& memoryName)
283 {
284 return useLoader(MemoryID().withMemoryName(memoryName));
285 }
286
287 Loader
288 MemoryNameSystem::useLoader(const std::string& memoryName, ManagedIceObject& component)
289 {
290 return useLoader(MemoryID().withMemoryName(memoryName), component);
291 }
292
293 Reader
295 {
296 auto server = resolveServer(memoryID);
297 return Reader(server.reading, server.prediction, server.readingLtm);
298 }
299
300 Reader
302 {
303 auto server = useServer(memoryID);
304 return Reader(server.reading, server.prediction, server.readingLtm);
305 }
306
307 Reader
309 {
310 auto server = useServer(memoryID, component);
311 return Reader(server.reading, server.prediction, server.readingLtm);
312 }
313
314 Reader
315 MemoryNameSystem::useReader(const std::string& memoryName)
316 {
317 return useReader(MemoryID().withMemoryName(memoryName));
318 }
319
320 Reader
321 MemoryNameSystem::useReader(const std::string& memoryName, ManagedIceObject& component)
322 {
323 return useReader(MemoryID().withMemoryName(memoryName), component);
324 }
325
326 template <class ClientT>
327 std::map<std::string, ClientT>
328 MemoryNameSystem::_getAllClients(ClientFactory<ClientT>&& factory) const
329 {
330 std::map<std::string, ClientT> result;
331 for (const auto& [name, server] : servers)
332 {
333 if (std::optional<ClientT> client = factory(server))
334 {
335 result[name] = client.value();
336 }
337 }
338 return result;
339 }
340
341 std::optional<Configurator>
342 configuratorFactory(const mns::dto::MemoryServerInterfaces& server)
343 {
344 if (auto config = server.configuration)
345 {
346 return Configurator(config);
347 }
348
349 return std::nullopt;
350 }
351
352 std::optional<Loader>
353 loaderFactory(const mns::dto::MemoryServerInterfaces& server)
354 {
355 if (auto load = server.loading)
356 {
357 return Loader(load);
358 }
359
360 return std::nullopt;
361 }
362
363 std::optional<Reader>
364 readerFactory(const mns::dto::MemoryServerInterfaces& server)
365 {
366 if (auto read = server.reading)
367 {
368 if (auto predict = server.prediction)
369 {
370 if (auto readLtm = server.readingLtm)
371 {
372 return Reader(read, predict, readLtm);
373 }
374
375 return Reader(read, predict);
376 }
377 else
378 {
379 return Reader(read);
380 }
381 }
382 return std::nullopt;
383 }
384
385 std::optional<Writer>
386 writerFactory(const mns::dto::MemoryServerInterfaces& server)
387 {
388 if (auto write = server.writing)
389 {
390 return Writer(write);
391 }
392 return std::nullopt;
393 }
394
395 std::map<std::string, Loader>
397 {
398 if (update)
399 {
400 this->update();
401 }
402
403 return _getAllClients<Loader>(loaderFactory);
404 }
405
406 std::map<std::string, Loader>
408 {
409 return _getAllClients<Loader>(loaderFactory);
410 }
411
412 std::map<std::string, Configurator>
414 {
415 if (update)
416 {
417 this->update();
418 }
419
420 return _getAllClients<Configurator>(configuratorFactory);
421 }
422
423 std::map<std::string, Configurator>
425 {
426 return _getAllClients<Configurator>(configuratorFactory);
427 }
428
429 std::map<std::string, Reader>
431 {
432 if (update)
433 {
434 this->update();
435 }
436
437 return _getAllClients<Reader>(readerFactory);
438 }
439
440 std::map<std::string, Reader>
442 {
443 return _getAllClients<Reader>(readerFactory);
444 }
445
446 Writer
448 {
449 return Writer(resolveServer(memoryID).writing);
450 }
451
452 Writer
454 {
455 return Writer(useServer(memoryID).writing);
456 }
457
458 Writer
460 {
461 return Writer(useServer(memoryID, component).writing);
462 }
463
464 Writer
465 MemoryNameSystem::useWriter(const std::string& memoryName)
466 {
467 return useWriter(MemoryID().withMemoryName(memoryName));
468 }
469
470 Writer
471 MemoryNameSystem::useWriter(const std::string& memoryName, ManagedIceObject& component)
472 {
473 return useWriter(MemoryID().withMemoryName(memoryName), component);
474 }
475
476 std::map<std::string, Writer>
478 {
479 if (update)
480 {
481 this->update();
482 }
483 return _getAllClients<Writer>(writerFactory);
484 }
485
486 std::map<std::string, Writer>
488 {
489 return _getAllClients<Writer>(writerFactory);
490 }
491
492 std::optional<wm::EntityInstance>
494 {
495 auto result = resolveEntityInstances({id});
496 if (result.size() > 0)
497 {
498 return result.begin()->second;
499 }
500 else
501 {
502 return std::nullopt;
503 }
504 }
505
506 std::map<MemoryID, wm::EntityInstance>
507 MemoryNameSystem::resolveEntityInstances(const std::vector<MemoryID>& ids)
508 {
509 std::stringstream errors;
510 int errorCounter = 0;
511
512 std::map<std::string, std::vector<MemoryID>> idsPerMemory;
513 for (const auto& id : ids)
514 {
515 idsPerMemory[id.memoryName].push_back(id);
516 }
517
518 std::map<MemoryID, wm::EntityInstance> result;
519 for (const auto& [memoryName, ids] : idsPerMemory)
520 {
521 Reader reader = getReader(MemoryID().withMemoryName(memoryName));
522 QueryResult queryResult = reader.queryMemoryIDs(ids);
523 if (queryResult.success)
524 {
525 for (const MemoryID& id : ids)
526 {
527 try
528 {
529 if (id.hasInstanceIndex())
530 {
531 result[id] = queryResult.memory.getInstance(id);
532 }
533 else if (id.hasTimestamp())
534 {
535 result[id] = queryResult.memory.getSnapshot(id).getInstance(0);
536 }
537 else if (id.hasEntityName())
538 {
539 result[id] =
540 queryResult.memory.getEntity(id).getLatestSnapshot().getInstance(0);
541 }
542 else
543 {
544 std::stringstream ss;
545 ss << "MemoryNameSystem::" << __FUNCTION__
546 << "requires IDs to be entity, snapshot or instance IDs,"
547 << "but ID has no entity name.";
548 throw error::InvalidMemoryID(id, ss.str());
549 }
550 }
551 catch (const error::ArMemError& e)
552 {
553 errors << "\n#" << ++errorCounter << "\n"
554 << "Failed to retrieve " << id << " from query result: \n"
555 << e.what();
556 }
557 }
558 }
559 else
560 {
561 errors << "\n# " << ++errorCounter << "\n"
562 << "Failed to query '" << memoryName << "': \n"
563 << queryResult.errorMessage;
564 }
565 }
566
567 if (errors.str().size() > 0)
568 {
569 ARMARX_INFO << "MemoryNameSystem::" << __FUNCTION__
570 << ": The following errors may affect your result: "
571 << "\n\n"
572 << errors.str() << "\n\n"
573 << "When querying entity instances: \n- "
574 << simox::alg::join(simox::alg::multi_to_string(ids), "\n- ");
575 }
576
577 return result;
578 }
579
580 void
582 mns::dto::MemoryServerInterfaces server)
583 {
584 mns::dto::RegisterServerInput input;
585 input.name = memoryID.memoryName;
586 input.server = server;
587 ARMARX_CHECK(server.reading or server.writing or server.configuration or server.loading or
588 server.readingLtm)
589 << VAROUT(server.reading) << " | " << VAROUT(server.writing) << " | "
590 << VAROUT(server.configuration) << " | " << VAROUT(server.loading) << " | "
591 << VAROUT(server.readingLtm);
592
594 mns::dto::RegisterServerResult result = mns->registerServer(input);
595 if (!result.success)
596 {
598 "register", memoryID, result.errorMessage);
599 }
600 }
601
602 void
604 {
605 mns::dto::RemoveServerInput input;
606 input.name = memoryID.memoryName;
607
609 mns::dto::RemoveServerResult result = mns->removeServer(input);
610 if (!result.success)
611 {
612 throw error::ServerRegistrationOrRemovalFailed("remove", memoryID, result.errorMessage);
613 }
614 }
615
616 mns::MemoryNameSystemInterfacePrx
618 {
619 return mns;
620 }
621
622 void
623 MemoryNameSystem::getMemoryNameSystem(mns::MemoryNameSystemInterfacePrx mns)
624 {
625 this->mns = mns;
626 }
627
628 void
630 {
632 this->component = component;
633 }
634
635} // namespace armarx::armem::client
#define VAROUT(x)
The ManagedIceObject is the base class for all ArmarX objects.
std::string memoryName
Definition MemoryID.h:50
Configure a memory server.
Load LTMs into WM.
Definition Loader.h:12
void initialize(mns::MemoryNameSystemInterfacePrx mns, ManagedIceObject *component=nullptr)
std::optional< wm::EntityInstance > resolveEntityInstance(const MemoryID &id)
Resolve a memory ID to an EntityInstance.
Loader getLoader(const MemoryID &memoryID)
mns::dto::MemoryServerInterfaces resolveServer(const MemoryID &memoryID)
Resolve the given memory server for the given memory ID.
Configurator useConfigurator(const MemoryID &memoryID)
Use a memory server and get a configurator for it.
std::map< std::string, Reader > getAllReaders() const
Get Readers for all registered servers (without updating).
Reader getReader(const MemoryID &memoryID)
Get a reader to the given memory name.
std::map< std::string, Writer > getAllWriters() const
Get Writers for all registered servers (without updating).
void removeServer(const MemoryID &memoryID)
Remove a memory server from the MNS.
std::map< std::string, Loader > getAllLoaders() const
Get Loaders for all registered servers (without updating).
Loader useLoader(const MemoryID &memoryID)
Use a memory server and get a configurator for it.
Writer useWriter(const MemoryID &memoryID)
Use a memory server and get a writer for it.
std::map< std::string, Configurator > getAllConfigurators() const
Get Configurators for all registered servers (without updating).
Reader useReader(const MemoryID &memoryID)
Use a memory server and get a reader for it.
Configurator getConfigurator(const MemoryID &memoryID)
Get a configurator to the given memory name.
void registerServer(const MemoryID &memoryID, mns::dto::MemoryServerInterfaces server)
Register a memory server in the MNS.
mns::MemoryNameSystemInterfacePrx getMemoryNameSystem() const
void update()
Update the internal registry to the data in the MNS.
void setComponent(ManagedIceObject *component)
std::map< MemoryID, wm::EntityInstance > resolveEntityInstances(const std::vector< MemoryID > &ids)
Writer getWriter(const MemoryID &memoryID)
Get a writer to the given memory name.
Reads data from a memory server.
Definition Reader.h:25
QueryResult queryMemoryIDs(const std::vector< MemoryID > &ids, armem::query::DataMode dataMode=armem::query::DataMode::WithData) const
Query a specific set of memory IDs.
Definition Reader.cpp:374
Helps a memory client sending data to a memory.
Definition Writer.h:23
MemoryListener(ManagedIceObject *component=nullptr)
void setComponent(ManagedIceObject *component)
Base class for all exceptions thrown by the armem library.
Definition ArMemError.h:19
Indicates that a query to the Memory Name System failed.
Definition mns.h:25
Indicates that a memory ID is invalid, e.g.
Definition ArMemError.h:152
Indicates that a query to the Memory Name System failed.
Definition mns.h:12
Indicates that a query to the Memory Name System failed.
Definition mns.h:36
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
This file is part of ArmarX.
std::optional< Reader > readerFactory(const mns::dto::MemoryServerInterfaces &server)
std::optional< Configurator > configuratorFactory(const mns::dto::MemoryServerInterfaces &server)
std::optional< Loader > loaderFactory(const mns::dto::MemoryServerInterfaces &server)
std::optional< Writer > writerFactory(const mns::dto::MemoryServerInterfaces &server)
const armem::MemoryID MemoryID
Definition memory_ids.cpp:6
void read(auto &eigen, auto *table)
auto & getEntity(const MemoryID &entityID)
Retrieve an entity.
auto & getInstance(const MemoryID &instanceID)
Retrieve an entity instance.
auto & getSnapshot(const MemoryID &snapshotID)
Retrieve an entity snapshot.
Result of a QueryInput.
Definition Query.h:51
wm::Memory memory
The slice of the memory that matched the query.
Definition Query.h:58