Autenticação de Usuários (Filter/Servlet)

Olá, tudo bem?

Vamos falar hoje sobre como controlar autenticações de usuário de modo manual? Para fazermos isso, iremos utilizar uma ferramenta do Java bastante simples e poderosa – Filtro (Filter). Será usado como base o código desenvolvido nos outros post sobre Web Applications: Criando um WebServer, Tratando Exceções.

Vou colocar abaixo o código (resumido) que iremos utilizar, será um arquivo do tipo Servlet, dois arquivos JSPs e o arquivo web.xml (apenas com esses arquivos conseguiremos colocar o Filtro em uso). Caso tenha problemas em apenas criar um projeto web com o código abaixo, olhe esse link que mostra um passo a passo: Criando um WebServer (com esses três arquivos você já será capaz de iniciar um webserver e navegar).
Nosso projeto se chama Servlet. O arquivo web.xml ficará dentro da pasta WebContent/WEB-INF

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
    <display-name>Servlet</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>  
    </welcome-file-list>
  
    <servlet>
        <servlet-name>hello</servlet-name>
        <jsp-file>/index.html</jsp-file>
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>final</servlet-name>
        <servlet-class>com.Servlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>final</servlet-name>
        <url-pattern>/mathit</url-pattern>
    </servlet-mapping>     
</web-app>

Código do arquivo com.Servlet.java

package com;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Servlet extends HttpServlet {
    public void doPost(HttpServletRequest req, HttpServletResponse res)    throws ServletException, IOException {
        int value1;
        int value2;
        int total = 0;
        String name = (String) req.getParameter("name");
        String warning = "";
        
        try {
            value1 = Integer.parseInt((String) req.getParameter("value1"));
            value2 = Integer.parseInt((String) req.getParameter("value2"));
        } catch (NumberFormatException e) {
            value1 = 0;
            value2 = 0; 
            warning = "We got some bad value(blank or non numerics values, we set 0 instead";
        }
        
        req.setAttribute("name", name);
        req.setAttribute("warning", warning);
        
        total = value1 + value2;
        
        req.setAttribute("total", total);
        
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("/WEB-INF/show.jsp");
        
        requestDispatcher.forward(req, res);
    }
}

Código do arquivo /WebContent/index.html

<html>
    <body>
        <form action="/Servlet/mathit" method="post">
            <h1>Hello</h1>
            Type your name: <input type="text" name="name"/> <br/><br/>
            Lets do some math?<br/>
            Type the first value to be added: <input type="text" name="value1"/> <br/>
            Type the second value to be added: <input type="text" name="value2"/> <br/><br/>
            <input type="submit" value="Do some math"/>
        </form>
    </body>
</html>

Código do arquivo /WebContent/WEB-INF/show.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <body>
        Thanks ${name} for passing by. <br/>
        The total is: ${total}. <br/>
        
        <br/>${warning}
    </body>
</html>

Para acessar, basta iniciar o Tomcat e acessar pelo endereço: http://localhost:8080/Servlet/hello.

O Filtro é uma classe do Java que pode interceptar as requisições feitas, apenas por mapear um padrão de requisição (URL, Servlet, etc…). Para começar, vamos criar uma classe de filtro e colocá-la para trabalhar.
O código da nossa classe filtro ficará assim:

package com;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * Servlet Filter implementation class UserCheckFilter
 */
public class UserCheckFilter implements Filter {
    /**
     * @see Filter#init(FilterConfig)
     */
    public void init(FilterConfig fConfig) throws ServletException {
    }

    /**
     * @see Filter#destroy()
     */
    public void destroy() {
    }

