Long Running Web Process (LRWP) in the Java Platform using GlassFish

The Long Running Web Process (LRWP) is a protocol used by a web server to communicate with its peers. LRWP is similar to CGI, but faster, since the peer is persistent across requests. In LRWP, a TCP connection is established between the LRWP peer and a LRWP agent. The LRWP agent could be the web container or a process running within the web container and the LRWP peer could be any process running on a network. The LRWP peer at connection registers the web context that the peer is interested in. The web context could be any context, such as "/osp", "/tep", or "/cgi-bin" itself. When a request for that context is made, the agent transfers the input to the LRWP peer and sends the output from the peer back to the web client. The LRWP agent should also be able to support multiple peers concurrently, and each peer makes a connection and registers the context it is interested in.

LRWP Protocol

A web server that implements LRWP protocol listens on a TCP/IP port, 1081 default, for LRWP peers to connect. A peer connects by opening a TCP/IP connection and sending in the context name and an optional host name. The host name is to support virtual host names. The peer then waits for a response from the web server, which is an OK to indicate a connection registration or an error message. After a successful registration, the peer then waits for requests from the web server. The web server sends in environment variables such as the cgi-bin request and the data, and waits for a response from the peer. The peer responds by sending in environment variables such as a cgi-bin program response and the data. The connection is terminated by the web server or the peer by closing the TCP/IP connection. The details of the protocol implementation can be found on the Xitami page, "Extending Xitami with External peer Processes".

LRWP Implementation in Xitami Web Server

Xitami is a lightweight, multithreaded, ServerWatch's hall of fame web server. It supports the following features:

The design for implementing the LRWP protocol in the Java platform uses a servlet container to handle HTTP requests and also to make use of servlets to handle the LRWP processing. The initial idea was to build a multithreaded LRWP Agent server, running within the servlet container, which would act as a broker between the LRWP peers and the servlets. It would accept requests from LRWP peers, pass on the incoming HTTP requests to the peers, and pass the response from the peers back to the servlets. On an HTTP request, the servlet would communicate the HTTP request to the LRWP agent, which would block the servlet thread, unblock the the peer thread, and pass on the request to the LRWP peer. Then, the response from the peer would be passed back to the servlet by waking it up and blocking the peer thread. This design was modified so that instead of having a multithreaded LRWP agent, we had a single threaded agent, which accepted the connection request from a LRWP peer and stored the connection in a ContextAssistantManager. Instead of blocking while passing on the request to the Agent, the servlet thread instead now looked up the connection to the peer using the ContextAssistantManager and passed on the HTTP request after transforming it to the LRWP protocol itself, waiting for a response from the LRWP peer, and then returning the response as its own.

Each peer can open multiple connections with the same LRWP agent, which is also configurable through web.xml.

Only one thread is used per LRWP agent; the servlet thread management is exploited for peer connectivity.

The implementations of the LRWPAgentManager, and the RequestHandler are made transparent through the use of interfaces.

LRWP Implementation in Java

Interface Classes

LRWPAgentManager
This class provides following methods to be implemented by the LRWPAgentManager implementation Class.

Methods

Description

start()

Starts the LRWPAgentManager.

setNumOfAgents

Defines the number of agents that would run.

setStartPort()

Defines the starting port to which LRWP agent instances would bind. For example, if the starting port is defined to be 1081 and number of agents is 2, then two instances of LRWP agent would start up - first binding to port 1081 and second binding to port 1082.

LRWPAgentRegistrar
This class provides following methods to be implemented by the LRWPAgentRegistrar Implementation Class.

Methods

Description

register()

Register the Proxy Service Instance (LRWP RequestHandler).

deregister()

De-register the Proxy Service Instance (LRWP RequestHandler)

HttpProxyService
This class provides following methods to be implemented by the LRWP RequestHandler Class.

Methods

Description

service()

Implement the request service algorithm in this method.

stop()

Method to stop the RequestHandler/Proxy service instance.

Classes

HttpProxyServlet
This is a simple HTTP servlet which implements following servlet methods:

Methods

Description

init()

Reads initialization parameters from the servlet deployment file (web.xml) and performs initialization of variables. It also creates an instance of LRWPAgentProxyManager, after fetching the implementation class name from the deployment parameter 'Proxy Manager'.

destroy()

Stops the LRWPAgentProxyManager instance and disposes of/destroys the servlet.

processRequest()

This method is invoked to service the HTTP Request. This method forwards/delegates the request to the LRWPAgentManager. Now the LRWPAgentProxyManager responds to this request.

LRWPAgent
The LRWP agent is a server thread that would bind itself to agent ports specified in the configuration file (web.xml). If multiple instances of LRWP agents are defined in the configuration file, then the port defined in web.xml is the starting port. When a new LRWP peer Process connects to an LRWP agent instance, it creates a RequestHandler instance and again waits for a new LRWP peer. This class implements the following methods:

Methods

Description

run()

