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.

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.

Tratando Exceções em uma Aplicação Web

Pessoal, boa noite. Tudo bem?

Vamos falar um pouco sobre como capturar exceções em uma aplicação web? Para aprender como criar uma aplicação web, visite esse tutorial: Criando um WebServer. Vamos usar esse projeto adicionando o tratamento de erros.

Situações inesperadas vão sempre acontecer, e pior ainda é quando problemas inesperados são exibidos ao cliente através mensagens que faz com que ele passe a ter certa desconfiança da funcionalidade. Esteja certo de que todo problema que ocorre a partir de então será “causado” pelo seu sistema na visão do usuário (mesmo sendo a internet que tenha caído).

OBS.: Nos artigos que costumo escrever não peço por tecnologia específica, mas por enquanto terei que fazer. Por favor, não usem o Intert Explorer (ou o browser do eclipse)! Ao final do artigo irei explicar o porquê desse pedido, pois esse pequeno detalhe me custou quase 120 minutos para descobrir o motivo do código não funcionar no IE (em pleno final de semana).

No código do projeto Servlet (Criando um WebServer) caso o usuário não digite um valor válido, utilizamos o seguinte código para tratar essa situação:

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";
}

Nesse exemplo quando acontece o erro um valor padrão para o usuário é passado, mas e quando essa situação não é possível? Existem situações em que quando uma exceção acontece temos que parar todo o processo e informar ao usuário que algo está errado. Existem também erros causados e que não são capturadas por nossos servlets, um exemplo disso é quando o usuário tenta acessar um recurso que não existe e um erro HTTP 404 é exibido em sua tela. Vamos tratar o erro do acesso indevido (404) e depois o erro nos dados (valor inválido digitado).

Vamos criar primeiro uma jsp para tratar nossos erros que ficará assim (crie a jsp dentro da pasta WebContent com o nome de “error.jsp”):

<%@ 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>

A atribuição isErrorPage permite que tenhamos acesso ao objeto do exception. O objeto errorData é criado pelo container e colocado no pageContext de modo automático. Basta configurar o “web.xml” para que o servidor possa encaminhar o erro obtido até a jsp.

O nosso arquivo web.xml terá as seguintes linhas a mais:

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

Com a tag configuramos o código do erro e qual o seu destino. Quando nosso usuário digitar um endereço inválido, ele será direcionado para nossa JSP de erro.

Para testar, inicie o container e depois basta digitar um endereço inválido apontando para dentro da nossa aplicação, como por exemplo:

http://localhost:8080/Servlet/ASD

Não existe a action ASD mapeada em nosso arquivo web.xml com isso ao invés de ser exibida a mensagem HTTP 404, será exibida nossa jsp responsável por tratar os erros. Veja como essa simples configuração conseguiu evitar uma mensagem que o usuário não iria entender nada.

Outro modo de tratar exceções pode ser direcionar o erro gerado para um servlet onde poderemos trata-los. O nosso código gera uma exceção quando tentamos realizar a soma sem digitar valor algum e na primeira versão desse programa, colocávamos um valor padrão para a variável, mas agora, iremos exibir uma página de erro onde o usuário verá que é necessária a entrada dos dados numéricos.

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

Veja como nosso código ficou, não estamos tratando mais a exceção, mas estamos informando para o container que algo aconteceu e é para que ele trate essa exceção.

Mas essa alteração, ainda não foi mapeada no arquivo “web.xml”.

<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>

Mapeamos o servlet que irá tratar o erro, e também informamos que todo erro do tipo NumberFormatException será tratado pelo nosso servlet. Poderíamos trambém declarar que ele irá capturar uma java.lang.Exception que toda e qualquer exceção seria tratada por nosso servlet.

Precisamos agora criar nosso servlet para tratar as exceções.

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);
    }   
}

Vamos realizar uma pequena alteração em nossa JSP de erro como bonus? A partir de agora ela irá exibir também o tipo do erro:

<%@ 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>

Foi alterado também o código do erro para ler o valor colocado no request em nossa Servlet, e na página estamos exibindo o conteúdo do objeto que foi criado de modo automático pelo container.

Inicie o Tomcat e mande realizar a soma sem ter número algum e o nosso container irá entender que houve uma exceção e irá redirecionar para o servlet que irá tratar o erro e finalizar a requisição na página de erro.
Utilizando um servlet para tratar de nossos erros podemos realizar diversas outras funções que não seria possível fazer apenas direcionando diretamente para a JSP. Podemos por exemplo, gravar no log da aplicação, enviar email para os responsáveis, etc.

Vou falar um pouco agora, do porque pedi a você para não usar o IE (Internet Explorer). Quando uma exceção acontece, o container altera o valor de uma variável chamada SC_INTERNAL_SERVER_ERROR, com isso o IE nota que esse cara teve seu valor alterado e passa a tratá-lo de um modo próprio que no caso, ignora o tratamento que foi dado no arquivo “web.xml”. Tente executar nossa aplicação agora pelo IE e note como ele acaba por tratar a exceção.

A primeira solução seria alterar uma configuração dentro do próprio IE. Ela fica em:

Opções da Internet > Avançadas > "Mostrar mensagens de erro http amigáveis"
Ou IE em inglês:
Internet Options > Advanced > "Show Friendly HTTP Error Messages"

Desmarque a opção, salve suas alterações, feche o IE e abra novamente e faça o mesmo teste. Perceba que agora ele já exibe a mensagem que desejávamos. Mas, como iríamos pedir que todo usuário de nosso sistema fizesse essa alteração? Imagine que um usuário iria pela primeira vez em nosso site, mas ele acabou por digitar o endereço errado, como ele iria ficar sabendo dessa opção?

A segunda solução, é alterar o status do objeto “response”. Quando alteramos esse status o IE passa a aceitar que não houve nenhum erro e nossa página será exibida normalmente.

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");

Realmente, essa parte do IE me tomou boa parte do fim de semana e inclusive durante a semana conversei muito com meu chefe sobre isso e só depois de mais pesquisa que encontrei esse assunto de modo mais detalhado.

Espero ter ajudado. Qualquer dúvida basta falar.

Código Limpo – Parte 03

Olá, tudo bem?

