How to grab uncaught exceptions in a Java servlet web application - java

Is there a standard way to catch uncaught exceptions that happen inside of a java servlet container like tomcat or Jetty? We run a lot of servlets that come from libraries so we cannot easily put our on try/catch code. It would also be nice to in as generic of a way as possible catch and log all uncaught exceptions in our web application (which runs in Jetty) to our bug tracker via the API provided.
Please not I need to log the exceptions only, whether a a redirect is issues to a custom error page will not help me. We do everything via GWT-RPC so the user would never see an error page.

I think a custom filter actually works best.
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (Throwable e) {
doCustomErrorLogging(e);
if (e instanceof IOException) {
throw (IOException) e;
} else if (e instanceof ServletException) {
throw (ServletException) e;
} else if (e instanceof RuntimeException) {
throw (RuntimeException) e;
} else {
//This should never be hit
throw new RuntimeException("Unexpected Exception", e);
}
}
}

In web.xml (the deployment descriptor) you can use the <error-page> element to specify error pages by exception type or HTTP response status code. For example:
<error-page>
<error-code>404</error-code>
<location>/error/404.html</location>
</error-page>
<error-page>
<exception-type>com.example.PebkacException</exception-type>
<location>/error/UserError.html</location>
</error-page>
For a NetBeans-centric description, mosey on over to Configuring Web Applications: Mapping Errors to Error Screens (The Java EE 6 Tutorial) (or see the Java EE 5 Tutorial's version).

Not 100% sure if this will work with a servlet container, or how far upstream this call would need to go, but you can call the static setDefaultUncaughtExceptionHandler method on Thread to set a handler that will handle all uncaught exceptions.

Related

How to listen to all errors in a servlet's request scope?

My web-service has 3 Servlets that instantiate the same request scoped object which stores information about that current request like URL path, resources used and also errors thrown during it's execution. The intention is to log those errors and also send them as part of the response for the client, in JSON or XML.
I wish to use:
public class ErrorEngine implements Thread.UncaughtExceptionHandler
creating a class to catch all errors (with / without try in classes code) and then save them to a log file and also to an array that will go to client later. I did:
public ErrorEngine() {
super();
Thread.setDefaultUncaughtExceptionHandler(this);
System.out.println("Error Handler Engine Started.");
}
#Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("Thread: "+t.getId()+"; Error: "+e.getMessage());
}
and the Error Handler Engine Started message appears on console, but when I test with a by zero division inside the service() method of the servlet that instantiated the Error Handler, the message I created to test does not show up, only the regular stack trace.
So, How to correctly listen for all errors in the request scope of the servlet?
I want to handle each of them in their own class and code, but I want to log them all from the same place, without having to call a method from my error handler class on every try/catch, even because errors may appear in places I did not handle the code for them, but I must see them in the log.
You can create a MyBaseServlet with final doGet() / final doPost() which call the methods myDoGet() / myDoPost() respectively (wrapped around try{}catch(Throwable t){uncaughtException(t)} ).
Every servlet should then extend MyBaseServlet and if needed override
default implementation of myDoPost() / myDoGet() or even uncaughtException();
The best way is to implement another servlet that you can redirect exceptions to. In that servlet you can process the exception and log it. Unless the error is thrown, however, it can not be handled and logged by and external class, you will still have to have logging infrastructure in each of your servlets for caught and handled exceptions.
Here is waht your web.xml will look like:
<servlet>
<servlet-name>ErrorHandler</servlet-name>
<servlet-class>ErrorHandler</servlet-class>
</servlet>
<!-- servlet mappings -->
<servlet-mapping>
<servlet-name>ErrorHandler</servlet-name>
<url-pattern>/ErrorHandler</url-pattern>
</servlet-mapping>
<error-page>
<exception-type>java.lang.Throwable</exception-type >
<location>/ErrorHandler</location>
</error-page>
Here is a link to a full tutorial:
https://www.tutorialspoint.com/servlets/servlets-exception-handling.htm
the Error Handler Engine Started
message appears on console, but when I test with a by zero division
inside the service() method of the servlet that instantiated the Error
Handler, the message I created to test does not show up, only the
regular stack trace.
You need to set the ExceptionHandler on the Servlet's thread, not the Error Handler's
See example below
package test;
import java.lang.Thread.UncaughtExceptionHandler;
public class ErrorHandler implements UncaughtExceptionHandler {
#Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("Exception occurred in thread "+t.getName());
System.out.println("Exception is "+e.getClass()+" ---------------");
System.out.println("Exception is "+e.getMessage());
}
}
package test;
public class ExceptionThrower {
void test(){
Thread.currentThread().setUncaughtExceptionHandler(new ErrorHandler());
Object obj = null;
System.out.println(obj.toString());
}
public static void main(String[] args) {
new ExceptionThrower().test();
System.out.println("After exception"); //this wont execute
}
}
And this is the output
Exception occurred in thread main
Exception is class java.lang.NullPointerException ---------------
Exception is null