This is the thread class method overridden by the LRWP agent Class. The LRWP agent binds itself to the server port defined in the configuration file, and waits for the peer process. As soon as the peer process opens a connection with the LRWP agent, it instantiates an LRWP RequestHandler.

stopThread()

Stops the LRWP agent server thread and closes the socket port for communication.

LRWPAgentProxyManager
This class manages the LRWP agent instances. It also maintains a repository of peers which would serve requests against a path (url) of a virtual host. This class implements the LRWPAgentManager and LRWPAgentRegistrar interfaces. It has following methods:

Defines the starting port on which LRWP agent would be started. If a new instance of LRWP agent is created, it would bind with a new port (starting port + n).

register()

Creates an entry in the repository for a virtual host, path and LRWP RequestHandler (implementor of Service Class interface).

deregister()

Removes a virtual host, path and LRWP RequestHandler entry from the repository.

Service()

This method implements the logic to get a RequestHandler instance which would serve the client request. If there is no instance of RequestHandler to support the request, or it is busy, the request would be put to wait, or would result in a default response.

LRWP RequestHandler
This class does the transformation of HTTP requests from the web client to the LRWP Request. The request is then sent to the LRWP peer over a socket connection. Each LRWP RequestHandler is bound to only one LRWP peer over socket connection. One LRWP peer process may be connected to multiple request handler instances over multiple socket connections. This class implements the HttpProxyService interfaces. It implements the following methods:

Methods

Description

init()

Receives and acknowledges the init message from the LRWP peer, which contains information about the virtual host and the path it will serve. Acknowledgment begins with "OK" if the init method is successfully received from the LRWP peer process, or else the acknowledgment contains "ERROR" as the starting string.

service()

This is the main method that does the transformation of the HTTP Request to the LRWP Request. The request is sent to the LRWP peer process. The response is then transformed to HTTP Response and sent back directly to the web client (browser).

2.1. Open the admin console of the Sun Web Application Server.
2.2. Give path to LRWPAgent.war file for deployment ($HOME_DIR/LRWPAgent/dist/LRWPAgent.war).
2.3. Deploy the war file on the root context of GlassFish. This can be done during the deployment of the war file.

The LRWP agent is now deployed. It can now be tested for LRWP connections from peers.

LRWP agent Configuration

The user can configure/tune different parameters of the LRWP agent module. All parameters are defined in the 'web.xml' file included in the distribution. The parameter names and their functions are described here:

Number of Agents - Defines the number of LRWP agent instances desired. Default Value is '01' (one instance). However, the LRWP module can support 10 instances of LRWP agents simultaneously. The parameter name in the configuration file (web.xml) is "numAgents".

Starting Port - Defines the port at which an LRWP agent would run. Default port is 1081. If there is more than one instance defined in "numAgents", then this parameter becomes the starting port. For example, if numAgents is '2', and starting port is defined as '1081', then two instances of the LRWP agent would run, the first instance bound to port 1081 and second instance bound to port 1082. The parameter name in the configuration file (web.xml) is "startPort".

peer Per Agent - Defines the number of LRWP peers that can connect to one instance of the LRWP agent. This parameter is included for load-balancing. The default number of peers that can be handled is '5'. An agent can handle maximum of fifteen LRWP peers. The parameter name in the configuration file (web.xml) is "peerPerAgent".

Testing with a C LRWP Peer

The LRWP peer is a client which connects to the LRWP agent running on the GlassFish application server . A sample program is available on the Xitami site. The program can be compiled and the resultant binary can serve as the basic testing tool for a LRWP agent on GlassFish.

The program can be compiled from command line and the SFL library from Imatix Inc. needs to be included as the library at the command line.

Before compiling the example code, change the arguments in the lrwp_connect() function. For example, localhost and the port number can be replaced with the hostname of the LRWP agent machine and the port number on which the LRWP agent is running.

This will launch the Sokrates default page. You can then run the different operations listed on this page.

Test Operations on the LRWP agent using Sokrates

The following set of operations can be tested on LRWP agent using the Sokrates servlet runner.

List Parameters

List Headers

List Request Attributes

List servlet Attributes

List request Methods

List Context Methods

List Cookies

List Session data

Test Form

Test Cookies

Test Sessions

Test Redirect

Test Binary

Test Choice

Test Bigdata

Test Forwarding

Test Include

The above listed operations are the standard test of a fully functional LRWP agent and failure of any of these operations shows a non-implementation of the functionality in the agent.

Conclusions

The LRWP agent in Java with GlassFish works well and works with different language-based LRWP peers. It has been tested with C, C++ and Java programming language-based LRWP peers. The performance of the LRWP agent is very good and in fact exceeds Xitami's implementation on a 4 core x86 system. The LRWP agent implementation will also be made available as open source on java.net.

Acknowledgments

We would like to thank Satyajit Tripathi for excellent project management, managing resources efficiently across time zones with time lines, making communication very efficient and Bruce Chapman for reviewing and providing some fine suggestions making the paper easier to read.