Vamos falar sobre a terceira parte do tema: “Código limpo”? Os primeiros artigos você encontra a seguir: Código Limpo – Parte 01, Código Limpo – Parte 02

Eu alterei a ordem do tema Código Limpo e hoje estaremos falando sobre Comentários:

  • Comente explicando o “por que” – Seu comentário deve explicar o porquê de sua execução e não “como”. A parte do “como” deve ser explicada pelo próprio código. Acontece que ao colocar o comentário de como o método funciona o código tende ficar mau feito, com péssimos padrões. Você começa a confiar que seu comentário irá explicar como o método deve funcionar, mas na verdade, o código deve ser “auto-explicável”.
    /**
     * This method publishes the documents using a proxy connection
     * to save the files in the necessary patterns
     * There is a loop (repetition) on going while the methods does not end
     * 
     */
    public void publishDocuments(){
        // some code...
    }

    No comentário do método está escrito o que ele faz, o modo como ele executa o processo, mas isso tem que ser percebido ao ler o código. Caso seja um pacote de classes exportadas, qual a finalidade do usuário ler esse tipo de comentário? O usuário precisa apenas saber o que esse método faz e pronto. Olhe como ficaria mais claro com o comentário mais objetivo:

    /**
     * Method that publishes the files, in html, which save them 
     * Applying w3c patterns.
     * 
     */
    public void publishDocuments(){
        // some code...
    }

    O comentário ele descreve o objetivo do método, o porquê de sua existência, e não dá descrições sobre sua implementação.

  • Sem abreviaturas – Não utilize abreviações em seus comentários, eles dificultam a leitura.
    //Hold ref to cli PPV
    Account account = daoFactory().getDaoAccount.getAccount();
    //Holds the reference to the clients Pay Per View
    Account account = daoFactory().getDaoAccount.getAccount();

    Comentando sem abreviar você gasta pouco tempo a mais digitando, mas deixa o código bem mais claro para quem o ler pela primeira vez. Lembre: “você cria o código para os outros lerem, ele te define como profissional”.

  • Não documentar o óbvio – Existem códigos que não tem a necessidade de serem documentados. Ao fazer isso, a qualidade do seu código irá diminuir. E pior, fazer isso é tão fácil…
    /**
     *Methods that calculates the bill total value
     * 
     */
    public void calculateBillTotalValue(Customer customer, Bill notPaidBill){
        // Creates the closed bill date with "today" date
        Date closedBillDate = new Date();
        
        // Sets unPaidBills to zero
        int unPaidBills = 0;
    
        // Check if the bills has the payment delayed
        if (notPaidBill.isPaymentDelayed(closedBillDate)){
            // If the payment is delayed add some interest
            notPaidBill.addInterest(closedBillDate);
        }
        
        // some code...
    }

    O código acima não precisava daquele tipo de comentário, e o comentário do método apenas repete o nome do método. Quando seu código está bem claro, não é necessário comentar todas as linhas.

    /**
     * Method that calculates the total bill value that has to be paid, add interest if needed.
     * 
     */
    public void calculateBillTotalValue(Customer customer, Bill notPaidBill){
        Date closedBillDate = new Date();
        int unPaidBills = 0;
    
        if (notPaidBill.isPaymentDelayed(closedBillDate)){
            notPaidBill.addInterest(closedBillDate);
        }
        
        // some code...
    }

    Conseguimos ler o código de modo claro, sem a necessidade de comentários desnecessários. O acúmulo de comentários repetitivos deixa seu código sujo, enorme, difícil de se ler, e ainda por cima, pode irritar o leitor. Sem falar que aumenta o tempo de desenvolvimento, pois serão muitas linhas escritas e formatadas sendo que acabam por ser desnecessárias.

  • /* fim for */ ou /* fim while */ – Colocar essa anotação ao final de uma repetição é útil apenas quando se tem uma seqüência aninhada de repetições.
    while ( /*  while controller */){
        while ( /*  while controller */){
            while ( /*  while controller */){
                
            }/* end while */
        }/* end while */
    }/* end while */
    car.turnOffEngine();

    Esse tipo de comentário torna mais claro a leitura quando temos uma seqüência de repetições aninhadas, mas fica prejudicial quando temos apenas uma repetição.

    while ( /*  while controller */){
    }/* end while */
    car.turnOffEngine();

    OBS.: No caso de muitas repetições aninhadas pode-se pensar em separá-las e colocando-as em métodos separados.

  • Comentários em excesso [1] – Quando se comenta em excesso, seu código fica poluído, difícil de ler. O foco de quem lê acaba indo para os comentários, quando o real foco tinha que ser o código escrito. Quando seu código está limpo e objetivo existe uma necessidade mínima em ter que comentar todo o código, aumentando a facilidade inclusive de localizar alguns bugs que acontecem com relação a regras de negócio, pois o foco passa de ser o comentário e vai para o código.
  • Comentários em excesso [2] – Ao notar uma quantidade enorme de comentários para um método ou algum cálculo talvez seja hora de refatorar o método. Seu código deve sempre ser claro, de fácil entendimento. Não deve existir a necessidade de escrever muitas palavras para descrever sua função.
  • Informar, caso exista, conseqüências – Sempre deixe claras as conseqüências de se executar o método. Existem métodos que podem ter conseqüências que realmente venham a afetar o comportamento do sistema de um modo não esperado. Como por exemplo: irá limpar dados temporários, apagar dados do banco de dados, iniciar, a cada chamada do método, uma conexão remota que irá pesar o processamento da máquina.
  • Necessidade dos comentários – Um código bem definido pode eliminar a maioria dos comentários. Utilize comentários apenas quando necessário, e deixe que seu código fale por ele mesmo.

Espero que esse artigo possa ter agregado valor ao seu conhecimento. Dúvidas? Basta comentar que eu respondo.

Até a próxima

TDD – Primeiros passos

O que é TDD? Por onde começar um Teste? Como se faz um Teste?

TDD é uma metodologia de validação das classes/métodos/atributos que serão criados. Por exemplo, foi solicitado criar um método que busque os dados de uma casa. Com o TDD, é possível validar todas as situações que o desenvolvedor possa imaginar, como: casa sem número, valor retornado null, dono se mudou, etc.

