Anders Kristensen wrote:

> "Craig R. McClanahan" wrote:
> >
> > Anders Kristensen wrote:
> >
> > > Hi,
> > >
> > > I'm trying to implement the 2.1 version of the servlet API and I have a
> > > question about how the RequestDispatcher mechanism is supposed to work
> > > plus a report of a couple of bugs in JSDK 2.1.
> > >
> > > RequestDispatcher.include makes it possible to include the output of
> > > another servlet into the output of the invoked servlet and the included
> > > servlet sees the same info in response to getServletPath, getPathInfo,
> > > getRequestURI as does the original servlet.
> > >
> > > This appears to me to be a problem when the included resource is a
> > > static file being served by a (system) FileServlet. In this case the
> > > FileServlet would use the getPathTranslated (or something similar) to
> > > figure out which file it should ship back.  However, if it was invoked
> > > from some other servlet using, say,
> > >
> > >   RequestDispatcher disp = ctxt.getRequestDispatcher ("/somepath.txt");
> > >   disp.include(request, response);
> > >
> > > it wouldn't see "/somepath.txt" in response to getPathTranslated. It is
> > > possible to achieve the desired behaviour by having FileServlet first
> > > check the request attribute javax.servlet.include.path_info and only if
> > > this returns null use getPathInfo.  Is this how the JSDK/JWS works?
> > > This basically means that *all* servlets using the extra path info needs
> > > to perform this extra step, as they won't otherwise work with the
> > > inclusion mechanism, and that seems a bit clunky to me. Maybe it would
> > > be better for included servlets to see altered request info (as does
> > > servlets forward()'ed to)?
> > >
> >
> > One way to deal with this is make your file-serving servlet work when it is
> > executed directly, or as an included servlet, like this:
> >
> >     String pathInfo =
> >         request.getAttribute("javax.servlet.include.path_info");
> >     if (pathInfo == null)
> >         pathInfo = request.getPathInfo();
> >     String pathname =
> >         getServletContext().getRealPath(pathInfo);
> >
> > Now, "pathname" contains the absolute pathname of the file to be returned, no
> > matter how this servlet is called.
>
> Right, so that's the workaround I mentioned. IMHO this is suboptimal
> because it means all servlets which use the extra path info and which
> potentially can be include()'d has to perform this extra step.
>

If the servlet API provided a method to retrieve the included path (it would have
to be different, because some included servlets will want to see what the original
request said too), you'd end up with exactly the same amount of code, with one
very smal difference -- something like:

    String pathInfo =
        req.getIncludedPathInfo();    // Assumed API addition
    if (pathInfo == null)
        pathInfo = request.getPathInfo();
    String pathname =
        getServletContext().getRealPath(pathInfo);

so what's the big deal?  In addition, the approach that was chosen has one huge
advantage -- it does not break binary compatibility with the existing API over
this issue, because it doesn't change the interface signature of
HttpServletRequest.


>
> And here's another, but similiar, gotcha: when the request method is a
> POST and the first servlet include()'s another one, that other servlet
> has to handle POSTs even when it wouldn't ordinarily do this. For
> example, it would probably be quite common to include a static file from
> a servlet handling form submissions (e.g. indirectly through JSP),
> meaning that the FileServlet suddenly has to treat POST requests just
> like GET requests (which is kindof a protocol vioaltion).
>

So just implement service() instead, of doGet(), and you don't give a rip.  Or,
make your doPost implementation look like this:

    public void doPost(HttpServletRequest req, HttpServletResponse res)
        throws IOException, ServletException {
            doGet(req, res);
    }


>
> Otherwise it has to inspect the javax.servlet.include.* attributes to
> try and guess that its being invoked as the result of an include()
> rather than directly. If this is going to be common it should probably
> be directly supported in the servlet API.
>

As mentioned above, a dual-mode servlet is still going to need to be dual-mode,
whether there is a separate method call for it or not.  Otherwise, you have to
decide that a servlet included by a request dispatcher never needs to see stuff
about the original request, and that would be a very bad restriction -- for
example, templating systems might care a lot about the parameters of the request
they are being included into.

>
> >
> > >
> > > Anther question:  Is it OK for a path argument to getRequestDispatcher
> > > to include a query string? I guess so since include() arranges for it to
> > > appear in the javax.servlet.include.query_string request attribute. But
> > > on the other side a forwarded request doesn't report those params. What
> > > gives?
> > >
> >
> > The ability to include a query string on an include() call was a recent
> > change.  I expect that the "forward" case will be clarified in the 2.2
> > servlet API spec -- probably by becoming the request parameters that the
> > forwarded-to servlet sees.
> >
> > You might try this under the recently released JSWDK servlet engine, which
> > will track the recent changes and clarifications much more closely than the
> > original JSDK 2.1 release.
>
> OK so it's going to change.  What is the JSWDK servlet engine and where
> can I get info on these recent changes in the servlet API that you
> mention? Has it been discussed on this list recently. (I apologise for
> not having the stamina to trawl through the archives - they're massive.)
>

The JSWDK is the newest release of a combination of the JSDK 2.1 servlet engine
and JSP 1.0ea2 JSP engine.  It is available at Java Developer Connection (free
registration required).

    http://developer.java.sun.com/developer/earlyAccess/jsp

or just follow the links from the normal "Products and APIs" page at JavaSoft.

At JavaOne, Sun announced that the source for this will be handed over to the
Apache Project, for redistribution under the Apache license (i.e. about as open
source as you can get).  Once the handover is complete, the code will be available
at the Jakarta Project web site (http://jakarta.apache.org).

The most recent "public access" clarifications to what the servlet API means are
in the JSP 1.0 Specification, in Appendix B.  These clarifications must be obeyed
to be compliant with 2.1.  There is a private "experts list" that is currently
reviewing (under non-disclosure) the 2.2 servlet API spec.  This is where the
details of what is upcoming get hashed out by participants.  The message traffic
there can make this mailing list seem pretty empty, so be glad you don't have to
put up with that volume all the time!  :-)

If you don't like something about the servlet API, the official way to submit
feedback is to follow the instructions in the API spec, and mail it to:

    [EMAIL PROTECTED]

instead of, or in addition to, this list.  That way, your feedback will get
formally included in the process.

>
> >
> > >
> > > Also, I believe the following are bugs in JSDK 2.1:
> > >
> > >   o RequestDispatcher.include throws an exception if the
> > >     ServletOutputStream has already been obtained. This is the
> > >     correct behaviour for forward but not for include.
> >
> > This is correct behavior on include as well, in some circumstances.  If the
> > original servlet has done a getWriter(), the included servlet will throw an
> > exception if it calls getOutputStream().  LIkewise, if the original servlet
> > has done a getOutputStream(), the included servlet cannot call getWriter().
> >
> > It only works if both the original servlet and the included servlet use the
> > same technique (either output stream or writer).
>
> This sounds like a bug to me. This is an unnecessary dependency between
> what ought to be independent servlets. It means I can't include the
> output of two different servlets if one happen to use
> ServletOutputStream and other happen to use PrintWriter for its output.
> I see no reason why the implementation can't take care of this. The
> problem appears to be that PrintWriter does its own buffering through
> BufferedWriter but this can be handled by the RequestDispatcher by
> flushing a PrintWriter (if one has been retrieved) before and after
> doing the include. This all comes down to implementation issues - I
> don't think there are any inherent reason for this to be this way.
> (Buffering may still be done at a lower level.)
>

Buffering is one issue.  Another is that you should use a ServletOutputStream for
binary data, whereas you use the PrintWriter for character data that may need to
be encoded for a particular character set (remember, Java uses Unicode internally,
and that has to get mapped to the character set requested by the client browser).
Mixing 8-bit binary data with 16-bit characters sounds pretty unnecessary to me.
Supporting internationalization like this is why the reader/writer stuff was added
to the core JDK in the first place.

For most purposes (i.e. when your servlets are producing HTML or XML), I would
recommend just using the writer and not worrying about it.  Use a
ServletOutputStream when you're creating dynamic GIF images, or serialized Java
objects to send back to an applet, or other things like that.


> --
> Anders Kristensen <[EMAIL PROTECTED]>,
> http://www-uk.hpl.hp.com/people/ak/
> Hewlett-Packard Labs, Bristol, UK
>

Craig McClanahan

___________________________________________________________________________
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff SERVLET-INTEREST".

Archives: http://archives.java.sun.com/archives/servlet-interest.html
Resources: http://java.sun.com/products/servlet/external-resources.html
LISTSERV Help: http://www.lsoft.com/manuals/user/user.html

Reply via email to