users@grizzly.java.net

Re: [Jersey] Refactoring the container SPI

From: Jeanfrancois Arcand <Jeanfrancois.Arcand_at_Sun.COM>
Date: Thu, 12 Jun 2008 09:44:14 -0400

Salut,


Paul Sandoz wrote:
> Done. I am rather pleased with the way it turned out :-) I think it is
> now much easier to write a container.
>
> The Grizzly container now consists of one java file and about 160 LOC
> (including license header and comments).
>
> Jean Francois, the Grizzly container no longer closes the response
> output stream, see below:
>
> public void service(GrizzlyRequest request, GrizzlyResponse response) {
> WebApplication _application = application;
>
> final URI baseUri = getBaseUri(request);
> /*
> * request.unparsedURI() is a URI in encoded form that contains
> * the URI path and URI query components.
> */
> final URI requestUri = baseUri.resolve(
> request.getRequest().unparsedURI().toString());
>
> try {
> final ContainerRequest cRequest = new ContainerRequest(
> _application,
> request.getMethod(),
> baseUri,
> requestUri,
> getHeaders(request),
> request.getInputStream());
>
> _application.handleRequest(cRequest, new Writer(response));
> } catch (IOException ex) {
> throw new RuntimeException(ex);
> }
> }
>
> public void afterService(GrizzlyRequest request, GrizzlyResponse
> response)
> throws Exception {
> }

Hum...the GrizzlyAdapter has the following code:

> GrizzlyRequest request = (GrizzlyRequest) req.getNote(ADAPTER_NOTES);
> GrizzlyResponse response = (GrizzlyResponse) res.getNote(ADAPTER_NOTES);
>
> if (request == null || response == null) {
> return;
> }
> try {
> response.finishResponse();
> req.action(ActionCode.ACTION_POST_REQUEST, null);
> res.finish();
> } catch (Throwable t) {
> getLogger().log(Level.SEVERE,"afterService exception",t);
> } finally {
> // Recycle the wrapper request and response
> request.recycle();
> response.recycle();
> req.recycle();
> res.recycle();
> }
> try{
> afterService(request,response);
> } catch (Exception ex){
> logger.log(Level.SEVERE,"afterService", ex);
> throw ex;
> }

Which close the connection. Which test case should I look at to
reproduce and debug the issue?


>
> But it works just fine for the unit tests (Grizzly and Grizzly-Servlet).
> Is that OK?

Connection will leaks if we don't close them properly.


If so it means we don't need to modify the Grizzly container
> to work with Comet support to avoid closing the connection, and i think
> we are done in terms of enabling multiple responses to be written.
>
> The ContainerResponse.setResponse(...) automatically resets the
> connection state. Then one can call ContainerResponse.write() to write
> the response to push things out.
>
> BTW how about making GrizzlyAdapter.afterService(...) a non abstract
> empty method?

I agree. If someone needs to do something afterService, they can just
override the method.

A+

-- Jeanfrancois


>
> Paul.
>
> Paul Sandoz wrote:
>> Hi,
>>
>> There are two use-cases that require refactoring of the container SPI:
>>
>> 1) Support for comet where a response is kept alive and used to
>> write/push further responses; and
>>
>> 2) Filtering.
>>
>> in addition i think i can improve the ease of use of integrating
>> containers.
>>
>> Currently it is necessary to extend the
>> AbstractContainerRequest/Response classes with container specific
>> classes. Instead the ContainerRequest/Response interfaces will be
>> turned into non-abstract classes with the same functionality as
>> AbstractContainerRequest/Response.
>>
>> public class ContainerRequest implements HttpRequestContext {
>> ContainerRequest(
>> WebApplication wa,
>> String method,
>> URI baseUri,
>> URI requestUri,
>> MultivaluedMap<String, String> headers,
>> InputStream entity
>> );
>>
>> ...
>> }
>>
>> public class ContainerResponse implements HttpResponseContext {
>> ContainerResponse(
>> WebApplication wa,
>> ContainerRequest request,
>> ResponseWriter adapter
>> );
>>
>> // write the response
>> write() throws IOException;
>>
>> // reset the state of the response so it can be used for
>> // writing further responses
>> reset();
>>
>> ...
>> }
>>
>> public interface ResponseWriter {
>> // Write the status and headers and
>> // return an output stream to write the
>> // entity
>> // The OutputStream.close method must not be called
>> OutputStream writeStatusAndHeaders(
>> long contentLength,
>> ContainerResponse response
>> ) throws IOException;
>> }
>>
>> It is the responsibility of the container to provide an an instance of
>> ContainerRequest and an implementation and instance of ResponseWriter.
>>
>> Paul.
>>
>