Por onde começar? Vamos configurar o JUnit para ficar mais clara nossa visão? Desculpe se você já sabe fazer isso, é coisa rápida (temos que ajudar quem está começando!).
Irei usar o Eclipse como IDE, mas na verdade o TDD pode (e deve) ser aplicado em qualquer IDE. Caso você use outra ferramenta de teste que não seja o JUnit, o conceito que será passado aqui é aplicável a qualquer ferramenta de teste.

OBS.: Esses pequenos passos de como criar classes/pacotes ou abrir uma view do Eclipse você pode achar em outro post aqui no blog: Criando um WebServer

Após criar um novo “Java Project” que chamarei de TDD, utilizando a View “Package Explorer”, adicione a biblioteca do JUnit:
Configurando 01
Configurando 02
Configurando 03

Vamos trabalhar em cima do seguinte caso de uso: Seu sistema terá uma classe User que manterá as informações de cada pessoa que faz o login no sistema. E como requisito, essa classe terá um método para bloquear o acesso de um usuário ao sistema.
Vamos criar um pacote chamado “test.com” e uma classe chamada TestUser dentro deste pacote.

package test.com;

public class TestUser {
}

A ideologia base do TDD é começar o teste pelo resultado esperado. (HEIN?!) No mercado o costume sempre foi começar a codificar pelo começo, mas no TDD nós começamos pelo fim. Por quê? Fazendo assim temos uma idéia para onde vamos, o que vamos precisar para chegar até lá, evitamos criação de parâmetros desnecessários, os métodos ficam mais objetivos e assim vai.

Ao escrever métodos temos que ter em mente a seguinte seqüência: “Vermelho, Verde, Refatorar”. O que seria isso? Quando escrevemos testes utilizando JUnit temos a barra (que em breve veremos) mostrando status vermelho para quando o teste falha, e verde para quando tudo é executado com sucesso.

Para garantir um resultado experado, existem métodos que fazem essa conferência. Vamos utilizar o assertEquals(valor desejado, valor retornado). Em nosso caso de uso, o que queremos? Sempre que o usuário estiver bloqueado o método terá que retornar verdade. Vamos escrever esse código?

package test.com;
import static org.junit.Assert.*;
import org.junit.Test;

public class TestUser {
    @Test
    public void isUserWithDeniedAccess(){
        assertEquals(true, user.accessDenied);
    }
}

Alguns detalhes sobre o código. Note que temos um annotation “@Test” e ao executarmos o framework do JUnit ele irá localizar os métodos que tiverem esse annotation, e irá executar a validação do teste. Estamos utilizando o método assertEquals que é importado do próprio JUnit utilizando o “import static”.

Perceba também que já estou “tentando” acessar um objeto que não existe tanto no método, tão pouco no projeto. Está lembrado de quando falei que começamos do fim? O nosso fim (alvo, meta) é que o usuário no final das contas esteja realmente bloqueado. Mesmo que não exista classe ou seus atributos ainda, iremos normalmente, como passo inicial, utilizá-lo em nosso código. Fazendo assim, já estamos pensando no nome da classe, dos atributos. Mesmo que não compile, estamos no caminho. Pequenos passos… Sempre pequenos passos…
Finalizando nosso teste, nosso código ficará assim:

@Test
public void isUserWithDeniedAccess(){
        User user = new User();
        assertEquals(true, user.accessDenied);
}

Note que foi “instanciada” a classe User mesmo sem ela existir no projeto. Agora temos um projeto em que o teste não é compilável.
Lembram-se dos passos do TDD? Vermelho, Verde e Refatorar? Temos que conseguir uma barra vermelha retirando os erros de compilação. Vamos criar nossa classe User (em um pacote chamado “com”) e adicionar o atributo necessário.

package com;
public class User {
    public boolean accessDenied;
}

Agora basta fazer o import na classe de teste (TestUser):

import com.User;

E já estamos prontos para conseguir nossa barra vermelha. Para rodar o teste pelo JUnit basta clicar com botão direito em cima da nossa classe de teste ir em “Run as > JUnit Test”.
Executando o JUnit
A barra vermelha nos indica que agora estamos prontos para trabalhar o nosso método para que ele possa retornar o valor desejado. Começamos pelo erro para saber que, ao conseguir o verde, nosso teste realmente esta trabalhando como desejamos. Nesse caso estamos a fazer um exemplo bem direto, mas se estivéssemos fazendo um método complexo, começar pelo erro faria com que tivéssemos a certeza de que atingimos nosso objetivo. Com isso, não precisamos executar toda a aplicação para fazer o teste da funcionalidade, basta rodar os testes e pronto, já podemos ver rapidamente o resultado da nossa alteração.

Agora vamos desenvolver nosso código para que nossa barra possa ficar verde? Nessa hora, geralmente, alteramos o método que acabamos de criar para retornar o valor desejado. Como nosso exemplo é simples, basta trabalhar com o valor do atributo para consigamos o valor desejado. O nosso teste é quem tem quem deve estimular a classe nas situações desejadas, por isso não estamos alterando em nada a classe User para que nosso teste execute. TDD trabalha com pequenos passos, caso você já esteja com um bom nível em TDD já seria possível criar os métodos de uma só vez. Por isso estamos acessando diretamente os atributos, mas de acordo com algumas literaturas de TDD é uma boa prática acessar os atributos pois você já estaria validando os mesmos em sua fase de teste, e depois, com a refatoração seriam criados os métodos para proteger os atributos

@Test
public void isUserWithDeniedAccess(){
        User user = new User();
        user.accessDenied = true;
        assertEquals(true, user.accessDenied);
}

E agora basta executar o JUnit o código que teremos a barra verde.

Note que nosso código está feio, e não está aplicando nenhum padrão OO. O que fazer? Esse ato de refatorar sempre fica para o final, então vamos adicionar ao final da nossa lista de tarefas onde iremos refatorar. Assim não iremos deixar nada para trás.

Usando essa abordagem de código temos uma visão melhor do código, de onde poderíamos alterá-lo ou melhorá-lo. E melhor, temos a certeza de que nosso código já está fazendo o que nós queríamos. Mas precisamos aplicar conceitos OO antes de dar a tarefa como concluída. Vamos primeiro criar um método para verificar se o usuário tem seu acesso negado ao invés de acessar o atributo direto.

