views:

486

answers:

2

I asked a question along similar lines yesterday as well. In that question I was suggested to have a global filter (which I already had).

So I have a JSP like below

....code...code
..tags...html...code
Object [] res = iBatisDAO.getReport_pging(null,null,0,null); //call to DB
...more code...
...tags...end

In the above code I am intentionally passing null's because I want it to fail and when it fails I want it to go to our centralized error page. I have the following in my web.xml

  <error-page>
    <exception-type>com.ibatis.common.jdbc.exception.NestedSQLException</exception-type>
    <location>/errorpages/Error.jsp</location>
  </error-page> 
  <error-page>
    <exception-type>org.springframework.dao.DataAccessException</exception-type>
    <location>/errorpages/Error.jsp</location>
  </error-page>
  <error-page>
    <exception-type>javax.servlet.ServletException</exception-type>
    <location>/errorpages/Error.jsp</location>
  </error-page>
  <error-page>
    <exception-type>java.sql.SQLException</exception-type>
    <location>/errorpages/Error.jsp</location>
  </error-page>
  <error-page>
    <exception-type>org.springframework.jdbc.UncategorizedSQLException</exception-type>
    <location>/errorpages/Error.jsp</location>
  </error-page>

the 'control' comes to the above JSP via a global filter that I have. it has chain.doFilter() wrapped in try/catch block. When exception happens it redirects to Error.jsp.

When the error happens...it is not being caught by the centralized error page and neither is it caught by the filter. I think filter is not catching it because when filter 'calls' the jsp...there IS no error yet.

I know call to DB is BAD inside a JSP but I am dealing with lot of legacy code.

What can I do to have errors go to centralized error page in this scenario? Also, the JSP does not have the error page imported. I would not want the option of importing an error page to all JSP's I want to have a more general solution.

A: 

You've undertaken a wrong approach. You must not have any logic processing code (business logic) in your JSP files. JSP is a view technology. Use servlets or some action/component framework (Struts2 / Spring MVC / JSF / etc.) to handle the business logic.

As for the filter approach - it is a good solution, but the filter must be mapped to /* (using <filter-mapping>):

<filter>
   <filter-name>exceptionFilter</filter-name>
   <filter-class>com.yourpackage.YourFilter</filter-class>
</filter>
<filter-mapping>
   <filter-name>exceptionFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>
Bozho
it is mapped to that. but since exception is happening INSIDE the JSP ...how will a filter catch that exception?...
drake
@drake The JSP is translated to a Servlet. So it happens in a servlet, which is processed after the `chain.doFilter()`. Please give the stacktrace that is generated from the exception.
Bozho
exception message is: `org.springframework.jdbc.UncategorizedSQLException: SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [null]; error code [17004];` which I am catching in web.xml. I noticed now that the code IS going in catch block for chain.doFilter however, in that catch block when I try to do `response.sendRedirect` it fails because the response has already been set. is there a way around this?
drake
+2  A: 

Exceptions in JSP cannot be handled nicely, because it's too late to change the response. JSP as being a view technology is responsible for the whole response at its own. It sends the response headers and the response content. When the response headers are sent, then it's a point of no return. Even a filter ain't going to help here.

Whenever an exception occurs halfway a JSP, then the response will be abruptly aborted and the client will face a blank or a halfbaked page and the exception can at highest only be logged to the server log. Maybe along an IllegalStateException: response already committed whenever an attempt is made to redirect/forward/display the error page while that's impossible, because the response is already committed.

In short: do not write raw Java code in JSP files. Put them in Java classes such as (in)direct in a Servlet. It get processed before the JSP get displayed. This way there's plenty of room to change the destination of the response.

If you insist in using JSP for business logic (which I do not recommend), then an alternative is to put all the business logic to the top of the JSP file, before any template text (HTML and so on) is to be sent to the response. If you're lucky, the servletcontainer will be able to change the response to an error page whenever an exception is been thrown.

BalusC
Thanks for the explanation. I understand that. but i am dealing with over 100+ legacy JSP's and can not afford to change them all to take out business logic out at this time. I noticed that the code IS going in catch block for `chain.doFilter` however, there if I try to do `response.sendRedirect` it fails because response is already set. is there way around this?
drake
No. It's a point of no return. You cannot send more than one response for a request.
BalusC
well thats bullocks. I noticed,as you said, if call to DB is the first thing in the JSP rather than being in middle then it gets caught via error-page declarations in web.xml. however, if it is somewhere in middle then it does not get caught by them. any reason behind this?
drake
Because the response is already committed. The client has already retrieved (parts of) the response. You cannot reset it. This is a point of no return.
BalusC
Note that this is not a JSP limitation but rather a HTTP limitation. HTTP doesn't allow to "suck" the response back.
BalusC