Active object concurrency pattern.
It has been a very long time since I have not published any blog. Most of my blogs are private. With this blog, I am starting my new blog series on patterns of distributed systems and multithreading. I believe I have done my homework, and now my private blogs are ready to go to the public domain.
Along with this, I would like to share another good news. I have become a father today. I am enjoying my paternal leaves and hence got some time off from my work, so just chilling and shaping my blogs for sharing.
Let's get back to business.
How will you make sure that your server would not block other clients while processing any client's request?
Though your server is multithreaded, and you have created a separate thread to take clients' requests. If the server request handler executes the method requested by the client in its control thread, it becomes a passive-synchronous way of handling the request, which is slow.
The solution is the active object pattern.
It helps us to increase server speed. The entry point of the server should not be involved in any method execution, and method execution should run in a different thread of control.
It is not only limited to the front entry points of your applications, wherever we increase the service, by unblocking its operations through separating the responsibility of execution and invocation. We apply active object pattern.
Along with this, I would like to share another good news. I have become a father today. I am enjoying my paternal leaves and hence got some time off from my work, so just chilling and shaping my blogs for sharing.
Let's get back to business.
Problem statement
Think of a client-server request and response. The client being your cellphones and server being any online shopping app or travel portal app, or maybe another server which has many clients' requests.How will you make sure that your server would not block other clients while processing any client's request?
Though your server is multithreaded, and you have created a separate thread to take clients' requests. If the server request handler executes the method requested by the client in its control thread, it becomes a passive-synchronous way of handling the request, which is slow.
The solution is the active object pattern.
How will the active object solve this?
Concurrency gives us the power to handle many client requests simultaneously. Active object patterns leverage the benefits of concurrency. It says the client's entry, and processing its request, has to be separated, both should present in different threads and execute independently and concurrently.It helps us to increase server speed. The entry point of the server should not be involved in any method execution, and method execution should run in a different thread of control.
It is not only limited to the front entry points of your applications, wherever we increase the service, by unblocking its operations through separating the responsibility of execution and invocation. We apply active object pattern.
Combination with other patterns
As we know, proxy design pattern and front controller design pattern are few patterns which use to take client's request and be in the front of your software modules. We can use the active object pattern along with one of them to handle clients' requests. It improves performance.
Example
It is a simple client-server communication, where the client sends the order request to the server. Server logs order in a separate file in the server location and gives order confirmation message to the client in response.
There are two modes of execution
There are two modes of execution
- Asynchronous way
- No blocking call here. Requests placed in a queue and a separate scheduler runs to handle individual requests.
- Note:- I could have avoided the scheduler, as it is just enqueued and dequeue operation, which can be achieved without it. It is a placeholder if you have complex requirements, where different scheduling algorithms are required. This can be useful.
- Synchronous way
- ClientRequestHandler has a blocking call, "Get." In this design, we don't process the next request until the server gives responses to the current request.
Please click on the image to see the zoom view. |
Please click on the image to see the zoom view. |
Classes - [C++ code implementation of active object]
Below is the class diagram, which shows how objects are talking to each other.
Please focus on the highlighted class. IHandlePurchaseOrder and ClientRequestHandler are active object classes.
Please click on the image to see the zoom view. |
Server code -
GlobalDefinitions.h
ClientRequestHandler.h
ClientRequestHandler.cpp
ServerProxy.h
ServerProxy.cpp
Scheduler.h
Scheduler.cpp
FutureObject.h
FutureObject.cpp
IRequest.h
Request.cpp
HandleOrder.h
HandleOrder.cpp
GlobalDefinitions.h
/*************************************************************************************************** // Author: Kunjesh Singh Baghel // Web-page: https://sites.google.com/site/kunjeshsinghbaghel/ ***************************************************************************************************/ #ifndef _ACTIVE_OBJECT_GLOBAL_DEFINITION_H_ #define _ACTIVE_OBJECT_GLOBAL_DEFINITION_H_ #pragma once namespace ActiveObject { enum MODE_OF_EXECUTION { SYNCHRONUS, SYNCHRONUS_WITH_TIME_LIMT, ASYNCHRONUS }; enum TASK_STATUS { NOT_SUBMITTED, IN_PROGRESS, COMPLETED }; } #endif // !_ACTIVE_OBJECT_GLOBAL_DEFINITION_H_
ClientRequestHandler.h
/*************************************************************************************************** // Author: Kunjesh Singh Baghel // Web-page: https://sites.google.com/site/kunjeshsinghbaghel/ ***************************************************************************************************/ #ifndef _CLIENT_REQUEST_HANDLER_H_ #define _CLIENT_REQUEST_HANDLER_H_ #pragma once #include "SocketAcceptor.h" #include "ServerProxy.h" #include "GlobalDefinitions.h" using namespace IO_MSG; using namespace SERVER_SOCKET; namespace ActiveObject { //class ClientRequestHandler : std::enable_shared_from_this<ClientRequestHandler> class ClientRequestHandler { private: std::unique_ptr<ServerProxy> pProxy; std::unique_ptr<SocketAcceptor> pConnect; std::shared_ptr<Socket> pSocket; thread* pListen; MODE_OF_EXECUTION eMode; public: /* constructor */ ClientRequestHandler(MODE_OF_EXECUTION mode = ASYNCHRONUS); /* destructor */ ~ClientRequestHandler(); /*! * Description : This function will help to open the server connection for always listening. */ void Setup(); void Cleanup(); void PlaceOrder(std::shared_ptr<IMessage> msg); void SendResponse(std::shared_ptr<IMessage> pMsg); MODE_OF_EXECUTION GetExecutionMode(); /*! * Description : This function is the starting point of new thread. */ static void Run(void* ptr); }; } #endif // !_CLIENT_REQUEST_HANDLER_H_
ClientRequestHandler.cpp
/*************************************************************************************************** // Author: Kunjesh Singh Baghel // Web-page: https://sites.google.com/site/kunjeshsinghbaghel/ ***************************************************************************************************/ #include "ClientRequestHandler.h" //#include "GlobalFactory.h" namespace ActiveObject { ClientRequestHandler::ClientRequestHandler(MODE_OF_EXECUTION mode) : pListen(nullptr), eMode(mode) { LOG_IT(SETUP_INFO, "Construction Process: ClientRequestHandler has begin"); pProxy = make_unique<ServerProxy>(); pConnect = std::make_unique<SocketAcceptor>(); if (!pConnect->IsServerSocketCreated()) { LOG_IT(ERROR_MSG, "Construction Process: Setting up the server socket has been failed"); } pSocket = std::make_shared<Socket>(); } ClientRequestHandler::~ClientRequestHandler() { LOG_IT(SETUP_INFO, "Cleanup Process: of ClientRequestHandler has begin"); Cleanup(); if (pListen != nullptr) { delete pListen; pListen = nullptr; } } void ClientRequestHandler::Setup() { LOG_IT(SETUP_INFO, " ClientRequestHandler is about to create a new listening thread."); pProxy->Setup(); pListen = new std::thread(ClientRequestHandler::Run, this); if (pConnect->IsServerSocketCreated()) { pConnect->MultiClientAccept(); } } void ClientRequestHandler::Cleanup() { if(pListen->joinable()) pListen->join(); pProxy->Cleanup(); } void ClientRequestHandler::Run(void *ptr) { LOG_IT(SETUP_INFO, " ClientRequestHandler Created new listening thread."); ClientRequestHandler* thisPtr = static_cast<ClientRequestHandler *>(ptr); Queue <shared_ptr<IMessage > >& Q = Socket::GetClientRequests(); while (true) { std::unique_lock<std::mutex> lockIt(Q.GetMutex()); Q.GetNotified().wait(lockIt, [&]() {return !Q.IsEmpty(); }); shared_ptr<IMessage > pMsg = Q.Front(); Q.Remove(); thisPtr->PlaceOrder(pMsg); } } void ClientRequestHandler::PlaceOrder(std::shared_ptr<IMessage> pMsg) { LOG_IT(SETUP_INFO, "Placing customer order"); string key = pProxy->PlaceOrder(pMsg); if (eMode == SYNCHRONUS) { std::shared_ptr<FutureObject> newFuObj = pProxy->GetConfirmation(key); newFuObj->SetClientRequestHandler(this); // set this, just to get the mode of execution. SendResponse(newFuObj->Get()); // This will be blocking call. } else if (eMode == ASYNCHRONUS) { std::shared_ptr<FutureObject> newFuObj = pProxy->GetConfirmation(key); newFuObj->SetClientRequestHandler(this); } } void ClientRequestHandler::SendResponse(std::shared_ptr<IMessage> pMsg) { LOG_IT(SETUP_INFO, "Sending response back to the customer"); pSocket->SendToClient(pMsg->GetResponse().c_str(), stoi(pMsg->GetClientSocket())); } MODE_OF_EXECUTION ClientRequestHandler::GetExecutionMode() { return eMode; } }
ServerProxy.h
/*************************************************************************************************** // Author: Kunjesh Singh Baghel // Web-page: https://sites.google.com/site/kunjeshsinghbaghel/ ***************************************************************************************************/ #ifndef _SERVER_PROXY_H #define _SERVER_PROXY_H #pragma once #include "IMessage.h" #include "Scheduler.h" #include "HandleOrder.h" #include <memory> using namespace IO_MSG; namespace ActiveObject { class FutureObject; /*! * Description : For each client request. ServerProxy will create concrete IRequest objects. - This class is also acting like Factory + Proxy. - Multiple clients can use same proxy object for request invocation, without explicit synchronization. */ class ServerProxy { private: std::shared_ptr<IHandlePurchaseOrder> pHandleOrder; std::shared_ptr<Scheduler> pScheduler; public: /*Constructor */ ServerProxy(); void Setup(); void Cleanup(); std::string PlaceOrder(std::shared_ptr<IMessage> msg); /*! * Description : * Output : std::shared_ptr<FutureObject> - This FutureObject will be returned to the client thread. */ std::shared_ptr<FutureObject> GetConfirmation(std::string key); bool IsNoOrderPending(); bool IsLoadedWithOrders(); }; } #endif // !_SERVER_PROXY_H
ServerProxy.cpp
/*************************************************************************************************** // Author: Kunjesh Singh Baghel // Web-page: https://sites.google.com/site/kunjeshsinghbaghel/ ***************************************************************************************************/ #include "ServerProxy.h" #include "GlobalFactory.h" using namespace SESSION; using namespace LOG; namespace ActiveObject { ServerProxy::ServerProxy() { LOG_IT(SETUP_INFO, "Construction Process: ServerProxy has begin"); pHandleOrder = std::make_shared<DomesticOrder>(); pScheduler = std::make_shared<Scheduler>(); } void ServerProxy::Setup() { pScheduler->StartScheduler(); } void ServerProxy::Cleanup() { pScheduler->StopScheduler(); } std::string ServerProxy::PlaceOrder(std::shared_ptr<IMessage> msg) { LOG_IT(SETUP_INFO, " Placing customer order"); string requestID = msg->GetKey(); std::shared_ptr<IRequest> newRequest = std::make_shared<Request>(msg, pHandleOrder); pScheduler->Insert(newRequest); return requestID; } std::shared_ptr<FutureObject> ServerProxy::GetConfirmation(std::string key) { LOG_IT(SETUP_INFO, "Placing customer response request."); std::shared_ptr<FutureObject> newFuObj = std::make_shared<FutureObject>(key); std::shared_ptr<IRequest> newResponse = std::make_shared<Response>(newFuObj, pHandleOrder); pScheduler->Insert(newResponse); return newFuObj; } bool ServerProxy::IsNoOrderPending() { return pHandleOrder->IsNoOrderPending(); } bool ServerProxy::IsLoadedWithOrders() { return pHandleOrder->IsLoadedWithOrders(); } }
Scheduler.h
/*************************************************************************************************** // Author: Kunjesh Singh Baghel // Web-page: https://sites.google.com/site/kunjeshsinghbaghel/ ***************************************************************************************************/ #ifndef _SCHEDULER_H_ #define _SCHEDULER_H_ #pragma once #include "IRequest.h" #include "Queue.h" using namespace Thread; namespace ActiveObject { /*! * Description : It act as command processor. Also strategy pattern. With different synchronization policy. */ class Scheduler { private: Queue <std::shared_ptr<IRequest> > Q; thread* pSchedulerThread; bool bEndPooling; // To indicate when to stop processing the queue. public: /*Constructor */ Scheduler(); /*Destructor */ ~Scheduler(); void StartScheduler(); void StopScheduler(); void Insert(std::shared_ptr<IRequest> req); /*! * Description : This gets executed in different thread. Not in the thread on which client put request. - If any IRequest, met condition to true and eligible to run. We will remove that request from the Q and run it through IRequest::Execute method. * Note : Implement producer-consume concept here. */ void Dispatch(std::shared_ptr<IRequest> pReq); /*! * Description : This function is the starting point of new thread. */ static void Run(void* thisPtr); }; } #endif // end of _SCHEDULER_H_
Scheduler.cpp
/*************************************************************************************************** // Author: Kunjesh Singh Baghel // Web-page: https://sites.google.com/site/kunjeshsinghbaghel/ ***************************************************************************************************/ #include "Scheduler.h" #include "GlobalFactory.h" using namespace SESSION; namespace ActiveObject { Scheduler::Scheduler(): bEndPooling(false) { LOG_IT(SETUP_INFO, "Construction Process: Scheduler has begin"); } Scheduler::~Scheduler() { LOG_IT(SETUP_INFO, "Cleanup Process: of Scheduler has been called."); } void Scheduler::StartScheduler() { LOG_IT(SETUP_INFO, "Construction Process: About to create scheduling thread."); pSchedulerThread = new std::thread(Scheduler::Run, this); } void Scheduler::StopScheduler() { bEndPooling = true; Q.StopEvent(); if (pSchedulerThread->joinable()) pSchedulerThread->join(); } void Scheduler::Insert(std::shared_ptr<IRequest> req) { Q.Insert(req); } void Scheduler::Dispatch(std::shared_ptr<IRequest> pReq) { LOG_IT(SETUP_INFO, "Scheduler : Execute the request"); pReq->Execute(); } void Scheduler::Run(void *thisPtr) { LOG_IT(SETUP_INFO, "Construction Process: created scheduling thread."); Scheduler* pThis = (Scheduler*)thisPtr; while (true) { std::unique_lock<std::mutex> lockIt(pThis->Q.GetMutex()); pThis->Q.GetNotified().wait(lockIt, [&]() {return (!(pThis->Q.IsEmpty()) // When Q is not empty. || pThis->bEndPooling); }); // When StopEvent occurred. if (pThis->bEndPooling == true && pThis->Q.IsEmpty()) { break; } std::shared_ptr<IRequest> pReq = pThis->Q.Front(); pThis->Q.Remove(); pThis->Dispatch(pReq); } } }
FutureObject.h
/*************************************************************************************************** // Author: Kunjesh Singh Baghel // Web-page: https://sites.google.com/site/kunjeshsinghbaghel/ ***************************************************************************************************/ #ifndef _FUTURE_OBJECT_H_ #define _FUTURE_OBJECT_H_ #pragma once #include "IMessage.h" #include "Log.h" #include "FutureObject.h" #include "GlobalDefinitions.h" using namespace IO_MSG; using namespace IO_MSG; using namespace LOG; namespace ActiveObject { class ClientRequestHandler; class FutureObject { private: ClientRequestHandler* pClientRequestHandler; //std::shared_ptr<ClientRequestHandler> pClientRequestHandler; std::shared_ptr<IMessage> pMsg; std::string sRequestKey; bool IsRequestCompleted; public: /* Constructor */ FutureObject(std::string key); /*! * Description : This will act like a blocking call, called by callee thread for synchronous execution. - If you are looking for fully Asynchronous execution avoid this call. */ std::shared_ptr<IMessage> Get(); std::string GetRequestKey(); /*! * Description : Respond client Asynchronously. */ void RespondClient(); /*! * Description : Specifically mentioning the request has been completed. */ void CompleteRequest(); void SetResponse(std::shared_ptr<IMessage> responce); //void SetClientRequestHandler(std::shared_ptr<ClientRequestHandler> handler); void SetClientRequestHandler(ClientRequestHandler* handler); void SetRequestCompletion(bool requestCompleted); MODE_OF_EXECUTION GetExecutionMode(); }; } #endif // end of _FUTURE_OBJECT_H_
FutureObject.cpp
/*************************************************************************************************** // Author: Kunjesh Singh Baghel // Web-page: https://sites.google.com/site/kunjeshsinghbaghel/ ***************************************************************************************************/ #include "FutureObject.h" #include "ClientRequestHandler.h" #include <chrono> namespace ActiveObject { FutureObject::FutureObject(std::string key) : pClientRequestHandler(nullptr), pMsg(nullptr), sRequestKey(key), IsRequestCompleted(false) { pMsg = std::make_shared<Message>(); } std::shared_ptr<IMessage> FutureObject::Get() { LOG_IT(INFO, "Blocking call Get called"); while (IsRequestCompleted == false) { std::this_thread::sleep_for(chrono::milliseconds(100)); } return pMsg; } MODE_OF_EXECUTION FutureObject::GetExecutionMode() { return pClientRequestHandler->GetExecutionMode(); } void FutureObject::RespondClient() { if (pClientRequestHandler != nullptr) { if (pClientRequestHandler->GetExecutionMode() == ASYNCHRONUS) { pClientRequestHandler->SendResponse(pMsg); } } } void FutureObject::SetResponse(std::shared_ptr<IMessage> responce) { pMsg = responce; } void FutureObject::CompleteRequest() { IsRequestCompleted = true; } //void FutureObject::SetClientRequestHandler(std::shared_ptr<ClientRequestHandler> handler) void FutureObject::SetClientRequestHandler(ClientRequestHandler* handler) { pClientRequestHandler = handler; } std::string FutureObject::GetRequestKey() { return sRequestKey; } void FutureObject::SetRequestCompletion(bool requestCompleted) { IsRequestCompleted = requestCompleted; } }
IRequest.h
/*************************************************************************************************** // Author: Kunjesh Singh Baghel // Web-page: https://sites.google.com/site/kunjeshsinghbaghel/ ***************************************************************************************************/ #ifndef _I_REQUEST_H_ #define _I_REQUEST_H_ #pragma once #include "HandleOrder.h" #include "IMessage.h" #include "FutureObject.h" #include <memory> using namespace IO_MSG; namespace ActiveObject { /*! * Description : This class will act as command design pattern. - It provide a uniform interface to Scheduler class. Which helps which help Scheduler to decouple from specific knowledge on how it has to trigger execution of request. - Concrete implementation of IRequest should have pointer to IHandlePurchaseOrder This will help IRequest's concrete implementation to execute the request. */ class IRequest { public: virtual void Execute() = 0; /*! * Description : To check whether IHandlePurchaseOrder has some work to do or not. * Input : Not Applicable. * Output : True if IHandlePurchaseOrder doesn't have work. */ virtual bool CanRun() = 0; virtual ~IRequest(); }; class Request : public IRequest { private: std::shared_ptr<IMessage> pMsg; std::shared_ptr<IHandlePurchaseOrder> pHandleOrder; public: /* Constructor*/ Request(std::shared_ptr<IMessage> msg, std::shared_ptr<IHandlePurchaseOrder> handler); /* Destructor */ ~Request(); virtual void Execute() override; virtual bool CanRun() override; }; class Response : public IRequest { private: std::shared_ptr<IHandlePurchaseOrder> pHandleOrder; std::shared_ptr<FutureObject> pFutureObject; public: /* Constructor*/ Response(std::shared_ptr<FutureObject> futureObj, std::shared_ptr<IHandlePurchaseOrder> handler); /* Destructor */ ~Response(); virtual void Execute() override; virtual bool CanRun() override; }; } #endif // end of _I_REQUEST_H_
Request.cpp
/*************************************************************************************************** // Author: Kunjesh Singh Baghel // Web-page: https://sites.google.com/site/kunjeshsinghbaghel/ ***************************************************************************************************/ #include "IRequest.h" namespace ActiveObject { IRequest::~IRequest() { LOG_IT(SETUP_INFO, "Cleanup Process: of Request base class."); } Request::Request(std::shared_ptr<IMessage> msg, std::shared_ptr<IHandlePurchaseOrder> handler) : pMsg(msg), pHandleOrder(handler) { LOG_IT(SETUP_INFO, "Construction Process: Request has begin"); } Request::~Request() { LOG_IT(SETUP_INFO, "Cleanup Process: of Request class of %s", pMsg->GetKey()); } void Request::Execute() { LOG_IT(SETUP_INFO, "Executing the client request"); pHandleOrder->PlaceOrder(pMsg); } bool Request::CanRun() { LOG_IT(SETUP_INFO, "Can we run the request"); return !pHandleOrder->IsNoOrderPending(); } Response::Response(std::shared_ptr<FutureObject> futureObj, std::shared_ptr<IHandlePurchaseOrder> handler) : pFutureObject(futureObj), pHandleOrder(handler) { LOG_IT(SETUP_INFO, "Construction Process: Response has begin"); } Response::~Response() { LOG_IT(SETUP_INFO, "Cleanup Process: of Response class of %s", pFutureObject->GetRequestKey()); } void Response::Execute() { LOG_IT(SETUP_INFO, "Executing the client Response request"); pHandleOrder->OrderResponse(pFutureObject); } bool Response::CanRun() { LOG_IT(SETUP_INFO, "Can we run the Response"); return !pHandleOrder->IsNoOrderPending(); } }
HandleOrder.h
/*************************************************************************************************** // Author: Kunjesh Singh Baghel // Web-page: https://sites.google.com/site/kunjeshsinghbaghel/ ***************************************************************************************************/ #ifndef _HANDLE_ORDER_H_ #define _HANDLE_ORDER_H_ #pragma once #include <set> #include <map> #include "FutureObject.h" #include "WriteOnlyFile.h" using namespace FILE_IO; namespace ActiveObject { /*! * Description : When IHandlePurchaseOrder's concrete implementation completes its execution. it can acquier a write lock on FutureObject (Which clients owns through ServerProxy:: GetConfirmation method) object and update it's value. - Any client thread who is waiting for result, can wake-up and see it after this. */ class IHandlePurchaseOrder { public: virtual void PlaceOrder(std::shared_ptr<IMessage> msg) = 0; virtual void OrderResponse(std::shared_ptr<FutureObject> pFutureObject) = 0; virtual bool IsNoOrderPending() = 0; virtual bool IsLoadedWithOrders() = 0; virtual ~IHandlePurchaseOrder(); }; class DomesticOrder : public IHandlePurchaseOrder { private: std::map <std::string, std::shared_ptr<IMessage> > responseMap; void LogOrder(std::shared_ptr<IMessage> msg, std::unique_ptr<IWriteOnlyFile>& pFile); public: virtual void PlaceOrder(std::shared_ptr<IMessage> msg) override; virtual void OrderResponse(std::shared_ptr<FutureObject> pFutureObject) override; virtual bool IsNoOrderPending() override; virtual bool IsLoadedWithOrders() override; }; class InternationalOrder : public IHandlePurchaseOrder { private: public: virtual void PlaceOrder(std::shared_ptr<IMessage> msg) override; virtual void OrderResponse(std::shared_ptr<FutureObject> pFutureObject) override; virtual bool IsNoOrderPending() override; virtual bool IsLoadedWithOrders() override; }; } #endif // end of _HANDLE_ORDER_H_
HandleOrder.cpp
/*************************************************************************************************** // Author: Kunjesh Singh Baghel // Web-page: https://sites.google.com/site/kunjeshsinghbaghel/ ***************************************************************************************************/ #include "HandleOrder.h" #include "GlobalFactory.h" #include "GlobalDefinitions.h" using namespace FILE_IO; using namespace SESSION; static const string RESPONSE = "Your order is placed "; namespace ActiveObject { IHandlePurchaseOrder::~IHandlePurchaseOrder() { LOG_IT(SETUP_INFO, "Cleanup Process: of IHandlePurchaseOrder base class."); } void DomesticOrder::PlaceOrder(std::shared_ptr<IMessage> msg) { LOG_IT(SETUP_INFO, "placing the order at server end"); std::string filePath = FactoryInstance::GetGlobalFactory()->GetFileName(); filePath = filePath.substr(0, filePath.find_last_of("\\")); filePath = filePath + "\\" + msg->GetClientCode() + "\\" + msg->GetClientSocket() + ".log"; std::unique_ptr<IWriteOnlyFile> pFile = std::make_unique<WriteOnlyFile>(filePath, KEEP_OLD_CONTENT_ON_EVERY_RELOAD, false); LogOrder(msg, pFile); } void DomesticOrder::LogOrder(std::shared_ptr<IMessage> msg, std::unique_ptr<IWriteOnlyFile>& pFile) { LOG_IT(INFO, "Create a folder and file at server, with client's request massage"); string response = msg->GetMsg(); response = RESPONSE + response; msg->SetResponse(response); pFile->Write(response.c_str()); responseMap.insert(pair<string, shared_ptr<IMessage> > (msg->GetKey(), msg)); } void DomesticOrder::OrderResponse(std::shared_ptr<FutureObject> pFutureObject) { LOG_IT(SETUP_INFO, "Responding to clients order"); auto response = responseMap.find(pFutureObject->GetRequestKey()); if (response != responseMap.end()) { pFutureObject->SetResponse(response->second); pFutureObject->SetRequestCompletion(true); responseMap.erase(response); // remove response from the map. if (pFutureObject->GetExecutionMode() == ASYNCHRONUS) { pFutureObject->RespondClient(); } } } bool DomesticOrder::IsNoOrderPending() { // to be implemented return true; } bool DomesticOrder::IsLoadedWithOrders() { // to be implemented return true; } void InternationalOrder::PlaceOrder(std::shared_ptr<IMessage> msg) { } void InternationalOrder::OrderResponse(std::shared_ptr<FutureObject> pFutureObject) { } bool InternationalOrder::IsNoOrderPending() { // to be implemented return true; } bool InternationalOrder::IsLoadedWithOrders() { // to be implemented return true; } }
Thanks for reading it. To learn more about design patterns and basic design principles, please see my web page.
Comments
Post a Comment