// TestUser.java
package test.com;

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import com.User;

public class TestUser {
    @Test
    public void isUserReallyBlocked(){
        User user = new User();
        user.accessDenied = true;
        assertEquals(true, user.hasAccesDenied());
    }
}

//User.java
package com;

public class User {
    public boolean accessDenied;

    public boolean hasAccesDenied() {
        return accessDenied;
    }
}

Não alteramos o acesso ao atributo ainda pois temos mais um passo pela frente. Vamos criar um meio para que a classe altere o atributo e proteja o atributo de um acesso direto. Para isso, vamos usar o conceito Diga, não pergunte. Fazendo assim, de um modo eficiente iremos terminar nosso caso de teste e nossa tarefa. Nosso código final seria:

package test.com;

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import com.User;

public class TestUser {
    @Test
    public void isUserReallyBlocked(){
        User user = new User();
        user.denyAcces();
        assertEquals(true, user.hasAccesDenied());
    }
}

package com;

public class User {
    private boolean accessDenied;

    public boolean hasAccesDenied() {
        return accessDenied;
    }

    public void denyAcces() {
        accessDenied = true;
    }
}

Note como o código da classe User ficou claro, objetivo, sem métodos desnecessários. Começando pelo teste nosso foco é maior no comportamento. Basta agora compilar o teste utilizando o JUnit e ver que concluímos tudo com sucesso.

Pessoal, esperem que ajude esse post para os primeiros passos. Em breve irei colocar aqui, boas práticas de TDD para que possamos aprimorar ainda mais o nosso desenvolvimento. O post de hoje foi apenas uma introdução mais a ferramenta em si, no próximo post sobre TDD iremos falar mais sobre conceitos e abordagens do TDD.

Boa noite a todos.

Código Limpo – Parte 02

Boa noite pessoal, tudo bem?
Vamos continuar com o assunto de como manter um código limpo? A primeira parte do assunto, você encontra aqui: Código Limpo – Parte 01.

Falemos um pouco sobre variáveis de escopo e atributos.

OBS.: Toda vez que eu escrever atributos eu estarei me referindo aos dois casos, ok? Tanto como variáveis de escopo (parametros de métodos, definições de variáveis dentro de loops), tanto quanto atributos de classe. Apenas para não ter que repetir atributo/variável toda hora aumentando o texto.

    • Usar camelCase no nome do atributo – essa dica é uma dica básica e bastante encontrada por aí. Facilita a leitura e é utilizado em convenções de várias linguagens de programação. Alguns exemplos seriam:
          String disapprovedStudent;
          double totalDivide;
          boolean isManager;

      Uma vantagem é que é mais fácil ler na forma camelCase do que:

          List player_own_goals;
          List playerOwnGoals;

      Uma desvantagem seria em um nome grande:

      Map allYellowHousesFromTheBlock;

      Ou seja, utilize e não abuse. ;)

    • Nome de lista no plural – para que colocar nome “listaPessoa” se colocar “pessoas” já dá o mesmo sentido? E existe uma diferença enorme entre pessoa e pessoasanalisando o conceito da palavra. Mantenha esse conceito em mente e verás como seu código ficará legível. Veja só o “foreach” como ficaria:
          List houses = new ArrayList();
          // adds the houses from the block at the list
          for (House house: houses) {
              this.ringBell(house);
              this.runForYouLife();
          }

      Perceba que ao ler o nome da lista “casas” fica claro que estamos falando de um conjunto de “casa”. Quanto mais frequente esse tipo de nomeclatura for utilizada em seu sistema, mais claro ficará para quem estiver lendo, o que o atributo significa e o seu valor no método.

    • Devemos dar nomes reais que sejam fáceis de falar, nomes que se “auto-expliquem”. Imagine só, caso você visse a seguinte declaração:
      public class Car{
          //... some code
          boolean caCra;
          //... some code
      }

      O que ela deve significar? Qual seria sua utilidade? Como se fala? Imagine você chamando seu colega de trabalho, e ao tentar explicar o que estás a fazer, ele pergunta: “Ta, mas você está falando de qual atributo?”! Como você falaria?
      Sendo o nome direto, objetivo e “falável” você já pode imaginar o que significa, e ao comentar o código com alguém, seria mais fácil de ser dito e a pessoa que o ouvir poderia se lembrar dessa parte do código facilmente. Ah sim, qual seria o nome mesmo daquele atributo?

      public class Car{
          //... some code
          boolean isCarCrashed;
          //... some code
      }
    • Caso você veja o código a seguir, cuidado pois ele pode trazer muito entendimento incorreto:
          int value1, value2, value3;
          // ou
          String name1, name2, name3;

      O que poderia significar o um, dois ou três? Veja que em nenhum momento o atributo dá a entender onde deveria ser utilizado, e qual seria sua função. O código fica difícil de entender. Caso você tenha o azar de cair em if/else/while aninhados com esse tipo de atributo, é hora de levantar e ir pegar um café por que a tarde será longa… Imagine a seguinte situação:

          String str1, str2, str3, str4;
          //... some code
          str4 = str3.substring(4,8) + str1.concat(str2);

      Agora, imagine se o código tivesse sido escrito assim:

          String userLogin, userPassword, lastLoginDate, userAccessKey;
          //... some code
          userAccessKey = lastLoginDate.replaceAll("/", "-") + userLogin.concat("-" + userPassword);

      Conseguimos entender o que esse código está fazendo apenas pelos nomes dos atributos. Se estiver dentro de um método que tenha um nome claro então… Faz a combinação para deixar qualquer programador que leia o seu código feliz. Eu vi um caso em que semanticamente (pois era um estudo de OO) ao qual não haveria outra possibilidade de se colocar nomes que não tivesse 1 e 2 no final. Caso você tenha em mente o mesmo conceito e percepção, de que o projeto perderia coesão e sua definição se os atributos não tivessem o número no final, vá em frente e implemente seu código.

    • Os nomes dos atributos têm que sempre manter sentio ao contexto ao qual estão sendo utilizados. Sempre que ao ler o nome de um atributo ele tem que fazer sentido no trecho em que está aparecendo.
          //... some code
          int total = 0;
          for (Trade tradedBall : tratedBalls) {
              total += tradedBall.getTotalTratedItens();
          }
          for (Trade tratedHelmet : tratedHelmets) {
              total += tratedHelmet.getTotalTratedItens();
          }
          StockFacade stockFacade = FacadeFactory.getStockFacade();
          stockFacade.updateAmountTratedItens(total);
          //... some code in the same method
          //...
          //... 15 lines after
          double totalSpent = financialFacade.calculateSpentValue(spentValuesWithEmployees + (valuePerIten * total));
          return totalSpent;

      Quem é esse total que apareceu do nada ali no cálculo final? De onde veio esse valor? Qual o papel dele nesse método? Agora, imagina se ao invés de total fosse totalItensTrocados? Leia o código novamente trocando o total pelo nome sugerido.
      Essa é a diferença de se manter um nome que sempre tenha valor no contexto em que está sendo utilizado.

    • Não especificar na frente do nome do atributo o seu tipo. É muito comum se encontrar intIdade, strNome, dtNascimento. Você pode se perguntar: Que mal há nisso? Lembre que uma das boas práticas seria o fato do próprio nome do atributo se “auto-explicar”? Colocando o atributo na frente existem algumas desvantagens:
      • Incentivo às más nomenclaturas – é muito mais fácil pensar em colocar dtNascimento do que dataNascimento. Com isso, a idéia de nomes “auto-explicativos” iria começar a falhar. Poderiam nomes estranho como dtNas ou dtMNat (dataMorteNatural).
      • Variação na abreviação do tipo – seria fácil começar a encontrar algumas variações como: strNome, stNome, sNome, ou nmNome(se fosse apenas nome resolveria). Até aí nada de exagerado, agora imagine se sua aplicação tem um javascript e nele você começa a ver: cbDtIni ou então txNmCp. Qual seria a sua reação? Você saberia explicar cada um deles? Creia em mim, não é exagero, eu já vi atributos com esse tipo de nome.

      Evite esse tipo de prática, esse tipo de nome nos seu atributo irá causar uma leitura de código demorada e trabalhosa.

  • Já pensou em ter atributos de nomes pequenos e fáceis de digitar? Suponhamos que em seu programa você tenha uma variável chamada “todosOsAliensDoUniverso”. Agora imagine você tendo que digitar isso toda vez… Se bem que se essa variável se chamasse “aliens” seria… hum… Bem mais fácil de digitar e deu a entender que é uma lista. Não tem hora que você está fazendo aquele código legal e você pensa: “Caramba, tenho que digitar esse nome de novo?!”. Com um auto-completar hoje das IDEs tem ficado mais facil, mas imagine a pessoa ter que escolher entre 5 nomes toda hora, sendo que ela poderia estar a digitá-caso ele fosse pequeno…  Lembre-se, o nome de um atributo não deve afastar pessoas.
  • Espaço entre seus atributos – um código que envolva cálculos sem espaço entre seus atributos, fica um código que causa dor de cabeça! Vejamos um exemplo:
    total=salesPerDay(today)-(COMMITTEE_PERCENTAGE*vendors+totalSoldItens);

    Um código ganha mais clareza quando se tem espaços entre seus atributos:

    total = salesPerDay(today) - (COMMITTEE_PERCENTAGE * vendors + totalSoldItens);
  • Evitar o envio de atributos nulos – o envio de atributos nulos é a raiz de muitos nullPointers! Imagine só, você está acessando um método que nunca usou, mas falaram para você: “Vai lá, coloque o código chamando o método e envie o produto para o cliente. Pode confiar que esse método nunca deu erro!”. Só que não te explicaram que não poderia passar null. Com isso, uma imagem muito feia apareceria para o cliente e a confiança do cliente no programa ficaria afetada.

