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. 


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 

  1. Asynchronous way
  2. Active object pattern sequence diagram
    Please click on the image to see the zoom view.
    • 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.
  3. Synchronous way
  4. Active object pattern sequence diagram
    Please click on the image to see the zoom view.
    • 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.

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.


Active object pattern class diagram
Please click on the image to see the zoom view.

Server code - 

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

Popular posts from this blog

Non-virtual interface idiom (NVI)

Architectural patterns => Mud to structure => layers.

Architectural style -> Adoptable system -> Reflection.