Differences between ServletResponse and HttpServletResponseWrapper? - java

I am new to servlet and reading some text about filters and wrappers. I can understand filters but got confused about wrappers. In the book, the author gives an example:
In case no wrapper:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
String name = request.getParameter("name").trim();
try {
chain.doFilter(request, response);
PrintWriter out = response.getWriter();
if (name.length() == 0) {
out.println("Some message");
out.println("</body>");
out.println("</html>");
out.close();
}
} catch (Throwable t) {
}
}
In case of wrapper:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
String name = request.getParameter("name").trim();
HttpServletResponse httpRes = (HttpServletResponse) response;
HttpServletResponseWrapper resWrapper = new HttpServletResponseWrapper(httpRes);
try {
chain.doFilter(request, response);
PrintWriter out = resWrapper.getWriter(); // why dont we just use response.getWriter();
if (name.length() == 0) {
out.println("<h3>Some message");
out.println("</body>");
out.println("</html>");
out.close();
}
} catch (Throwable t) {
}
}
Why we need HttpServletResponseWrapper while we can do the same thing with ServletResponse in case 1? Can anyone give me a clear example that we MUST use HttpServletResponseWrapper instead of ServletResponse? I have tried to google but found no luck.

BalusC's answer is good, but it might be a little overwhelming if you're just starting out.
Put simply: SerlvetResponse and its extension, HttpServletResponse, are interfaces telling you what methods are available to call to do the things you need. In the normal course of working with Filters, Servlets, et al., you'll use HttpServletResponse often to tell your app how to respond to requests.
HttpServletResponseWrapper is one particular implementation of HttpServletResponse which gives you a convenient way to wrap an existing response with some logic of your own without having to write a whole new implementation of the interface. It has a lot of methods, so this is really nice. As a trivial example, suppose you wanted to disallow calls to response.flushBuffer(). This code, using HttpServletResponseWrapper, will do that:
class DisallowFlushResponseWrapper extends HttpServletResponseWrapper {
public DisallowFlushResponseWrapper(HttpServletResponse response) {
super(response);
}
#Override
public void flushBuffer() {
throw new UnsupportedOperationException("Don't call this!");
}
}
The typical way to use such a wrapper would be to create a filter like this:
class DisallowFlushFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) {
if (response instanceof HttpServletResponse) {
HttpServletResponse newResponse =
new DisallowFlushResponseWrapper((HttpServletResponse) response);
chain.doFilter(request, newResponse);
}
...
}
...
}
Note that we wrap the response coming into the filter with an instance of our own wrapper. Then we hand the wrapper down to the next item in the filter chain. Thus anything that comes after this filter will get an exception if it calls flushBuffer() because it will be calling it on our wrapper. The wrapper, due to its default behavior, will delegate any other call to the wrapped response, which is the real one, so everything except calls to that one method will work normally.

That's really a stupid example which does not show the benefit of request/response wrapper. Actually, the whole filter example is poor. Emitting HTML should be done by a JSP or at highest a servlet (but also that is still poor). Go through our filters wiki page to get some ideas about what a filter can be used for.
A response wrapper is useful if you want to modify the response's behaviour or just want to collect information about the response while it is been used in the request-response chain. The modified behaviour takes then place whenever some servlet or JSP calls a certain method on the response. If you have overriden it in your wrapper class, then this one will be called instead. You could alter the behaviour or collect information there.
Here on Stackoverflow you can find some concrete examples of useful HttpServletResponseWrapper implementations.
How to insert response size and time into the page itself, at least partially?
MD5 Signing a HttpServletResponse
How to configure Tomcat to not encode the session id into the URL when HttpServletResponse.encodeURL() is invoked
How to add response headers based on Content-type; getting Content-type before the response is committed
How is annotations support in jsp implemented in sitebricks?
Capture and log the response body
Log only http servlet response headers
How to include a JSP page in a Facelets page?
Capture generated dynamic content at server side

Related

SlingServletFilter: Get status code before doFilter