Bem pessoal, espero que esse artigo de hoje possa lhes ajudar.

Esse assunto terá continuação.

Até mais. [=

Criando um WebServer

Boa tarde, tudo bem?

Hoje o post vai ser um pouco diferente. Vou postar como levantar um Servlet “Hello World” utilizando forward. O propósito do post é para que mais para frente, eu possa postar aqui WebService com integração de Hibernate, Struts, Ajax, Log4J, RB e mais outras coisas. Já é uma base para quem não sabe como levantar um WebService, para depois poder acompanhar os exemplos mais complexos e até mesmo aprender como se faz o simples. E ao final, assuntos vistos sobre SCWCD (certificação Java para Web). É necessário ter o Java JDK instalado.

Vou fazer utilizando uma IDE, pois fica mais fácil, mas caso queira fazer todo o processo sem IDE, basta utilizar todos os arquivos criados aqui (XML, Java, JSP, HTML). Ao final do artigo vou mostrar como se faz sem IDE.

Dois downloads são necessários:

Primeiro, vamos instalar o Tomcat.
01) Utilizei a configuração Full e “padrão Microsoft: Next, Next, Finish”.
Instal Tomcat 01

02) O ícone do Tomcat vai aparecer na barra do sistema, caso não esteja verde, bastar clicar com o botão direito e selecionar “Start Service”.
Instal Tomcat 02

03) Depois abra seu browser e digite http://localhost:8080, será exibido que o servidor está instalado e pronto para usar.
Instal Tomcat 03

04) Vamos parar o serviço do Tomcat. Nós iremos executá-lo através do eclipse, então não existe a necessidade de deixarmos ele ativo.
Instal Tomcat 04

Após descompactar o Eclipse, vamos abri-lo e começar a configurar o Tomcat. O Eclipse irá solicitar que você escolha um “workspace”, um espaço de trabalho onde o eclipse irá guardar os projetos assim como as configurações que fizermos. A escolha desse diretório, não afetará o resultado final desse artigo, então fique a vontade para escolher o diretório que mais lhe agradar.
Config Eclipse 01

Vai aparecer a tela de “Seja Bem Vindo”. Vamos então mudar para a perspectiva Java.
Config Eclipse 02

Vamos agora escolher a View de servidores.
Config Eclipse 03

Digite Servers e selecione a View.
Config Eclipse 04

