266#include <yarp/os/all.h>
269using namespace yarp::os;
271#define CMD_ADD createVocab32('a','d','d')
272#define CMD_DEL createVocab32('d','e','l')
273#define CMD_GET createVocab32('g','e','t')
274#define CMD_SET createVocab32('s','e','t')
275#define CMD_LOCK createVocab32('l','o','c','k')
276#define CMD_UNLOCK createVocab32('u','n','l','o')
277#define CMD_OWNER createVocab32('o','w','n','e')
278#define CMD_TIME createVocab32('t','i','m','e')
279#define CMD_DUMP createVocab32('d','u','m','p')
280#define CMD_ASK createVocab32('a','s','k')
281#define CMD_SYNC createVocab32('s','y','n','c')
282#define CMD_ASYNC createVocab32('a','s','y','n')
283#define CMD_QUIT createVocab32('q','u','i','t')
284#define CMD_BYE createVocab32('b','y','e')
286#define REP_ACK createVocab32('a','c','k')
287#define REP_NACK createVocab32('n','a','c','k')
288#define REP_UNKNOWN createVocab32('u','n','k','n')
290#define OPT_ALL createVocab32('a','l','l')
291#define OPT_DISABLED (-1.0)
292#define OPT_OWNERSHIP_ALL ("all")
294#define PROP_ID ("id")
295#define PROP_LIFETIMER ("lifeTimer")
296#define PROP_SET ("propSet")
297#define BCTAG_EMPTY ("empty")
298#define BCTAG_SYNC ("sync")
299#define BCTAG_ASYNC ("async")
315 if (a.isFloat64() && b.isFloat64())
316 return (a.asFloat64()>b.asFloat64());
317 else if (a.isInt32() && b.isInt32())
318 return (a.asInt32()>b.asInt32());
327 if (a.isFloat64() && b.isFloat64())
328 return (a.asFloat64()>=b.asFloat64());
329 else if (a.isInt32() && b.isInt32())
330 return (a.asInt32()>=b.asInt32());
339 if (a.isFloat64() && b.isFloat64())
340 return (a.asFloat64()<b.asFloat64());
341 else if (a.isInt32() && b.isInt32())
342 return (a.asInt32()<b.asInt32());
351 if (a.isFloat64() && b.isFloat64())
352 return (a.asFloat64()<=b.asFloat64());
353 else if (a.isInt32() && b.isInt32())
354 return (a.asInt32()<=b.asInt32());
363 if (a.isFloat64() && b.isFloat64())
364 return (a.asFloat64()==b.asFloat64());
365 else if (a.isInt32() && b.isInt32())
366 return (a.asInt32()==b.asInt32());
367 else if (a.isString() && b.isString())
369 string aStr=a.asString();
370 string bStr=b.asString();
381 if (a.isFloat64() && b.isFloat64())
382 return (a.asFloat64()!=b.asFloat64());
383 else if (a.isInt32() && b.isInt32())
384 return (a.asInt32()!=b.asInt32());
385 else if (a.isString() && b.isString())
387 string aStr=a.asString();
388 string bStr=b.asString();
437 delete it->second.prop;
445 delete it->second.prop;
454 fprintf(stream,
"item_%d (%s %d) (%s)\n",
455 i++,
PROP_ID,it->first,it->second.prop->toString().c_str());
460 deque<string> &opList,
const unsigned int i=0)
463 if (item->check(condList[i].prop))
466 Value &val=item->find(condList[i].prop);
469 result=(*condList[i].compare)(val,condList[i].val);
474 if ((i+1)>=condList.size())
476 else if (opList[i]==
"||")
481 for (j=i+1; j<condList.size(); j++)
485 if (item->check(condList[j].prop))
487 Value &val=item->find(condList[j].prop);
488 result=result&&(*condList[j].compare)(val,condList[j].val);
499 if (j>=condList.size())
540 yWarning(
"database already initialized ...");
545 if (!
rf.check(
"no-load-db"))
550 yInfo(
"database ready ...");
552 if (
rf.check(
"sync-bc"))
554 setPeriod(
rf.check(
"sync-bc",Value(1.0)).asFloat64());
570 string dbFileName=
rf->findFile(
"db");
571 if (dbFileName.empty())
573 yWarning(
"requested database to be loaded not found!");
577 yInfo(
"loading database from %s ...",dbFileName.c_str());
579 lock_guard<mutex> lck(
mtx);
583 Property finProperty;
584 finProperty.fromConfigFile(dbFileName);
587 finBottle.fromString(finProperty.toString());
588 for (
int i=0; i<finBottle.size(); i++)
592 Bottle &b1=finBottle.findGroup(tag.str());
599 yWarning(
"error while loading %s!",tag.str().c_str());
603 Bottle *b2=b1.get(1).asList();
604 Bottle *b3=b1.get(2).asList();
605 if ((b2==NULL) || (b3==NULL))
607 yWarning(
"error while loading %s!",tag.str().c_str());
613 yWarning(
"error while loading %s!",tag.str().c_str());
617 int id=b2->get(1).asInt32();
618 itemsMap[id].prop=
new Property(b3->toString().c_str());
624 yInfo(
"database loaded");
633 lock_guard<mutex> lck(
mtx);
634 string dbFileName=
rf->getHomeContextPath();
636 dbFileName+=
rf->find(
"db").asString();
637 yInfo(
"saving database in %s ...",dbFileName.c_str());
639 FILE *fout=fopen(dbFileName.c_str(),
"w");
643 yInfo(
"database stored");
649 lock_guard<mutex> lck(
mtx);
650 yInfo(
"dumping database content ...");
665 lock_guard<mutex> lck(
mtx);
669 bottle.addString(type);
672 else for (map<int,Item>::iterator it=
itemsMap.begin(); it!=
itemsMap.end(); it++)
674 Bottle &item=bottle.addList();
675 item.read(*it->second.prop);
677 Bottle &idList=item.addList();
679 idList.addInt32(it->first);
695 yWarning(
"%s field cannot be specified as a property!",
PROP_ID);
699 lock_guard<mutex> lck(
mtx);
700 itemsMap[
idCnt].prop=
new Property(content->toString().c_str());
712 if (content->size()==1)
714 if (content->get(0).isVocab32() || content->get(0).isString())
716 if (content->get(0).asVocab32()==
OPT_ALL)
718 lock_guard<mutex> lck(
mtx);
720 yInfo(
"database cleared");
728 yWarning(
"%s field not present within the request!",
PROP_ID);
732 int id=content->find(
PROP_ID).asInt32();
734 lock_guard<mutex> lck(
mtx);
735 map<int,Item>::iterator it=
itemsMap.find(
id);
738 Bottle *propSet=content->find(
PROP_SET).asList();
741 for (
int i=0; i<propSet->size(); i++)
742 it->second.prop->unput(propSet->get(i).asString());
744 it->second.lastUpdate=Time::now();
756 bool get(Bottle *content, Bottle &response)
763 yWarning(
"%s field not present within the request!",
PROP_ID);
767 int id=content->find(
PROP_ID).asInt32();
769 lock_guard<mutex> lck(
mtx);
770 map<int,Item>::iterator it=
itemsMap.find(
id);
773 Property *pProp=it->second.prop;
776 Bottle *propSet=content->find(
PROP_SET).asList();
780 for (
int i=0; i<propSet->size(); i++)
782 string propName=propSet->get(i).asString();
783 if (pProp->check(propName))
784 prop.put(propName,pProp->find(propName));
790 response.read(*pProp);
799 bool set(Bottle *content,
const string &agent)
806 yWarning(
"%s field not present within the request!",
PROP_ID);
810 int id=content->find(
PROP_ID).asInt32();
812 lock_guard<mutex> lck(
mtx);
813 map<int,Item>::iterator it=
itemsMap.find(
id);
816 string owner=it->second.owner;
819 Property *pProp=it->second.prop;
820 for (
int i=0; i<content->size(); i++)
822 if (Bottle *option=content->get(i).asList())
824 if (option->size()<2)
827 string prop=option->get(0).asString();
828 Value val=option->get(1);
834 pProp->put(prop,val);
840 it->second.lastUpdate=Time::now();
849 bool lock(Bottle *content,
const string &agent)
856 yWarning(
"%s field not present within the request!",
PROP_ID);
860 int id=content->find(
PROP_ID).asInt32();
862 lock_guard<mutex> lck(
mtx);
863 map<int,Item>::iterator it=
itemsMap.find(
id);
866 string owner=it->second.owner;
869 it->second.owner=agent;
878 bool unlock(Bottle *content,
const string &agent)
885 yWarning(
"%s field not present within the request!",
PROP_ID);
889 int id=content->find(
PROP_ID).asInt32();
891 lock_guard<mutex> lck(
mtx);
892 map<int,Item>::iterator it=
itemsMap.find(
id);
895 string owner=it->second.owner;
907 bool owner(Bottle *content, Bottle &response)
914 yWarning(
"%s field not present within the request!",
PROP_ID);
918 int id=content->find(
PROP_ID).asInt32();
920 lock_guard<mutex> lck(
mtx);
921 map<int,Item>::iterator it=
itemsMap.find(
id);
925 string &
owner=it->second.owner;
926 response.addString(
owner);
934 bool time(Bottle *content, Bottle &response)
941 yWarning(
"%s field not present within the request!",
PROP_ID);
945 int id=content->find(
PROP_ID).asInt32();
947 lock_guard<mutex> lck(
mtx);
948 map<int,Item>::iterator it=
itemsMap.find(
id);
952 if (it->second.lastUpdate<0.0)
953 response.addFloat64(it->second.lastUpdate);
956 double dt=Time::now()-it->second.lastUpdate;
957 response.addFloat64(dt);
966 bool ask(Bottle *content, Bottle &response)
971 lock_guard<mutex> lck(
mtx);
972 if (content->size()==1)
974 if (content->get(0).isVocab32() || content->get(0).isString())
976 if (content->get(0).asVocab32()==
OPT_ALL)
981 response.addInt32(it->first);
988 deque<Condition> condList;
989 deque<string> opList;
993 if (!(content->size()&0x01))
995 yWarning(
"uncorrect conditions received!");
1000 for (
int i=0; i<content->size(); i+=2)
1002 if (Bottle *b=content->get(i).asList())
1009 condition.
prop=b->get(0).asString();
1012 else if (b->size()>2)
1014 condition.
prop=b->get(0).asString();
1015 operation=b->get(1).asString();
1016 condition.
val=b->get(2);
1020 else if (operation==
">=")
1022 else if (operation==
"<")
1024 else if (operation==
"<=")
1026 else if (operation==
"==")
1028 else if (operation==
"!=")
1032 yWarning(
"unknown relational operator '%s'!",operation.c_str());
1038 yWarning(
"wrong condition given!");
1042 condList.push_back(condition);
1044 if ((i+1)<content->size())
1046 operation=content->get(i+1).asString();
1047 if ((operation!=
"||") && (operation!=
"&&"))
1049 yWarning(
"unknown boolean operator '%s'!",operation.c_str());
1053 opList.push_back(operation);
1058 yWarning(
"wrong condition given!");
1066 for (map<int,Item>::iterator it=
itemsMap.begin(); it!=
itemsMap.end(); it++)
1071 response.addInt32(it->first);
1082 for (map<int,Item>::iterator it=
itemsMap.begin(); it!=
itemsMap.end(); it++)
1084 Property *pProp=it->second.prop;
1114 void respond(ConnectionReader &connection,
const Bottle &command, Bottle &reply)
1116 string agent=connection.getRemoteContact().getName();
1117 if (command.size()<1)
1124 int cmd=command.get(0).asVocab32();
1130 if (command.size()<2)
1136 Bottle *content=command.get(1).asList();
1140 Bottle &b=reply.addList();
1157 if (command.size()<2)
1163 Bottle *content=command.get(1).asList();
1179 if (command.size()<2)
1186 Bottle *content=command.get(1).asList();
1187 if (
get(content,response))
1190 reply.addList()=response;
1201 if (command.size()<2)
1207 Bottle *content=command.get(1).asList();
1208 if (
set(content,agent))
1223 if (command.size()<2)
1229 Bottle *content=command.get(1).asList();
1230 if (
lock(content,agent))
1241 if (command.size()<2)
1247 Bottle *content=command.get(1).asList();
1248 if (
unlock(content,agent))
1259 if (command.size()<2)
1266 Bottle *content=command.get(1).asList();
1267 if (
owner(content,response))
1270 reply.addList()=response;
1281 if (command.size()<2)
1288 Bottle *content=command.get(1).asList();
1289 if (
time(content,response))
1292 reply.addList()=response;
1311 if (command.size()<2)
1317 int opt=command.get(1).asVocab32();
1318 if (opt==Vocab32::encode(
"start"))
1320 if (command.size()>=3)
1321 setPeriod(command.get(2).asFloat64());
1325 else if (isSuspended())
1330 else if (opt==Vocab32::encode(
"stop"))
1332 if (isRunning() && !isSuspended())
1346 if (command.size()<2)
1352 int opt=command.get(1).asVocab32();
1353 if (opt==Vocab32::encode(
"on"))
1358 else if (opt==Vocab32::encode(
"off"))
1372 if (command.size()<2)
1379 Bottle *content=command.get(1).asList();
1380 if (
ask(content,response))
1383 Bottle &b=reply.addList();
1385 b.addList()=response;
1405 yWarning(
"received unknown command!");
1414 if (content.size()==0)
1417 string type=content.get(0).asString();
1427 for (
int i=1; i<content.size(); i++)
1429 if (Bottle *item=content.get(i).asList())
1431 if (Bottle *idList=item->get(0).asList())
1433 if (idList->size()==2)
1435 if (idList->get(0).asString()==
PROP_ID)
1437 int id=idList->get(1).asInt32();
1438 itemsMap[id].prop=
new Property(item->tail().toString().c_str());
1468 bool read(ConnectionReader &connection)
1471 if (!command.read(connection) || (
pDataBase==NULL))
1475 double t0=Time::now();
1476 pDataBase->respond(connection,command,reply);
1480 if (ConnectionWriter *writer=connection.getWriter())
1481 reply.write(*writer);
1543 BufferedPort<Bottle> bcPort;
1547 unsigned int nCallsOld;
1554 dataBase.configure(rf);
1555 stats=rf.check(
"stats");
1557 string name=rf.check(
"name",Value(
"objectsPropertiesCollector")).asString();
1558 dataBase.setBroadcastPort(bcPort);
1559 rpcProcessor.setDataBase(dataBase);
1560 rpcPort.setReader(rpcProcessor);
1561 modifyPort.setDataBase(dataBase);
1562 modifyPort.useCallback();
1563 rpcPort.open(
"/"+name+
"/rpc");
1564 bcPort.open(
"/"+name+
"/broadcast:o");
1565 modifyPort.open(
"/"+name+
"/modify:i");
1577 modifyPort.disableCallback();
1580 rpcPort.interrupt();
1582 modifyPort.interrupt();
1605 unsigned int nCalls;
double cumTime;
1606 rpcProcessor.getStats(nCalls,cumTime);
1608 unsigned int calls=nCalls-nCallsOld;
1609 double timeSpent=cumTime-cumTimeOld;
1610 yInfo(
"*** Statistics: received %d/%g [requests/s]; %g [ms/request] spent on average",
1611 calls,
getPeriod(),timeSpent==0.0?0.0:(1e3*timeSpent)/(
double)calls);
1617 return !dataBase.isQuitting();
1634 rf.setDefaultContext(
"objectsPropertiesCollector");
1635 rf.setDefault(
"db",
"dataBase.ini");
1636 rf.configure(argc,argv);
1638 if (rf.check(
"help"))
1640 printf(
"Options\n");
1641 printf(
"\t--name <name>: collector name (default: objectsPropertiesCollector)\n");
1642 printf(
"\t--db <fileName>: database file name to load at startup/save at shutdown (default: dataBase.ini)\n");
1643 printf(
"\t--context <context>: context to search for database file (default: objectsPropertiesCollector)\n");
1644 printf(
"\t--no-load-db : start an empty database\n");
1645 printf(
"\t--no-save-db : prevent from saving the content of database at shutdown\n");
1646 printf(
"\t--sync-bc <T>: broadcast the database content each T seconds\n");
1647 printf(
"\t--async-bc : broadcast the database content whenever a change occurs\n");
1648 printf(
"\t--stats : enable statistics printouts\n");
1653 if (!
yarp.checkNetwork())
1655 yError(
"YARP server not available!");
1660 return collector.runModule(rf);
void setDataBase(DataBase &dataBase)
void onRead(Bottle &content)
BufferedPort< Bottle > * pBroadcastPort
map< int, Item > itemsMap
bool owner(Bottle *content, Bottle &response)
void broadcast(const string &type)
bool add(Bottle *content)
bool modify(const Bottle &content)
bool remove(Bottle *content)
void respond(ConnectionReader &connection, const Bottle &command, Bottle &reply)
bool time(Bottle *content, Bottle &response)
bool get(Bottle *content, Bottle &response)
bool recursiveCheck(Property *item, deque< Condition > &condList, deque< string > &opList, const unsigned int i=0)
bool unlock(Bottle *content, const string &agent)
void setBroadcastPort(BufferedPort< Bottle > &broadcastPort)
bool set(Bottle *content, const string &agent)
void periodicHandler(const double dt)
void configure(ResourceFinder &rf)
void eraseItem(map< int, Item >::iterator &it)
bool ask(Bottle *content, Bottle &response)
bool lock(Bottle *content, const string &agent)
void getStats(unsigned int &nCalls, double &cumTime) const
bool read(ConnectionReader &connection)
void setDataBase(DataBase &dataBase)
bool configure(ResourceFinder &rf)
#define OPT_OWNERSHIP_ALL
bool equal(Value &a, Value &b)
bool lower(Value &a, Value &b)
bool greater(Value &a, Value &b)
bool alwaysTrue(Value &a, Value &b)
bool greaterEqual(Value &a, Value &b)
bool notEqual(Value &a, Value &b)
bool lowerEqual(Value &a, Value &b)
Copyright (C) 2008 RobotCub Consortium.
bool(* compare)(Value &, Value &)