Tomcat doesnt use my Error-Page [duplicate]

I have a web-app developed with servlet & JSP. I configured my app to throw an IllegalArgumentException if I insert bad parameters.
Then I configured my web.xml file in this way:
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error.jsp</location>
</error-page>
When I rise a 404 error, then it works and calls error.jsp, but when I rise a java.lang.IllegalArgumentException, then it does not work and I've a blank page instead of error.jsp. Why?
The server is Glassfish, and logs show really IllegalArgumentException rised.
You should not catch and suppress it, but just let it go.
I.e. do not do:
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
doSomethingWhichMayThrowException();
} catch (IllegalArgumentException e) {
e.printStackTrace(); // Or something else which totally suppresses the exception.
}
}
But rather just let it go:
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doSomethingWhichMayThrowException();
}
Or, if you actually intented to catch it for logging or so (I'd rather use a filter for that, but ala), then rethrow it:
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
doSomethingWhichMayThrowException();
} catch (IllegalArgumentException e) {
e.printStackTrace();
throw e;
}
}
Or, if it's not an runtime exception, then rethrow it wrapped in ServletException, it will be automatically unwrapped by the container:
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
doSomethingWhichMayThrowException();
} catch (NotARuntimeException e) {
throw new ServletException(e);
}
}
See also:
How does server prioritize which type of web.xml error page to use?
Submitting form to Servlet which interacts with database results in blank page
Another (simplified) approach is not to declare multiple handlers for various <error-code> and <exception-type> situations but rather have one, sort of catch-all sink, e.g.
<error-page>
<location>/error-page.jsp</location>
</error-page>
Inside your error-page.jsp you can determine the cause, be it a return status code or an exception as described here: https://www.tutorialspoint.com/servlets/servlets-exception-handling.htm These constants are a part of the standard Servlet 3.0 API.
For instance a primitive error-page.jsp response handler placed into the root of your webapp can look like this:
Server encountered a situation
Status code: <%=(Integer) request.getAttribute(javax.servlet.RequestDispatcher.ERROR_STATUS_CODE)%>
<br>
Exception: <%=(Throwable) request.getAttribute(javax.servlet.RequestDispatcher.ERROR_EXCEPTION)%>
For security reasons I wouldn't recommend sending the exact exception type to the client; this is just an example of how to handle different types of errors and response statuses inside a JSP handler; a servlet can be used instead of JSP.
One common catch-all handler vs one per status code is certainly dependent on the situation and requirements.
I have today the same issue. (JavaEE 7 and Glassfish 4.0)
The problem seems that the framework check it as String instead with the Class.
String based check (the hypothesis)
When a Exception is twrown, e.getClass() is compared with <exception-type> as string.
So you can't use inheritance.
Note that nested classes must be pointed as '$' instead '.' (same as getClass() method).
Class based check
The framework create an instance of the class, and <exception-type> text refer to it, and the class.isInstance() is used to check.
This will need reflection and policy file could break it.
I hope that this response solves future issues.

ServletExceptions thrown by HttpServlet are logged as 'SEVERE' by Tomcat, although processed in a recommended manner