Agora, vamos adicionar o Tomcat. Botão direito em Servers -> New -> Server.
Config Eclipse 05

Vamos selecionar o Tomcat 7
Config Eclipse 06

E temos agora que apontar o diretório onde foi instalado o Tomcat. E depois clicar em Finish.
Config Eclipse 07

Estamos acabando. Falta agora uma última configuração. Vamos dar duplo clique sobre o servidor Tomcat que acabou de aparecer na View Servers. Uma tela de configuração irá aparecer.
Vamos alterar a configuração o “Server Locations” para “Use Tomcat installation (takes control of Tomcat installation)”. Essa configuração faz com que o Eclipse tenha o controle sobre o Tomcat, com isso, toda vez que precisarmos alterar alguma coisa no servidor, iremos fazer daqui mesmo. Depois de alterar, basta fechar e salvar.
Config Eclipse 08

E finalmente, vamos aos códigos!!! Uhull! o
Criemos um novo projeto no Eclipse. Vamos chamar esse projeto de Servlet. File > New > Other (Ctrl+N).
Projeto 01

Digite “Dynamic Web Project” para selecionar um projeto Web. (Lembro que ainda vou mostrar como fazer tudo isso sem precisar do Eclipse).
Projeto 02

Digite Servlet como nome do projeto e clique em Finish.
Projeto 03

O Eclipse vai perguntar se deseja mudar de perspectiva. Marque em não. Vamos nos acostumar com uma perspectiva, depois, podem tentar as outras à vontade.
Projeto 04

Vamos criar a página inicial. Um HTML mesmo de boas vindas. Botão direito sobre “WebContent > New > File”.
Projeto 05

Coloque o nome do arquivo de index.html e clique em “Finish”.
Projeto 06

Vamos editar o arquivo index.html, para isso, dê um duplo clique nele. Vou colocar apenas o código aqui.

<html>
    <body>
        <h1>Olá</h1>
    </body>
</html>

Criaremos agora um arquivo “web.xml” para acessarmos nossa página inicial. Para isso, com o botão direito, vamos clicar na pasta “WEB-INF > New > File” e vamos criar o arquivo. Se lembrem, esse arquivo fica na pasta “WEB-INF”!
Projeto 07

O arquivo web.xml tem como suas linhas iniciais várias configurações que são padronizadas. Você pode encontrar facilmente na internet, por isso vou apenas colocar aqui sem explicar o que significam.

<web-app id="WebApp_ID" version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <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>

Depois em um futuro artigo explicarei melhor sobre as tags do arquivo web.xml, por hora:

  • Para cada servlet (< servlet >) precisamos de um Mapeamento (< servlet-mapping >). O mapeamento é quem define o destino das urls digitadas no browser. O Servlet não precisa ser necessariamente uma classe Java. Note que estamos mapeando a url digitada e destinando para uma página HTML. Ou seja, mapping é para capturar o que é digitado na url e passar para o servlet.

Para executarmos nossa pequena aplicação basta clicar com botão direito no nosso projeto Servlet > Run As > Run on Server.
Projeto 08

Basta clicar em “Finish”.
Projeto 09

O Eclipse irá abrir um browser e irá mostrar a tela inicial. Caso seu Eclipse não abra esse browser, após o Tomcat estar ativo, basta digitar o seguinte endereço no seu browser predileto: http://localhost:8080/Servlet/hello . Após a tela inicial, clique no botão vermelho para parar o servidor, pois temos mais trabalho pela frente.
Projeto 10

Vamos alterar o index.html para que ele possa enviar valores, nosso servlet irá tratar esses valores, e enviar para uma próxima página. Os campos serão nome, valor1 e valor2. A pessoa irá digitar seu nome e dois valores a serem somados. Note que existem três tags: “form”, “action” e “method”. Form coloca todos os valores dentro do seu corpo, é como uma sacola ou uma mochila. Tudo que estiver dentro dele irá dentro da requisição. Method define qual o tipo de requisição vamos fazer, existem vários e por hora vamos usar o “post”. A Action define o destino, para onde iremos enviar a requisição.

<html>
    <body>
        <form action="/Servlet/calculemos" method="post">
            <h1>Olá</h1>
            Digite seu nome: <input type="text" name="nome"/> <br/><br/>
            Vamos as somas?<br/>
            Digite o primeiro valor a ser somado: <input type="text" name="valor1"/> <br/>
            Digite o segundo valor a ser somado: <input type="text" name="valor2"/> <br/><br/>
            <input type="submit" value="Calcule"/>
        </form>
    </body>
</html>

Vamos agora criar um Servlet (classe Java que irá tratar a requisição). No eclipse dentro da pasta src vamos criar um package e uma classe Java que “extenda” a classe HttpServlet. Essa classe irá receber os valores da nossa index.html, irá somar os números e encaminhar para uma jsp.
Projeto 11a

Projeto 11b

Projeto 12

Projeto 13

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 valor1;
        int valor2;
        int total = 0;
        String nome = (String) req.getParameter("nome");
        String aviso = "";
        try {
            // Eu sei que está feio, em um futuro poderemos refatorar e aplicar princípios de OO e Design 
            valor1 = Integer.parseInt((String) req.getParameter("valor1"));
        } catch (NumberFormatException e) {
            // Tratando para caso seja digitado um valor inválido 
            valor1 = 0;
            aviso = "Algum valor foi digitado incorretamente (em branco ou caractercs não numérimos), atribuímos 0";
        }
        
        try {
            // Eu sei que está feio, em um futuro poderemos refatorar e aplicar princípios de OO e Design 
            valor2 = Integer.parseInt((String) req.getParameter("valor2"));
        } catch (NumberFormatException e) {
            // Tratando para caso seja digitado um valor inválido
            valor2 = 0;
            aviso = "Algum valor foi digitado incorretamente (em branco ou caracters não numérimos), atribuímos 0";
        }
        // Colocando o nome digitado no request que será enviado ao cliente
        req.setAttribute("nome", nome);
        
        // Enviado o aviso ao cliente
        req.setAttribute("aviso", aviso);

        total = valor1 + valor2;
        
        // Atribuindo o valor da soma ao rquest que será enviado ao cliente
        req.setAttribute("total", total);
        
        // O Request Dispatcher determina o próximo caminho a seguir.
        // Vamos direcioná-lo para a JSP que iremos criar.
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("/WEB-INF/show.jsp");
        
        // Enviamos o processo para frente passando request e o response
        requestDispatcher.forward(req, res);
    }
}

