users@glassfish.java.net

Re: How to manipultate response in Sun One 6?

From: <glassfish_at_javadesktop.org>
Date: Mon, 14 Apr 2008 10:37:25 PDT

I've noticed several problems with the WAR file you attached.

- GenericResponseWrapper.java:

You don't want each call to getOutputStream() or getWriter() to allocate a new output stream or print writer, respectively.

Also, the spec mandates that getOutputStream() throw an IllegalStateException if getWriter() has already been called, and vice versa.

So, this code:

    public ServletOutputStream getOutputStream() {
        return new FilterServletOutputStream(output);
    }

    public PrintWriter getWriter() {
        return new PrintWriter(getOutputStream(), true);
    }

should be replaced with:

    private ServletOutputStream outStream;
    private PrintWriter writer;

    public synchronized ServletOutputStream getOutputStream() {
        if (writer != null) {
            throw new IllegalStateException("getWriter already called");
        }
        if (outStream == null) {
            outStream = new FilterServletOutputStream(output);
        }
        return outStream;
    }

    public synchronized PrintWriter getWriter() {
        if (outStream != null) {
            throw new IllegalStateException("getOutputStream already called");
        }
        if (writer == null) {
            writer = new PrintWriter(getOutputStream(), true);
        }
        return writer;
    }

- PrePostFilter.java:

Notice that the JSP container writes the output of a JSP page to the underlying ServletOutputStream provided to it, without flushing this underlying
ServletOutputStream (unless, of course, the JSP page itself calls out.flush(), as in your test2.jsp). It is the responsibility of the servlet container to close (and therefore flush) the ServletOutputStream after the request has returned from the JSP container.

However, if you replace the ServletOutputStream with a different kind of output stream (as GenericResponseWrapper, which is instantiated by PrePostFilter, does), it is the responsibility of the filter's post-invoke logic to flush the response wrapper, so that any output written to it will be flushed to the underlying stream (in this case: ByteArrayOutputStream).

I've added this code to PrePostFilter.java:

        chain.doFilter(request, wrapper);
        wrapper.flushBuffer(); <<- NEW

and overrode flushBuffer() in GenericResponseWrapper.java as follows:

    public synchronized void flushBuffer() throws IOException {
        if (writer != null) {
            writer.flush();
        } else if (outStream != null) {
            outStream.flush();
        }
    }

With these changes in place, test1.jsp and test2.jsp start behaving identically, as expected.

Please find attached responsemanipulateWorking.war, which is the original responsemanipulate.war with my suggested fixes applied to it.
[Message sent by forum member 'jluehe' (jluehe)]

http://forums.java.net/jive/thread.jspa?messageID=269094