icub-client
opcClient.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 WYSIWYD Consortium, European Commission FP7 Project ICT-612139
3  * Authors: Stéphane Lallée
4  * email: stephane.lallee@gmail.com
5  * website: https://github.com/robotology/icub-client/
6  * Permission is granted to copy, distribute, and/or modify this program
7  * under the terms of the GNU General Public License, version 2 or any
8  * later version published by the Free Software Foundation.
9  *
10  * A copy of the license can be found at
11  * icub-client/license/gpl.txt
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16  * Public License for more details
17  */
18 
19 
21 
22 #include <yarp/os/all.h>
23 #include <iostream>
24 #include <string>
25 #include <map>
26 #include <list>
27 
28 using namespace std;
29 using namespace yarp::os;
30 using namespace icubclient;
31 
32 OPCClient::OPCClient(const string &moduleName)
33 {
34  opc.open("/" + moduleName + "/world/opc:rpc");
35 
36  isVerbose = false;
37 }
38 
39 bool OPCClient::write(Bottle &cmd, Bottle &reply, bool Verbose)
40 {
41  if (opc.getOutputCount() > 0)
42  {
43  if (Verbose)
44  yDebug()<<"Sending to OPC: "<<cmd.toString().c_str();
45 
46  opc.write(cmd,reply);
47 
48  if (Verbose)
49  yDebug()<<"Receiving from OPC: "<<reply.toString().c_str();
50 
51  if (reply.get(0).asVocab() == yarp::os::createVocab('n','a','c','k'))
52  return false;
53  else
54  return true;
55  }
56  else
57  {
58  if (Verbose)
59  yWarning()<<"Not connected to OPC...";
60  return false;
61  }
62 }
63 
64 void OPCClient::interrupt()
65 {
66  opc.interrupt();
67 }
68 
69 void OPCClient::close()
70 {
71  opc.close();
72  //Clear the content of dictionaries
73  for(map<int,Entity*>::iterator it=entitiesByID.begin(); it!=entitiesByID.end(); it++)
74  {
75  delete it->second;
76  }
77  this->entitiesByID.clear();
78 }
79 
80 void OPCClient::clear()
81 {
82  Bottle cmd,reply;
83  cmd.addVocab(Vocab::encode("del"));
84  cmd.addList().addString("all");
85 
86  //Clear the content of dictionaries
87  for(map<int,Entity*>::iterator it=entitiesByID.begin(); it!=entitiesByID.end(); it++)
88  {
89  delete it->second;
90  }
91  this->entitiesByID.clear();
92  write(cmd,reply);
93 }
94 
95 void OPCClient::addEntity(Entity* e)
96 {
97  Bottle cmd,reply;
98  cmd.addVocab(Vocab::encode("add"));
99  Bottle& query = cmd.addList();
100  query = e->asBottle();
101  write(cmd,reply,isVerbose);
102 
103  if (reply.get(0).asVocab() == yarp::os::createVocab('n','a','c','k'))
104  {
105  yError() << "Impossible to communicate correctly with OPC";
106  return;
107  }
108 
109  //Update the assigned ID
110  e->m_opc_id = reply.get(1).asList()->get(1).asInt();
111 
112  //Forces an update of the object
113  update(e);
114 
115  //Commit to the dictionary
116  entitiesByID[e->opc_id()] = e;
117 }
118 
122 bool OPCClient::setEntityProperty(std::string sourceEntityName, std::string propertyName, std::string targetEntityName)
123 {
124  Entity* source = getEntity(sourceEntityName,false);
125  Entity* target = getEntity(targetEntityName,false);
126  if (source == nullptr || target == nullptr)
127  return false;
128 
129  source->m_properties[propertyName] = targetEntityName;
130  return true;
131 }
132 
133 //Get by name
134 Entity* OPCClient::getEntity(const string &name, bool forceUpdate)
135 {
136  //If the object is already in the dictionary we return it.
137  for(map<int,Entity*>::iterator it=entitiesByID.begin(); it!=entitiesByID.end(); it++) {
138  if(it->second->name() == name) {
139  if (forceUpdate)
140  update(it->second);
141  return it->second;
142  }
143  }
144 
145  //Else we try to find the item in the OPC
146  Bottle cmd, reply;
147  cmd.addVocab(Vocab::encode("ask"));
148  Bottle& query = cmd.addList();
149 
150  Bottle& sub = query.addList();
151  sub.addString("name");
152  sub.addString("==");
153  sub.addString(name.c_str());
154 
155  write(cmd,reply,isVerbose);
156 
157  if (reply.get(0).asVocab() == yarp::os::createVocab('n','a','c','k'))
158  {
159  yError() << "Unable to talk correctly to OPC in getEntity with name";
160  yError() << "Command was:" << cmd.toString();
161  yError() << "Reply was:" << reply.toString();
162  return nullptr;
163  }
164 
165  if (reply.get(1).asList()->get(1).asList()->size() == 0)
166  {
167  //yError() << "Entity doesn't exist yet. Use addEntity<>() first.";
168  return nullptr;
169  }
170 
171  if (reply.get(1).asList()->get(1).asList()->size() > 1)
172  {
173  yError() << "[IMPORTANT] Duplicated names... You should fix this!";
174  }
175 
176  int item_id = reply.get(1).asList()->get(1).asList()->get(0).asInt();
177  return getEntity(item_id);
178 }
179 
180 //Get by ID
181 Entity *OPCClient::getEntity(int id, bool forceUpdate)
182 {
183  //If the object is already in the dictionary we return it.
184  map<int, Entity*>::iterator itE = entitiesByID.find(id);
185  if (itE != entitiesByID.end())
186  {
187  if (forceUpdate)
188  update(itE->second);
189  return itE->second;
190  }
191 
192  Bottle cmd,reply;
193  //Performs an update
194  cmd.addVocab(Vocab::encode("get"));
195  Bottle& query = cmd.addList();
196  Bottle& sub = query.addList();
197  sub.addString("id");
198  sub.addInt(id);
199  write(cmd,reply,isVerbose);
200 
201  if (reply.get(0).asVocab() == yarp::os::createVocab('n','a','c','k'))
202  {
203  yError() << "Unable to talk correctly to OPC in getEntity with ID";
204  yError() << "Command was:" << cmd.toString();
205  yError() << "Reply was:" << reply.toString();
206  return nullptr;
207  }
208 
209  Bottle* reply_bottle = reply.get(1).asList();
210  if(!reply_bottle) {
211  yError() << "Unable to talk correctly to OPC in getEntity with ID";
212  yError() << "Reply does not contain Bottle as expected";
213  return nullptr;
214  }
215 
216  Entity* newE = nullptr;
217  std::string newEntityType = reply_bottle->find("entity").asString().c_str();
218 
219  //Cast to the right type
220  if(newEntityType == "entity")
221  newE = new Entity();
222  else if (newEntityType == ICUBCLIENT_OPC_ENTITY_OBJECT)
223  newE = new Object();
224  else if (newEntityType == ICUBCLIENT_OPC_ENTITY_AGENT)
225  newE = new Agent();
226  else if (newEntityType == ICUBCLIENT_OPC_ENTITY_ACTION)
227  newE = new Action();
228  else if (newEntityType == "bodypart")
229  newE = new Bodypart();
230  else {
231  yError() << "getEntity: Unknown Entity type!";
232  return nullptr;
233  }
234 
235  //Update the fields
236  newE->fromBottle(*reply_bottle);
237  newE->m_opc_id = id;
238  newE->m_original_entity = newE->asBottle();
239 
240  //Commit to the dictionary
241  entitiesByID[newE->opc_id()] = newE;
242 
243  return newE;
244 }
245 
246 bool OPCClient::removeEntity(const string &name)
247 {
248  if (Entity *e=getEntity(name,true))
249  {
250  Bottle cmd,reply;
251  cmd.addVocab(Vocab::encode("del"));
252  Bottle &payLoad=cmd.addList().addList();
253  payLoad.addString("id");
254  payLoad.addInt(e->opc_id());
255 
256  if (write(cmd,reply,isVerbose))
257  {
258  if (reply.get(0).asVocab()==yarp::os::createVocab('a','c','k')) {
259  entitiesByID.erase(e->opc_id());
260  return true;
261  }
262  else {
263  yError()<<"Unable to talk correctly to OPC in removeEntity by name for " << name << "(id " << e->opc_id() << ")";
264  yError()<<"Command sent:" << cmd.toString();
265  yError()<<"Reply:" << reply.toString();
266  }
267  }
268  }
269 
270  return false;
271 }
272 
273 bool OPCClient::removeEntity(int id)
274 {
275  if (Entity *e=getEntity(id,true))
276  {
277  Bottle cmd,reply;
278  cmd.addVocab(Vocab::encode("del"));
279  Bottle &payLoad=cmd.addList().addList();
280  payLoad.addString("id");
281  payLoad.addInt(e->opc_id());
282 
283  if (write(cmd,reply,isVerbose))
284  {
285  if (reply.get(0).asVocab()==yarp::os::createVocab('a','c','k'))
286  {
287  entitiesByID.erase(e->opc_id());
288  return true;
289  }
290  else {
291  yError()<<"Unable to talk correctly to OPC in removeEntity by ID for id" << id << "(" << e->name() << ")";
292  yError()<<"Command sent:" << cmd.toString();
293  yError()<<"Reply:" << reply.toString();
294  }
295  }
296  }
297 
298  return false;
299 }
300 
301 //Returns the OPCid of a relation on the server side
302 int OPCClient::getRelationID(
303  Entity* subject,
304  Entity* verb,
305  Entity* object,
306  Entity* complement_place,
307  Entity* complement_time,
308  Entity* complement_manner)
309 {
310  Relation r(subject,verb,object,complement_place,complement_time,complement_manner);
311  //Check if the relation already exists on the server side (which means same source/target/type)
312  Bottle cmd,reply;
313  cmd.addString("ask");
314 
315  Bottle& query = cmd.addList();
316  Bottle sub;
317 
318  sub.addString(ICUBCLIENT_OPC_ENTITY_TAG);
319  sub.addString("==");
320  sub.addString(ICUBCLIENT_OPC_ENTITY_RELATION);
321  query.addList() = sub;
322 
323  query.addString("&&");
324 
325  sub.clear();
326  sub.addString("rSubject");
327  sub.addString("==");
328  sub.addString(r.subject().c_str());
329  query.addList() = sub;
330 
331  query.addString("&&");
332 
333  sub.clear();
334  sub.addString("rVerb");
335  sub.addString("==");
336  sub.addString(r.verb().c_str());
337  query.addList() = sub;
338 
339  query.addString("&&");
340 
341  sub.clear();
342  sub.addString("rObject");
343  sub.addString("==");
344  sub.addString(r.object().c_str());
345  query.addList() = sub;
346 
347  query.addString("&&");
348 
349  sub.clear();
350  sub.addString("rCompPlace");
351  sub.addString("==");
352  sub.addString(r.complement_place().c_str());
353  query.addList() = sub;
354 
355  query.addString("&&");
356 
357  sub.clear();
358  sub.addString("rCompTime");
359  sub.addString("==");
360  sub.addString(r.complement_time().c_str());
361  query.addList() = sub;
362 
363  query.addString("&&");
364 
365  sub.clear();
366  sub.addString("rCompManner");
367  sub.addString("==");
368  sub.addString(r.complement_manner().c_str());
369  query.addList() = sub;
370 
371  write(cmd,reply,isVerbose);
372 
373  if (reply.get(0).asVocab() == yarp::os::createVocab('n','a','c','k'))
374  {
375  yError()<<"Unable to talk correctly to OPC in getRelationID";
376  yError() << "Command was:" << cmd.toString();
377  yError() << "Reply was:" << reply.toString();
378  return false;
379  }
380 
381  //Relation already exists on the server
382  if (reply.get(1).asList()->get(1).asList()->size() >= 1)
383  {
384  return (reply.get(1).asList()->get(1).asList()->get(0).asInt());
385  }
386 
387  return -1;
388 }
389 //Adds a relation between 2 entities
390 bool OPCClient::addRelation(const Relation &r, double lifeTime)
391 {
392  Entity* subject = getEntity(r.subject());
393  Entity* object = getEntity(r.object());
394  Entity* cPlace = getEntity(r.complement_place());
395  Entity* cTime = getEntity(r.complement_time());
396  Entity* cManner = getEntity(r.complement_manner());
397  Entity* verb = getEntity(r.verb());
398  if (subject == nullptr || verb == nullptr)
399  {
400  yError() << "Verb and subject should exist before you try to add a relation";
401  return false;
402  }
403 
404  return addRelation(subject,verb,object,lifeTime,cPlace,cTime,cManner);
405 }
406 
407 //Adds a relation between 2 entities
408 bool OPCClient::addRelation(
409  Entity* subject,
410  Entity* verb,
411  Entity* object,
412  double lifeTime,
413  Entity* complement_place,
414  Entity* complement_time,
415  Entity* complement_manner)
416 {
417 
418  //Check if the relation already exists on the server side (which means same source/target/type)
419  int index = getRelationID(subject,verb,object,complement_place,complement_time,complement_manner);
420  Bottle cmd,reply;
421  //Relation already exists on the server, we just reset the lifeTimer
422  if (index != -1)
423  {
424  if (isVerbose)
425  yWarning() << "This relation already exist, only reseting lifeTimer";
426  return setLifeTime(index,lifeTime);
427  }
428 
429  //Relation has to be created
430  Relation r(subject,verb,object,complement_place,complement_time,complement_manner);
431  cmd.clear();
432  cmd.addString("add");
433  Bottle sub = r.asBottle(true); //ignoring the ID
434  cmd.addList() = sub;
435 
436  write(cmd,reply,isVerbose);
437 
438  if (reply.get(0).asVocab() == yarp::os::createVocab('n','a','c','k'))
439  {
440  yError() << "Unable to talk correctly to OPC in addRelation";
441  yError() << "Command was:" << cmd.toString();
442  yError() << "Reply was:" << reply.toString();
443  return false;
444  }
445  index = reply.get(1).asList()->get(1).asInt();
446  return setLifeTime(index,lifeTime);
447 }
448 
449 //Removes a relation between 2 entities
450 bool OPCClient::removeRelation(const Relation &r)
451 {
452  Entity* subject = getEntity(r.subject());
453  Entity* object = getEntity(r.object());
454  Entity* cPlace = getEntity(r.complement_place());
455  Entity* cTime = getEntity(r.complement_time());
456  Entity* cManner = getEntity(r.complement_manner());
457  Entity* verb = getEntity(r.verb());
458  return removeRelation(subject,verb,object,cPlace,cTime,cManner);
459 }
460 
461 //Removes a relation between 2 entities
462 bool OPCClient::removeRelation(
463  Entity* subject,
464  Entity* verb,
465  Entity* object,
466  Entity* complement_place,
467  Entity* complement_time,
468  Entity* complement_manner)
469 {
470 
471  int index = getRelationID(subject,verb,object,complement_place,complement_time,complement_manner);
472 
473  if (index == -1)
474  {
475  yWarning() << "This relation does not exist on the OPC server, not removed";
476  }
477  else
478  {
479  Bottle cmd,reply;
480  Bottle sub ;
481  cmd.addString("del");
482 
483  sub.addString("id");
484  sub.addInt(index);
485 
486  cmd.addList().addList() = sub;
487 
488  write(cmd,reply,isVerbose);
489  if (reply.get(0).asVocab() == yarp::os::createVocab('n','a','c','k'))
490  {
491  yError() << "Unable to talk correctly to OPC in removeRelation. Item not deleted.";
492  yError() << "Command was:" << cmd.toString();
493  yError() << "Reply was:" << reply.toString();
494  return false;
495  }
496  }
497 
498  return true;
499 }
500 
501 bool OPCClient::containsRelation(
502  Entity* subject,
503  Entity* verb,
504  Entity* object,
505  Entity* complement_place,
506  Entity* complement_time,
507  Entity* complement_manner)
508 {
509  int index = getRelationID(subject,verb,object,complement_place,complement_time,complement_manner);
510  return (index != -1);
511 }
512 
513 bool OPCClient::containsRelation(const Relation &r)
514 {
515  Entity* subject = getEntity(r.subject());
516  Entity* object = getEntity(r.object());
517  Entity* cPlace = getEntity(r.complement_place());
518  Entity* cTime = getEntity(r.complement_time());
519  Entity* cManner = getEntity(r.complement_manner());
520  Entity* verb = getEntity(r.verb());
521  return containsRelation(subject,verb,object,cPlace,cTime,cManner);
522 }
523 
524 bool OPCClient::setLifeTime(int opcID, double lifeTime)
525 {
526  Bottle cmd,reply;
527  //Do the right lifeTimer operation (we simply remove it if it is -1)
528  if (lifeTime == -1)
529  {
530  cmd.clear();
531  cmd.addString("del");
532 
533  Bottle &args = cmd.addList();
534  Bottle &id = args.addList();
535  id.clear();
536  id.addString("id");
537  id.addInt(opcID);
538  Bottle &props = args.addList();
539  props.clear();
540  props.addString("propSet");
541  props.addList().addString("lifeTimer");
542  }
543  else
544  {
545  cmd.clear();
546  cmd.addString("set");
547 
548  Bottle &args = cmd.addList();
549  Bottle &id = args.addList();
550  id.clear();
551  id.addString("id");
552  id.addInt(opcID);
553  Bottle &props = args.addList();
554  props.clear();
555  props.addString("lifeTimer");
556  props.addDouble(lifeTime);
557  }
558 
559  write(cmd,reply,isVerbose);
560  if (reply.get(0).asVocab() == yarp::os::createVocab('n','a','c','k'))
561  {
562  yError() << "Unable to talk correctly to OPC in setLifeTime";
563  yError() << "Command was:" << cmd.toString();
564  yError() << "Reply was:" << reply.toString();
565  return false;
566  }
567  return true;
568 }
569 
570 list<Relation> OPCClient::getRelations()
571 {
572  list<Relation> relations;
573 
574  //Checkout the relations
575  Bottle cmd,sub,reply;
576  cmd.addString("ask");
577  Bottle& cond = cmd.addList();
578 
579  sub.addString(ICUBCLIENT_OPC_ENTITY_TAG);
580  sub.addString("==");
581  sub.addString(ICUBCLIENT_OPC_ENTITY_RELATION);
582  cond.addList() = sub;
583  write(cmd,reply,isVerbose);
584 
585  if (reply.get(0).asVocab() == yarp::os::createVocab('n','a','c','k'))
586  {
587  yError() << "Unable to talk to OPC.";
588  return relations;
589  }
590 
591  //yDebug() << reply.toString();
592  Bottle* ids = reply.get(1).asList()->get(1).asList();
593  for(unsigned int i=0;i<ids->size();i++)
594  {
595  Bottle getReply;
596  int currentID = ids->get(i).asInt();
597  cmd.clear();
598  cmd.addString("get");
599  sub.clear();
600  sub.addString("id");
601  sub.addInt(currentID);
602  cmd.addList().addList() = sub;
603  write(cmd,getReply,isVerbose);
604  if (getReply.get(0).asVocab() == yarp::os::createVocab('n','a','c','k'))
605  {
606  yError() << "Unable to talk to OPC.";
607  return relations;
608  }
609 
610  Relation r(*getReply.get(1).asList());
611  r.m_opcId = currentID;
612  relations.push_back(r);
613  }
614  return relations;
615 }
616 
617 std::list<Relation> OPCClient::getRelationsMatching(std::string subject,std::string verb, std::string object, std::string c_place, std::string c_time, std::string c_manner)
618 {
619  list<Relation> relations;
620  //Checkout the relations
621  Bottle cmd,sub,reply;
622  cmd.addString("ask");
623  Bottle& cond = cmd.addList();
624 
625  sub.addString(ICUBCLIENT_OPC_ENTITY_TAG);
626  sub.addString("==");
627  sub.addString(ICUBCLIENT_OPC_ENTITY_RELATION);
628  cond.addList() = sub;
629  if (subject != "any")
630  {
631  cond.addString("&&");
632  Bottle& subCond = cond.addList();
633  subCond.addString("rSubject");
634  subCond.addString("==");
635  subCond.addString(subject.c_str());
636  }
637  if (verb != "any")
638  {
639  cond.addString("&&");
640  Bottle& subCond = cond.addList();
641  subCond.addString("rVerb");
642  subCond.addString("==");
643  subCond.addString(verb.c_str());
644  }
645  if (object != "any")
646  {
647  cond.addString("&&");
648  Bottle& subCond = cond.addList();
649  subCond.addString("rObject");
650  subCond.addString("==");
651  subCond.addString(object.c_str());
652  }
653  if (c_time != "any")
654  {
655  cond.addString("&&");
656  Bottle& subCond = cond.addList();
657  subCond.addString("rCompTime");
658  subCond.addString("==");
659  subCond.addString(c_time.c_str());
660  }
661  if (c_place != "any")
662  {
663  cond.addString("&&");
664  Bottle& subCond = cond.addList();
665  subCond.addString("rCompPlace");
666  subCond.addString("==");
667  subCond.addString(c_place.c_str());
668  }
669  if (c_manner != "any")
670  {
671  cond.addString("&&");
672  Bottle& subCond = cond.addList();
673  subCond.addString("rCompManner");
674  subCond.addString("==");
675  subCond.addString(c_manner.c_str());
676  }
677  write(cmd,reply,isVerbose);
678 
679  if (reply.get(0).asVocab() == yarp::os::createVocab('n','a','c','k'))
680  {
681  yError() << "Unable to talk to OPC.";
682  return relations;
683  }
684 
685  //yDebug() << reply.toString();
686  Bottle* ids = reply.get(1).asList()->get(1).asList();
687  for(unsigned int i=0;i<ids->size();i++)
688  {
689  Bottle getReply;
690  int currentID = ids->get(i).asInt();
691  cmd.clear();
692  cmd.addString("get");
693  sub.clear();
694  sub.addString("id");
695  sub.addInt(currentID);
696  cmd.addList().addList() = sub;
697  write(cmd,getReply,isVerbose);
698  if (getReply.get(0).asVocab() == yarp::os::createVocab('n','a','c','k'))
699  {
700  yError() << "Unable to talk to OPC.";
701  return relations;
702  }
703 
704  Relation r(*getReply.get(1).asList());
705  r.m_opcId = i;
706  relations.push_back(r);
707  }
708  return relations;
709 }
710 std::list<Relation> OPCClient::getRelationsMatchingLoosly(std::string subject, std::string verb, std::string object, std::string c_place, std::string c_time, std::string c_manner)
711 {
712  list<Relation> relations = getRelations();
713  list<Relation> filteredRelations;
714  for (list<Relation>::iterator it = relations.begin(); it != relations.end(); it++)
715  {
716  if (it->subject() == subject ||
717  it->verb() == verb ||
718  it->object() == object ||
719  it->complement_time() == c_time ||
720  it->complement_place() == c_place ||
721  it->complement_manner() == c_manner)
722  {
723  filteredRelations.push_back(*it);
724  }
725  }
726  return filteredRelations;
727 }
728 
729 std::list<Relation> OPCClient::getRelations(std::string entity)
730 {
731  list<Relation> relations = getRelations();
732  list<Relation> filteredRelations;
733  for(list<Relation>::iterator it = relations.begin(); it != relations.end() ; it++)
734  {
735  if (it->subject() == entity ||
736  it->verb() == entity ||
737  it->object() == entity ||
738  it->complement_time() == entity ||
739  it->complement_place() == entity ||
740  it->complement_manner() == entity)
741  {
742  filteredRelations.push_back(*it);
743  }
744  }
745  return filteredRelations;
746 }
747 
748 std::list<Relation> OPCClient::getRelations(Entity* entity)
749 {
750  return getRelations(entity->name());
751 }
752 
753 //Clear local dictionnaries and populate them using the server content
754 void OPCClient::checkout(bool updateCache)
755 {
756  if (updateCache)
757  {
758  //Clear the content of dictionaries
759  for(map<int,Entity*>::iterator it=entitiesByID.begin(); it!=entitiesByID.end(); it++)
760  {
761  delete it->second;
762  }
763  entitiesByID.clear();
764  }
765 
766  //Find the ids of all entities within the OPC
767  Bottle cmd,sub,reply;
768  cmd.addString("ask");
769 
770  Bottle& cond = cmd.addList();
771  sub.addString(ICUBCLIENT_OPC_ENTITY_TAG);
772  sub.addString("!=");
773  sub.addString(ICUBCLIENT_OPC_ENTITY_RELATION);
774  cond.addList() = sub;
775 
776  write(cmd,reply,isVerbose);
777  if (reply.get(0).asVocab() == yarp::os::createVocab('n','a','c','k'))
778  {
779  yError() << "Unable to talk to OPC.";
780  return;
781  }
782 
783  Bottle* ids = reply.get(1).asList()->get(1).asList();
784  for(unsigned int i=0;i<ids->size();i++)
785  {
786  int currentID = ids->get(i).asInt();
787  getEntity(currentID, updateCache); //Automatically update the dictionnaries
788  }
789  if (isVerbose)
790  yInfo() << "Checkout result: "<< ids->size() << " entities added.";
791 }
792 
793 //Update the whole content of the world (poll the OPC for all items)
794 void OPCClient::update()
795 {
796  for(map<int, Entity* >::iterator it = entitiesByID.begin(); it != entitiesByID.end(); it++)
797  {
798  update(it->second);
799  }
800 }
801 
802 //Update a given entity
803 void OPCClient::update(Entity *e)
804 {
805  //Try to retrieve the object based on its OPC ID
806  Bottle cmd,reply;
807  cmd.addVocab(Vocab::encode("get"));
808  Bottle& query = cmd.addList();
809  Bottle& id = query.addList();
810  id.addString("id");
811  id.addInt(e->opc_id());
812 // yDebug() << "OPCClient send request to OPC: " << cmd.toString();
813  write(cmd,reply,isVerbose);
814 // yDebug() << "OPCClient response: " << reply.toString();
815 
816  if (reply.get(0).asVocab() == yarp::os::createVocab('n','a','c','k'))
817  {
818  yError() << "OPC Client: error while updating " << e->opc_id();
819  return;
820  }
821 
822  //Fill the datastructure with the bottle content
823  Bottle props = *reply.get(1).asList();
824  if(!e->fromBottle(props)) {
825  yError() << "Error updating entity " << e->name() << "fromBottle! Type: " << e->entity_type();
826  yDebug() << "OPCClient props:" << props.toString();
827  }
828 // yDebug() << "OPCClient fromBottle success";
829 
830  //Set the initial signature of this entity
831  e->m_original_entity = e->asBottle();
832 }
833 
834 //Commit the whole world to the OPC (erase everything)
835 void OPCClient::commit()
836 {
837  for(map<int, Entity* >::iterator it = entitiesByID.begin(); it != entitiesByID.end(); it++)
838  {
839  commit(it->second);
840  }
841 }
842 
843 //Commit a single entity to the OPC (erase it)
844 void OPCClient::commit(Entity *e)
845 {
846  Bottle cmd,reply;
847  cmd.addVocab(Vocab::encode("set"));
848  Bottle& query = cmd.addList();
849  Bottle& id = query.addList();
850  id.addString("id");
851  id.addInt(e->opc_id());
852 
853  Bottle props=e->asBottleOnlyModifiedProperties();
854  for (unsigned int i=0; i<props.size(); i++)
855  query.addList()=*props.get(i).asList();
856 
857  write(cmd,reply,isVerbose);
858  if (reply.get(0).asVocab()==yarp::os::createVocab('n','a','c','k'))
859  {
860  yError() << "OPC Client: error while commiting " << e->opc_id();
861  return;
862  }
863 }
864 
865 std::list<Entity*> OPCClient::Entities(const yarp::os::Bottle &condition)
866 {
867  list<Entity*> matchingEntities;
868  //Find the ids of all entities within the OPC
869  Bottle cmd,reply;
870  cmd.addString("ask");
871  cmd.addList() = condition;
872 
873  write(cmd,reply,isVerbose);
874 
875  if (reply.get(0).asVocab() == yarp::os::createVocab('n','a','c','k'))
876  {
877  yError() << "Unable to talk to OPC.";
878  return matchingEntities;
879  }
880 
881  Bottle* ids = reply.get(1).asList()->get(1).asList();
882  for(unsigned int i=0;i<ids->size();i++)
883  {
884  int currentID = ids->get(i).asInt();
885  matchingEntities.push_back(getEntity(currentID)); //Automatically update the dictionnaries
886  update(matchingEntities.back());
887  }
888  if (isVerbose)
889  yInfo() << "Checkout result: " << ids->size() << " entities added.";
890  return matchingEntities;
891 }
892 
893 list<Entity*> OPCClient::Entities(const string &prop, const string &op, const string &value)
894 {
895  //Find the ids of all entities within the OPC
896  Bottle cond,sub;
897  sub.addString(prop.c_str());
898  sub.addString(op.c_str());
899  sub.addString(value.c_str());
900  cond.addList() = sub;
901  return Entities(cond);
902 }
903 
904 //Getter of the list of entities stored locally
905 list<Entity*> OPCClient::EntitiesCache() const
906 {
907  list<Entity*> lR;
908  for(const auto& it : this->entitiesByID)
909  {
910  lR.push_back(it.second);
911  }
912  return lR;
913 }
914 
915 
916 //Getter of the list of entities stored locally
917 std::list<std::shared_ptr<Entity>> OPCClient::EntitiesCacheCopy() const
918 {
919  list<std::shared_ptr<Entity>> lR;
920  for(const auto& it : this->entitiesByID)
921  {
922  std::shared_ptr<Entity> E;
923  if (it.second->m_entity_type == ICUBCLIENT_OPC_ENTITY_AGENT)
924  {
925  E = std::shared_ptr<Agent>(new Agent());
926  }
927  else if (it.second->m_entity_type == ICUBCLIENT_OPC_ENTITY_OBJECT)
928  {
929  E = std::shared_ptr<Object>(new Object());
930  }
931  else if (it.second->m_entity_type == ICUBCLIENT_OPC_ENTITY_ACTION)
932  {
933  E = std::shared_ptr<Action>(new Action());
934  }
935  else if (it.second->m_entity_type == "bodypart")
936  {
937  E = std::shared_ptr<Bodypart>(new Bodypart());
938  }
939  else
940  {
941  yError() << "EntitiesCacheCopy: Unknown entity type!";
942  }
943 
944  if(E != nullptr) {
945  E->fromBottle(it.second->asBottle());
946  E->m_opc_id = it.second->m_opc_id;
947  lR.push_back(E);
948  }
949  }
950  return lR;
951 }
952 
953 //Return a (printable) string with the contents of the OPC
954 string OPCClient::toString()
955 {
956  string s="WORLD STATE \n";
957  for(const auto& it : entitiesByID)
958  {
959  s += it.second->toString();
960  }
961  s+= "RELATIONS \n";
962  list<Relation> rels = getRelations();
963  for(const auto& it : rels)
964  s += it.toString() + '\n';
965 
966  return s;
967 }
968 
969 bool OPCClient::changeName(Entity *e, const std::string &newName)
970 {
971  for(auto& entity : entitiesByID)
972  {
973  if(entity.second->name() == newName) {
974  yError() << "Entity with name " << newName << " is already existing.";
975  return false;
976  }
977  }
978  e->changeName(newName);
979  return true;
980 }
int opc_id() const
Return the id of an entity (which has to be unique within the OPC) Typically, modules should employ t...
Definition: entity.h:101
std::string complement_manner() const
Get the complement of manner of the relation.
Definition: relation.cpp:236
virtual bool fromBottle(const yarp::os::Bottle &b)
Fill entity fields from a bottle representation.
Definition: entity.cpp:95
yarp::os::Bottle asBottle(bool ignoreID=false) const
Definition: relation.cpp:90
Represent any entity that can be stored within the OPC.
Definition: entity.h:40
std::string subject() const
Get the name of the relation&#39;s subject.
Definition: relation.cpp:211
std::string complement_time() const
Get the complement of time of the relation.
Definition: relation.cpp:231
STL namespace.
Represent any physical entity (including objects and agents) that can be stored within the OPC...
Definition: object.h:35
void changeName(std::string sName)
Definition: entity.cpp:149
Represents an action, whether composite or not.
Definition: action.h:33
#define ICUBCLIENT_OPC_ENTITY_RELATION
Definition: tags.h:42
Represent an agent.
Definition: agent.h:93
Represents a body part of the robot.
Definition: bodypart.h:29
std::string complement_place() const
Get the complement of place of the relation.
Definition: relation.cpp:226
#define ICUBCLIENT_OPC_ENTITY_TAG
Definition: tags.h:37
std::string object() const
Get the name of the relation&#39;s object.
Definition: relation.cpp:216
std::string name() const
Return the name of an entity (which has to be unique within the OPC)
Definition: entity.h:93
std::string verb() const
Get the type of the relation.
Definition: relation.cpp:221
Represent a relation between two entities.
Definition: relation.h:31
#define ICUBCLIENT_OPC_ENTITY_OBJECT
Definition: tags.h:38
virtual yarp::os::Bottle asBottle() const
Return the entity as a bottle.
Definition: entity.cpp:45
#define ICUBCLIENT_OPC_ENTITY_ACTION
Definition: tags.h:41
#define ICUBCLIENT_OPC_ENTITY_AGENT
Definition: tags.h:40
std::string entity_type() const
Return the specific type of an entity.
Definition: entity.h:121