MemoryNameSystem.cpp
Go to the documentation of this file.
1 #include "MemoryNameSystem.h"
2 
5 
9 
10 #include <SimoxUtility/algorithm/string/string_tools.h>
11 
12 
13 
14 namespace armarx::armem::client
15 {
16 
18  {
19  }
20 
21 
22  MemoryNameSystem::MemoryNameSystem(mns::MemoryNameSystemInterfacePrx mns, ManagedIceObject* component) :
23  util::MemoryListener(component),
24  mns(mns), component(component)
25  {
26  }
27 
28 
29  void MemoryNameSystem::initialize(mns::MemoryNameSystemInterfacePrx mns, ManagedIceObject* component)
30  {
31  this->mns = mns;
33  }
34 
35 
37  {
39 
40  mns::dto::GetAllRegisteredServersResult result;
41  try
42  {
43  result = mns->getAllRegisteredServers();
44  }
45  catch (const Ice::NotRegisteredException& e)
46  {
47  throw error::MemoryNameSystemQueryFailed(e.what());
48  }
49 
50  if (result.success)
51  {
52  for (const auto& [name, server] : result.servers)
53  {
54  auto [it, inserted] = servers.try_emplace(name, server);
55  if (inserted)
56  {
57  // OK
58  }
59  else
60  {
61  // Compare ice identities, update if it changed.
62  auto foo = [](auto & oldProxy, const auto & newProxy)
63  {
64  if (oldProxy->ice_getIdentity() != newProxy->ice_getIdentity())
65  {
66  // Replace old proxy by new one.
67  oldProxy = newProxy;
68  }
69  };
70  foo(it->second.reading, server.reading);
71  foo(it->second.writing, server.writing);
72  foo(it->second.prediction, server.prediction);
73  foo(it->second.actions, server.actions);
74  }
75  }
76  // Remove all entries which are not there anymore.
77  for (auto it = servers.begin(); it != servers.end();)
78  {
79  if (result.servers.count(it->first) == 0)
80  {
81  it = servers.erase(it);
82  }
83  else
84  {
85  ++it;
86  }
87  }
88  }
89  else
90  {
91  throw error::MemoryNameSystemQueryFailed(result.errorMessage);
92  }
93  }
94 
95 
96  mns::dto::MemoryServerInterfaces
98  {
99  if (auto it = servers.find(memoryID.memoryName); it != servers.end())
100  {
101  return it->second;
102  }
103  else
104  {
105  update();
106  if (auto it = servers.find(memoryID.memoryName); it != servers.end())
107  {
108  return it->second;
109  }
110  else
111  {
113  }
114  }
115  }
116 
117 
118  mns::dto::MemoryServerInterfaces MemoryNameSystem::waitForServer(const MemoryID& memoryID)
119  {
120  if (auto it = servers.find(memoryID.memoryName); it != servers.end())
121  {
122  return it->second;
123  }
124  else
125  {
126  mns::dto::WaitForServerInput input;
127  input.name = memoryID.memoryName;
128 
130  ARMARX_INFO << "Waiting for memory server for " << memoryID << " ...";
131  mns::dto::WaitForServerResult result = mns->waitForServer(input);
132  if (result.success)
133  {
134  ARMARX_INFO << "Resolved memory for " << memoryID << ".";
135  return result.server;
136  }
137  else
138  {
139  throw error::CouldNotResolveMemoryServer(memoryID, result.errorMessage);
140  }
141  }
142  }
143 
144  mns::dto::MemoryServerInterfaces MemoryNameSystem::useServer(const MemoryID& memoryID)
145  {
146  ARMARX_CHECK_NOT_NULL(component)
147  << "Owning component not set when using a memory server. \n"
148  << "When calling `armem::mns::MemoryNameSystem::useServer()`, the owning component which should "
149  << "receive the dependency to the memory server must be set beforehand. \n\n"
150  << "Use `armem::mns::MemoryNameSystem::setComponent()` or pass the component on construction "
151  << "before calling useServer().";
152  return useServer(memoryID, *component);
153  }
154 
155 
156  mns::dto::MemoryServerInterfaces MemoryNameSystem::useServer(const MemoryID& memoryID, ManagedIceObject& component)
157  {
158  mns::dto::MemoryServerInterfaces server = waitForServer(memoryID);
159  // Add dependency.
160  component.usingProxy(server.reading->ice_getIdentity().name);
161  return server;
162  }
163 
164 
165  mns::dto::MemoryServerInterfaces MemoryNameSystem::useServer(const std::string& memoryName)
166  {
167  return useServer(MemoryID().withMemoryName(memoryName));
168  }
169 
170 
171  mns::dto::MemoryServerInterfaces MemoryNameSystem::useServer(const std::string& memoryName, ManagedIceObject& component)
172  {
173  return useServer(MemoryID().withMemoryName(memoryName), component);
174  }
175 
176 
178  {
179  auto server = resolveServer(memoryID);
180  return Reader(server.reading, server.prediction);
181  }
182 
183 
185  {
186  auto server = useServer(memoryID);
187  return Reader(server.reading, server.prediction);
188  }
189 
190 
192  {
193  auto server = useServer(memoryID, component);
194  return Reader(server.reading, server.prediction);
195  }
196 
197 
199  {
200  return useReader(MemoryID().withMemoryName(memoryName));
201  }
202 
203 
205  {
206  return useReader(MemoryID().withMemoryName(memoryName), component);
207  }
208 
209 
210  template <class ClientT>
211  std::map<std::string, ClientT>
212  MemoryNameSystem::_getAllClients(ClientFactory<ClientT>&& factory) const
213  {
214  std::map<std::string, ClientT> result;
215  for (const auto& [name, server] : servers)
216  {
217  if (std::optional<ClientT> client = factory(server))
218  {
219  result[name] = client.value();
220  }
221  }
222  return result;
223  }
224 
225 
226  std::optional<Reader> readerFactory(const mns::dto::MemoryServerInterfaces& server)
227  {
228  if (auto read = server.reading)
229  {
230  if (auto predict = server.prediction)
231  {
232  return Reader(read, predict);
233  }
234  else
235  {
236  return Reader(read);
237  }
238  }
239  return std::nullopt;
240  }
241 
242 
243  std::optional<Writer> writerFactory(const mns::dto::MemoryServerInterfaces& server)
244  {
245  if (auto write = server.writing)
246  {
247  return Writer(write);
248  }
249  return std::nullopt;
250  }
251 
252 
253  std::map<std::string, Reader> MemoryNameSystem::getAllReaders(bool update)
254  {
255  if (update)
256  {
257  this->update();
258  }
259 
260  return _getAllClients<Reader>(readerFactory);
261  }
262 
263 
264  std::map<std::string, Reader> MemoryNameSystem::getAllReaders() const
265  {
266  return _getAllClients<Reader>(readerFactory);
267  }
268 
269 
271  {
272  return Writer(resolveServer(memoryID).writing);
273  }
274 
275 
277  {
278  return Writer(useServer(memoryID).writing);
279  }
280 
281 
283  {
284  return Writer(useServer(memoryID, component).writing);
285  }
286 
287 
289  {
290  return useWriter(MemoryID().withMemoryName(memoryName));
291  }
292 
293 
295  {
296  return useWriter(MemoryID().withMemoryName(memoryName), component);
297  }
298 
299 
300  std::map<std::string, Writer> MemoryNameSystem::getAllWriters(bool update)
301  {
302  if (update)
303  {
304  this->update();
305  }
306  return _getAllClients<Writer>(writerFactory);
307  }
308 
309 
310  std::map<std::string, Writer> MemoryNameSystem::getAllWriters() const
311  {
312  return _getAllClients<Writer>(writerFactory);
313  }
314 
315 
316  std::optional<wm::EntityInstance> MemoryNameSystem::resolveEntityInstance(const MemoryID& id)
317  {
318  auto result = resolveEntityInstances({id});
319  if (result.size() > 0)
320  {
321  return result.begin()->second;
322  }
323  else
324  {
325  return std::nullopt;
326  }
327  }
328 
329 
330  std::map<MemoryID, wm::EntityInstance> MemoryNameSystem::resolveEntityInstances(const std::vector<MemoryID>& ids)
331  {
332  std::stringstream errors;
333  int errorCounter = 0;
334 
335  std::map<std::string, std::vector<MemoryID>> idsPerMemory;
336  for (const auto& id : ids)
337  {
338  idsPerMemory[id.memoryName].push_back(id);
339  }
340 
341  std::map<MemoryID, wm::EntityInstance> result;
342  for (const auto& [memoryName, ids] : idsPerMemory)
343  {
344  Reader reader = getReader(MemoryID().withMemoryName(memoryName));
345  QueryResult queryResult = reader.queryMemoryIDs(ids);
346  if (queryResult.success)
347  {
348  for (const MemoryID& id : ids)
349  {
350  try
351  {
352  if (id.hasInstanceIndex())
353  {
354  result[id] = queryResult.memory.getInstance(id);
355  }
356  else if (id.hasTimestamp())
357  {
358  result[id] = queryResult.memory.getSnapshot(id).getInstance(0);
359  }
360  else if (id.hasEntityName())
361  {
362  result[id] = queryResult.memory.getEntity(id).getLatestSnapshot().getInstance(0);
363  }
364  else
365  {
366  std::stringstream ss;
367  ss << "MemoryNameSystem::" << __FUNCTION__ << "requires IDs to be entity, snapshot or instance IDs,"
368  << "but ID has no entity name.";
369  throw error::InvalidMemoryID(id, ss.str());
370  }
371  }
372  catch (const error::ArMemError& e)
373  {
374  errors << "\n#" << ++errorCounter << "\n"
375  << "Failed to retrieve " << id << " from query result: \n" << e.what();
376  }
377  }
378  }
379  else
380  {
381  errors << "\n# " << ++errorCounter << "\n"
382  << "Failed to query '" << memoryName << "': \n" << queryResult.errorMessage;
383  }
384  }
385 
386  if (errors.str().size() > 0)
387  {
388  ARMARX_INFO << "MemoryNameSystem::" << __FUNCTION__ << ": The following errors may affect your result: "
389  << "\n\n" << errors.str() << "\n\n"
390  << "When querying entity instances: \n- "
391  << simox::alg::join(simox::alg::multi_to_string(ids), "\n- ");
392  }
393 
394  return result;
395  }
396 
397 
398  void MemoryNameSystem::registerServer(const MemoryID& memoryID, mns::dto::MemoryServerInterfaces server)
399  {
400  mns::dto::RegisterServerInput input;
401  input.name = memoryID.memoryName;
402  input.server = server;
403  ARMARX_CHECK(server.reading or server.writing) << VAROUT(server.reading) << " | " << VAROUT(server.writing);
404 
406  mns::dto::RegisterServerResult result = mns->registerServer(input);
407  if (!result.success)
408  {
409  throw error::ServerRegistrationOrRemovalFailed("register", memoryID, result.errorMessage);
410  }
411  }
412 
413 
415  {
416  mns::dto::RemoveServerInput input;
417  input.name = memoryID.memoryName;
418 
420  mns::dto::RemoveServerResult result = mns->removeServer(input);
421  if (!result.success)
422  {
423  throw error::ServerRegistrationOrRemovalFailed("remove", memoryID, result.errorMessage);
424  }
425  }
426 
427 
428  mns::MemoryNameSystemInterfacePrx MemoryNameSystem::getMemoryNameSystem() const
429  {
430  return mns;
431  }
432 
433 
434  void MemoryNameSystem::getMemoryNameSystem(mns::MemoryNameSystemInterfacePrx mns)
435  {
436  this->mns = mns;
437  }
438 
439 
441  {
443  this->component = component;
444  }
445 
446 }
447 
448 
449 
armarx::armem::detail::SuccessHeader::success
bool success
Definition: SuccessHeader.h:20
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:97
armarx::armem::client::MemoryNameSystem::removeServer
void removeServer(const MemoryID &memoryID)
Remove a memory server from the MNS.
Definition: MemoryNameSystem.cpp:414
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:243
armarx::ProxyType::component
@ component
armarx::armem::error::MemoryNameSystemQueryFailed
Indicates that a query to the Memory Name System failed.
Definition: mns.h:12
armarx::armem::client::MemoryNameSystem::getAllReaders
std::map< std::string, Reader > getAllReaders() const
Get Readers for all registered servers (without updating).
Definition: MemoryNameSystem.cpp:264
armarx::armem::base::detail::GetFindEntityMixin::getEntity
auto & getEntity(const MemoryID &entityID)
Retrieve an entity.
Definition: lookup_mixins.h:445
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:276
armarx::armem::client::MemoryNameSystem::getAllWriters
std::map< std::string, Writer > getAllWriters() const
Get Writers for all registered servers (without updating).
Definition: MemoryNameSystem.cpp:310
armarx::armem::client
This file is part of ArmarX.
Definition: forward_declarations.h:7
armarx::armem::client::MemoryNameSystem::registerServer
void registerServer(const MemoryID &memoryID, mns::dto::MemoryServerInterfaces server)
Register a memory server in the MNS.
Definition: MemoryNameSystem.cpp:398
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:316
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::getWriter
Writer getWriter(const MemoryID &memoryID)
Get a writer to the given memory name.
Definition: MemoryNameSystem.cpp:270
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:290
armarx::armem::detail::SuccessHeader::errorMessage
std::string errorMessage
Definition: SuccessHeader.h:21
armarx::armem::MemoryID
A memory ID.
Definition: MemoryID.h:47
armarx::armem::client::readerFactory
std::optional< Reader > readerFactory(const mns::dto::MemoryServerInterfaces &server)
Definition: MemoryNameSystem.cpp:226
ManagedIceObject.h
armarx::aron::input
ReaderT::InputType & input
Definition: rw.h:19
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:184
armarx::read
void read(auto &eigen, auto *table)
Definition: FTSensorCalibrationGuiWidgetController.cpp:462
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:67
armarx::armem::MemoryID::memoryName
std::string memoryName
Definition: MemoryID.h:50
armarx::armem::client::MemoryNameSystem::getMemoryNameSystem
mns::MemoryNameSystemInterfacePrx getMemoryNameSystem() const
Definition: MemoryNameSystem.cpp:428
ExpressionException.h
armarx::armem::client::MemoryNameSystem::resolveEntityInstances
std::map< MemoryID, wm::EntityInstance > resolveEntityInstances(const std::vector< MemoryID > &ids)
Definition: MemoryNameSystem.cpp:330
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:163
armarx::armem::client::MemoryNameSystem::setComponent
void setComponent(ManagedIceObject *component)
Definition: MemoryNameSystem.cpp:440
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:174
VAROUT
#define VAROUT(x)
Definition: StringHelpers.h:182
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:40
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:29
armarx::armem::client::MemoryNameSystem::initialize
void initialize(mns::MemoryNameSystemInterfacePrx mns, ManagedIceObject *component=nullptr)
Definition: MemoryNameSystem.cpp:29
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:130
armarx::armem::error::CouldNotResolveMemoryServer
Indicates that a query to the Memory Name System failed.
Definition: mns.h:26
MemoryNameSystem.h
armarx::armem::client::MemoryNameSystem::update
void update()
Update the internal registry to the data in the MNS.
Definition: MemoryNameSystem.cpp:36
armarx::armem::client::MemoryNameSystem::getReader
Reader getReader(const MemoryID &memoryID)
Get a reader to the given memory name.
Definition: MemoryNameSystem.cpp:177
armarx::armem::client::MemoryNameSystem::MemoryNameSystem
MemoryNameSystem()
Definition: MemoryNameSystem.cpp:17
armarx::human::MemoryID
const armem::MemoryID MemoryID
Definition: memory_ids.cpp:29