views:

935

answers:

2

This may be a little confusing but I having some trouble. My goal is to take an input HTML document and then process that document and use the HTML data to output a image document. For example, a user will request a URL, with some action=png in the querystring and then the filter will get invoked for the URL and output image document.

I have tried everything but in my environment (Websphere), I am only able to output of one type. If the input type is text/html then I can only output a text document, I can't seem to output a binary document. Why? Because I get an illegal state exception each time.

[1/29/09 17:59:57:576 EST] 00000020 SystemErr R java.lang.IllegalStateException: SRVE0209E: Writer already obtained [1/29/09 17:59:57:576 EST] 00000020 SystemErr R at com.ibm.ws.webcontainer.srt.SRTServletResponse.getOutputStream(SRTServletResponse.java:505)

I am using pseudo code not to reveal all of my code:

<filter>
 <filter-name>TestFilter</filter-name>
 <filter-class>
  com.util.TestFilter
 </filter-class>
</filter>

<filter-mapping>
 <filter-name>TestFilter</filter-name>
 <url-pattern>/index_test2.html</url-pattern>
</filter-mapping>

The Wrapper Class code is essentially this:

public class ContentCaptureServletResponse extends HttpServletResponseWrapper { 
    private ByteArrayOutputStream contentBuffer;
    private PrintWriter writer; 
    public PrintWriter getWriter() throws IOException {
     if (writer == null) {
      contentBuffer = new ByteArrayOutputStream();
      writer = new PrintWriter(contentBuffer);
     }  
     return writer;
    } 
    public String getContent(){
     try {
      writer = getWriter();
     } catch (IOException e) {       
      e.printStackTrace();
     }
     writer.flush();
     String xhtmlContent = new String(contentBuffer.toByteArray());             
        System.out.println(xhtmlContent);                
     return xhtmlContent; 
    }
}

And the filter code is this:

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        final String renderType = request.getParameter("R"); 
        final String renderClassName = request.getParameter("C");
        if ((renderType != null) && (renderClassName != null)) {
            try {
                this.setFilterChain(filterChain);
          response.setContentType("image/png");
          PrintWriter out = response.getWriter();            
          // I call getWriter but not BOTH!
          //response.getOutputStream();       
          response.getWriter();

          // Build up the HTML document into a string.
                    CaptureResponse capContent = new CaptureResponse(response);            
          this.mainFilterChain.doFilter(req, );
          String myString = capHtmlContent.getContent();

          // What I really want to do here is output an output stream
          // so I can write a binary image
          processStr(myString);
          response.getOutputStream();       
          response.write(binaryimage)

            } catch (Exception e) {            
                e.printStackTrace();
            }
            // No data will be output to the user.
        } else {
            filterChain.doFilter(request, response);
        }  // End of if-else        
    } // End of the method.

The code works if I want to take some input html text document. I am assuming because of the open printwriter stream. But I am having trouble going to a different format. Basically, because I can't call response.getOutputStream()

A: 

I have no experience with Websphere, but one common problem is that you try to manipulate the HTTP header after you already committed to sending the body -- once the webserver started to deliver the content, you cannot update the headers any more since they've already been sent.

Maybe you need to review your documentation and examples. For example, I don't see why you call response.get*() without actually looking at the result. Are you sure this is necessary or is this because you trimmed your code?

Cheers, Volker

ShiDoiSi
+1  A: 

The issue does appear to be that you are opening the response Writer prior to wrapping the response.

It looks like you should be able to do:

this.setFilterChain(filterChain);
CaptureContent capContent = new CaptureResponse(response);
doFilter()
process();
response.setContentType("image/png");
response.getOutputStream().write(imagedata);

You definitely cannot safely open both the Writer and the OutputStream

jdewald
Yea, I tried that. And that is what I tought. But for some reason with Websphere, for things to work properly, I had to 'open the print writer' before calling chain.doFilter(wrapper). I guess a print writer needs to be open to join the html content. I ended up using a session attr and redirect.
Berlin Brown
Because I wouldn't 'collect/join' the html content within the same request. So I just forwarded to a simple servlet which in turn output the binary file. it is strange, but it worked.
Berlin Brown