Em nossa jsp iremos exibir o valor da soma e o nome enviado da página inicial. Nossa jsp irá ficar dentro da pasta WEB-INF. Atenção, dentro da pasta WEB-INF!
Projeto 14

Projeto 15

<%@page isELIgnored="false" %>
<html>
    <body>
        Obrigado pela visita ${nome}. <br/>
        O valor da some é: ${total}. <br/>
        
        <br/>${aviso}
    </body>
</html>

Quase acabando. Vamos alterar o arquivo web.xml para que ele possa receber a nova requisição. Lembra da tag “action=calculemos.do” no index.html? É agora que vamos mapeá-lo para que o Tomcat saiba direcioná-lo.

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <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>/calculemos</url-pattern>
    </servlet-mapping> 
</web-app>

Agora basta iniciarmos o Tomcat e pronto (como fizemos da primeira vez para ver nossa primeira página), nosso servlet vai funcionar.

OBS.: Caso seu Tomcat mostre uma telinha com erro e acabe por não funcionar, vá em: Servers > Tomcat (pasta) > Server.xml. Após abrir o arquivo aperte F5. Execute o Tomcat novamente.
Projeto 16

Agora, para executar sem o Eclipse, é mais simples ainda. Vamos utilizar todos os arquivos criados aqui (que podem ser criados inclusive com um notepad). Primeiro, dentro da instalação do seu Tomcat, basta criar dentro da pasta wtpwebapps, a árvore de arquivos e pastas a serguir (dentro da pasta WEB-INF deve ficar igual na foto):
Projeto 17

Projeto 18

Dentro da pasta Servlet coloque o arquivo index.html. E dentro da pasta “/classes/com” ficará nossa classe Servlet.class. Nosso arquivo .class você poderá encontrar dentro do workspace que você configurou.

Agora, basta executar o Tomcat (como feito no início após instalarmos o Tomcat) e digitar no browser http://localhost:8080/Servlet/hello e boa navegação.

Sobre o SCWCD:

  • Todos os arquivos dentro da pasta WEB-INF estão protegidos. Tentem acessar nossa jsp: http://localhost:8080/Servlet/show.jsp Já no caso do index.html conseguimos este acesso pois o arquivo não encontra dentro da pasta WEB-INF http://localhost:8080/Servlet/index.html . Todos os arquivos que se encontram dentro da pasta WEB-INF estão protegidos de acesso direto. Grave isso! ;)
  • Vale a pena, sempre decorar um web.xml de exemplo (com todas as outras tags existentes), pois esse mapeamento cai na prova.

Espero que esse post possa lhe ser muito útil
Até a próxima.

Código Limpo – Parte 01

Já pensou no que as pessoas dizem sobre você após lerem seu código? Não me refiro apenas às pessoas das quais hoje você convive, imagine sobre a primeira empresa que você trabalhou, será que seu código é elogiado? Se seu companheiro de trabalho for ler e entender seu ultimo código, será que ele poderá ter um surto psicótico? O que você pensa, hoje, sobre a qualidade do código que deixaram para você alterar? Qual o nível de habilidade você daria para essa pessoa?

A pergunta que vai ecoar é: “Após analisarem nosso código, eles poderão nos indicar como referência para desenvolvimento?” (ouch!).

Para que isso aconteça, devemos adotar certas boas práticas e costumes enquanto estivermos fazendo nosso “if de cada dia”. Como esse conteúdo é extenso, vou dividi-lo em várias partes.

Como exemplo, iremos utilizar um sistema de consulta à informações das partidas de futebol. Eis um breve resumo: “O sistema Futebol Show tem por objetivo informar dados das partidas. O sistema deve conter: data/horário das partidas agendadas, local da partida, times que estarão jogando (e seus jogadores), trio de arbitragem. Ao final de cada jogo, o sistema retornará a quantidade de gols (total, e gol marcado por cada jogador), o resultado, soma dos cartões aplicados pelo juiz”.

1 – Classes

  • É aconselhável que as classes tenham nomes de substantivos. No nosso exemplo, poderíamos identificar: Partida, Estádio (local da partida), Time, Arbitragem, Jogadores. Isso lhe ajudará a pensar e entender o que está sendo feito, e para onde o sistema está caminhando. Dar-te-á uma melhor visão do contexto. Imagine se colocássemos Estádio como String na classe Partida. Se pedissem para adicionar mais tarde capacidade de pessoas, teríamos que criar mais um atributo em Partida, a classe partida começaria a perder sua Coesão, pois quem deve saber a capacidade de pessoa no estádio é o Estádio, não a Partida.
  • Nome das classes no singular. Se você acabasse de ler uma classe nomeada como Jogadores. O que vem a sua cabeça? Provavelmente, um conjunto de Jogadores. Bem óbvio, mas acreditem, já vi acontecer de encontrar nome de classes no plural. E ao questionar o porquê, não me disseram (ninguém sabia), sendo que a função da classe era de ser um objeto único mesmo. Nomeando corretamente sua classe, irá trazer mais clareza ao propósito da classe.

