I have an application where the servlets generate XML and their output
goes through an XSLT filter. This all works fine, except when I try to
use RequestDispatcher's include() method to paste in some external
content. Whenever I try to do this, the XS:T filter bombs out with
an IllegalStateException at the point where it calls getWriter() to
get the output stream. The code looks something like this:
In the servlet, inside doGet(), I have:
println("<html>");
try {
RequestDispatcher disp =
context.getRequestDispatcher("/foo.html");
disp.include(request,response);
}
catch (Exception e) {
System.out.println("Include failed: " + e.getMessage());
// this never happens... ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
e.printStackTrace();
}
println("</html>");
(using <html> to delimit HTML content in the enclosing XML).
In the XSLT filter I have:
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws ServletException, IOException {
try {
CharResponseWrapper wrapper =
new CharResponseWrapper((HttpServletResponse)response);
chain.doFilter(request,wrapper);
String s = wrapper.toString();
if (s.length() > 0) {
InputSource input = new InputSource(new StringReader(s));
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
SAXParser parser = spf.newSAXParser();
reader = parser.getXMLReader();
stf = (SAXTransformerFactory) TransformerFactory.newInstance();
filter = stf.newXMLFilter(new StreamSource(stylesheet));
filter.setParent(reader);
StreamResult result = new StreamResult(response.getWriter());
// fails here... ^^^^^^^^^^^^^^^^^^^^
// but only when I've used include() in the servelt being filtered!
Transformer transformer = stf.newTransformer();
SAXSource transformSource = new SAXSource(filter, input);
transformer.transform(transformSource, result);
(... and so on...)
Does anyone have any idea why the response writer might end up in
an illegal state because of using include()?
Andrea Desole - 15 Jul 2005 12:44 GMT
> Does anyone have any idea why the response writer might end up in
> an illegal state because of using include()?
the documentation is clear:
IllegalStateException - if the getOutputStream method has already been
called for this response object
maybe the included page uses getOutputStream? Try to call
response.getOutputStream instead of getWriter
John English - 17 Jul 2005 04:24 GMT
>> Does anyone have any idea why the response writer might end up in
>> an illegal state because of using include()?
[quoted text clipped - 6 lines]
> maybe the included page uses getOutputStream? Try to call
> response.getOutputStream instead of getWriter
The included page is just vanilla HTML. (Well, XHTML, suitable for shoving
through an XSLT filter.)
So, maybe include() uses getOutputStream() rather than getWriter(), which is
what I use everywhere else. In which case, it's a waste of space AFAICS.
Anyway, in the meantime I'm just creating a FileInputStream and reading from
that instead... Most of the J2EE API just seems to be designed to prevent you
doing anything useful in a finite amount of time!
However, when I get some free time to ponder this without worrying about
hitting targets, I might well investigate further... Suggestions welcome
in the meantime from anyone with more experience and/or free time.
Thanks...
John English - 18 Jul 2005 17:34 GMT
>> Does anyone have any idea why the response writer might end up in
>> an illegal state because of using include()?
[quoted text clipped - 6 lines]
> maybe the included page uses getOutputStream? Try to call
> response.getOutputStream instead of getWriter
The included page is plain old HTML, not a servlet, so any streams needed
to include it must be opened by the server when it serves up the page...
Could try getOutputStream, but the examples I've seen show the base servlet
using getWriter and including another resource as well. What puzzles me is
that the error occurs in the filter, not in the original servlet. From examples
on Sun's website, I would expect what I've done to be perfectly legit.
Andrea Desole - 19 Jul 2005 08:54 GMT
> The included page is plain old HTML, not a servlet, so any streams needed
> to include it must be opened by the server when it serves up the page...
that's probably what happens
> Could try getOutputStream, but the examples I've seen show the base servlet
> using getWriter and including another resource as well. What puzzles me is
> that the error occurs in the filter, not in the original servlet. From
> examples
> on Sun's website, I would expect what I've done to be perfectly legit.
why should you have it in the servlet? You are not calling
response.getWriter there, are you?
I don't know the examples you are talking about (do you have a url?),
but looking better at the documentation I saw that getWriter should be
used for non binary streams, while for binary and mixed streams you
should use getOutputStream. So I was guessing that maybe setting the
content type to "text/html" (and maybe the character encoding) at the
beginning of the filter, before anything is written to the response,
might help.
Anyway, if you really need a writer you can use:
new PrintWriter( response.getOutputStream() );
Raymond DeCampo - 15 Jul 2005 13:29 GMT
> I have an application where the servlets generate XML and their output
> goes through an XSLT filter. This all works fine, except when I try to
[quoted text clipped - 26 lines]
> throws ServletException, IOException {
> try {
[snip]
> StreamResult result = new StreamResult(response.getWriter());
> // fails here... ^^^^^^^^^^^^^^^^^^^^
> // but only when I've used include() in the servelt being filtered!
[snip]
> (... and so on...)
>
> Does anyone have any idea why the response writer might end up in
> an illegal state because of using include()?
Here's a thought. The servlet API allows you to get a writer to write
the response or a stream to write the response, but not both. It is
possible that the RequestDispatcher.include() used the stream, not the
writer, thereby hosing your future attempt to use the writer.
HTH,
Ray

Signature
XML is the programmer's duct tape.
junaid - 19 Jul 2005 05:15 GMT
have you tried to add following in web.xml
<filter-mapping>
<filter-name>VJFilterTest</filter-name>
<!--<servlet-name>VJServlet</servlet-name>-->
<url-pattern>/servlet/MyTest</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>