Showing posts with label servlet error handling. Show all posts
Showing posts with label servlet error handling. Show all posts

Tuesday, March 29, 2011

Chapter 28: The setStatus Method

In the previous chapter, we saw the sendError method. We saw how Tomcat implements it and we saw a wrapper method that used it but did some handling for custom error messages. Well, in this chapter, we are going to see the twin brother of the sendError method, the setStatus method.

So, lets get started…

The setStatus Method

The setStatus method sets the status code for a given response. Use this method, instead of sendError, when there is no exception or serious error (such as a blocked or a page inaccessible to the user). If there is a serious error, the sendError method should be used; otherwise use setStatus. Like the sendError method, using this method clears the buffer, but leaves cookies and other headers unmodified.

Let us now take a look at how Tomcat has implemented the setStatus method.

Code:

/**
* Set the HTTP status and message to be returned
* with this response.
*
* @param status The new HTTP status
* @param message The associated text message
*
* @deprecated As of Version 2.1 of the Java Servlet
* API, this method has been deprecated due to the
* ambiguous meaning of the message
* parameter.
*/
public void setStatus(int status, String message) {

if (included)
return; //Ignore any call from included servlet

this.status = status;
this.message = message;

}

As you can see in the code above, this method has been deprecated because the message functionality isn't reliable. The setStatus method will remain (the one taking only a status code), but without a message parameter in a future version, Maybe.

However, you can always write a wrapper to use the setStatus method effectively. (Just like we did for the sendError method)

Code:

/**
* statusManager Method.
*/
void checkCarStatus(HttpServletResponse response)
throws ServletException
{
if( !isValid(carName) )
{
response.setStatus(response.SC_BAD_REQUEST);
} else if( !isValid(carModel) )
{
response.setStatus(response.SC_BAD_REQUEST);
} else if( !isValid(carMakeYear) )
{
response.setStatus(response.SC_BAD_REQUEST);
} else if( !isValid(creditCardNumber) )
{
response.setStatus(response.SC_BAD_REQUEST);
} else
{
response.setStatus(response.SC_OK);
}
}

The code above is pretty straight forward. I suppose this can be used in a car repair garage. We first check if the cars name is valid and then check if the cars model is valid and then check its manufacture year. We also check the credit card number of the customer (because we need to get paid right) and if all these are valid, we set a OK response, else we set a bad request response. It's a simple implementation and you can alter it anyway you want, as long as it serves your purpose and uses the setStatus method, we are good…

The same status codes that are used for the sendError method can be used for the setStatus method, too. The primary difference is that the former prevents any further response to the client and throws an exception if you try. This is not so for the latter. There is one point of confusion with the setStatus method. The specification says the buffer is cleared when called. In other words, you should set this first before you send anything back to the client. However, I looked in Tomcat and did not observe the buffer being cleared. The following snippet:

out.println("pre setStatus message.");
response.setStatus(HttpServletResponse.SC_OK);
out.println("post setStatus message.");

produced this:
pre setStatus message.
post setStatus message.

Exam Trivia:
Containers don't always follow the specifications! As you can see, Tomcat does not clear the buffer as the specification says. The specification doesn't make sense as of this moment because, the way Tomcat implemented it is better. However, since other containers may follow the specification here and the exam will be based on the specification, assume that is how it actually works.

Previous Chapter: Chapter 27 - sendError Method

Next Chapter: Chapter 29 - WebApp Log

Chapter 27: The sendError Method

In the chapter on introduction to Servlet Exception Handling, we have used the term, use the sendError method and in the previous chapter, we saw an example that actually used this method. This chapter is dedicated solely for the purpose of explaining the features of this method and how to use it effectively.

So, lets get started!!!

The sendError Method

The sendError method sends an error response to the client using the specified status (Remember the bunch of status codes we saw in one of the previous chapters?). Using this method clears the buffer. The server creates an HTML-formatted server error page. This page contains a default, or the message you provide, as an argument. It also sets the content type to “text/html”, even if you changed this, but leaves cookies and other headers unmodified.

