I am trying to log every incoming request and outgoing response in my application. I am using jee 6 so I do not have ContainerRequestFilter and ContainerResponseFilter classes. So I decided to use Filter.
I annotated a class with @WebFilter("/*") and implemented Filter interface. I successfully read the request headers and request body. With some difficulty I also read the response headers and response body. Below is a code snippet
MyHttpServletResponseWrapper wrapper = new MyHttpServletResponseWrapper((HttpServletResponse) response);
chain.doFilter(request, wrapper);
MyHttpServletResponseWrapper class
public class MyHttpServletResponseWrapper extends HttpServletResponseWrapper {
private StringWriter sw = new StringWriter();
public MyHttpServletResponseWrapper(HttpServletResponse response) { super(response); }
public PrintWriter getWriter() { return new PrintWriter(sw); }
public ServletOutputStream getOutputStream() {
return new ServletOutputStream (){
public void write(int B) { sw.append((char) B); }
};
}
public String getCopy() { sw.toString(); }
}
After logging the response I am writing the response back to the output stream so that the client can receive the response. Below is the code
logResponse(wrapper);
response.getOutputStream().write(wrapper.getCopy().getBytes());
What I am not able to understand is, how to put back the request body in the input stream after reading it.
In standard APIs like the Jersey, there is a convenient way to put it back using setEntityInputStream(inputStream)
How do I do it with the standard Java ServletOutputStream api.
I am not trying to reinvent the wheel. I am trying to avoid using Jersey so that my code can be easily migrated to new jee versions. Also I would like to understand how APIs like Jersey does it.
To read the response from the body I read the below link but it did not work for me. Container threw an exception saying writer already obtained.
Capture and log the response body
P.S.
I think I figured out how to set the input stream back. Below is some code
MyRequestWrapper requestwrapper = new MyRequestWrapper((HttpServletRequest) request);
chain.doFilter(requestwrapper, wrapper);
MyRequestWrapper class
public class MyRequestWrapper extends HttpServletRequestWrapper {
String body;
int counter;
public MyRequestWrapper(HttpServletRequest request) { super(request); }
public void setBody(String body) { this.body = body;}
public ServletInputStream getInputStream() {
return new ServletInputStream() {
public interest read() throws IOException {
if(counter >=body.length()) return -1;
return body.charAt(counter++);
}
};
}
}
I know that the quality of the code in overrided getInputStream and getOutputStream are not so great. Right now I am not worried about that. I want to know if this is a right idea? If then then I would like to concentrate on the code quality.