    /**
     * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        System.out.println("Hello World");
        
        chain.doFilter(request, response);
    }
}

Note que o método init e destroy pertencem à interface Filter e devem ser implementados. Estamos apenas exibindo “Hello World” para certificar que nosso filtro esteja correto e funcionando.

Temos agora que adicionar as seguintes tags ao arquivo web.xml:

<filter>
    <filter-name>UserCheckFilter</filter-name>
    <filter-class>com.UserCheckFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>UserCheckFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Explicando as tags: “url-pattern” define a url que estaremos mapeando, e em nosso caso estamos capturando qualquer url que for solicitada. “filter-name” define o nome do filtro mapeado que será acionado. O “filter-class” é a nossa classe Java que já foi criada.

Inicie o Tomcat e acesse pelo link: http://localhost:8080/Servlet/hello (caso você tenha problemas em visualizar a página, visite o primeiro post para tirar suas dúvidas: Criando um WebServer)
Olhe no console e veja que a nossa mensagem irá aparecer lá.
Hello World Screen

Com nosso filtro em pleno funcionamento, vamos criar uma classe de usuário. Um POJO simples, contendo nome do usuário e senha. Nossa classe ficará assim:

package com;

public class User {
    private String name = "UNKNOW";
    private String password = "UNKNOW";
    
    public User(String name, String password){
        this.name = name;
        this.password = password;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

Precisamos de um Servlet para fazer a validação de quem está acessando nosso servidor, vamos criá-lo de modo que valide nome/senha do usuário. Vamos criar nosso Servlet com um método para fazer essa validação (não vamos entrar em detalhes de patterns no momento).

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class UserValidator extends HttpServlet {
    private static final Map users = getUsers();
    
    /**
     * Creates valid users 
     * 
     * This User Map could be users returned from a database
     * or a simple select with the user.name
     * 
     * @return a Map of valid users
     */
    private static Map getUsers() {
        Map users = new HashMap();
        
        User userOne = new User("one","one");
        User userTwo = new User("two","TWO");
        
        users.put(userOne.getName(), userOne);
        users.put(userTwo.getName(), userTwo);
        
        return users;
    }

    public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        doPost(req, res);
    }

    public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        RequestDispatcher rd;
        String name = req.getParameter("name");
        String password = req.getParameter("password");
    
        User user = validateLogin(name, password);
        
        if (user == null){
            rd = req.getRequestDispatcher("/loginError.jsp");
        }
        else{
            HttpSession session = req.getSession();
            session.setAttribute("user", user);
            rd = req.getRequestDispatcher("/loginSuccess.jsp");
        }
        
        rd.forward(req, res);
    }

    /**
     * Validate the entered data
     * 
     * If there is no valid data, the method will return null
     * 
     * @param name given at the jsp
     * @param password given at the jsp
     * @return a user if one was found and validated
     */
    private User validateLogin(String name, String password) {
        // All parameters must be valid
        if (name == null || password == null){
            return null;
        }
        
        // Get a user by key
        User user = users.get(name);
        
        if (user == null){
            return null;
        }
        
        // Check if the password is valid
        if (!user.getPassword().equals(password.trim())){
            return null;
        }
        
        return user;
    }
}

O Map “users” e a função “getUsers” existem apenas para gerar usuários válidos. Caso nosso usuário não tenha seus dados válidos o método “validateLogin” retorna o valor null. Dependendo dos dados fornecidos pelo usuário, caso válido ele será redirecionado para a página de sucesso, caso contrário, irá para a página de erro.

Precisamos alterar o arquivo “web.xml” e adicionar o mapeamento do Servlet que acabamos de criar:

<servlet>
    <servlet-name>userValidator</servlet-name>
    <servlet-class>com.UserValidator</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>userValidator</servlet-name>
    <url-pattern>/userValidator</url-pattern>
</servlet-mapping>

Vamos criar 3 arquivos do tipo JSP, para: login, erro no login e login com sucesso:
/WebContent/login.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title>Login</title>
    </head>
    <body>
        <form action="/Servlet/userValidator" method="post">
            Name: <input type="text" name="name"/>
            Password: <input type="password" name="password"/>
            <input type="submit" value="LogIn"/>
        </form>
    </body>
</html>

/WebContent/loginError.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title>Error</title>
    </head>
    <body>
        Wrong user/password
    </body>
</html>

/WebContent/loginSuccess.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title>Success</title>
    </head>
    <body>
        You have loged in.
    </body>
</html>

Precisamos alterar agora nosso Filtro. Essa será a alteração mais delicada, pois será nosso filtro que irá definir se nosso usuário pode continuar em sua requisição ou não.

package com;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * Servlet Filter implementation class UserCheckFilter
 */
public class UserCheckFilter implements Filter {
    private String LOGIN_ACTION_URI;
    
    /**
     * @see Filter#init(FilterConfig)
     */
    public void init(FilterConfig fConfig) throws ServletException {
        LOGIN_ACTION_URI = fConfig.getInitParameter("loginActionURI");
    }

    /**
     * @see Filter#destroy()
     */
    public void destroy() {
    }

