Request Handling and Threading
This is the code to create a custom connector class:
#include <iostream>
#include <stdlib.h>
#include <rwsf/core/Config.h> //1
#include <rwsf/handlers/AgentContext.h> //2
#include <rwsf/handlers/ConnectorImp.h>
MyConnector : public rwsf::ConnectorImp
{
public:
virtual void init(const rwsf::Config& config,
const rwsf::AgentContext& context);
virtual void start();
virtual void stop();
private:
example::Socket serverSocket;
};
If you are most interested in learning more about the virtual method implementations for
init(),
start() and
stop(), skip to
Implementing the Virtual Methods. The remainder of this section discusses the message handling aspects of the connector.
The following lines are pseudo code for creating a threading framework. This framework is needed so the start() method can be implemented as non-blocking.
namespace example
{
class SocketThread : public Thread
{
public:
SocketThread(example::Socket socket); //1
void run( void ); //2
private:
example::Socket socket;
};
}
void SocketThread::run( void );
{
while( not end ) //3
{
clientRequest = socket.accept(); //4
RequestHandler(clientRequest).start(); //5
}
}
A connector needs to do the following work:
Collect incoming requests off the wire and place data into an
rwsf::MessageInfo instance. See the description of this class for information on the data structures and methods it provides. At a minimum, the connector should save any transport-level data in another
rwsf::MessageInfo instance, and the message payload in an
std::string instance.
Pass the
rwsf::MessageInfo instance to a handler chain. Usually this will be the chain configured in
rwagent.xml. However, the connector can retrieve and invoke an alternative chain, which must include the
servlet handler that knows how to dispatch the service request to the Agent servlet container.
This sample code declares the RequestHandler class:
class RequestHandler : public Thread
{
public:
RequestHandler(clientRequest);
void run();
private:
clientRequest;
}
Here is the implementation for the run() method that actually processes the request:
#include <rwsf/handlers/MessageInfo.h>
#include <rwsf/handlers/MessageInfoHandlerChain.h>
void RequestHandler::run()
{
std::string payload = //1
while( (c = clientRequest.read()) != end of data )
payload += c;
rwsf::MessageInfo message;
message.set<std::string>("rwsf/request/payload", payload); //2
rwsf::MessageInfoHandlerChain chain = getHandlerChain(); //3
chain.invoke(message); //4
std::responseMsg = message.get<std::string>("rwsf/response/payload"); //5
clientRequest.write(responseMsg); //6
}
When the invoke has completed, the
rwsf::MessageInfo should contain any information needed to send back a response. This information might include a response payload, headers, a status code, and so on. You need to implement code for writing that information to a location where the client can retrieve it.
Finally, use the following convenience macro that generates code to create a connector instance.
RWSF_DEFINE_CONNECTOR(MyConnector);
The following table shows some of the main data structures in
rwsf::MessageInfo.
Table 11 – Data structures in rwsf::MessageInfo
Name | Type | Description |
---|
rwsf/request/payload | std::string | The request payload of this message. |
rwsf/response/payload | std::string | The response payload of this message. |
rwsf/response/transport/headers | | Data specific to transport headers. |