MIRA
RPCServer.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012 by
3  * MetraLabs GmbH (MLAB), GERMANY
4  * and
5  * Neuroinformatics and Cognitive Robotics Labs (NICR) at TU Ilmenau, GERMANY
6  * All rights reserved.
7  *
8  * Contact: info@mira-project.org
9  *
10  * Commercial Usage:
11  * Licensees holding valid commercial licenses may use this file in
12  * accordance with the commercial license agreement provided with the
13  * software or, alternatively, in accordance with the terms contained in
14  * a written agreement between you and MLAB or NICR.
15  *
16  * GNU General Public License Usage:
17  * Alternatively, this file may be used under the terms of the GNU
18  * General Public License version 3.0 as published by the Free Software
19  * Foundation and appearing in the file LICENSE.GPL3 included in the
20  * packaging of this file. Please review the following information to
21  * ensure the GNU General Public License version 3.0 requirements will be
22  * met: http://www.gnu.org/copyleft/gpl.html.
23  * Alternatively you may (at your option) use any later version of the GNU
24  * General Public License if such license has been publicly approved by
25  * MLAB and NICR (or its successors, if any).
26  *
27  * IN NO EVENT SHALL "MLAB" OR "NICR" BE LIABLE TO ANY PARTY FOR DIRECT,
28  * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
29  * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF "MLAB" OR
30  * "NICR" HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * "MLAB" AND "NICR" SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
33  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
34  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
35  * ON AN "AS IS" BASIS, AND "MLAB" AND "NICR" HAVE NO OBLIGATION TO
36  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR MODIFICATIONS.
37  */
38 
47 #ifndef _MIRA_RPCSERVER_H_
48 #define _MIRA_RPCSERVER_H_
49 
50 #include <functional>
51 
52 #ifndef Q_MOC_RUN
53 #include <boost/preprocessor/repetition.hpp>
54 #include <boost/thread/mutex.hpp>
55 #endif
56 
57 #include <platform/Environment.h>
58 
60 
61 #include <error/LoggingCore.h>
62 #include <error/LoggingAux.h>
63 
64 #include <rpc/RPCSignature.h>
65 #include <rpc/RPCInvoker.h>
66 #include <rpc/RPCError.h>
67 #include <rpc/BinaryRPCBackend.h>
68 #include <rpc/JSONRPCBackend.h>
69 
71 
72 #include <utils/ToString.h>
73 
74 namespace mira {
75 
77 
108 {
109 public:
110 
116  {
118 
119  ParameterInfo(const std::string& iName, const std::string& iDescription)
120  : name(iName), description(iDescription) {}
121 
122  template<typename Reflector>
123  void reflect(Reflector& r)
124  {
125  r.member("Name", name, "");
126  r.member("Description", description, "");
127  }
128 
130  std::string name;
131 
133  std::string description;
134 
135  public:
136 
137  friend std::ostream& operator<<(std::ostream& s, const ParameterInfo& v)
138  {
139  s << v.name << " \t: " << v.description;
140  return s;
141  }
142  };
143 
144  typedef std::vector<ParameterInfo> ParameterDescriptions;
145 
150  struct MethodInfo
151  {
152  class ReflectMethodParamsDocumentation : public Singleton<ReflectMethodParamsDocumentation>
153  {
155 
156  protected:
157  ReflectMethodParamsDocumentation() : mReflectMethodParamsDocumentation(true)
158  {
159  try {
160  resolveEnvironmentVariable("MIRA_RPC_METHODS_REFLECT_NO_PARAMS_DOCUMENTATION");
161  // if resolve succeeds (--> variable exists), do not reflect version and parameter documentation
162  mReflectMethodParamsDocumentation = false;
163  MIRA_LOG(WARNING) << "Found definition of environment variable "
164  << "MIRA_RPC_METHODS_REFLECT_NO_PARAMS_DOCUMENTATION "
165  << "- RPC parameter documentation will not be shared with "
166  << "remote frameworks (ensuring backward compatibility)";
167  }
168  catch(...) {}
169  }
170 
171  public:
172  static bool enabled() { return instance().mReflectMethodParamsDocumentation; }
173 
174  private:
175  bool mReflectMethodParamsDocumentation;
176  };
177 
179 
180  MethodInfo(const RPCSignature& iSignature, const std::string& iComment) :
181  signature(iSignature), comment(iComment), parameterSamplesDefault(true) {}
182 
183  MethodInfo(const RPCSignature& iSignature, const std::string& iComment,
184  const ParameterDescriptions& iParameterDescriptions) :
185  signature(iSignature), comment(iComment),
186  parameterDesc(iParameterDescriptions), parameterSamplesDefault(true) {}
187 
188  template<typename Reflector>
189  void reflect(Reflector& r)
190  {
191  serialization::VersionType version = r.version(3, this);
192 
193  r.member("Signature", signature, "");
194  r.member("Comment", comment, "");
195 
196  if (version >= 2) {
197  r.member("ParameterDescriptions", parameterDesc, "");
198  r.member("ParameterSamples", parameterSamples, "");
199 
200  if (version >= 3)
201  r.member("ParameterSamplesDefault", parameterSamplesDefault, "");
202  }
203  }
204 
205  template<typename Reflector>
206  void reflectBinaryV0(Reflector& r)
207  {
208  serialization::VersionType version = 0;
209 
211  version = r.version(2, this); // version 3 did not exist with serialization format v0
212 
213  r.member("Signature", signature, "");
214  r.member("Comment", comment, "");
215 
216  if (version >= 2) {
217  r.member("ParameterDescriptions", parameterDesc, "");
218  r.member("ParameterSamples", parameterSamples, "");
219  }
220  }
221 
222  // Specialization for serialization format v0
223  template<typename Stream>
225  {
226  reflectBinaryV0(r);
227  }
228 
229  // Specialization for deserialization format v0
230  template<typename Stream>
232  {
233  reflectBinaryV0(r);
234  }
235 
236  bool operator<(const MethodInfo& rhs) const {
237  return signature < rhs.signature;
238  }
239 
240  bool operator==(const MethodInfo& rhs) const {
241  return signature==rhs.signature;
242  }
243 
244  std::string extendedSignature() const;
245 
247  std::string parameterDescriptions(const std::string& prefix = "") const;
248 
249  std::string sampleParametersSet(bool formatted = false) const;
250 
253 
255  std::string comment;
256 
259 
262  std::list<json::Value> parameterSamples;
263  };
264 
270  struct Method : public MethodInfo
271  {
272  Method(const RPCSignature& signature, const std::string& comment) :
274 
275  Method(const RPCSignature& signature, const std::string& comment,
278 
280  template<typename Backend>
282  {
283  invokers.insert(std::make_pair(typeId<Backend>(),
284  boost::shared_ptr<RPCInvoker>(invoker)));
285  }
286 
288  std::map<int, boost::shared_ptr<RPCInvoker>> invokers;
289  };
290 
291  typedef std::set<Method> MethodSet;
292 
293  typedef std::set<MethodInfo> MethodInfoSet;
294 
295 
301  template <typename TMethodSet>
302  struct ServiceInfo
303  {
304  ServiceInfo(const std::string& iName="") :
305  name(iName) {}
306 
307  template<typename Reflector>
308  void reflect(Reflector& r)
309  {
310  r.member("Name", name, "");
311  r.member("Methods", methods, "");
312  r.member("Interfaces", interfaces, "");
313  }
314 
316  std::string name;
318  TMethodSet methods;
320  std::set<std::string> interfaces;
321  };
322 
324 
325  typedef std::map<std::string, Service> ServiceMap;
326 
327 
339  class RPCReflector : public ReflectorInterface<RPCReflector>
340  {
341  public:
342 
354  RPCReflector(Service& iService) :
355  mService(iService) {}
356 
357 
358  public:
359 
361  template <typename Base>
362  void reflectBase(Base& base) {
363  // simplified (compared to AbstractReflector), but should be enough for the RPCServer
364  base.reflect(*this);
365  }
366 
367  public:
368 
370  const std::set<RPCSignature>& getAddedMethods() const {
371  return mAddedMethods;
372  }
373 
375  const std::set<std::string>& getAddedInterfaces() const {
376  return mAddedInterfaces;
377  }
378 
379  public:
380 
381  void interface(const char* name) {
382  if(mService.interfaces.insert(std::string(name)).second)
383  mAddedInterfaces.insert(std::string(name));
384  }
385 
386  template<typename R, typename... Args, typename F, typename... Description>
387  InvalidRPCDescription<R(Args...), Description...>
388  method(const char*, F&&, Description&&...)
389  {
390  Private::rpc::invalidAssertion<R(Args...), Description...>();
391  }
392 
393  template<typename F, typename... Description>
394  InvalidRPCDescription<F, Description...>
395  method(const char*, F&&, Description&&...)
396  {
397  Private::rpc::invalidAssertion<F, Description...>();
398  }
399 
400  template<typename R, typename Class, typename... Args, typename... Description>
401  InvalidRPCDescription<R (Class::*)(Args...), Description...>
402  method(const char*, R (Class::*)(Args...), Class*, Description&&...)
403  {
404  Private::rpc::invalidAssertion<R (Class::*)(Args...), Description...>();
405  }
406 
407  template<typename R, typename Class, typename... Args, typename... Description>
408  InvalidRPCDescription<R (Class::*)(Args...) const, Description...>
409  method(const char*, R (Class::*)(Args...) const, Class*, Description&&...)
410  {
411  Private::rpc::invalidAssertion<R (Class::*)(Args...) const, Description...>();
412  }
413 
414  template<typename R, typename... Args, typename F, typename... Description>
415  ValidRPCDescription<R(Args...), Description...>
416  method(const char* name, F&& fn, Description&&... descriptions)
417  {
418  concreteMethod<R, Args...>(name, std::forward<F>(fn), std::forward<Description>(descriptions)...);
419  }
420 
421  template<typename F, typename... Description>
422  ValidRPCDescription<F, Description...>
423  method(const char* name, F&& fn, Description&&... descriptions)
424  {
425  concreteMethodHelper<typename Private::FunctionTraits<F>::ReturnValue>(
426  name, std::forward<F>(fn), typename Private::FunctionTraits<F>::Arguments{},
427  std::forward<Description>(descriptions)...);
428  }
429 
430  template<typename R, typename Class, typename... Args, typename... Description>
431  ValidRPCDescription<R (Class::*)(Args...), Description...>
432  method(const char* name, R (Class::*fn)(Args...), Class* This, Description&&... descriptions)
433  {
434  auto func = Private::MemberInvoker<decltype(std::mem_fn(fn)), Class>(std::mem_fn(fn), This);
435  concreteMethod<R, Args...>(name, std::move(func), std::forward<Description>(descriptions)...);
436  }
437 
438  template<typename R, typename Class, typename... Args, typename... Description>
439  ValidRPCDescription<R (Class::*)(Args...) const, Description...>
440  method(const char* name, R (Class::*fn)(Args...) const, Class* This, Description&&... descriptions)
441  {
442  auto func = Private::MemberInvoker<decltype(std::mem_fn(fn)), Class>(std::mem_fn(fn), This);
443  concreteMethod<R, Args...>(name, std::move(func), std::forward<Description>(descriptions)...);
444  }
445 
446  private:
447  template<typename R, typename... Args, typename F, typename... Description>
448  void concreteMethodHelper(const char* name, F&& fn, Private::ArgumentTuple<Args...> args,
449  Description&&... descriptions)
450  {
451  concreteMethod<R, Args...>(name, std::forward<F>(fn), std::forward<Description>(descriptions)...);
452  }
453 
454  template<typename R, typename... Args, typename F, typename Comment, typename... Description>
455  void concreteMethod(const char* name, F&& fn, Comment&& comment, Description&&... descriptions)
456  {
457  Method m(makeRPCSignature<R, Args...>(name), std::forward<Comment>(comment));
458  m.parameterDesc.reserve(sizeof...(Args));
459  addParameterDescription<Args...>(m, std::forward<Description>(descriptions)...);
460  m.addInvoker(make_RPCInvoker<BinaryRPCBackend, R, Args...>(fn));
461  m.addInvoker(make_RPCInvoker<BinaryRPCBackendLegacy, R, Args...>(fn));
462  m.addInvoker(make_RPCInvoker<JSONRPCBackend, R, Args...>(fn));
463  addMethod(m);
464  }
465 
466  private:
467 
468  void addMethod(const Method& method) {
469  foreach (const MethodInfo& m, mService.methods) {
470  // more than 1 method with same name and number of parameters?
471  if ((m.signature.name == method.signature.name) &&
472  (m.signature.parameterTypes.size() == method.signature.parameterTypes.size())) {
473  MIRA_LOG(WARNING) << mService.name << "." << m.signature << " and "
474  << mService.name << "." << method.signature
475  << " are ambiguous when called through JSON RPC"
476  << " - choosing different method names is strongly recommended!";
477  }
478  }
479 
480  if(mService.methods.insert(method).second)
481  mAddedMethods.insert(method.signature);
482  // adding the same method multiple times, is handled correctly
483  }
484 
485  template<typename... RECURSIONSTOP>
486  typename std::enable_if<(sizeof...(RECURSIONSTOP)) == 0>::type addParameterDescription(Method& m)
487  {}
488 
489  template<typename ParameterType, typename... Args>
490  MIRA_DEPRECATED("_________________Please provide parameter descriptions (and sample values, if appropriate) for RPC methods!_________________",
491  void addParameterDescription(Method& m)
492  {
493  m.parameterSamples.emplace_back(createParameterSample<Private::StrippedType<ParameterType>>());
494  addParameterDescription<Args...>(m);
495  }
496  )
497 
498  template<typename ParameterType, typename... Args, class Name, class Description, typename... Tail,
499  typename = typename std::enable_if<(sizeof...(Args)) * 2 == sizeof...(Tail)>::type>
500  void addParameterDescription(Method& m, Name&& name, Description&& description, Tail&&... tail)
501  {
502  m.parameterDesc.emplace_back(std::forward<Name>(name), std::forward<Description>(description));
503  m.parameterSamples.emplace_back(createParameterSample<Private::StrippedType<ParameterType>>());
504  addParameterDescription<Args...>(m, std::forward<Tail>(tail)...);
505  }
506 
507  template<typename ParameterType, typename... Args, class Name, class Description, class Example,
508  typename... Tail,
509  typename = typename std::enable_if<(sizeof...(Args)) * 3 == sizeof...(Tail)>::type>
510  void addParameterDescription(Method& m, Name&& name, Description&& description, Example&& example,
511  Tail&&... tail)
512  {
513  m.parameterDesc.emplace_back(std::forward<Name>(name), std::forward<Description>(description));
514  m.parameterSamples.emplace_back(
515  createParameterSample<Private::StrippedType<ParameterType>>(std::forward<Example>(example)));
516  m.parameterSamplesDefault = false; // this will be assigned multiple times in recursive calls,
517  // but the alternative seems to be to double the number of methods needed for this
518  addParameterDescription<Args...>(m, std::forward<Tail>(tail)...);
519  }
520 
521  template<typename T>
522  json::Value createParameterSample(const T& v = T())
523  {
524  return mJSONSerializer.serialize(v);
525  }
526 
528  JSONSerializer mJSONSerializer;
529 
530  private:
531 
533  Service& mService;
534 
536  std::set<RPCSignature> mAddedMethods;
537 
539  std::set<std::string> mAddedInterfaces;
540  };
541 
542 public:
543 
551  template <typename T>
552  const Service& registerServiceObject(const std::string& serviceName,
553  T& serviceObject,
554  std::set<RPCSignature>* addedMethods = NULL,
555  std::set<std::string>* addedInterfaces = NULL)
556  {
557  boost::mutex::scoped_lock lock(mMutex);
558 
559  // use already created service, or create new one
560  ServiceMap::iterator it = mServices.find(serviceName);
561  if (it==mServices.end())
562  it = mServices.insert(std::make_pair(serviceName,
563  Service(serviceName))).first;
564 
565  // reflect the service object and add its methods to the service
566  Service& s = it->second;
567  RPCReflector r(s);
568  serviceObject.reflect(r);
569 
570  MIRA_LOG(NOTICE) << "Registered service object for service: '" <<
571  serviceName << "'. With the following new methods:";
572  foreach(const RPCSignature& m, r.getAddedMethods())
573  MIRA_LOG(NOTICE) << " " << m;
574 
575  if(addedMethods!=NULL)
576  *addedMethods = r.getAddedMethods();
577 
578  if(addedInterfaces!=NULL)
579  *addedInterfaces = r.getAddedInterfaces();
580 
581  return s;
582  }
583 
588  void unregisterService(const std::string& serviceName)
589  {
590  boost::mutex::scoped_lock lock(mMutex);
591  MIRA_LOG(NOTICE) << "Unregistering service: '" << serviceName << "'.";
592  mServices.erase(serviceName);
593  }
594 
595 public:
596 
600  const ServiceMap& getServices() const
601  {
602  return mServices;
603  }
604 
610  const Service& getService(const std::string& name) const
611  {
612  boost::mutex::scoped_lock lock(mMutex);
613  auto i = mServices.find(name);
614  if (i == mServices.end())
615  MIRA_THROW(XInvalidParameter, "No such service '" << name << "'");
616 
617  return i->second;
618  }
619 
623  bool existsService(const std::string& name) const
624  {
625  boost::mutex::scoped_lock lock(mMutex);
626  auto i = mServices.find(name);
627  return i!= mServices.end();
628  }
629 
634  std::list<std::string> queryServicesForInterface(const std::string& interface) const
635  {
636  boost::mutex::scoped_lock lock(mMutex);
637  std::list<std::string> res;
638  // for all services
639  for(auto it=mServices.begin(); it!=mServices.end(); ++it)
640  // does service implements the desired interface?
641  if(it->second.interfaces.count(interface)!=0)
642  res.push_back(it->second.name); // yes? so add its name to the list
643  return res;
644  }
645 
649  bool implementsInterface(const std::string& name, const std::string& interface) const
650  {
651  boost::mutex::scoped_lock lock(mMutex);
652  auto it = mServices.find(name);
653  if (it == mServices.end())
654  return false;
655  return it->second.interfaces.count(interface) > 0;
656  }
657 
658 public:
659 
666  template <typename Backend>
667  void processCall(typename Backend::ServerRequest& request,
668  typename Backend::ServerResponse& response)
669  {
670  boost::shared_ptr<TRPCInvoker<Backend>> invoker;
671  Service* service;
672  std::string callId;
673 
674  Method* method = NULL;
675  if(!processCallCommon<Backend>(request, response, callId, invoker, service, method))
676  return; // an error has occured, abort, error already is reported in response
677 
678  // and finally invoke the method
679  response.setHeader(callId);
680  try
681  {
682  invoker->invoke(request, response);
683  }
684  catch(std::exception& ex) {
685  // handle possible exceptions in getParameter() and return them to caller
686  MIRA_LOG(WARNING) << "Invalid RPC Request: " << ex.what();
687  response.returnException(RPC_INVALID_PARAMS, ex.what());
688  }
689  }
690 
698  template <typename Backend>
700  {
701  public:
702  DeferredInvoker(typename Backend::ServerRequest& request,
703  typename Backend::ServerResponse& response,
704  const std::string& callId,
705  const std::string& service,
706  const std::string& method,
707  boost::shared_ptr<TRPCInvoker<Backend>> invoker) :
708  AbstractDeferredInvoker(callId,service,method),
709  mRequest(request), mResponse(response),
710  mInvoker(invoker) {}
711  public:
712  virtual void invoke() {
713  mResponse.setHeader(mCallId);
714  try
715  {
716  mInvoker->invoke(mRequest, mResponse);
717  }
718  catch(std::exception& ex) {
719  // handle possible exceptions in getParameter() and return them to caller
720  MIRA_LOG(WARNING) << "Invalid RPC Request: " << ex.what();
721  mResponse.returnException(RPC_INVALID_PARAMS, ex.what());
722  }
723  try {
724  if(mFinishHandler!=NULL)
726  } catch(std::exception& ex) {
727  // catch broken promise
729  }
730  }
731  private:
732  typename Backend::ServerRequest& mRequest;
733  typename Backend::ServerResponse& mResponse;
734  boost::shared_ptr<TRPCInvoker<Backend>> mInvoker;
735  };
736 
748  template <typename Backend>
749  AbstractDeferredInvokerPtr processCallDeferred(typename Backend::ServerRequest& request,
750  typename Backend::ServerResponse& response)
751  {
752  boost::shared_ptr<TRPCInvoker<Backend>> invoker;
753  Service* service = NULL;
754  std::string callId;
755 
756  Method* method;
757 
758  if(processCallCommon<Backend>(request, response, callId, invoker, service, method)) {
759  assert(service!=NULL);
760  AbstractDeferredInvokerPtr deferredInvoker(
761  new DeferredInvoker<Backend>(request, response, callId,
762  service->name,
763  method->signature.name, invoker));
764  return deferredInvoker;
765  } else {
766  // error already is reported in response
768  }
769  }
770 
771 protected:
772 
774  template <typename Backend>
775  bool processCallCommon(typename Backend::ServerRequest& request,
776  typename Backend::ServerResponse& response,
777  std::string &oCallId,
778  boost::shared_ptr<TRPCInvoker<Backend>>& oInvoker,
779  Service* &oService, Method* &oMethod)
780  {
781  std::string name;
782  std::string callId;
783  std::string serviceStr;
784 
785  try {
786  request.getHeader(callId, serviceStr);
787  } catch(std::exception& ex) {
788  // handle possible exceptions in getHeader() and return them to caller
789  MIRA_LOG(WARNING) << "Invalid RPC Request: " << ex.what();
790  generateErrorResponse<Backend>(callId, RPC_INVALID_REQUEST, ex.what(), response);
791  return false;
792  }
793 
794  boost::mutex::scoped_lock lock(mMutex);
795 
796  // find the service
797  auto serviceIt = mServices.find(serviceStr);
798 
799  if(serviceIt==mServices.end()) {
800  MIRA_LOG(WARNING) << "RPC service not found: " << serviceStr;
801  generateErrorResponse<Backend>(callId, RPC_METHOD_NOT_FOUND,
802  "Cannot process RPC call, a service named '"
803  + serviceStr + "' does not exist", response);
804  return false;
805  }
806 
807  Service& service = serviceIt->second;
808 
809  // find the method
810  oMethod=NULL;
811  Method* method = NULL;
812 
813  foreach(const Method& m, service.methods)
814  {
815  if(request.checkSignature(m.signature)) {
816  // found method with the correct signature
817  method = const_cast<Method*>(&m);
818  break; // break for each
819  }
820  }
821 
822  // abort, if we did not find the method, but produce a (hopefully)
823  // helpful exception message
824  if(method==NULL) {
825  std::string methodName = request.getSignature().name;
826  std::string candidates;
827  foreach(const Method& m, service.methods)
828  {
829  if(methodName == m.signature.name) {
830  if(!candidates.empty())
831  candidates += ", ";
832  candidates += toString(m.signature);
833  }
834  }
835 
836  if(!candidates.empty())
837  candidates = " Candidates are: " + candidates;
838  else
839  candidates = " No candidates found.";
840 
841  MIRA_LOG(WARNING) << "RPC method does not exist: "
842  << toString(request.getSignature())
843  << ", candidates: " << candidates;
844  generateErrorResponse<Backend>(callId,
845  RPC_INVALID_PARAMS, "Cannot process RPC call, the service '" +
846  serviceStr + "' does not have a method '" +
847  toString(request.getSignature()) + "'." + candidates,
848  response);
849  return false;
850  }
851 
852  // now get the invoker for our backend
853  auto invokerIt = method->invokers.find(typeId<Backend>());
854  if(invokerIt == method->invokers.end())
855  MIRA_THROW(XLogical, "Cannot process RPC call, no invoker for service method '" <<
856  serviceStr << "." << request.getSignature() <<
857  "' was registered for backend type '" <<
858  typeName<Backend>() << "'.");
859  // the above exception is not send to the caller, since it is caused by
860  // a problem here in our server
861 
862  // cast invoker into typed invoker for our Backend
863  oInvoker = boost::static_pointer_cast<TRPCInvoker<Backend>>(invokerIt->second);
864  oCallId = callId;
865  oService = &service;
866  oMethod = method;
867  return true;
868  }
869 
870  template <typename Backend>
871  void generateErrorResponse(const std::string& callId,
872  RPCError reason, const std::string& message,
873  typename Backend::ServerResponse& oResponse)
874  {
875  oResponse.setHeader(callId);
876  oResponse.returnException(reason, message);
877  }
878 
879 private:
880 
881  ServiceMap mServices;
882  mutable boost::mutex mMutex;
883 };
884 
886 
887 } // namespace
888 
889 #endif /* _MIRA_RPCSERVER_H_ */
DeferredInvoker(typename Backend::ServerRequest &request, typename Backend::ServerResponse &response, const std::string &callId, const std::string &service, const std::string &method, boost::shared_ptr< TRPCInvoker< Backend >> invoker)
Definition: RPCServer.h:702
ServiceInfo< MethodSet > Service
Definition: RPCServer.h:323
MethodInfo(const RPCSignature &iSignature, const std::string &iComment)
Definition: RPCServer.h:180
Definition: BinarySerializer.h:324
Contains all available information about a single RPC service, including the service&#39; name...
Definition: RPCServer.h:302
AbstractDeferredInvokerPtr processCallDeferred(typename Backend::ServerRequest &request, typename Backend::ServerResponse &response)
Similar to processCall() this method decodes the RPCRequest which was received from the client-side...
Definition: RPCServer.h:749
void unregisterService(const std::string &serviceName)
Unregisters the specified service with all methods of all service objects that were registered...
Definition: RPCServer.h:588
Method(const RPCSignature &signature, const std::string &comment, const ParameterDescriptions &parameterDescriptions)
Definition: RPCServer.h:275
Provides binary client and server side requests and responses.
bool implementsInterface(const std::string &name, const std::string &interface) const
Returns if the given service implements a certain interface.
Definition: RPCServer.h:649
std::string comment
User comments and description.
Definition: RPCServer.h:255
Definition: RPCPatternCheck.h:82
Contains information on an RPC method&#39;s parameter: name, description.
Definition: RPCServer.h:115
Invalid parameters were specified for the method.
Definition: RPCError.h:68
void reflect(ConcreteBinarySerializer< Stream, 0 > &r)
Definition: RPCServer.h:224
RPCReflector(Service &iService)
Definition: RPCServer.h:354
const std::set< std::string > & getAddedInterfaces() const
Returns all interfaces that were added to the service while visiting the service object.
Definition: RPCServer.h:375
ValidRPCDescription< R(Class::*)(Args...), Description... > method(const char *name, R(Class::*fn)(Args...), Class *This, Description &&... descriptions)
Definition: RPCServer.h:432
Implementation of the CreationPolicy that is used by the Singleton template.
Definition: Singleton.h:174
Contains information on an existing RPC method: the signature of the method, comments, etc.
Definition: RPCServer.h:150
MethodInfo()
Definition: RPCServer.h:178
static Type & instance()
Returns a reference to the singleton instance.
Definition: Singleton.h:544
bool existsService(const std::string &name) const
Returns true, if a service with the specified name exists, otherwise false.
Definition: RPCServer.h:623
InvalidRPCDescription< R(Args...), Description... > method(const char *, F &&, Description &&...)
Definition: RPCServer.h:388
specialize cv::DataType for our ImgPixel and inherit from cv::DataType<Vec>
Definition: IOService.h:67
Error codes for reasons of errors/exceptions while processing an rpc call.
std::map< int, boost::shared_ptr< RPCInvoker > > invokers
stores corresponding RPCInvoker for each backend type
Definition: RPCServer.h:288
InvalidRPCDescription< R(Class::*)(Args...) const, Description... > method(const char *, R(Class::*)(Args...) const, Class *, Description &&...)
Definition: RPCServer.h:409
Invoker that is used to invoke an RPC method call for a special backend.
Definition: RPCInvoker.h:94
#define MIRA_LOG(level)
Use this macro to log data.
Definition: LoggingCore.h:528
std::string description
Parameter description.
Definition: RPCServer.h:133
Class object which supports some kind of class reflection.
Definition: Class.h:97
std::list< json::Value > parameterSamples
Definition: RPCServer.h:262
ParameterInfo()
Definition: RPCServer.h:117
Abstract interface for DeferredInvoker which is a class to support different RPC backends.
Definition: AbstractDeferredInvoker.h:80
Contains toString and fromString functions for converting data types to strings and the other way rou...
Definition: BinarySerializer.h:991
std::string extendedSignature() const
void reflect(Reflector &r)
Definition: RPCServer.h:123
bool processCallCommon(typename Backend::ServerRequest &request, typename Backend::ServerResponse &response, std::string &oCallId, boost::shared_ptr< TRPCInvoker< Backend >> &oInvoker, Service *&oService, Method *&oMethod)
contains common functionality that is used by processCall() and processCallDeferred() ...
Definition: RPCServer.h:775
uint8 VersionType
Definition: ReflectorInterface.h:72
#define MIRA_THROW(ex, msg)
Macro for throwing an exception.
Definition: Exception.h:81
This is the public interface of all reflectors that are able to visit a class&#39; reflect() method...
Definition: ReflectorInterface.h:111
Provides JSON client and server side requests and responses.
Definition: RPCInvoker.h:181
std::string toString(const T &value, int precision=-1)
Converts any data type to string (the data type must support the stream << operator).
Definition: ToString.h:256
void reflectBinaryV0(Reflector &r)
Definition: RPCServer.h:206
const Service & registerServiceObject(const std::string &serviceName, T &serviceObject, std::set< RPCSignature > *addedMethods=NULL, std::set< std::string > *addedInterfaces=NULL)
Registers the methods of the specified service object under the specified service name...
Definition: RPCServer.h:552
TMethodSet methods
All methods that were registered for this service.
Definition: RPCServer.h:318
Contains the base interface of all Reflectors, Serializers, etc.
Special visitor for the reflect() method that visits all method() and interface() calls within the re...
Definition: RPCServer.h:339
void interface(const char *name)
Definition: RPCServer.h:381
Auxiliary logging macros for special entities like exceptions, etc.
InvalidRPCDescription< F, Description... > method(const char *, F &&, Description &&...)
Definition: RPCServer.h:395
A singleton template class that can be freely configured using policies that control the instantiatio...
Definition: Singleton.h:531
MIRA_BASE_EXPORT std::string resolveEnvironmentVariable(const std::string &envVar)
Resolves an environmental variable.
PropertyHint type(const std::string &t)
Sets the attribute "type" to the specified value.
Definition: PropertyHint.h:295
Core class of the logging library.
std::string name
Parameter name.
Definition: RPCServer.h:130
RPCSignature for storing all information about an RPC method signature.
Contains all information on a registered RPC method, including the signature of the method...
Definition: RPCServer.h:270
Implements the RPCInvoker and TRPCInvoker classes.
bool operator<(const MethodInfo &rhs) const
Definition: RPCServer.h:236
void reflect(Reflector &r)
Definition: RPCServer.h:308
Abstract interface for DeferredInvoker.
ServiceInfo(const std::string &iName="")
Definition: RPCServer.h:304
std::string sampleParametersSet(bool formatted=false) const
std::string name
The method&#39;s name.
Definition: RPCSignature.h:134
std::string mCallId
Definition: AbstractDeferredInvoker.h:113
bool operator==(const MethodInfo &rhs) const
Definition: RPCServer.h:240
void generateErrorResponse(const std::string &callId, RPCError reason, const std::string &message, typename Backend::ServerResponse &oResponse)
Definition: RPCServer.h:871
RPCError
enumeration of possible reasons for errors/exceptions while performing an RPC call ...
Definition: RPCError.h:64
typename std::enable_if< Private::rpc::isValid< F, Description... >()>::type ValidRPCDescription
Definition: RPCPatternCheck.h:307
const std::set< RPCSignature > & getAddedMethods() const
Returns all methods that were added to the service while visiting the service object.
Definition: RPCServer.h:370
typename std::enable_if<!Private::rpc::isValid< F, Description... >()>::type InvalidRPCDescription
Definition: RPCPatternCheck.h:310
json_spirit::mValue Value
A value is an abstract description of data in JSON (underlying data can either be one of the JSON bas...
Definition: JSON.h:176
virtual void invoke()
Invokes the RPC call that is represented by this DeferredInvoker.
Definition: RPCServer.h:712
void addInvoker(TRPCInvoker< Backend > *invoker)
adds a new invoker that processes the method for a certain backend
Definition: RPCServer.h:281
void processCall(typename Backend::ServerRequest &request, typename Backend::ServerResponse &response)
Decodes the Request which was received from the client-side and invokes the RPC call immediately...
Definition: RPCServer.h:667
void reflectBase(Base &base)
implements ReflectorInterface (for documentation see ReflectorInterface)
Definition: RPCServer.h:362
InvalidRPCDescription< R(Class::*)(Args...), Description... > method(const char *, R(Class::*)(Args...), Class *, Description &&...)
Definition: RPCServer.h:402
std::list< std::string > queryServicesForInterface(const std::string &interface) const
Returns a string list with the names of all registered services, that implement the specified interfa...
Definition: RPCServer.h:634
#define MIRA_LOG_EXCEPTION(level, ex)
Log the specified exception, including all information that the exception object carries.
Definition: LoggingAux.h:107
std::set< MethodInfo > MethodInfoSet
Definition: RPCServer.h:293
std::map< std::string, Service > ServiceMap
Definition: RPCServer.h:325
Definition: RPCPatternCheck.h:88
Definition: LoggingCore.h:75
ValidRPCDescription< R(Class::*)(Args...) const, Description... > method(const char *name, R(Class::*fn)(Args...) const, Class *This, Description &&... descriptions)
Definition: RPCServer.h:440
Functions for platform independent resolving of environment variables.
friend std::ostream & operator<<(std::ostream &s, const ParameterInfo &v)
Definition: RPCServer.h:137
RPCSignature signature
The signature of the method (including its name)
Definition: RPCServer.h:252
std::set< Method > MethodSet
Definition: RPCServer.h:291
std::set< std::string > interfaces
All interfaces that this service supports.
Definition: RPCServer.h:320
Requested method was not found.
Definition: RPCError.h:67
std::string name
The name of this service.
Definition: RPCServer.h:316
void reflect(ConcreteBinaryDeserializer< Stream, 0 > &r)
Definition: RPCServer.h:231
static bool enabled()
Definition: RPCServer.h:172
Definition: LoggingCore.h:74
const ServiceMap & getServices() const
Returns the map with all known services.
Definition: RPCServer.h:600
Stores the signature of an RPC method including the methods name and its parameter types...
Definition: RPCSignature.h:68
ParameterDescriptions parameterDesc
User info on method parameters.
Definition: RPCServer.h:258
The request is invalid or can not be parsed.
Definition: RPCError.h:66
virtual void onRPCfinished(AbstractDeferredInvoker *invoker)=0
called upon finish of the RPC call, the ID of the call is passed as parameter.
void reflect(Reflector &r)
Definition: RPCServer.h:189
ParameterInfo(const std::string &iName, const std::string &iDescription)
Definition: RPCServer.h:119
const Service & getService(const std::string &name) const
Returns a reference to the service with the given name.
Definition: RPCServer.h:610
bool parameterSamplesDefault
Sample parameter values.
Definition: RPCServer.h:261
Method(const RPCSignature &signature, const std::string &comment)
Definition: RPCServer.h:272
boost::shared_ptr< AbstractDeferredInvoker > AbstractDeferredInvokerPtr
Definition: AbstractDeferredInvoker.h:119
std::string parameterDescriptions(const std::string &prefix="") const
The RPCServer is responsible for handling the server-side of an rpc call.
Definition: RPCServer.h:107
MethodInfo(const RPCSignature &iSignature, const std::string &iComment, const ParameterDescriptions &iParameterDescriptions)
Definition: RPCServer.h:183
std::vector< ParameterInfo > ParameterDescriptions
Definition: RPCServer.h:144
ValidRPCDescription< R(Args...), Description... > method(const char *name, F &&fn, Description &&... descriptions)
Definition: RPCServer.h:416
Definition: LoggingCore.h:76
constexpr std::enable_if<!FunctionTraits< F >::isFunction >::type invalidAssertion()
Definition: RPCPatternCheck.h:282
DeferredInvokerFinishHandler * mFinishHandler
Definition: AbstractDeferredInvoker.h:116
ValidRPCDescription< F, Description... > method(const char *name, F &&fn, Description &&... descriptions)
Definition: RPCServer.h:423
Stores all necessary information to invoke a previously decoded and prepared RPC call.
Definition: RPCServer.h:699