2

I'm having a tough time consolidating errors in my application. Currently, my error.jsp looks like following (part of it):

 <%@ page isErrorPage="true" %>
 <%@page contentType="text/html"%>
 <%@page import="java.util.*"%>
 <%@page import="javax.servlet.*"%>
 <%@page import="javax.servlet.http.*"%>
 <%@page import="java.util.Calendar"%>
 <%@page import="java.text.SimpleDateFormat"%>

<html>
<%
String code = null, message = null, type = null, uri = null, time = null;
Object codeObj=null, messageObj=null, typeObj=null;
if (request.getAttribute("javax.servlet.error.status_code") != null)
    codeObj = request.getAttribute("javax.servlet.error.status_code");
if (request.getAttribute("javax.servlet.error.message") != null)
    messageObj = request.getAttribute("javax.servlet.error.message");
if (request.getAttribute("javax.servlet.error.exception_type")!=null)
    typeObj = request.getAttribute("javax.servlet.error.exception_type");

if (codeObj != null) code = codeObj.toString();
if (messageObj != null) message = messageObj.toString();
if (typeObj != null) type = typeObj.toString();
uri = (String) request.getAttribute("javax.servlet.error.request_uri");
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
time = sdf.format(cal.getTime());

String error = "Code:\t\t" + code + "\nType:\t\t" + type + "\nURL:\t\t" + uri + "\nTime:\t\t" + time +"\nMessage:\t" + message;
%>

This works fine in all scenarios except!: Sometimes in my application I am catching built-in exceptions in MyException class with the following code:

catch(MyException ex){
    log.error(ex.getMessage(), uivex);
    String originalURL = "/errorpages/error.jsp?errorcode=" + (ex.getMajor() + ex.getMinor()) + "&errormessage=" + ex.getMessage();
    RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(address);
    dispatcher.forward(request,response);   
}

Now the problem is that when I get forwarded to error.jsp page...Instead of seeing the actual error from MyException class..I'm seeing NullPointerException because nothing is present in javax.servlet.error.status_code and the page is declared as isErrorPage="true"

What should I do in this case? One solution is to make a completely different error.jsp (name it error1.jsp) page and forward the exceptions from MyException class to that page. Though, I would like to have everything in one place.

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
learn_plsql
  • 1,681
  • 10
  • 28
  • 34

3 Answers3

4

This code honestly hurts my eyes. Here is how a generic one should look like. You may find it useful.

<%@ page pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<jsp:useBean id="date" class="java.util.Date" />
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Error</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <h1>Error</h1>
        <p>Unfortunately an unexpected error has occurred. Below you can find the error details.</p>
        <h2>Details</h2>
        <ul>
            <li>Timestamp: <fmt:formatDate value="${date}" type="both" dateStyle="long" timeStyle="long" />
            <li>Action: <c:out value="${requestScope['javax.servlet.forward.request_uri']}" />
            <li>Exception: <c:out value="${requestScope['javax.servlet.error.exception']}" />
            <li>Message: <c:out value="${requestScope['javax.servlet.error.message']}" />
            <li>Status code: <c:out value="${requestScope['javax.servlet.error.status_code']}" />
            <li>User agent: <c:out value="${header['user-agent']}" />
        </ul>
    </body>
</html>

The @page isErrorPage is by the way only useful if you want to have the ${exception} (i.e. request.getAttribute("exception") available in the JSP. In this particular case you don't need it.

And indeed, do not forward in the catch block at all. Just let it go. It will be dealt by the error page then.

} catch (MyException ex) {
    log.error(ex.getMessage(), uivex);
    throw ex; // Or throw new ServletException(ex.getMessage(), ex);
}
Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • If I `throw ex` then error stack is written in server.log . I want it to only be written in `my_system.log` (comes from `log.error`) – learn_plsql Aug 24 '10 at 13:25
  • I really don't see how that's a problem. You're already logging it to your own log using `log.error()`. If you want to disable server stderr logging, just configure so in the server config. – BalusC Aug 24 '10 at 13:29
  • Ideally I would like to do exaclty that! so that Instead of dealing with exceptions I can just log it to my own log and then just throw it out! How would I configure/disabled stderr logging in GlassFish. I can search on google as well but not sure exactly what to look for – learn_plsql Aug 24 '10 at 13:38
  • Again, I really don't see how that's a problem. You could just ignore the server's own logfile at its whole own. Anyway, you can configure logging in the admin console. – BalusC Aug 24 '10 at 13:48
  • @BalusC Thanks for another excellent answer. This one is good for reference too. – C. Ross Nov 02 '11 at 12:02
1

Put all details in the logs and show the user only a vague message that something went wrong, regardless of what the exception is. So your error page may look like (to quote twitter):

<%@ page isErrorPage="true" %>

Something went technically wrong. 

And do not catch & forward - simply let the exception bubble. The other alternative is, as you say, make two separate pages that include the common content, and differ only in the isErrorPage definition.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • but the problem will still be there. when a jsp page is decalared is `isErrorPage` the `javax.servlet.error.status_code` must have something in it or else a Null Pointer Exception is thrown. – Omnipresent Aug 24 '10 at 11:31
  • I thought in last question you suggested that if I want to avoid putting exceptions in server.log then I need to catch them and that's the only option. that's why I am now catching it and forwarding. – learn_plsql Aug 24 '10 at 13:23
  • Yes, given the other question (I didn't relate the two initially) then forwarding sounds less bad. – Bozho Aug 24 '10 at 13:28
1

You can create a custom stackTrace jsp tag and include it in a special error page:

The tag file (WEB-INF/tags/stackTrace.tag)

<%@tag description="Prints stack trace of the specified Throwable"
          pageEncoding="UTF-8"%>

<%-- content (prints stack trace) --%>
<%
      java.io.PrintWriter pOut = new java.io.PrintWriter(out);
      try {
         // The Servlet spec guarantees this attribute will be available
         Throwable err = (Throwable) 
             request.getAttribute("javax.servlet.error.exception");

         if(err != null) {
            if(err instanceof ServletException) {
               // It's a ServletException: we should extract the root cause
               ServletException se = (ServletException) err;
               Throwable rootCause = se.getRootCause();
               if(rootCause == null) {
                  rootCause = se;
               }
               out.println("** Root cause is: " + rootCause.getMessage());
               rootCause.printStackTrace(pOut);
            }else {
               // It's not a ServletException, so we'll just show it
               err.printStackTrace(pOut);
            }
         }else {
            out.println("No error information available");
         }

         // Display cookies
         out.println("\nCookies:\n");
         Cookie[] cookies = request.getCookies();
         if(cookies != null) {
            for(int i = 0; i < cookies.length; i++) {
               out.println(cookies[i].getName() + "=[" + 
                   cookies[i].getValue() + "]");
            }
         }

      }catch(Exception ex) {
         ex.printStackTrace(pOut);
      }
%>

The error.jsp could be like so: (Add some humor to it, if you app somewhat casual)

<%@ page isErrorPage="true" %>
<html>
   <head>
    <title>Error</title>
   </head>
   <body>
      <div>
         <textarea class="para error">
            Aww Snap!! :( Something went wrong where it was not supposed to. 
            Must be something
            <a href="http://en.wikipedia.org/wiki/Jack_the_Ripper">Jack</a> did!
            Please report this to the dev team.

            <!-- 
               <util:stackTrace />
            -->

         </p>
      </div>
   </body>
</html>

The "Report this Error button can submit the stack trace or mail it!

naikus
  • 24,302
  • 4
  • 42
  • 43