Problem description
Tomcat is logging a SEVERE message including a stacktrace when my HttpServlet is throwing a ServletException, although it is properly re-directed to another HttpServlet in the web.xml.
Tomcat logs the following message with stacktrace:
21-Mar-2015 15:24:57.521 SEVERE [http-nio-8080-exec-28] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [MyHttpServlet] in context with path [/HttpServletExceptionHandler] threw exception [CustomException] with root cause CustomException
at MyHttpServlet.doGet(MyHttpServlet.java:20)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:516)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1086)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:659)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1558)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1515)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
What did I do?
First, MyHttpServlet throws a ServletException wrapping a CustomException (subclass of Exception) in it's doGet() method:
public class MyHttpServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
throw new ServletException(new CustomException());
}
}
Then, the thrown CustomException is re-directed to MyServletExceptionHandler (mapped to location '/MyServletExceptionHandler'. This re-direction is defined in the following manner in the web.xml:
<error-page>
<exception-type>CustomException</exception-type>
<location>/MyServletExceptionHandler</location>
</error-page>
Finally, MyServletExceptionHandler receives the thrown exception and prints it:
public class MyServletExceptionHandler extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
final Throwable throwable = (Throwable) req.getAttribute("javax.servlet.error.exception");
System.out.println("MyServletExceptionHandler caught Throwable: " + throwable.toString());
}
}
This results in the expected 'MyServletExceptionHandler caught Throwable: CustomException' print so this does work, but somehow Tomcat also logs the SEVERE message mentioned above, including that stacktrace. This messes up my logging.
Why do I want it this way?
According to Java Beat's OCEJWCD 6 Mock Exam – 4 the above mentioned method is the proper way to deal with Exception handling in Servlets. Question 29 states (spoiler alert: bold are correct answers):
Which of the following is a sensible way of sending an error page to the client in case of a business exception that extends from java.lang.Exception?
Catch the exception and use RequestDispatcher to forward the request to the error page
Don’t catch the exception and define the ‘exception to error-page’ mapping in web.xml
Catch the exception, wrap it into ServletException and define the ‘business exception to error-page’ mapping in web.xml
Catch the exception, wrap it into ServletException, and define the ‘ServletException to error-page’ mapping in web.xml
Don’t do anything, the servlet container will automatically send a default error page
The third answer (which is marked as correct) clearly states that my way of re-directing the exceptions is a sensible solution.
Further discussion material
I found the following quote on this page (from 10-2-2012 by Tom Holloway at CodeRanch.com)
Actually, a ServletException has nowhere to go uphill in a webapp, and therefore having it appear on the master console isn't really that unreasonable, because it indicates that the application isn't handling the problem itself.
In fact, the Javadocs say this about the ServletException constructor:
"Constructs a new servlet exception with the specified message. The message can be written to the server log and/or displayed for the user."
Note that it explicitly says server log.
The server can get involved in a number of ways here. First, you should be able to define a general exception handler in web.xml to permit the app to deal with the exception, where that handler can not only log to the application log, but can determine what, if any, recovery action should be taken (something that the more generic server code cannot do). Secondly, you can define a custom error page, in which case Tomcat will catch the ServletException and dispatch that page. Note, however that the operative word is page. Like login screens, these pages are invoked directly from Tomcat, and therefore cannot be routed through servlets. In other words, use HTML or JSP, not Struts or JSF.
Bottom line, though, is that throwing ServletExceptions is a sign of bad application design. It means that someone was too lazy or too rushed to properly deal with a problem. Compared to that, the location where the error is logged is of secondary importance.
This statement makes me question the Java Beat's OCEJWCD Mock Exam (mentioned above) and my own solution as good practice. Do you think business exceptions should be handled by another Servlet? And if so, do you think that the Servlet Container (Tomcat) should log the stacktrace of these Exceptions or not? If not, what would then be the best practice?
Final remarks
Throwing RuntimeExceptions instead of ServletExceptions results in the same SEVERE log.
A working example of the problem is provided via this Bitbucket repository.
It seems your basic problem is that you want to centralize your error handling but without using a mechanism that causes Tomcat to log the errors as SEVERE?
Since you control all the servlets AFAICT from your question would it not make more sense to define an abstract base servlet that defines all the error handling logic and then just have the rest of your servlets derive from this class?
So you have an abstract base servlet:
public abstract class MyServletBase extends HttpServlet {
#Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
try {
doGetInternal(req, resp);
} catch (RuntimeException e) {
handleError(e, req, resp);
}
}
protected void handleError(RuntimeException e, HttpServletRequest req, HttpServletResponse resp) {
// Error handling logic goes here
}
protected void doGetInternal(HttpServletRequest req, HttpServletResponse resp);
}
And then your actual servlet:
public class MyServlet extends MyServletBase {
#Override
protected void doGetInternal(HttpServletRequest req, HttpServlet resp) {
// Actual servlet logic here
}
}
This is a rough sketch off the top of my head with no reference to the Javadoc so may not have the method signatures perfect but hopefully you get the idea.
It also has the advantage that if you ever need to add extra error handling logic to a derived servlet and you don't want to change the base servlet for whatever reason you can just override the handleError() method which is not something you can so easily do when using Tomcat's exception handler mechanism

