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;
};
//1 The rwsf::Config class holds properties passed to the connector. For more information on the data and methods available through this class, see its class description in the HydraExpress C++ API Reference Guide.
//2 The rwsf::AgentContext class provides access to Agent resources.
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
}
}
//1 Create a socket thread based on the supplied socket.
//2 Call the run() method to activate the connector.
//3 The run() method must test some condition that lets it know when to return.
//4 The socket accepts the message off the line and stores it in some kind of object.
//5 The message off the socket is executed in a RequestHandler thread. The start() method starts the thread and then calls the run() method of RequestHandler. See below for a pseudo code implementation of this class.
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
}
//1 Read the data taken off the line by the socket into a string.
//2 Sets the payload into the rwsf:request:payload data structure of an rwsf::MessageInfo instance. See the table at the end of this section.
//3 Obtains the handler chain configured for this connector (see an example below).
//4 Dispatches the message to the handler chain.
//5 Obtains the response payload data structure.
//6 Writes the response message to the socket.
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.