    /**
     * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpSession session = req.getSession();
        User user = (User) session.getAttribute("user");
        
        if (user == null && !LOGIN_ACTION_URI.equals(req.getRequestURI())){
            RequestDispatcher rd = req.getRequestDispatcher("/login.jsp");
            rd.forward(request, response);
            return;
        }
        
        chain.doFilter(request, response);
    }
}

Alguns detalhes sobre o código acima: “req.getSession()” – retorna a sessão do usuário, mas caso não tenha nenhuma sessão o próprio container fica encarregado de criar uma. Buscamos dentro da sessão o objeto usuário, em nosso servlet ao efetuar o login um objeto do tipo User é inserido na sessão. Caso não exista um objeto do tipo User na sessão, o valor retornado é null e com isso direcionamos o usuário para a tela de login. Note também que temos um atributo LOGIN_ACTION_URI que é retornado das configurações do filtro, ele será configurado daqui a pouco no arquivo web.xml. O atributo LOGIN_ACTION_URI existe para caso o usuário esteja tentando realizar a validação ele possa chegar ao nosso Servlet de validação de usuário, caso esse atributo não existisse, não seria possível realizar o login pois o objeto User nunca seria adicionado à sessão.

Falta agora colocar o parâmetro de inicialização do filtro no arquivo web.xml:

<filter>
    <filter-name>UserCheckFilter</filter-name>
    <filter-class>com.UserCheckFilter</filter-class>
    <init-param>
        <param-name>loginActionURI</param-name>
        <param-value>/Servlet/userValidator</param-value>
    </init-param>
</filter>

Ao acessar o link http://localhost:8080/Servlet/hello, o usuário será redirecionado para a página de login. Após digitar um usuário/senha que sejam válidos, ele terá sua sessão validada. E não será mais necessário realizar essa validação.

Caso tenha alguma dúvida/colocação a fazer, basta postar.

Até a próxima.

Clean Code – Part 04

Hello, how are you? To make our code cleaner, let’s keep the study about Clean Code? The others articles you will find here: Part OnePart TwoPart Three.

Today the subject will be Constants and Exceptions.

  • Constants name pattern – The Constant name has its name written with high caps “COLOR”; and will receive “_” when is a composite name “OWN_GOAL”. You don’t have to start a Constant name with “_” because there is no need for it; this was a name pattern created, in another development language, to make distinct the methods of the attributes.
  • Constants name should explain its use – A Constant gets clear thanks to its name which must be objective. Constants name must be understandable wherever it’s placed. Imagine you got a Constant used to log messages, if we just name it as LOG it would not be a clear name as LOGGER. There is a difference in the meaning of the words, LOG is “something” created and LOGGER is the creator. Wherever the LOGGER name is, we always will understand its usability.
  • When Constants are needed – We always should be looking for repetitions in our code. Always that we repeat an action or value there is something wrong happening. Image we have a method that modifies soccer game score:
    public void changeScore(Team team, int goal){
        this.fullScore(team, gol);
    }

    And this method is invoked by other method to register an own goal:

    public void recordOwnGoal(Team team){
        match.changeScore(team, -1);
    }

    Imagine if every time we have to inform an own goal to any method, if we have to write the “-1”, by example: “registerToPlayerAGoal (player, “-1”)”; Why we don’t create a Constant? In this soccer sample, creating a Constant we will be able to eliminate a method. Let’s see our final code:

    //Our declared Constant in the Match class.
    public static final int OWN_GOAL = -1;
    
    public void changeScore(Team team, int goal){
        this.fullScore(team, goal);
    }

    Notice that we don’t have the need of a method to register only the own goal (recordOwnGoal), this method was created only to pass the value of an own goal as negative. When we invoke the method that will change the game score (changeScore) we just have to put the “OWN_GOAL” as parameter instead creating a method just to do that (  changeScore(team, OWN_GOAL);  ). By example, Constants are welcome in templates building: “ADD_SIMPLE_INDENT”, “ADD_DOUBLE_INDENT”, and others. Just notice: “Do you have to pass the same value? It’s time to use Constants”.

  • There is a reason. Why does this exception exist? – When we create a catcher for an exception we must pay attention to the reason of that exception it’s been thrown. We must keep in mind that if a method throws an exception we must handle it. We must be prepared to give the best treatment to the exception. Some ways of doing a good handling it would be: show to the user (exception that were handled), handle unfinished actions (files, databases transactions, log, etc).
    When we ignore an exception, by do not working with the Exception object, we are disrespecting the method contract that may result in problems to the user and to the application.
  • Exception that it’s declared, but it’s impossible to happen? Once I was working in a software by refactoring a method, to adapt it to a new customer request, and when I was testing my code it did not worked but it did not failed either. Even after review my code I didn’t find any error, it was ok.
    What did I do to find what was happening? Debug!
    When I was checking the code in runtime, I found the following code:

    //...
    validateCreditCard(creditCard);
    //...
    }catch(CreditCardInUseException){
        //Impossible to get here
    }

    When the validate credit card was created it was impossible of it been in use, that’s why there was a comment saying that it was impossible to get there. We can see two possible aspects that we could change:

    1. Non cohesion method – notice that sometimes the method to validate the credit card throws an exception and sometimes it doesn’t; there is inside its method a business rule that make its behavior to change, this behavior changing will define how the method signature will be handled (future talk about OO). A good solution to this issue it would be splitting this method instead keeping all this rules in one method; this method it’s too complicated and has too much decisions in it.
      If an exception it’s declared, this exception must be handled and in our case – when the code was created – it was impossible of that exception to be thrown. If there is a method that declares an exception that will never happen, there is something wrong!
    2. If an exception it’s been thrown, there is a reason for this exception to exist. Notice that if the exception were handled, at least, with “System.out.println ();” it would have a message to notify that error. When I say “at least”, it’s because we can handle an exception by a lot of different ways like send an email, record a log, etc. Something was happening, an exception was thrown, but there wasn’t anything to take care of it. Remember: “If a method declares an exception, there is a reason for it and it should be handled”.
  • Straight error message – when you write an error message avoid thinking like: “I will put the message like this, it’s clear that we are talking about this subject”. Are you sure about this? The user does not think as a developer, he does not need to know that a value X come from screen Y and it is needed to Z screen.
    When you do not know the best message for that situation, try looking at the screen and forgetting everything you know about it and think: “If I were someone that didn’t know anything about development, how I would understand this error message?” Make changes to this question and adapt it to what you are developing, change your way of thinking, and keep your focus on the user. Another good thing to do is ask some coworker to give an opinion.
  • Avoid some exception error messages when developing – When you write an exception message, even in a test environment, avoid some messages like: “Can’t you see that it’s by your fault that this error happened!” or “Hey loser, type something here!” Sometimes it is fun to see those types of messages; or it can give us some relieve to see that our code reached there, but doing this is very dangerous. Imagine if this message stays in the code and goes to the client? Even if those messages bring us some kind of happiness, it’s better to avoid it.
  • Log4J – It’s a good tool that can be useful if you want to log your exception. With this library it is possible to log messages in different event levels and more. I will write a tutorial about it very soon, until there here it goes a link that might help you to study it: http://www.developer.com/open/article.php/10930_3097221_3/Logging-with-log4jmdashAn-Efficient-Way-to-Log-Java-Applications.htm.

I hope these tips might help you.
See you guys later.

Código Limpo – Parte 04

Olá, tudo bem? Para melhorar nosso código, vamos continuar o estudo sobre código limpo? Os outros artigos estão aqui: Parte UmParte DoisParte Três.

Hoje será abordado Constantes e Exceptions.

  • Formato do nome – A constante tem seu nome escrito em caixa alta “COR”; e separado por “_” quando é um nome composto: “GOL_CONTRA”. Não começar com “_” pois não existe necessidade, essa técnica era utilizada em outras linguagens para diferenciar método de atributo.
  • Nome define o uso – Uma constante fica clara graças ao se nome, que deve ser objetivo. Ela deve ser entendível onde quer que seja utilizada. Caso você tenha uma constante de log, por exemplo, utilizando apenas LOG como nome não seria tão claro como LOGGER. A diferença é clara quanto à própria definição da palavara, LOG é algo gerado e LOGGER é quem gera. Não importa onde esteja o nome LOGGER, sempre conseguiremos entender a função dessa constante.
  • Quando constantes são necessárias – Devemos sempre estar atentos quanto a repetições. Sempre que estamos repetindo uma ação ou valor tem algo errado acontecendo. Vamos supor que temos um método que altera o placar em uma partida de futebol:
    public void changeScore(Team team, int goal){
        this.fullScore(team, gol);
    }

    E esse método é utilizado da seguinte forma para registrar um gol contra:

    public void recordOwnGoal(Team team){
        match.changeScore(team, -1);
    }

    Imagine toda vez que fosse necessário informar um gol contra a algum método; teríamos sempre que escrever o “-1″ por exemplo:“registrarGolParaJogador(jogador, -1);”. Por que não criar uma constante? Com essa constante iríamos poder eliminar um método. Veja como o processo final para registrar um gol contra ficaria:

    //Our declared Constant in the Match class.
    public static final int OWN_GOAL = -1;
    
    public void changeScore(Team team, int goal){
        this.fullScore(team, goal);
    }

    Note que não existe mais a necessidade de utilizar o método “registrarGolContra”, pois a única razão de sua existência era colocar o valor do gol como negativo. Com isso, ao chamar o método alterarPlacar bastaria passar a constante GOL_CONTRA ao invés de ter que chamar/criar um método para isso ( alterarPlacar(time, GOL_CONTRA); ). Constantes são muito bem vindos por exemplo, em construção de templates: “ADICIONAR_LINHA_SIMPLES”, “ADICIONAR_LINHA_COMPOSTA”, “PARAGRAFO”, e outros mais. Basta notar, está sempre tendo que passar um mesmo valor? É hora de utilizar uma constante.

  • Existe uma razão, qual é? – Ao criar uma captura de exceção devemos nos ater ao porque daquela captura. Devemos sempre focar no fato de que, se algum método declara que uma exceção pode ser lançada, um tratamento deve ser dada para ela. Devemos sempre ver o melhor modo de tratar esse infortúnio, alguns exemplos seriam: o que mostrar ao usuário (exceção tratada), como tratar as ações inacabadas (arquivos, transações com db, log, etc).
    Ao ignorar um exceção, não tratando seu objeto do tipo “Exception”, estamos simplesmente desrespeitando o contrato do método o que poderia acarretar problemas para o usuário e à sua aplicação.
  • Exception impossível de acontecer, mas é declarada? Certa vez enquanto alterava um código, notei que ao testar a funcionalidade ela não funcionava e não apontava erro. E mesmo revisando meu código ví que ele estava correto e não achei problema algum.
    O que fazer para achar o erro? Debug!
    Comecei a percorrer o código e me deparei com o seguinte código:

    //...
    validateCreditCard(creditCard);
    //...
    }catch(CreditCardInUseException){
        //Impossible to get here
    }

    Quando o método de validar cartão crédito foi criado realmente não havia a possibilidade de o cartão estar em uso, e por isso o comentário descrevia que seria impossível chegar ali. Mas vemos nesse caso dois pontos passíveis de melhorias:

    1. Método não coeso – note que o método de validar o cartão lança uma exceção que às vezes é valida e outras não. Existe dentro deste método uma regra de negócio que diferencia seu comportamento, e a diferença de comportamento altera o tratamento dado a sua assinatura (futuro assunto sobre OO); uma solução seria separar esse método que está tendo tantos comportamentos diferentes, pois ele está em um estado “delicado” tendo muitas decisões dentro dele.
      Para uma exceção acontecer, ela deve ser tratada e em nosso caso – quando o código foi criado – não tinha como acontecer nenhum tratamento. Se existe um método que declara uma exceção que nunca irá acontecer, tem algo errado!
    2. Se uma exceção é lançada, ela tem o seu motivo e ela deve ser tratada. Perceba que se a exceção estivesse sendo tratada, e no mínimo, com “System.out.println();” haveria uma mensagem informando que algo aconteceu. Digo no mínimo, pois poderíamos dar diversos tratamentos como registrar em log, enviar email, etc. Algo estava acontecendo, uma exceção sendo lançada, mas nenhuma ação estava sendo tomada. Lembre-se: “Se uma exceção é lançada, existe um motivo e ela deve ser levada em consideração.”.
  • Mensagens de erros claras – As mensagens de erros devem ser claras, de modo que um usuário possa entender. Afinal, é ele quem estará lendo e tem a “obrigação” de entender. Evite mensagens como: “Ação Ilegal!” ou “Erro!”. Esse tipo de mensagem não esclarece em nada o usuário, e pelo contrário, apenas fará com que ele fique mais confuso.
    Um bom momento de se escrever as mensagens de erro é enquanto se desenvolve/refatora a função, pois você estará ciente de todo o processo.
  • Escrevendo mensagens de erro – Ao escrever uma mensagem de erro evite pensar: “Vou colocar a mensagem assim, pois está bem claro que é sobre esse assunto que estamos falando.”. Será? O usuário não pensa como desenvolvedor, ele não tem que saber que o valor X vem da tela Y e é necessário para chegar à tela Z.
    Quando estiver em dúvida de como colocar a mensagem, olhe para tela e tente esquecer tudo o que você sabe sobre ela e pense: “Sendo alguém que nada sabe sobre desenvolvimento, como entenderia melhor essa mensagem de erro?” Adapte essa pergunta ao que você está desenvolvendo, mude seu modo de pensar e mantenha seu foco no usuário. Uma outra boa opção é chamar um colega do trabalho para dar uma opinião.
  • Evite certas mensagens de erro ao desenvolver – Enquanto estiver a desenvolver, evite mensagens como: “Ta vendo? Por sua culpa gerou erro!” ou “Seu Zé Mané, digita alguma coisa aqui!”. Às vezes é divertido e até mesmo gera certo alívio quando uma mensagem desse tipo é exibida, mas é aí que mora o perigo. Imagina se essa mensagem permanece salva no código e é enviada ao cliente. Por mais divertido que seja, é melhor evitar.
  • Log4J – Uma boa ferramenta que poderá ser util na hora de registrar exceções é o Log4J. Com essa biblioteca é possível registrar log em diferentes tipos de níveis e outras opções mais. Pretendo ainda escrever um tutorial sobre ela, mas enquanto não fica pronto, vai aí uma dica para quem se interessar: http://www.guj.com.br/article.show.logic?id=130

Espero que essas dicas possam ter ajudado.
Até a próxima pessoal.

Handling Exceptions on a WebApp

Hello everyone, how are you doing?

Let’s talk about how to handle exceptions in a web application? To learn how to create a web application, check this tutorial: Creating a WebServer. We will be using this tutorial to work with today.

Unexpected situations always going to happen and the worst part of it is when these problems go to the client’s screen, through messages that he won’t understand. When the client reads this kind of message he will begin to be suspicious about your software, and for every problem that happens he will blame your software (even when he gets disconnected from the internet).

PS.: In my articles, I usually don’t ask for specific software/technology but this time I will. Please, do not use the Internet Explorer (or Eclipses browser). In the end of this article I will tell you the reason that I’m asking this. This information about how IE handle exceptions, cost me 120 minutes (in my weekend), to find out the reason for today articles code does not work on Internet Explorer.

In our Servlet project (Creating a WebServer) when the user does not type a valid number, we use this piece of code to handle the situation:

try {
    // I know this is ugly, but in a future we can do some refactor and apply some OO and Design principles
    value1 = Integer.parseInt((String) req.getParameter("valor1"));
} catch (NumberFormatException e) {
    // Catching this execption in case some invalid value was sent
    value1 = 0;
    warning = "We got some bad value(like blank or non numerics values, we set 0 instead";
}

In this piece of code, when an error occurs a default value is given to the parameter, but what will happen when we cannot give a default value? There are some situations that exceptions happens and we have to inform the user about this problem. Also there are some exceptions that don’t reach our servlets; one of those exceptions would be when the user types a wrong http address he will receive a HTTP 404 error message on the screen. First let’s handle the 404 error and then an error caused by a wrong typing.

Let’s create a JSP that will handle the exception (inside the WebContent folder with “error.jsp” as its name):

<%@ page isErrorPage="true" language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title>Erro</title>;
    </head>
    <body>
        Ops, something happend! <br/>
        Error code: ${pageContext.errorData.statusCode}
    </body>
</html>

The isErrorPage parameter makes possible the access to the Exception object. The errorData object is created by the container inside the pageContext automatically. To finish, we need to chance the “web.xml” configuration so the container might be able to redirect our request to the error page.

We will have the following lines added to the web.xml file:

<error-page>
    <error-code>404</error-code>
    <location>/error.jsp</location>
</error-page>

With this error tag we indicate to the container which kind of error is mapped and which destine it will have. When our user types an invalid address, he will be redirected to our error page.

To test, let’s start the container and then just type an invalid address directing it to our application:

http://localhost:8080/Servlet/ASD

There is not such servlet/url “ASD” mapped at the web.xml file; instead a HTTP 404 error, the user will see our error jsp. Can you see the benefits of that simple error-page configuration? The user will be redirected to that destination only when he types a wrong address, but we can also set for every kind of error to be redirected there, we just need to map the java.lang.Exception (we will see it soon).

Another option to handle exceptions is to redirect our error to a servlet where we can do several actions. Our sample code throws an exception when it try to sum the values without a valid data – like non numbers characters. At the first version of our software it gives a default value to the user when an exception was detected, but now, we will redirect the user to the error page where we might be able to tell him to type the value.

try {
    valor1 = Integer.parseInt((String) req.getParameter("valor1"));
} catch (NumberFormatException e) {
    throw new NumberFormatException("No numbers were typed");
}

Notice that now we are not setting a default value, but an exception is being thrown. It’s like we are telling to the container that something bad happened and the container should take care of it.

But we have not changed it on the web.xml file yet.

<servlet>
    <servlet-name>errorServlet</servlet-name>
    <servlet-class>com.ErrorController</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>errorServlet</servlet-name>
    <url-pattern>/errorServlet</url-pattern>
</servlet-mapping>
<error-page>
    <exception-type>java.lang.NumberFormatException</exception-type>
    <location>/errorServlet</location>
</error-page>

We have mapped the servlet that will handle the exception, and the described the error type that will be handled “NumberFormatException”. We could also set as the handled error type the “java.lang.Exception” so our servlet would capture every kind of error that would be raised at our application.

Let’s create now our servlet:

package com;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class ServletError
 */
public class ErrorController extends HttpServlet {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    public void doPost(HttpServletRequest req, HttpServletResponse res)    throws ServletException, IOException{
        Throwable throwable = (Throwable) req.getAttribute("javax.servlet.error.exception");
        Integer statusCode = (Integer) req.getAttribute("javax.servlet.error.status_code");

