#pragma once #include "ApiTypes.h" #include namespace resource_api { // a base class for routing requests to handler methods // nothing is thread safe here class ResourceRouter { public: virtual ~ResourceRouter(); // can return NULL, if the request was processed // if the Response can not be created immediately, // then return a object which implements the ResponseTask interface ResponseTask* handleRequest(Request& req, Response& resp); template void addResourceHandler(std::string name, T* instance, ResponseTask* (T::*callback)(Request& req, Response& resp)); template void addResourceHandler(std::string name, T* instance, void (T::*callback)(Request& req, Response& resp)); bool isNameUsed(std::string name); private: class HandlerBase { public: virtual ~HandlerBase(){} virtual ResponseTask* handleRequest(Request& req, Response& resp) = 0; }; template class Handler: public HandlerBase { public: virtual ResponseTask* handleRequest(Request &req, Response &resp) { return (instance->*method)(req, resp); } T* instance; ResponseTask* (T::*method)(Request& req, Response& resp); }; template class InstantResponseHandler: public HandlerBase { public: virtual ResponseTask* handleRequest(Request &req, Response &resp) { (instance->*method)(req, resp); return 0; } T* instance; void (T::*method)(Request& req, Response& resp); }; std::vector > mHandlers; }; // the advantage of this approach is: // the method name is arbitrary, one class can have many different handler methods // with raw objects the name of the handler method would be fixed, and we would need one class for every handler // the downside is complicated template magic template void ResourceRouter::addResourceHandler(std::string name, T* instance, ResponseTask* (T::*callback)(Request& req, Response& resp)) { if(isNameUsed(name)) { std::cerr << "ResourceRouter::addResourceHandler ERROR: name=" << name << " alerady in use. Not adding new Handler!" << std::endl; } Handler* handler = new Handler(); handler->instance = instance; handler->method = callback; mHandlers.push_back(std::make_pair(name, handler)); } template void ResourceRouter::addResourceHandler(std::string name, T* instance, void (T::*callback)(Request& req, Response& resp)) { if(isNameUsed(name)) { std::cerr << "ResourceRouter::addResourceHandler ERROR: name=" << name << " alerady in use. Not adding new Handler!" << std::endl; } InstantResponseHandler* handler = new InstantResponseHandler(); handler->instance = instance; handler->method = callback; mHandlers.push_back(std::make_pair(name, handler)); } } // namespace resource_api