Exam Trivia:
We cannot or rather should not send data to a client after the sendError() method is invoked. Once this method is invoked, all the buffered output will be discarded. If data has been written to the response buffer but not yet returned to the client (i.e., response not committed), the data is cleared and replaced with the data sent by the sendError() method. Data written to the response after the sendError() is called is ignored. However, if you write data to the response buffer and try to commit it after the sendError is invoked, an IllegalStateException will be thrown.
Be cautious and watch out for code that does exactly this in the exam question. It may look legit but it will throw an exception and you may overlook the exception choice in the answer.

The sendError method will set the appropriate headers and content body for an error message to return to the client. An optional String argument can be provided to the sendError method, which can be used in the content body of the error. Using this method will commit the response (if not already committed) and terminate it. The data stacked in the output stream to the client before calling sendError() method is ignored.

Internally, the servlet base classes prevent you from writing to the output stream after calling sendError(). In the write-to-stream methods there is a test for a previous error in the servlet that looks like this:

//suspended is a flag set once output is committed
if (suspended)//true if sendError has been called
throw new IOException
(sm.getString("responseBase.write.suspended"));

That is why you can't add to the outputstream after calling sendError().
The best way to understand the sendError() method is to look at it directly. Lets take a look at some sample code that will help us do just that.

Code: This is the actual code implementation of how Tomcat implements the sendError method.

/**
* Send an error response with the status and message.
*
* @param status HTTP status code to send
* @param message Corresponding message to send
*
* @exception IllegalStateException if this response has
* already been committed
* @exception IOException if an input/output error occurs
*/
public void sendError(int status, String message)
throws IOException
{
if (isCommitted())
throw new IllegalStateException
(sm.getString("httpResponseBase.sendError.ise"));

if (included)
return; //Ignore any call from an included servlet

setError();

// Record the status code and message.
this.status = status;
this.message = message;

// Clear any data content that has been buffered
resetBuffer();

// Cause the response to be finished
// (from the application perspective)
setSuspended(true);
}

If you observe the code above, the first thing it does is, throw an IllegalStateException if the response was already committed. Then it returns from the method if it is not invoked by the outermost servlet. The next thing it does is, call the setError method which updates an internal flag. Then it updates the status and message fields. These two fields are of most importance to us. Then it clears the buffer and finally suspends any further output stream access.

You can make better use of this method if you create a wrapper for it. You might want to do this if you care to send custom messages to the client rather than accept the default ones provided by the container.

Below is code for a sample wrapper that can be used for sending custom messages instead of using the default one.

Code:

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import java.io.PrintWriter;
import java.io.IOException;

public class ErrorHandlingServlet extends HttpServlet
{
//your own custom flag:
static final int SC_CUSTOM_ERROR_FIRST_NAME = 3229;

public void sendError(HttpServletResponse response,
int code)
throws ServletException, IOException
{
// Message sent by sendError().
String message = getErrorMessage(code);

if(message.equals("NONE"))
{
response.sendError(HttpServletResponse.SC_ FORBIDDEN);
} else
{
response.sendError(HttpServletResponse.SC_ FORBIDDEN,
message);
}

//update your own log
//logError(code, message);
}

public String getErrorMessage(int code)
{
String message = "NONE";
switch (code)
{
case HttpServletResponse.SC_OK:
return ("OK");
case HttpServletResponse.SC_ACCEPTED:
return ("Accepted");
case HttpServletResponse.SC_BAD_GATEWAY:
return ("Bad Gateway");
case HttpServletResponse.SC_BAD_REQUEST:
return ("Bad Request");
case HttpServletResponse.SC_CONFLICT:
return ("Conflict");

//There are a lot more codes.
//Just put a few for example

//first custom message; overrides the default message
case HttpServletResponse.SC_GONE:
return ("Sorry, this resource +
"is not available any more.");
case
HttpServletResponse.SC_HTTP_VERSION_NOT_ SUPPORTED:
return ("Hey! You are doing something Hinky" +
" and we do not support it.");
case HttpServletResponse.SC_INTERNAL_SERVER_ERROR:
return ("I Have no clue as to what happened, but it "
"was a bad server error");
case HttpServletResponse.SC_MOVED_PERMANENTLY:
return ("This Page has moved For good"
"permanently!");
// You can add a lot more custom error messages and provide
// handling for it.
default:
return ("NONE");
}
}
}