Java EE / Struts Exception Handling

I have started developing Java EE web applications mainly on Struts and Servlets. Most of the codes have a try catch block within Servlet or Struts Action class.
Is it a must to have try catch block for every servlet or action? The only advantages I saw with this kind of code template is stacktrace are log to application specified logging framework such as log4j.
If the runtime exception floats up, it will be printed on the server (Tomcat / Glassfish / Weblogic) logs instead.
public class HelloWorldAction extends Action{
public ActionForward execute(ActionMapping mapping,ActionForm form,
HttpServletRequest request,HttpServletResponse response)
throws Exception {
try {
// do all the processing here
} catch (Exception e) {
// log all exceptions
}
}
}
public class HelloWorldExample extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
try {
// do all the processing here
} catch (Exception e) {
// log all exceptions
}
}
}
Catching Exception is almost never what you really want to do. Hopefully it's obvious that it's not mandatory to always have a try/catch block–it depends on what the underlying code is doing, and how you want to handle any exceptions it may throw.
Catching Exception eliminates the ability to use Struts' declarative exception handling.
I would recommend against using a filter to handle exceptions in Struts 1 since it already has a mechanism built in. If there are exceptions at the framework level they'll be displayed anyway, and they generally indicate a development, not runtime, issue.
I echo Andrea's sentiments: unless you have a Very Good Reason, learning Struts 1 isn't useful. Consider instead Struts 2 or Spring MVC for "traditional" framework development, or Play, Grails, JRuby on Rails, etc. for a more modern approach.
If you are looking for one place to do exception logging, you can create ServletFilter:
public class ExceptionLoggerFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) {
try {
filterChain.doFilter(req, res);
}
catch(Exception e) { // Log exception }
}
}
You shouldn't really have to catch exceptions everywhere unless you want to handle that particular exception in a special way. Most of the time it's just noise getting in the way for the "real" code. The important thing is that you log the exception and enough context information that you can figure out what caused the error. To the user, you should probably just display a general error page.
You can specify global exception in struts-config.xml. It catches unhandled exceptions all over the application.
You need to implement your own ExceptionHandler class. Then write code what to want to do.
4.5 Exception Handler
http://www.jajakarta.org/struts/struts1.2/documentation/ja/target/userGuide/building_controller.html

UncaughtExceptionHandler on Google App Engine Java

I would like to do some custom logic anytime there is an uncaught exception in my application. Normally I would do something like:
Thread.setDefaultUncaughtExceptionHandler(myCustomHandler);
However, Thread is locked down on Google App Engine. The above code raises a security exception. Is there anyway to achieve similar functionality on Google App Engine?
EDIT: I have implemented my approach as a Servlet Filter. My experience with Java web programming is fairly limited. Can someone comment on such an approach? Since all requests in AppEngine originate as HTTP requests, I think this is a comprehensive solution.
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (RuntimeException ex) {
// Work my magic here...
throw ex;
}
}
Servlets handle threads on their own so you should not mess with it in this way.
Instead, install a servlet Error Handler:
<error-page>
<error-type>com.package.YourException</error-type>
<location>/errors/handler</location>
</error-page>
then have /errors/handler map to servlet that handles the error and returns the appropriate response.

Categories

Resources