I'm trying to make unexisting pages under my domain go to a 404 page. I need to distinguish 404 pages from the other pages. However, I do not know how to do this. And the thing below is not working.
#Component(service = Filter.class,
property = {
"service.ranking=" + Integer.MIN_VALUE})
#SlingServletFilter(scope = {SlingServletFilterScope.REQUEST},
pattern = "/content/foo/.*",
resourceTypes = "cq:Page",
extensions = {"html"},
methods = {"GET"})
public class NotFoundFilter implements Filter {
private static final String DEFAULT_METHOD = "GET";
#Reference
private UrlOperationsManager urlOperationsManager;
#Reference
private RequestResponseFactory requestResponseFactory;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (!(request instanceof SlingHttpServletRequest) ||
!(response instanceof SlingHttpServletResponse)) {
chain.doFilter(request, response);
return;
}
SlingHttpServletResponse slingResponse = (SlingHttpServletResponse) response;
//this condition here is not working since slingResponse has no getStatusCode method.
if(slingResponse.getStatusCode() == 404) {
//do something
}
chain.doFilter(request, response);
}
#Override
public void destroy() {
}
}
You could work around this by implementing your own HttpServletResponseWrapper to save the value and access it later. The Sling implementation is marginally different (at least as far as this particular mechanic is concerned) from the generic Servlet API, which is covered in depth in How can I get the HTTP status code out of a ServletResponse in a ServletFilter?
However, if your intention is to serve a particular error document for a given status code, I'd approach it differently. Assuming you use a Dispatcher, you could have the web server take care of it.
The official AEM project archetype comes with a few simple examples that you could enable if you use Apache. The details will depend on your site structure but the gist is that it's possible to provide a similar configuration using the ErrorDocument directive to point to a cached error page relative to the document root, usually making it use content-editable error pages.
Some errors, especially HTTP 5** family could be a bit more tricky that way in that they usually happen when there's something wrong with AEM itself so it's prudent to make sure a fully static version is always available.

How to redirect in javax.servlet.Filter's doFilter [duplicate]

I'm trying to find a method to redirect my request from a filter to the login page but I don't know how to redirect from servlet. I've searched but what I find is sendRedirect() method. I can't find this method on my response object in the filter. What's the cause? How can I solve this?
In Filter the response is of ServletResponse rather than HttpServletResponse. Hence do the cast to HttpServletResponse.
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.sendRedirect("/login.jsp");
If using a context path:
httpResponse.sendRedirect(req.getContextPath() + "/login.jsp");
Also don't forget to call return; at the end.
I'm trying to find a method to redirect my request from filter to login page
Don't
You just invoke
chain.doFilter(request, response);
from filter and the normal flow will go ahead.
I don't know how to redirect from servlet
You can use
response.sendRedirect(url);
to redirect from servlet
If you also want to keep hash and get parameter, you can do something like this (fill redirectMap at filter init):
String uri = request.getRequestURI();
String[] uriParts = uri.split("[#?]");
String path = uriParts[0];
String rest = uri.substring(uriParts[0].length());
if(redirectMap.containsKey(path)) {
response.sendRedirect(redirectMap.get(path) + rest);
} else {
chain.doFilter(request, response);
}
why are you using response object . it is a ServletResponse Object ,it does not provide sendRedirect() method . instead use request object of ServletRequest to forward the request.
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
// place your code here
request.getRequestDispatcher("login.html").forward(request,response);
return;
}
see javadoc
Try and check of your ServletResponse response is an instanceof HttpServletResponse like so:
if (response instanceof HttpServletResponse) {
response.sendRedirect(....);
}
Your response object is declared as a ServletResponse. To use the sendRedirect() method, you have to cast it to HttpServletResponse. This is an extended interface that adds methods related to the HTTP protocol.

How do I handle error states in servlet filters without showing the user a stack trace?

