ctkNetworkConnectorQXMLRPC.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * ctkNetworkConnectorQXMLRPC.cpp
  3. * ctkEventBus
  4. *
  5. * Created by Daniele Giunchi on 11/04/10.
  6. * Copyright 2009 B3C. All rights reserved.
  7. *
  8. * See Licence at: http://tiny.cc/QXJ4D
  9. *
  10. */
  11. #include "ctkNetworkConnectorQXMLRPC.h"
  12. #include "ctkEventBusManager.h"
  13. #include <service/event/ctkEvent.h>
  14. using namespace ctkEventBus;
  15. ctkNetworkConnectorQXMLRPC::ctkNetworkConnectorQXMLRPC() : ctkNetworkConnector(), m_Client(NULL), m_Server(NULL), m_RequestId(0) {
  16. //generate remote signal, this signal must map in the
  17. //possible connection with the remote server.
  18. //Server, in this case XMLRPC, will register a method with id REMOTE_COMMUNICATION
  19. //and parameters QVariantList
  20. m_Protocol = "XMLRPC";
  21. }
  22. void ctkNetworkConnectorQXMLRPC::initializeForEventBus() {
  23. ctkRegisterRemoteSignal("ctk/remote/eventBus/comunication/send/xmlrpc", this, "remoteCommunication(const QString, ctkEventArgumentsList *)");
  24. ctkRegisterRemoteCallback("ctk/remote/eventBus/comunication/send/xmlrpc", this, "send(const QString, ctkEventArgumentsList *)");
  25. }
  26. ctkNetworkConnectorQXMLRPC::~ctkNetworkConnectorQXMLRPC() {
  27. if(m_Client) {
  28. delete m_Client;
  29. m_Client = NULL;
  30. }
  31. if(m_Server) {
  32. stopServer();
  33. }
  34. }
  35. //retrieve an instance of the object
  36. ctkNetworkConnector *ctkNetworkConnectorQXMLRPC::clone() {
  37. ctkNetworkConnectorQXMLRPC *copy = new ctkNetworkConnectorQXMLRPC();
  38. return copy;
  39. }
  40. void ctkNetworkConnectorQXMLRPC::createClient(const QString hostName, const unsigned int port) {
  41. bool result(false);
  42. if(m_Client == NULL) {
  43. m_Client = new xmlrpc::Client(NULL);
  44. result = connect( m_Client, SIGNAL(done( int, QVariant )),
  45. this, SLOT(processReturnValue( int, QVariant )) );
  46. result = connect( m_Client, SIGNAL(failed( int, int, QString )),
  47. this, SLOT(processFault( int, int, QString )) );
  48. }
  49. m_Client->setHost( hostName, port );
  50. }
  51. void ctkNetworkConnectorQXMLRPC::createServer(const unsigned int port) {
  52. if(m_Server != NULL) {
  53. unsigned int p = m_Server->property("port").toUInt();
  54. if(p != port) {
  55. stopServer();
  56. }
  57. }
  58. m_Server = new xmlrpc::Server(NULL);
  59. m_Server->setProperty("port", port);
  60. // Create a new ID to allow methods registration on new server instance.
  61. QString id_name(tr("ctk/remote/eventbus/communication/send/xmlrpc/serverMethods%1").arg(port));
  62. // Register the signal to the event bus.
  63. /*mafRegisterRemoteSignal(id_name, this, "registerMethodsServer(mafRegisterMethodsMap)");
  64. connect(this, SIGNAL(registerMethodsServer(mafRegisterMethodsMap)),
  65. this, SLOT(registerServerMethod(mafRegisterMethodsMap)));*/
  66. QList<QVariant::Type> parametersForRegisterteredFunction;
  67. parametersForRegisterteredFunction.append(QVariant::String); //return argument
  68. parametersForRegisterteredFunction.append(QVariant::List); //parameters to send, event control parameters
  69. parametersForRegisterteredFunction.append(QVariant::List); //parameters to send, data parameters
  70. //registration of the method maf.remote.eventBus.comunication.xmlrpc at XMLRPC level
  71. // the connect uses function name ad signature defined by parametersForRegisterteredFunction
  72. mafRegisterMethodsMap methodsMapping;
  73. methodsMapping.insert("ctk/remote/eventBus/comunication/send/xmlrpc", parametersForRegisterteredFunction);
  74. registerServerMethod(methodsMapping);
  75. //if a user want to register another method, it is important to know that ctkEventDispatcherRemote allows
  76. // the registration of function with QVariantList parameter.
  77. }
  78. void ctkNetworkConnectorQXMLRPC::stopServer() {
  79. unsigned int p = m_Server->property("port").toUInt();
  80. if(p != 0) {
  81. // get the ID for the previous server;
  82. /*QString old_id_name(tr("ctk/remote/eventbus/communication/send/xmlrpc/serverMethods%1").arg(p));
  83. // Remove the old signal.
  84. ctkBusEvent props;
  85. props[TOPIC] = old_id_name;
  86. props[TYPE] = ctkEventTypeRemote;
  87. props[SIGNATURE] = "registerMethodsServer(mafRegisterMethodsMap)";
  88. ctkEventBusManager::instance()->removeEventProperty(props);*/
  89. // Delete (and stop) the previous instance of the server.
  90. if(m_Server) {
  91. delete m_Server;
  92. m_Server = NULL;
  93. }
  94. }
  95. }
  96. void ctkNetworkConnectorQXMLRPC::registerServerMethod(mafRegisterMethodsMap registerMethodsList) {
  97. if(m_Server->isListening()) {
  98. qDebug("%s", tr("Server is already listening on port %1").arg(m_Server->property("port").toUInt()).toAscii().data());
  99. return;
  100. }
  101. // cycle over map: method name and parameter list
  102. foreach (QString key, registerMethodsList.keys()) {
  103. const unsigned int parametersNumber = registerMethodsList.value(key).count();
  104. switch(parametersNumber) {
  105. case 1:
  106. m_Server->registerMethod(key, registerMethodsList.value(key).at(0) );
  107. break;
  108. case 2:
  109. m_Server->registerMethod(key, registerMethodsList.value(key).at(0), registerMethodsList.value(key).at(1));
  110. break;
  111. case 3:
  112. m_Server->registerMethod(key, registerMethodsList.value(key).at(0), registerMethodsList.value(key).at(1), registerMethodsList.value(key).at(2));
  113. break;
  114. case 4:
  115. m_Server->registerMethod(key, registerMethodsList.value(key).at(0), registerMethodsList.value(key).at(1), registerMethodsList.value(key).at(2), registerMethodsList.value(key).at(3));
  116. break;
  117. case 5:
  118. m_Server->registerMethod(key, registerMethodsList.value(key).at(0), registerMethodsList.value(key).at(1), registerMethodsList.value(key).at(2), registerMethodsList.value(key).at(3) , registerMethodsList.value(key).at(4));
  119. break;
  120. default:
  121. break;
  122. }
  123. }
  124. }
  125. void ctkNetworkConnectorQXMLRPC::startListen() {
  126. connect( m_Server, SIGNAL(incomingRequest( int, QString, QList<xmlrpc::Variant>)),
  127. this, SLOT(processRequest( int, QString, QList<xmlrpc::Variant>)));
  128. unsigned int port = m_Server->property("port").toInt();
  129. if( m_Server->listen( port ) ) {
  130. qDebug() << "Listening for XML-RPC requests on port" << port;
  131. } else {
  132. qDebug() << "Error listening port" << port;
  133. }
  134. }
  135. void ctkNetworkConnectorQXMLRPC::send(const QString event_id, ctkEventArgumentsList *argList) {
  136. QList<xmlrpc::Variant> *vl = NULL;
  137. if(argList != NULL) {
  138. vl = new QList<xmlrpc::Variant>();
  139. int i=0, size = argList->count();
  140. for(;i<size;i++) {
  141. QString typeArgument;
  142. typeArgument = argList->at(i).name();
  143. if(typeArgument != "QVariantList") {
  144. qDebug() << typeArgument;
  145. qWarning("%s", tr("Remote Dispatcher need to have arguments that are QVariantList").toAscii().data());
  146. delete vl;
  147. return;
  148. }
  149. void *vp = argList->at(i).data();
  150. QVariantList *l;
  151. l = (QVariantList *)vp;
  152. xmlrpc::Variant var;
  153. var.setValue(*l);
  154. vl->push_back(var); //only the first parameter represent the whole list of arguments
  155. }
  156. if(size == 0) {
  157. qWarning("%s", tr("Remote Dispatcher need to have at least one argument that is a QVariantList").toAscii().data());
  158. return;
  159. }
  160. }
  161. xmlrpcSend(event_id, *vl);
  162. delete vl;
  163. }
  164. void ctkNetworkConnectorQXMLRPC::xmlrpcSend(const QString &methodName, QList<xmlrpc::Variant> parameters) {
  165. const unsigned int parametersNumber = parameters.count();
  166. switch(parametersNumber) {
  167. case 1:
  168. m_RequestId = m_Client->request(methodName, parameters.at(0) );
  169. break;
  170. case 2:
  171. m_RequestId = m_Client->request(methodName, parameters.at(0), parameters.at(1));
  172. break;
  173. case 3:
  174. m_RequestId = m_Client->request(methodName, parameters.at(0), parameters.at(1), parameters.at(2));
  175. break;
  176. case 4:
  177. m_RequestId = m_Client->request(methodName, parameters.at(0), parameters.at(1), parameters.at(2), parameters.at(3));
  178. break;
  179. default:
  180. break;
  181. }
  182. }
  183. void ctkNetworkConnectorQXMLRPC::processReturnValue( int requestId, QVariant value ) {
  184. Q_UNUSED( requestId );
  185. Q_ASSERT( value.canConvert( QVariant::String ) );
  186. qDebug("%s", value.toString().toAscii().data());
  187. ctkEventBusManager::instance()->notifyEvent("ctk/local/eventBus/remoteCommunicationDone", ctkEventTypeLocal);
  188. }
  189. void ctkNetworkConnectorQXMLRPC::processFault( int requestId, int errorCode, QString errorString ) {
  190. // Log the error.
  191. qDebug("%s", tr("Process Fault for requestID %1 with error %2 - %3").arg(QString::number(requestId), QString::number(errorCode), errorString).toAscii().data());
  192. ctkEventBusManager::instance()->notifyEvent("ctk/local/eventBus/remoteCommunicationFailed", ctkEventTypeLocal);
  193. }
  194. void ctkNetworkConnectorQXMLRPC::processRequest( int requestId, QString methodName, QList<xmlrpc::Variant> parameters ) {
  195. Q_UNUSED( methodName );
  196. //first parameter is ctkEventBus message
  197. enum {
  198. EVENT_PARAMETERS,
  199. DATA_PARAMETERS,
  200. };
  201. enum {
  202. EVENT_ID,
  203. EVENT_ITEM_TYPE,
  204. EVENT_SIGNATURE_TYPE,
  205. EVENT_METHOD_SIGNATURE,
  206. };
  207. if(parameters.at(EVENT_PARAMETERS).toList().count() == 0) {
  208. m_Server->sendReturnValue( requestId, QString("No Command to Execute, command list is empty") );
  209. }
  210. //here eventually can be used a filter for events
  211. //first argument regards local signal to be called.
  212. QString id_name = parameters.at(EVENT_PARAMETERS).toList().at(EVENT_ID).toString();
  213. int size = parameters.count();
  214. ctkEventArgumentsList *argList = NULL;
  215. QVariantList p;
  216. p.append((parameters.at(1).value< QVariantList >()));
  217. if(size > 1 && p.count() != 0) {
  218. argList = new ctkEventArgumentsList();
  219. argList->push_back(Q_ARG(QVariantList, p));
  220. }
  221. if ( ctkEventBusManager::instance()->isLocalSignalPresent(id_name) ) {
  222. ctkBusEvent dictionary(id_name,ctkEventTypeLocal,0,NULL,"");
  223. /*dictionary.setEventTopic(id_name);
  224. dictionary.setEventType(ctkEventTypeLocal);*/
  225. ctkEventBusManager::instance()->notifyEvent(dictionary, argList);
  226. m_Server->sendReturnValue( requestId, QString("OK") );
  227. } else {
  228. m_Server->sendReturnValue( requestId, QString("FAIL") );
  229. }
  230. if(argList){
  231. delete argList;
  232. argList = NULL;
  233. }
  234. }