2 – Métodos

  • O nome dos métodos devem indicar um verbo. Após ler a ação no nome, já temos uma boa idéia do que ele irá realizar. Por exemplo:
    match.goal(value);

    O que esse código faz? O que ele retorna? Lá se vai um tempo para ter que entrar na classe, analisar o método… Imaginem se fosse escrito assim:

    match.getGoalsByPlayer(player);

    Ao ler o nome do método (com o verbo), já dá para ter uma noção do retorno, e inclusive, um provável comportamento do método.

  • É indicado que cada método mantenha um único objetivo. Imagine se você for chamar o método para buscar o total de pessoas presentes na partida:
    List presentAudience = match.getTotalPresentAudience();

    Mas ao executar o método, a seguinte mensagem é retornada:

    Exception in thread "main" main.DaoPublicException
      at main.DaoPublic.updateTotalProfitMatch(DaoPublic.java:6)
      at main.PresentAudience.getPresentAudience(PresentAudience.java:7)
      at main.match.getPresentAudience(match.java:7)
      at main.Principal.main(Principal.java:13)

    Espere, porque um método de atualizar renda da partida está sendo executado onde uma simples consulta deveria ser feita? Seu método tem que ser “Coeso”. Caso não haja outra opção, como última escolha, altere o nome do método para que o desenvolvedor que usar o método esteja ciente do que vai ocorrer. (Sei que o nome ficou feio, mas…).

    match.getPresentAudienceAndUpdateProfit();
  • Identação: “Deve ser a primeira regra do desenvolvedor”. O problema é que cada pessoa tem seu modo predileto, e às vezes não condiz com o padrão da empresa. Uma coisa é certa, não sei qual o padrão que você irá adotar, mas, por favor, sempre adote um. Abaixo dois códigos onde que, em sua leitura, fica clara a diferença de leitura:
            public int calculateScoredGoals()
        {int total = visitorTeam.getScoredTeam() +
    houseTeam.getScoredTeam();
                return total
            ;}
      public int calculateScoredGoals(){
        int total = visitorTeam.getScoredTeam() +
        houseTeam.getScoredTeam();
        return total;
      }

    Não importa qual a sua identação, apenas adote uma que facilite a leitura não só sua, mas de toda empresa.

  • Não devemos preservar referências retornadas por métodos que não terão utilizade depois. Vamos imaginar um método de atualização, que retorna a lista com os objetos que foram atualizados para caso queira utilizar:
      public void updateMatchDate() {
        //... Some code
        List expelledPlayers = DaoFactory.getDaoMatch().updatePlayers(expelledPlayers);
        //... More code, but none of them accessing expelledPlayers
      }

    Qual o motivo de ter criado a referência para a lista? Para que? Bastaria chamar o método e pronto. A lista será atualizada e você terá uma referência a um objeto alocado na memória que não será utilizado.

Esse foi o primeiro post sobre esse assunto, ainda falta muito pela frente!

Caso queria debater sobre essas idéias, podem postar que eu responderei. Gosto de aprender com a experiência de todos.

Diga, não pergunte!

Às vezes ao programar OO nos deparamos com situações das quais nos sentimos tentados sempre em colocar um valor em um atributo de modo mais rápido. Talvez o prazo para entrega do projeto esteja curto, ou então a alteração em questão é grande e não nos preocupanos com pequenos detalhes… Com isso é mais fácil deixar ser levado pelas circunstâncias do que analisar o que estamos fazendo.

Suponhamos que nós temos uma classe Porta e queremos saber se a ela está aberta ou não, e queremos mais, queremos mudar o estado dela de aberta para fechado e vice-versa. Um modo bem simples seria criar a classe e nela colocarmos um atributo booleano:

 public class Door {
     private boolean doorIsOpen = false;
}

Até aí tudo tranquilo, mas agora começa o perigo. Como iremos fazer com que essa variável tenha seu valor alterado? Devemos optar que essa alteração fosse realizada pela classe Porta? Ou pelo objeto que está chamando o objeto Porta? A solução mais comum que vemos por aí é fazer um get/set muito encontrado em códigos legados:

public void setDoorIsOpen(boolean doorIsOpen) {  
	this.doorIsOpen = doorIsOpen;  
}

public boolean getDoorIsOpen() {  
	return doorIsOpen;  
}  
// To close the Door  
if (door.getDoorIsOpen() == true)  
	door.setDoorIsOpen(false);  

// To open the Door
if (door.getDoorIsOpen() == false)  
	porta.setDoorIsOpen(true);

Pense comigo, e se, essa condição de pergunta (if + get) e o método set estivesse em 30 pontos do sistema e o cliente pedir uma nova regra de negócio. Imaginemos que, para ser fechada, a Porta tem que estar com o alarme ligado:

  public class Door {  
       private boolean doorIsOpen = false;  
       private boolean alarmIsActive = true;  
       public boolean getAlarmIsActive() {  
            return alarmIsActive;  
       }  
  }
  // To close the Door  
  if (door.doorIsOpen() && door.getAlarmIsActive ())  
       door.setDoorIsOpen(false);

Utilizando esse tipo de código, seria necessário ter que alterar todo os método do projeto que utilizassem esse código. Imagine todo o trabalho que teríamos para realizar essa alteração por todo o código…

Para não ter todo esse trabalho, basta dizer ao objeto Porta o que fazer, e não perguntar o estado do seu atributo para depois alterá-lo.

Utilizando esse conceito, alteração do código aconteceria apenas em um ponto e os outros 30 pontos do sistema continuariam intactos. O código inicial, antes da alteração solicitada pelo cliente (alarme ligado), ficaria assim:

  public class Door {  
      private boolean doorIsOpen = false;  
      private boolean alarmIsActive = true;  
      public boolean getAlarmIsActive() {  
           return alarmIsActive;  
      }  
      public boolean isOpen() {  
           return doorIsOpen;  
      }  
       public void closeDoor(){  
          doorIsOpen = false;  
       }  
       public void openDoor(){  
            doorIsOpen = true;  
       }  
  }

E o código para fechar/abrir a Porta seria bem mais simples:

  // Closes the Door
  if (door.isOpen())  
       door.closeDoor();  
  // Opens the Door
  if (!door.isOpen())  
       door.openDoor();

Após essa alteração, para aplicarmos o código novo (verificando o alarme), basta apenas colocar a condição do alarme dentro do método de fechar a Porta, e pronto, alteramos uma linha em uma classe todo o resto do sistema fica intocável:

  public void closeDoor(){  
       if (alarmIsActive)  
            doorIsClose = false;
  }

Agora, toda vez que a regra de negócio mudar (ex.: fechar a Porta), basta apenas alterar um método dentro da classe específica que o restante do projeto continuará intacto.

Utilizando esse princípio, diminuímos o acoplamento entre as classes e seu código está apto a ser utilizado em todas as partes do sistema.

Fica a dica.

Inspirado por: “The pragmatic Bookshelf – Alec Sharp”

Edit: Código final, dica do H.Fernandes. [=