I'm working on a Jetty/RESTEasy app. If I throw a WebApplicationException(myResponse) from one of my REST endpoints, it sends the given response to the client.
When a filter detects an error, I want the same behavior:
It should stop execution from proceeding, and
It should give the user a clear, JSON-formatted error that does not include a stack trace.
Obviously, just writing to the response stream and returning works from within the doFilter method. But this doesn't work for other methods called by doFilter.
Throwing any exception will meet condition #1 but I haven't figured out a sane way to meet condition #2 then. (You can see my best attempt at the bottom.)
As Perception explained in his answer, WebApplicationExceptions are treated like any other exception in the context of a Filter, and therefore give the user a nice ugly stack trace.
So, to sum up my questions:
Do serveltt containers have any equivalent to throw new WebApplicationException(Response)?
And perhaps more importantly, how do other java projects handle this?
I have this code in one filter and it works, but I'd prefer a more elegant solution that automatically applies to all filters:
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
try {
doFilterOrThrow(request, response, chain);
} catch (WebApplicationException e) {
Response res = e.getResponse();
((HttpServletResponse) response).sendError(res.getStatus(), (String) res.getEntity());
}
}
The specific handling you mention for web application exceptions is only defined within the context of a JAX-RS container, which, by the way, is not the same thing as a Servlet container.
Web filters are handled by the Servlet container, which does not know or care that a JAX-RS container exists within the same application server. It also does not know or care about web application exceptions. So when you throw the WAE from within the filter it is treated just the same as any other exception (server error with a stack trace, or a preconfigured error page if you set one up in your web application).
It would seem to me if you are indicating an error to the client you could simply do so from the filter, by writing directly to the response stream. But if you are trying to leverage some existing JAX-RS logic then a (RESTEasy specific) solution would be to flag the request as error'ed out in your filter, then generate a WAE in JAX-RS, using a provider class. Example:
#WebFilter(urlPatterns = "*")
public class ForwardingFilter implements Filter {
#Override
public void destroy() {
return;
}
#Override
public void doFilter(final ServletRequest request,
final ServletResponse response, final FilterChain chain)
throws IOException, ServletException {
// Add an error response to be processed by the JAX-RS container.
// This would obviously be based on some condition.
request.setAttribute("errorResponse",
Response.status(500).entity("Didn't work out!").build());
chain.doFilter(request, response);
}
#Override
public void init(FilterConfig arg0) throws ServletException {
return;
}
}
#Provider
#ServerInterceptor
#HeaderDecoratorPrecedence
#RequestScoped
public class ForwardingHandlerProvider implements PreProcessInterceptor {
#Override
public ServerResponse preProcess(final HttpRequest request,
final ResourceMethod method) throws Failure,
WebApplicationException {
final Response errorResponse = (Response) request
.getAttribute("errorResponse");
if (errorResponse != null)
throw new WebApplicationException(errorResponse);
return null;
}
}
Since the provider exists in JAX-RS land, the web application exception is processed according to the rules of Section 3.3.4 of the JAX-RS specification, and you get the desired response at the client side.
* EDIT:*
The bottom line is, there is no standard Java EE prescribed way (currently) to handle servlet exceptions in a centralized fashion similar to what is available in JAX-RS. Since you are using JBoss/RestEASY though, you could utilize the JBoss Seam Catch library to get pretty close.
#HandlesExceptions
public class ExceptionHandler {
public void handleServletException(
final #Handles #WebRequest CaughtException<ServletException> caught,
#Context final HttpServletResponse response) {
try {
response.sendError(500, "An error occured");
} catch (final IOException ioe) {
System.err.println("Dumb IO Exception: " + ioe);
}
}
}
The above illustrates an exception handler, as described in the Seam Catch documentation. Note that the library is in massive flux right now, so you will want to utilize it only as a last resort.

Updating response after doFilter

I wish to add a HTTP header after the doFilter() function has finished running.
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpResp = (HttpServletResponse) response;
try {
chain.doFilter(request, httpResp);
} finally {
httpResp.setHeader("ADD A HEADER: ", "HEADER");
}
}
It seems that doFilter flushes the response.
UPDATE:
Thanks. After viewing IgorMadjeric and richardtz answers I decided to try Response wrapper:
This is the wrapper:
public class BufferedHttpServletResponse extends HttpServletResponseWrapper {
public BufferedHttpServletResponse(HttpServletResponse response) {
super(response);
}
public void flushBuffer() {
System.out.println("flush");
}
}
This is the Altered code:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpResp = (HttpServletResponse) response;
try {
BufferedHttpServletResponse bufferedResponse = new BufferedHttpServletResponse(httpResp);
chain.doFilter(request, bufferedResponse);
} finally {
bufferedResponse.setHeader("ADD A HEADER: ", "HEADER");
}
}
Still does not working. Did I do something wrong?
you cannot modify the response of the header once it has been flushed/commited (it has already been sent to the client).
doFilter does not flush the response, but many things in the execution of the request may cause it.
(explicit call to response.flush(), too large body in the response), and you cannot control it.
However, you can use a HttpServletResponseWrapper to change this.
Hope it helps.
As already mentioned in the comments and in this question it might not be enough to overwrite flushBuffer(), but you need to also overwrite getWriter() and getOutputStream(). In certain cases even that might not be enough. For instance if the sendError(int) is called on the response it can also get commited.
In your case from code which you have posted, you can not to say:
It seems that doFilter flushes the response.
There is some rules about committing response.
Response is probably already committed by some component after you filter.
If you want to avoid this behavior you should use Request/Response wrappers, this will prevent components, on which your filter is applied to commit response.

