Using Filters and Wrappers

I have been trying to use a Filter to add code to my html after a servlet is run. I decided to wrap the response and then use a filter to add stuff before and after it. The problem is I'm having problems getting the content of the actual page to display. The filter works its just the it bypasses the writing of the content of the page itself.

I'm running on a tomcat server 6.0 with no warnings or errors

Here is my code:

ApplicationResponseWrapper.java

package com.safetab.wrapper;

import javax.servlet.ServletOutputStream;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpServletResponseWrapper;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.PrintWriter;

publicclass ApplicationResponseWrapperextends HttpServletResponseWrapper{

private ByteArrayOutputStream output;

privateint contentLength;

private String contentType;

public ApplicationResponseWrapper(HttpServletResponse response){

super(response);

output =new ByteArrayOutputStream();

}

public ServletOutputStream getOutputStream()throws IOException{

returnnew FilterServletOutputStream(output);

}

public PrintWriter getWriter()throws IOException{

returnnew PrintWriter(getOutputStream(),true);

}

publicbyte[] getData(){

return output.toByteArray();

}

publicint getContentLenght(){

return this.contentLength;

}

publicvoid setContentLength(int len){

this.contentLength = len;

super.setContentLength(len);

}

public String getContentType(){

return this.contentType;

}

publicvoid setContentType(String type){

this.contentType=type;

super.setContentType(type);

}

}

FilterServletOutputStream.java

package com.safetab.wrapper;

import javax.servlet.ServletOutputStream;

import java.io.DataOutputStream;

import java.io.IOException;

import java.io.OutputStream;

publicclass FilterServletOutputStreamextends ServletOutputStream{

private DataOutputStream stream;

public FilterServletOutputStream(OutputStream output){

stream =new DataOutputStream(output);

}

publicvoid write(int b)throws IOException{

stream.write(b);

}

publicvoid write(byte[] b,int off,int len)throws IOException{

stream.write(b, off, len);

}

publicvoid write(byte[] b)throws IOException{

stream.write(b);

}

}

GenericFilter.java

package com.safetab.wrapper;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

publicclass GenericFilterimplements javax.servlet.Filter{

private FilterConfig filterConfig;

publicvoid doFilter(final ServletRequest request,

final ServletResponse response, FilterChain chain)

throws java.io.IOException, javax.servlet.ServletException{

chain.doFilter(request, response);

}

public FilterConfig getFilterConfig(){

return filterConfig;

}

publicvoid init(FilterConfig config){

this.filterConfig = config;

}

publicvoid destroy(){

this.filterConfig =null;

}

}

TestFilter.java

package com.safetab.wrapper;

import javax.servlet.FilterChain;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.io.OutputStream;

publicclass TestFilterextends GenericFilter{

publicvoid doFilter(final ServletRequest request,final ServletResponse

response, FilterChain chain)

throws IOException, ServletException

{

OutputStream out = response.getOutputStream();

out.write("<HR>PRE<HR>".getBytes());

ApplicationResponseWrapper wrapper =new ApplicationResponseWrapper((HttpServletResponse) response);

chain.doFilter(request, wrapper);

out.write(wrapper.getData());

out.write("<HR>POST<HR>".getBytes());

out.close();

}

}

web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"

version="2.4">

<description>

Sample web.xmlfor MyFaces 1.1.5, taken from MyFaces site, but

with .jsf extension changed back to standard .faces.

http://www.coreservlets.com/JSF-Tutorial/

</description>

<filter>

<filter-name>TestFilter</filter-name>

<filter-class>com.safetab.wrapper.TestFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>TestFilter</filter-name>

<url-pattern>*.jsp</url-pattern>

</filter-mapping>

</web-app>

test.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"

pageEncoding="ISO-8859-1"%>

<!DOCTYPE html PUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">

<HTML>

<HEAD>

<TITLE>Lesson 3</TITLE>

</HEAD>

<BODY>

<P>This is a pure testpage</P>

</BODY>

</HTML>

outcome

PRE

POST

-

[10592 byte] By [tonyhaubera] at [2007-11-27 10:25:15]
# 1

The problem is that JSP output to the JspWriter can not be handled the same as output to the ServletOutputStream. I don't know the details of why but the two scenarios need to be handled seperately.

In your ApplicationResponseWrapper you'll need to do something like :

package com.safetab.wrapper;

import javax.servlet.ServletOutputStream;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpServletResponseWrapper;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.PrintWriter;

public class ApplicationResponseWrapper extends HttpServletResponseWrapper {

private ByteArrayOutputStream output;

private int contentLength;

private String contentType;

private CharArrayWriter myOut ;

private int mode;

public ApplicationResponseWrapper(HttpServletResponse response) {

super(response);

output = new ByteArrayOutputStream();

this.myOut = new CharArrayWriter();

}

public ServletOutputStream getOutputStream() throws IOException {

this.setMode(2);

return new FilterServletOutputStream(output);

}

public PrintWriter getWriter() throws IOException {

this.setMode(1);

return new PrintWriter(this.myOut);

}

public byte[] getData(){

return output.toByteArray();

}

public int getContentLenght(){

return this.contentLength;

}

public void setContentLength(int len) {

this.contentLength = len;

super.setContentLength(len);

}

public String getContentType() {

return this.contentType;

}

public void setContentType(String type) {

this.contentType=type;

super.setContentType(type);

}

public int getMode() {

return mode;

}

public void setMode(int mode) {

this.mode = mode;

}

public String toString() {

return myOut.toString();

}

}

and then in your filter you access the proper output mechanism based on the mode

package com.safetab.wrapper;

import javax.servlet.FilterChain;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.io.OutputStream;

public class TestFilter extends GenericFilter{

public void doFilter(final ServletRequest request, final ServletResponse

response, FilterChain chain)

throws IOException, ServletException

{

OutputStream out = response.getOutputStream();

out.write("<HR>PRE<HR>".getBytes());

ApplicationResponseWrapper wrapper = new ApplicationResponseWrapper((HttpServletResponse) response);

chain.doFilter(request, wrapper);

if (wrapper.getMode() == 1) {

response.getOutputStream().println(wrapper.toString());

} else if (wrapper.getMode() == 2) {

response.getOutputStream().write(wrapper.getData());

}

out.write("<HR>POST<HR>".getBytes());

out.close();

}

}

This is just cutting and pasting from some of my sample to yours to illustrate the concept o don't expect it to run perfectly as is.

tolmanka at 2007-7-28 17:32:35 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 2

hey . i don't know why if i do as tolmank say , it' just print out the content of web page + "<HR>POST<HR>" , i can't see this "<HR>PRE<HR>". but if we move this line :

out.write("<HR>PRE<HR>".getBytes());

to after :

chain.doFilter(request, wrapper);

it will work fine !!! , can't understand.

secmaska at 2007-7-28 17:32:35 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 3

I moved the project to a WAS and it worked fine. I think it was a problem with tomcat and where it keeps its compiled code compared to its uncompiled code

tonyhaubera at 2007-7-28 17:32:36 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 4

ok, thanks for your information tonyhauber , i'll try other web container.

secmaska at 2007-7-28 17:32:36 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...