tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Craig R. McClanahan" <cmcclana...@mytownnet.com>
Subject Re: [LONG TERM PLAN] Proposed Architecture for Tomcat.Next Servlet Container
Date Sun, 09 Jan 2000 22:47:09 GMT
Hans Bergsten wrote:

> [snip]

>
> Revolution vs. evolution
> ------------------------
> It seems like this discussions came to the conclusion that we should do
> both; move towards Tomcat.next when we clean up the code, and possibly
> start from scratch with a "refactoring" effort in a separate CVS directory (not
> a branch). I can live with this approach, especially since I see pros and
> cons with both approaches and can't say which one is the "right" one ;-)
>

I wish that were the conclusion that was reached; however, parallel processing (via a
branch for Tomcat.Next) got -1'd.  I very much favor the two-track approach -- bug
fixes and enhancements on the existing code base as needed, and a CVS branch (starting
with just the component interfaces plus a bunch of discussion to agree on the method
signatures in those interfaces).

>
> Questions
> ---------
> A couple of questions that I have not seen any discussion about yet are:
>
> * Why are Request/Response representations of HttpServletRequest/Response
>   instead of ServletRequest/Response?
>

It's based on my feeling that Tomcat is, first and foremost, an *HTTP* servlet
container.  Most of the design energy and features focus is around things that only
matter when the container knows the contents of the HTTP headers.

It would be reasonable to build a servlet engine for non-interactive, non-HTTP-based
request/response stuff, but I don't see a lot of value add for doing this versus
alternative solutions based on RMI and/or CORBA APIs.

>
> * What's the motivation for calling Interceptor preService() in LIFO order
>   and postService() in FIFO order? To me it would be natural to use LIFO
>   for both, but I'm sure I'm missing something here.
>

The idea is that a particular interceptor is a layer -- it wants to be as independent
as possible of the layers above it and below it.  So, for a particular interceptor, I
want to have my preService() method called on the way in before any lower Interceptor
is invoked, and I want my postService() method called after any lower Interceptor has
finished.

A picture might help -- let's say you add interceptors A, B, C, D, and E in that order
(so E was added last).  The call path goes like this (which stretches my ASCII art
skills to the utmost :-):

      |                  ^
      v                  |
    E.preService()    E.postService()
      |                  ^
      v                  |
    D.preService()    D.postService()
      |                  ^
      v                  |
    C.preService()    C.postService()
      |                  ^
      v                  |
    B.preService()    B.postService()
      |                  ^
      v                  |
    A.preService()    A.postService()
      |                  ^
      v                  |
       Container.service()

This way, each layer can be designed to operate totally independently of anything below
them, or above them, no matter which order they get added in (assuming no
cross-interceptor side effects) and no matter how many interceptors are on any one
stack.

In addition, a particular interceptor can decide to create the response itself and skip
the rest of the stack.  In that case, you want its postService() method, plus the
postService() method of any interceptor higher on the stack (i.e. those whose
preService() method had been called), to be called.

In the scenario above, assume that C.preService was an interceptor that implements the
access control restrictions in the web-apps's deployment descriptor, and it decides
that it needs to challenge the user for their credentials.  By this time,
A.preService() and B.preService() have already been called.  Now that C.preService()
sends back the SC_UNUAUTHORIZED response, you want the following method calls to
happen:  C.postService(), B.postService(), and A.postService().  Essentially, the
interceptor contract guarantees that, in the absence of exceptions, if your
preService() method is called then your postService() method will also be called.


>
> So, thanks Craig for a great proposal. I hope we can get there soon.
>

Given that the functional code already exists and just needs to be reorganized some,
this is about 1-2 months effort if you do it on a separate branch, but more like 4-5
months if you do it incrementally on the main branch, with the requirement that it
always has to work at any given moment.

>
> Hans

Craig



Mime
View raw message