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