Avoiding the endless loop in JSP servlet mapping

I've got this issue, recently I read about the REST arquitecture and it makes a perfect sense, so I'd like to achieve a RESTful web application.
Now, I'm following the Front Controller pattern that means that all of the URL mappings go to the controller.java servlet, I map the by specific URLs, not by using the /* wildcard,
the controller implements the four HTTP methods POST,GET,PUT,DELETE, each method calls the controllers service method and there I determine based on the HttpServletRequest and pathInfo the action to execute.
Controller.java
#Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
IAction action;
View view;
try {
action = ActionFactory.produceAction(req);
view = action.execute(req, resp);
switch (view.getDispatchMethod()) {
case REDIRECT:
resp.sendRedirect(resp.encodeURL(view.getResource()));
break;
case FORWARD:
req.getRequestDispatcher(view.getResource()).forward(req, resp);
break;
case INCLUDE:
req.getRequestDispatcher(view.getResource()).include(req,resp);
break;
default:
}
} catch (ActionFailedException uae) {
req.setAttribute("ActionName", "Action");
req.setAttribute("FailCause", uae.getMessage());
req.getRequestDispatcher(VIEW_FAIL.getResource()).forward(req, resp);
}
}
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.service(req, resp);
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.service(req, resp);
}
#Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.service(req, resp);
}
#Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.service(req, resp);
}
I've run into a particular issue when loading a specific order by the URI /orders/*, it is mapped to the controller servlet, the the action is executed and I load the appropriate order the action returns a View.java class
//ommited accessors and mutators for brevety.
public class View {
public enum DispatchMethod {
INCLUDE, FORWARD, REDIRECT
}
private DispatchMethod dispatchMethod;
private String resource;
public View(DispatchMethod dispatchMethod, String resource) {
this.dispatchMethod = dispatchMethod;
this.resource = resource;
}
}
Then the request is dispatched according to the getDispatchMethod() of the returned view.
Now, here is where the loop gets triggered, I use the following URL, myapp/orders/78965 /orders/* gets mapped to controller.java the appropriate action is executed and the correct order is found by the pathInfo() the returned view is new View(View.DispatchMethod.FORWARD,"order_details.jsp") the problem is that with the three available dispatch methods REDIRECT,FORWARD and INCLUDE a request is re-triggered on the URL and so on and on and on I never reach the order_details.jsp that renders the data.
So, how would you avoid the looping, as I'd like to preserve the URI displaying the order number I use the forward method, also, I'd like to do it using servlets, I've heard of the UrlRewriteFilter maybe in the future, but right now, how would it be done using "Plain Vanilla" since I'm using the Front Controller pattern, will it be necessary to add an additional servlet in the /orders/ URI ?
Any help or insights is truly appreciated.
EDIT 1:
Pasted the source code of the controller, a very basic one, I have my suspicions that the way the service method calls all of the overriden do[Method] of the servlet is triggering the loop and that it may be solved by splittig them.
Implementing a RESTful HTTP interface in Java is a lot easier using a JAX-RS implementation like RESTEasy or Jersey.
Using a Front Controller to dispatch requests to the right resource is a good approach, it's exactly the approach taken by these JAX-RS frameworks. I fear you may be re-inventing the wheel here by writing a bespoke URL parsing and dispatching mechanism when this can be taken off-the-shelf.
JAX-RS is a lightweight way to expose resources. By using a couple of simple annotations you can expose a REST interface without any plumbing required. For example:
public class Order {
#GET
#Path("/orders/{orderId}")
#Produces("text/html")
public void getOrder(#Context HttpServletResponse response,
#Context HttpServletRequest request,
#PathParam("orderId") String orderId) throws ServletException, IOException {
// ... create view and add to request here
request.getRequestDispatcher("orders.jsp").forward(request, response);
}
}
You can see how simple it is to attach this class to a URL path (using the #Path annotation), and how easily you can parse values from the URL using #PathParam. Since you get all the plumbing/dispatching/parsing off-the-shelf, you can concentrate on the bits of your app that are specific to your domain (such as what an order contains).

Categories

Resources