        req.setAttribute("errorType", throwable);
        req.setAttribute("statusCode", statusCode);

        RequestDispatcher requestDispatcher = req.getRequestDispatcher("/error.jsp");
        requestDispatcher.forward(req, res);
    }

    public void doGet(HttpServletRequest req, HttpServletResponse res)    throws ServletException, IOException{
        doPost(req, res);
    }
}

As bonus, what if we do a little change at our error.jsp? From now on our page will display the error type:

<%@ page isErrorPage="true" language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title>Erro</title>
    </head>
    <body>
        Ops, something happend! <br/>
        Error code: ${statusCode} <br/>
        The error type is: ${errorType.message}
        <br/>
    </body>
</html>

It was changed the “Error code” that we now are getting it from the Request, and we are accessing the “error type” from the error object that the container created for us.

Start the Tomcat and try to sum the values without any number and our container will understand that an exception happened and will redirect it to our servlet; the servlet will handle the exception and will redirect the request to the “error.jsp”. Using a servlet to handle our exceptions it’s a good idea because now we can log an error; send emails to the administrators, etc.

I will explain now why I’ve asked you to do not use the IE (Internet Explorer). When an exception happens, the container changes an attribute named SC_INTERNAL_SERVER_ERROR. The IE notices that this value has changed and take a default action by itself, ignoring all configuration that we have done. Try to run our application using the IE and you shall see how the IE handle the exception.
The first solution if would be change a configuration inside the IE:

Internet Options > Advanced > "Show Friendly HTTP Error Messages"

Uncheck this option, save, close the IE and open it again; try one more time to generate the exception. The IE will display the message that we wanted all the time. How we would ask to all of our customers to change this IE specific configuration? Imagine if a user is coming for the first time at our website and he typed the wrong address. How would he see the wrong message once the IE won’t display any of our messages?

Our second solution would be to change the response object statuses. When we change the responses statuses the IE thinks that there is no error, and will let the user see our “error.jsp”.

req.setAttribute("statusCode", statusCode);

res.setStatus(HttpServletResponse.SC_OK);
// We have to remove the exception from the request. If we do not remove the IE9 will not display out error page.
// IE9 will think that some error created a crash inside our application if we do not remove the exception from the request.
req.setAttribute("javax.servlet.error.exception", null);
req.setAttribute("javax.servlet.error.status_code", null);

RequestDispatcher requestDispatcher = req.getRequestDispatcher("/error.jsp");

This IE problem took me a good time of my weekend, and during the week I’ve talked a lot with my boss about it. Just after more research I could find some info about this.

I hope this post can help you. Any question? Just ask!