Previous Chapter: Chapter 26 - Returning an Error Code to the Client

Next Chapter: Chapter 27 - setStatus Method

Monday, March 28, 2011

Chapter 26: Returning an Error Code to the Client

In the previous chapter, we learnt what the error codes are and what they signify. We also saw an introduction to servlet exception handling. Before we get any further on this topic of exception handling, we need to know how to send error codes to the browser. That is exactly what we are going to learn now.

So, lets get started!!!

Returning an Error Code to the Client

The servlet is just as prone to logic errors and bugs as standalone applications. Java has a smart facility for handling them in both environments. Let's look at a very simple example of how you might handle an error in a servlet. The TestErrorServlet servlet illustrates the use of the sendError() method. It takes an error code as a parameter and an optional custom message associated with that error

Source Code:

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletException;
import java.io.PrintWriter;
import java.io.IOException;

public class TestErrorServlet extends HttpServlet {

public void service(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {

response.sendError(HttpServletResponse.SC_FORBIDDEN,
"Sorry, restricted to Authorized Personnel.");
}
}

Compile the TestErrorServlet file and hit the servlet with your browser.
The container will send an error message to the client. You should see a page that looks like below.


Previous Chapter: Chapter 25 - Introduction to Servlet Exception Handling

Next Chapter: Chapter 27 - sendError Method

Chapter 25: Introduction to Servlet Exception Handling

Any technology, any programming language you learn, exception handling is an integral part of it. And the SCWCD exam covers topics related to Exception Handling in the Servlet Technology as well. Though, there are numerous ways of customized error handling available with servlets, the exam covers two main topics. Using the SENDERROR and SETSTATUS.

That is exactly what we are going to learn in this chapter and the next few chapters too.

So, lets get started!!!

Introduction to Servlet Exception Handling:

The way in which you create and manage exceptions in servlets is slightly different from how you do this with standalone applications.

We always use the response object (HttpServletResponse) and not the request object, to tell the browser that there is a problem.

The exam includes both exceptions (The ones caused by the Servlet) and HTTP Error Codes (Those you send back to the client).

Before we jump into the world of exceptions, lets quickly review the HTTP Protocol standards. This is essential because, the servlets communicate with clients using HTTP and it is helpful to know a little about this protocol.

The HTTP Protocol:

The HTTP protocol is a request/response scheme where a client sends a request to the server. There are four major portions of this request, which include, a request method (GET, POST…), URI (such as www.abc.com), protocol version (HTTP/1.1), and finally a MIME-like message. This message can be any size, and normally includes request modifiers, client information, and body content.

In this series of chapters, we will learn how we can send error information to the client using the sendError method, which sends a status line with the protocol version and a success or error code. It also returns a MIME like message containing server information, entity meta information and body content. You must remember that both the severity and type of error to properly tell the client what went wrong. Your error handling logic needs to determine the most appropriate severity for a particular error.

After receiving a request, the server responds. It returns an HTTP response message. The first line of this response message is called the status line. The status line has three parts. They are, in this order, protocol version, numeric status code, and status textual phrase. This status code is what you are setting when you use sendError and setStatus methods.

The Error Codes:

If you have been using the internet and J2EE applications for a while, you are sure to have encountered the 404: PAGE NOT FOUND message at some websites. This tells you that the URL is bad. i.e., if you try login to www.thisissurelyanincorrectwebsite.com you will probably get this message. The emphasis is on the number 404, this is the status code, a 3 digit integer number. The first digit defines the class of response, while the last two digits do not have any categories; they give an indication of what the problem is.

Let us now take a look at all the error codes that we can encounter in a HTTP based J2EE system. This list just contains the broad categorization based on the 1st digit.

Number Type Description
1XX Informational Request received, continuing to process.
2XX Success The action was successfully received, understood, and accepted.
3XX Redirection Further action must be taken in order to complete the request.
4XX Client Error The request contains bad syntax or cannot be fulfilled.
5XX Server Error The server failed to fulfill an apparently valid request.
While, the above table describes five set of status codes, we will primarily focus on the Server Error Category – the 5XX codes.

As mentioned previously, the HTTP protocol is a request/response scheme where a client sends a request to the server. When you need to inform the client of a problem at the server end, you call the sendError method. This causes the server to respond with a status line, with protocol version and a success or error code (this is what sendError affects directly). Of course, it also returns a MIME-like message containing server information, entity meta information, and body content.

Actually, the sendError() and setStatus are closely related. In fact, they both set the error message to be displayed by the client and the status code used by the client. The default status code is HttpServletResponse.SC_OK ="OK"; however, there are a few other standard codes as well.
That being said, lets take a look at the list of status codes available. These codes were defined by the W3C and are sanctioned by the Internet Society (ISOC). The constant names, quoted messages that get displayed in the browser, and code descriptions are a combination of the servlet specification and Tomcat's implementation of that specification. The exam will not test your memory of these directly. However, taking five minutes to study this table will help you understand what these codes do and figure out which ones you need to use with the sendError and setStatus methods. Notice that the RFC column provides the Request For Comment document and section, the Internet's way of documenting standards. Also, some browsers allow the user to hide “friendly” error messages. If they do that, they will not see many of these errors, even if they occur.

Code Constant RFC Message Description
100 SC_CONTINUE 10.1.1 “Continue” Client can continue.
101 SC_SWITCHING_PROTOCOLS 10.1.2 “Switching Protocols” Server is switching protocols according to Upgrade header.
200 SC_OK 10.2.1 “OK” Request succeeded normally.
201 SC_CREATED 10.2.2 “Created” Request succeeded and created a new resource on the server.
202 SC_ACCEPTED 10.2.3 “Accepted” Request was accepted for processing but was not completed.
203 SC_NON_AUTHORITATIVE_INFORMATION 10.2.4 “Non-Authoritative Information” Meta information presented by the client did not originate from the server.
204 SC_NO_CONTENT 10.2.5 “No Content” Request succeeded but there was no new information to return.
205 SC_RESET_CONTENT 10.2.6 “Reset Content” Agent should reset the document view which caused the request to be sent.
206 SC_PARTIAL_CONTENT 10.2.7 “Partial Content” Server has fulfilled the partial GET request for the resource.
300 SC_MULTIPLE_CHOICES 10.3.1 “Multiple Choices” Requested resource corresponds to any one of a set of representations with each with its own specific location.
301 SC_MOVED_PERMANENTLY 10.3.2 “Moved Permanently” Resource has permanently moved to a new location and future references should use a new URI with their requests.
302 SC_MOVED_TEMPORARILY 10.3.3 “Moved Temporarily” Resource has temporarily moved to another location but future references should still use the original URI to access the resource.
303 SC_SEE_OTHER 10.3.4 “See Other” Response to the request can be found under a different URI.
304 SC_NOT_MODIFIED 10.3.5 “Not Modified” Conditional GET operation found that the resource was available and not modified.
305 SC_USE_PROXY 10.3.6 “Use Proxy” Requested resource must be accessed through the proxy given by the Location field.
307 SC_TEMPORARY_REDIRECT 10.3.8 N/A Requested resource resides temporarily under a different URI. The temporary URI should be given by the Location field in the response.
400 SC_BAD_REQUEST 10.4.1 “Bad Request” Request sent by the client was syntactically incorrect.
401 SC_UNAUTHORIZED 10.4.2 “Unauthorized” Request requires HTTP authentication.
402 SC_PAYMENT_REQUIRED 10.4.3 “Payment Required” Reserved for future use.
403 SC_FORBIDDEN 10.4.4 “Forbidden” Server understood the request but refused to fulfill it.
404 SC_NOT_FOUND 10.4.5 “Not Found” Requested resource is not available.
405 SC_METHOD_NOT_ALLOWED 10.4.6 “Method Not Allowed” Method specified in the Request-Line is not allowed for the resource identified by the Request-URI.
406 SC_NOT_ACCEPTABLE 10.4.7 “Not Acceptable” Resource identified by the request is only capable of generating response entities that have content characteristics not acceptable according to the accept headers sent in the request.
407 SC_PROXY_AUTHENTICATION_REQUIRED 10.4.8 “Proxy Authentication Required” Client must first authenticate itself with the proxy.
408 SC_REQUEST_TIMEOUT 10.4.9 “Request Timeout” Client did not produce a request within the time that the server was prepared to wait.
409 SC_CONFLICT 10.4.10 “Conflict” Request could not be completed due to a conflict with the current state of the resource.
410 SC_GONE 10.4.11 “Gone” Resource is no longer available at the server and no forwarding address is known. This condition should be considered permanent.
411 SC_LENGTH_REQUIRED 10.4.12 “Length Required” Request cannot be handled without a defined Content-Length.
412 SC_PRECONDITION_FAILED 10.4.13 “Precondition Failed” A precondition given in one or more of the request-header fields evaluated to false when it was tested on the server.
413 SC_REQUEST_ENTITY_TOO_LARGE 10.4.14 “Request Entity Too Large” Server is refusing to process the request because the request entity is larger than the server is willing or able to process.
414 SC_REQUEST_URI_TOO_LONG 10.4.15 “Request URI Too Long” Server is refusing to service the request because the Request-URI is longer than the server is willing to interpret.
415 SC_UNSUPPORTED_MEDIA_TYPE 10.4.16 “Unsupported Media Type” Server is refusing to service the request because the entity of the request is in a format not supported by the requested resource for the requested method.
416 SC_REQUESTED_RANGE_NOT_SATISFIABLE 10.4.17 “Requested Range Not Satisfiable” Server cannot serve the requested byte range.
417 SC_EXPECTATION_FAILED 10.4.18 “Expectation Failed” Server could not meet the expectation given in the Expect request header.
500 SC_INTERNAL_SERVER_ERROR 10.5.1 “Internal Server Error” Error inside the server which prevented it from fulfilling the request. This error represents many server problems such as exceptions or perhaps a database hiccup.
501 SC_NOT_IMPLEMENTED 10.5.2 “Not Implemented” Server does not support the functionality needed to fulfill the request.
502 SC_BAD_GATEWAY 10.5.3 “Bad Gateway” Server received an invalid response from a server it consulted when acting as a proxy or gateway.
503 SC_SERVICE_UNAVAILABLE 10.5.4 “Service Unavailable” Server is temporarily overloaded and unable to handle the request.
504 SC_GATEWAY_TIMEOUT 10.5.5 “Gateway Timeout” Server did not receive a timely response from the upstream server while acting as a gateway or proxy.
505 SC_HTTP_VERSION_NOT_SUPPORTED 10.5.6 “HTTP Version Not Supported” Server does not support or refuses to support the HTTP protocol version that was used in the request message.
Let me repeat, you need not memorize these status codes but knowing them would be useful to understand the servlet exception handling concepts.

Previous Chapter: Self Test - Chapters 20 to 24

Next Chapter: Chapter 26 - Returning Error Codes
© 2013 by www.inheritingjava.blogspot.com. All rights reserved. No part of this blog or its contents may be reproduced or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, or otherwise, without prior written permission of the Author.

ShareThis

Google+ Followers

Followers