Sie sind auf Seite 1von 22

Mdulo 6

Programao WEB

Lio 3
Classes Servlets Avanadas

Verso 1.0 - Nov/2007

JEDITM

Autor Daniel Villafuerte Equipe Rommel Feria John Paul Petines

Necessidades para os Exerccios

Sistemas Operacionais Suportados NetBeans IDE 5.5 para os seguintes sistemas operacionais: Microsoft Windows XP Profissional SP2 ou superior Mac OS X 10.4.5 ou superior Red Hat Fedora Core 3 Solaris 10 Operating System (SPARC e x86/x64 Platform Edition) NetBeans Enterprise Pack, poder ser executado nas seguintes plataformas: Microsoft Windows 2000 Profissional SP4 Solaris 8 OS (SPARC e x86/x64 Platform Edition) e Solaris 9 OS (SPARC e x86/x64 Platform Edition) Vrias outras distribuies Linux Configurao Mnima de Hardware Nota: IDE NetBeans com resoluo de tela em 1024x768 pixel Sistema Operacional Microsoft Windows Linux Solaris OS (SPARC) Solaris OS (x86/x64 Platform Edition) Mac OS X Processador 500 MHz Intel Pentium III workstation ou equivalente 500 MHz Intel Pentium III workstation ou equivalente UltraSPARC II 450 MHz AMD Opteron 100 Srie 1.8 GHz PowerPC G4 Memria 512 MB 512 MB 512 MB 512 MB 512 MB HD Livre 850 MB 450 MB 450 MB 450 MB 450 MB

Configurao Recomendada de Hardware Sistema Operacional Microsoft Windows Linux Solaris OS (SPARC) Solaris OS (x86/x64 Platform Edition) Mac OS X Processador 1.4 GHz Intel Pentium III workstation ou equivalente 1.4 GHz Intel Pentium III workstation ou equivalente UltraSPARC IIIi 1 GHz AMD Opteron 100 Series 1.8 GHz PowerPC G5 Memria 1 GB 1 GB 1 GB 1 GB 1 GB HD Livre 1 GB 850 MB 850 MB 850 MB 850 MB

Requerimentos de Software NetBeans Enterprise Pack 5.5 executando sobre Java 2 Platform Standard Edition Development Kit 5.0 ou superior (JDK 5.0, verso 1.5.0_01 ou superior), contemplando a Java Runtime Environment, ferramentas de desenvolvimento para compilar, depurar, e executar aplicaes escritas em linguagem Java. Sun Java System Application Server Platform Edition 9. Para Solaris, Windows, e Linux, os arquivos da JDK podem ser obtidos para sua plataforma em http://java.sun.com/j2se/1.5.0/download.html Para Mac OS X, Java 2 Plataform Standard Edition (J2SE) 5.0 Release 4, pode ser obtida diretamente da Apple's Developer Connection, no endereo: http:// developer.apple.com/java ( necessrio registrar o download da JDK). Para mais informaes: http://www.netbeans.org/community/releases/55/relnotes.html

Programao WEB

JEDITM

Colaboradores que auxiliaram no processo de traduo e reviso


Acio Jnior Alexandre Mori Alexis da Rocha Silva Allan Souza Nunes Allan Wojcik da Silva Angelo de Oliveira Aurlio Soares Neto Bruno da Silva Bonfim Carlos Fernando Gonalves Denis Mitsuo Nakasaki Emanoel Tadeu da Silva Freitas Felipe Gacho Jacqueline Susann Barbosa Joo Vianney Barrozo Costa Luciana Rocha de Oliveira Luiz Fernandes de Oliveira Junior Marco Aurlio Martins Bessa Maria Carolina Ferreira da Silva Massimiliano Giroldi Mauro Cardoso Mortoni Paulo Oliveira Sampaio Reis Pedro Henrique Pereira de Andrade Ronie Dotzlaw Sergio Terzella Thiago Magela Rodrigues Dias Vanessa dos Santos Almeida Wagner Eliezer Roncoletta

Auxiliadores especiais
Reviso Geral do texto para os seguintes Pases:
Brasil Tiago Flach Guin Bissau Alfredo C, Bunene Sisse e Buon Olossato Quebi ONG Asas de Socorro

Coordenao do DFJUG

Daniel deOliveira JUGLeader responsvel pelos acordos de parcerias Luci Campos - Idealizadora do DFJUG responsvel pelo apoio social Fernando Anselmo - Coordenador responsvel pelo processo de traduo e reviso, disponibilizao dos materiais e insero de novos mdulos Rodrigo Nunes - Coordenador responsvel pela parte multimdia Srgio Gomes Veloso - Coordenador responsvel pelo ambiente JEDITM (Moodle)

Agradecimento Especial
John Paul Petines Criador da Iniciativa JEDITM Rommel Feria Criador da Iniciativa JEDITM

Programao WEB

JEDITM

1. Objetivos
Na lio anterior, reparamos como as classes Servlets podem ser utilizadas pelos desenvolvedores Java para receber requisies de clientes e produzir respostas dinamicamente. Tambm vimos como distribuir Servlets empacotando-as em arquivos WAR e carregando-as no continer WEB. Ao final desta lio, o estudante ser capaz de:

Redirecionar respostas Identificar o escopo dos objetos Utilizar sesses e rastreamento de sesso Utilizar Filtros

Programao WEB

JEDITM

2. Redirecionamento de Resposta
Existem casos onde queremos que a servlet tenha somente a responsabilidade de fazer algum processamento inicial e deixe a gerao do contedo a alguma outra entidade. Suponhamos que seja obtido do usurio algum valor e o apresentemos com diversas vises baseadas no valor. Digamos tambm que tenhamos um site que, aps processar a entrada do usurio, apresente diferentes pginas dependendo do perfil do usurio no sistema. Colocar toda a gerao de contedo para todas as pginas em uma nica servlet pode torn-la no gerencivel. Nestes casos, seria melhor a servlet redirecionar a gerao da sada. Existem dois modos que podemos utilizar para realizar esse redirecionamento.

Atravs do objeto RequestDispatcher Atravs do mtodo sendRedirect() encontrado no objeto HttpServletResponse

2.1. RequestDispatcher
possvel obter uma instncia do objeto RequestDispatcher invocando o seguinte mtodo: public RequestDispatcher getRequestDispatcher(String path) Este mtodo pode ser encontrado no objeto HttpServletRequest. O parmetro String que este mtodo recebe a localizao da pgina HTML, JSP ou a servlet para a qual se queria disparar a requisio. Uma vez com a instncia do objeto RequestDispatcher, existe a opo de se invocar um dos seguintes mtodos: public void include(ServletRequest req, ServletResponse res) public void forward(ServletRequest req, ServletResponse res) Ambos mtodos pegam o contedo produzido no local especificado e torna-o parte da resposta da servlet para o usurio. A principal diferena entre eles que, o mtodo forward faz com que a pgina alvo tenha toda a responsabilidade de gerar a resposta, enquanto que o include s incorpora o contedo da pgina alvo. Utilizando o mtodo include, pode-se adicionar outro contedo a reposta ou mesmo incluir outra pgina alvo. Para ilustrar a diferena entre os dois, so apresentadas duas Servlets abaixo. O cdigo virtualmente idntico. A primeira faz o uso do mtodo include enquanto a segunda faz uso do mtodo forward. public DispatchServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("Error occurred during login request processing"); RequestDispatcher rd = request.getRequestDispatcher("/login.html"); rd.include(request, response); } } public DispatchServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("Error occurred during login request processing"); RequestDispatcher rd = request.getRequestDispatcher("/login.html"); rd.forward(request, response); } } Ambas servlets definidas acima usam uma pgina denominada login.html para formar a base da

Programao WEB

JEDITM

sada dos dados. A definio desta pgina segue abaixo: <H1>Login Page</H1> <form action="DispatchServlet"> User name : <input type="text" name="loginName"><br/> Password : <input type="password" name="password"><br/> <input type="submit"/> </form> Ao executar a primeira Servlet, a que utiliza o mtodo include, a seguinte sada gerada:

Figura 1: Sada de DispatchServlet utilizando o mtodo include

Executando a segunda Servlet temos o seguinte resultado:

Figura 2: Sada de DispatchServlet utilizado mtodo forward

Dos cdigos praticamente idnticos, temos duas sadas diferentes. Ao utilizar o mtodo include, a mensagem que enviada para o usurio antes de se chamar o mtodo. Este no o caso para a sada do mtodo forward onde a mensagem apresentada antes da chamada do mtodo no se tornar parte da sada. Com o mtodo forward, todo o contedo do buffer da resposta limpo antes da chamada do mtodo, e depois a resposta imediatamente enviada. Nenhum contedo pode ser adicionado. Com o mtodo include, todo o contedo colocado no buffer de resposta mantido antes e depois da chamada do mtodo.

Programao WEB

JEDITM

Utilizando-se o mtodo include, possvel que a servlet apresente a sada de diferentes fontes de uma s vez. tambm permitido concatenar mensagens a outro contedo esttico. Tome-se o seguinte exemplo: public LoginServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { RequestDispatcher rd = null; // recupera os parmetros do formulrio do usurio String loginName = request.getParameter("loginName"); String password = request.getParameter("password"); User user = null; // cria o JavaBean implementando a funcionalidade de autenticao UserService service = new UserService(); user = service.authenticateUser(loginName, password); if (user == null) { // gera a mensagem de erro response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("User does not exist with given login and/or password"); // retorna para a pgina de login do usurio rd = request.getRequestDispatcher("/login.html"); rd.include(request, response); out.close(); } else { // armazena o objeto User na sesso HttpSession session = request.getSession(); session.setAttribute(ApplicationConstants.USER_OBJECT, user); // constri a resposta a partir de mltiplos componentes HTML rd = request.getRequestDispatcher("/header.html"); rd.include(request, response); rd = request.getRequestDispatcher("/mainContent.html"); rd.include(request, response); rd = request.getRequestDispatcher("/footer.html"); rd.include(request, response);

Como o mtodo include somente adiciona contedo de outra fonte e no envia a resposta aps sua chamada, podemos utiliz-lo repetidamente. Utilizando este princpio, a classe LoginServlet apresentada acima capaz de criar uma resposta contendo trs pginas diferentes.

2.2. sendRedirect
A outra forma de redirecionar a sada de uma entidade fora de uma servlet o mtodo sendRedirect. Este mtodo tem a seguinte assinatura e pode ser encontrado no objeto HttpServletResponse: public void sendRedirect(String relativePath) O parmetro que o mtodo recebe um String que representa o caminho para a pgina alvo a ser redirecionada para o usurio. A chamada a este mtodo instrui o browser para enviar outra requisio HTTP para a pgina alvo especificada. Isto torna a pgina alvo a nica entidade responsvel por gerar o contedo que, de certa forma, de resultado similar ao se utilizar o mtodo forward do objeto RequestDispatcher discutido anteriormente. Contudo, a requisio reenviada apresenta diversas diferenas prticas comparadas ao mtodo forward:
Programao WEB 7

JEDITM

A URL no browser reflete o alvo especificado. Isto torna do mtodo sendRedirect no desejvel caso no se queira que o usurio esteja ciente do redirecionamento. Como efetivamente uma nova requisio, os dados armazenados no objeto da requisio so descartados. Os parmetros fornecidos pelo usurio, se existirem, devem ser resubmetidos caso a pgina alvo necessite destes. Os dados que estiverem armazenados no objeto request devem ser mantidos de alguma forma. Caso contrrio, sero perdidos.

recomendado ento que o mtodo include seja utilizado para permitir sada a partir de diversas fontes. O mtodo forward deveria ser utilizado no redirecionamento para componentes cujo contedo seja gerado de forma dinmica (ex: Servlets e JSPs), enquanto que o mtodo sendRedirect deveria ser utilizado no redirecionamento para componentes que gerem contedo esttico.

Programao WEB

JEDITM

3. Objetos de Escopo
A especificao servlet nos apresenta quatro escopos onde os dados podem ser armazenados, de forma que possam ser compartilhados entre os componentes. Eles esto listados abaixo em ordem crescente de visibilidade:

Pgina O escopo de pgina definido para ser o escopo de uma pgina JSP simples. As variveis declaradas dentro da pgina so visveis somente nela e deixaram de ser visveis uma vez que o servio da pgina for finalizado. O objeto associado a esse escopo o objeto PageContext. Requisio O escopo de requisio definido pela requisio simples proveniente do cliente. Os dados que so armazenados neste escopo so visveis a todos componentes WEB que manipulam a requisio do cliente. Aps a requisio do cliente ter sido finalizada, ou seja, o cliente recebeu uma resposta HTTP e finalizou a conexo com o servidor, todos os dados armazenados dentro deste escopo no so mais visveis.

O objeto associado a este escopo o objeto HttpServletRequest. As instncias deste objeto esto prontamente disponveis s Servlets como parmetros que podem ser obtidos nos mtodos de servio invocados pelo continer atravs da requisio do cliente.

Sesso Este o escopo que abrange uma sesso com o cliente. Esta sesso se inicia quando o cliente acessa a aplicao pela primeira vez e finaliza quando o usurio realiza o logout do sistema ou a partir de um timeout definido no servidor. Os dados deste escopo esto visveis a todos componentes WEB que o cliente utilizar durante este intervalo. Os dados de uma sesso de usurio, contudo, no esto visveis para outros usurios.

O objeto associado com este escopo o objeto HttpSession. Uma instncia deste objeto pode ser obtida utilizando o mtodo getSession() do objeto HttpServletRequest.

Aplicao Este escopo abrange toda a aplicao. Os dados armazenados neste escopo so visveis a todos os componentes, independente de requisio de usurio ou sesso que os estejam manipulando, e dura at a aplicao ser finalizada.

O objeto associado com esse escopo o objeto ServletContext. Como citado anteriormente, ele pode ser obtido atravs da chamada do mtodo getServletContext() do um objeto ServletConfig vlido.

3.1. Armazenando e Recuperando Dados do Escopo


Todos os objetos do escopo mencionados acima contm mtodos comuns para recuperar e armazenar dados neles. Para armazenar os dados, utilize o mtodo: public void setAttribute(String chave, Object valor); O parmetro String que o mtodo recebe armazenar o Objeto associado a a este valor. Para recuperar os dados posteriormente, passar a mesma chave como parmetro para o mtodo: public Object getAttribute(String chave); Se no houver objeto a ser recuperado para uma dada chave, o valor null retornado pelo mtodo. Alm disso, como o tipo de retorno Object, fica a cargo do desenvolvedor fazer o casting para a classe apropriado e realizar checagem de tipo. Para remover um atributo do escopo, simplesmente invoque o mtodo removeAttribute() e passe a chave do atributo como parmetro.

3.2. Cenrio de Exemplo


Vamos analisar o seguinte cenrio: a aplicao dever exibir os detalhes de uma pessoa a partir de seu personalID. Este personalID ser fornecido pelo usurio. Para promover a manutenibilidade, o componente que recuperar os detalhes pessoais ser separado do componente que exibir as informaes para o usurio. Estes dois componentes faro a
Programao WEB 9

JEDITM

comunicao utilizando o armazenamento de dados e as estruturas disponveis no escopo de requisio. public PersonalDataRetrievalServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // recupera o parmetro personalID informado pelo usurio String personalID = request.getParameter("personalID"); // cria o objeto de negcios que manipula uma implementao para obteno de // dados para um dado id. DataService service = new DataService(); // recupera o objeto person que contm os detalhes necessrios Person person = service.retrievePersonalDetails(personalID); // armazena os dados no escopo requisio utilizando uma chave request.setAttribute(ApplicationConstants.PERSON, person); // forward da requisio para o componente que exibir os detalhes RequestDispatcher dispatcher = request.getRequestDispatcher("/DisplayServlet"); dispatcher.forward(request, response);

public DisplayServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // recupera o objeto Person que contm os detalhes Person person = (Person) request.getAttribute(ApplicationConstants.PERSON); // constri a resposta baseado nas informaes StringBuffer buffer = new StringBuffer(); buffer.append("<HTML><TITLE>Personal Info</TITLE>"); buffer.append("<BODY><H1>Details : </H1><br/>"); buffer.append("Name : "); buffer.append(person.getName()); buffer.append("<br> Address : "); buffer.append(person.getAddress()); buffer.append("</BODY>"); // exibe a resposta response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println(buffer.toString()); out.close();

O cdigo para o objeto DataService e o objeto Person no so listados aqui com suas implementaes porqu no so relevantes para nosso exemplo. O que o exemplo acima mostra como armazenar os dados de um objeto em uma servlet e como recuperar os mesmos dados a partir de outra servlet que possui acesso ao mesmo escopo. Seguem algumas notas sobre o exemplo. Primeiro, a segunda servlet foi capaz de recuperar os dados da requisio porqu ela parte da mesma requisio. Se fosse usado o mtodo sendRedirect() como meio de redirecionamento de controle da servlet, o mtodo getAttribute() retornaria null j que o mtodo sendRedirect() teria feito com que o browser enviasse outra requisio. Isto efetivamente acabaria com o tempo de vida da requisio, e com os objetos armazenados dentro dela. Segundo, recomendado que as chaves utilizadas para armazenar e recuperar os dados estejam
Programao WEB 10

JEDITM

disponveis para a aplicao como constantes, conforme o exemplo acima. Isto assegura que a mesma chave seja utilizada para armazenamento e recuperao, reduzindo a possibilidade de erros que possam ser encontrados durante o desenvolvimento.

Programao WEB

11

JEDITM

4. Rastreabilidade e Gerncia de Sesso


Recordemos que o protocolo HTTP foi projetado para ser um protocolo conectado, sem estado. Quando um browser enviar uma requisio para o servidor, ele abre uma conexo, envia uma requisio HTTP, consome a resposta HTTP, e ento fecha a conexo. Como cada requisio de um browser efetivamente enviada por diferentes conexes a cada vez, e o servidor no sabe dos clientes que o esto acessando, o problema da manuteno do estado para uma transao de um usurio em particular um problema a ser enfrentado. Uma soluo para este problema o servidor manter o conceito de uma sesso de usurio. Com uma sesso, o servidor capaz de reconhecer um cliente no meio de mltiplas requisies. Com este caracterstica, o servidor consegue agora ser capaz de manter o estado para um cliente. Para tal sesso existir, o browser cliente deve ser capaz de enviar dados para o servidor alm da requisio HTTP padro. Estes dados permitem ao servidor identificar qual usurio est realizando a requisio, e manter seu estado conciso. Existem 3 solues tpicas para esse problema: cookies, URL-rewriting (reescrita de URL) e campos ocultos no formulrio.

4.1. Mtodos Tradicionais para manter o Estado da Sesso


4.1.1. Cookies Cookies so pequenas estruturas de dados utilizados pelo servidor WEB que entregam dados para o browser cliente. Estes dados so armazenados pelo browser e, e em algumas circunstncias, o browser retorna os dados de volta ao servidor WEB. Ao utilizar cookies, os Servlets podem armazenar identificadores das sesses que podem ser utilizados para identificar o usurio como um participante de uma sesso em particular. Aps o identificador ser gerado, ele armazenado num objeto Cookie, e enviado de volta ao browser cliente para ser armazenado. Este objeto Cookie pode ento ser obtido toda vez a partir do objeto da requisio para determinar se o usurio est em determinada sesso. Abaixo segue um trecho de cdigo sobre como utilizar Cookies para rastreamento de sesses nas Servlets: ... // gerar um novo session ID para o usurio String sessionID = generateSessionID(); // criar novo mapa que ser utilizado para armazenar os dados a serem mantidos na sesso HashMap map = new HashMap(); // recuperar um mapa utilizado como continer para as informaes do usurio HashMap containerMap = retrieveSessionMaps(); // adicionar o novo mapa criado no mapa contendo todas as informaes de sesso containerMap.put(sessionID, map); // criar o cookie que ser armazenado no browser Cookie sessionCookie = new Cookie("JSESSIONID", sessionID); // adicionar o cookie resposta e pedir ao browser para armazen-lo response.addCookie(sessionCookie); ... Para obter o MAP contendo os dados da sesso, as Servlets obtm o Cookie contendo o ID da sesso, e ento obtm o HashMap apropriado utilizando o identificador da sesso como uma chave. Embora os Cookies sejam uma boa soluo para o rastreamento, seu uso requer que os desenvolvedores manipulem diversos detalhes, como:

gerar um id nico para a sesso de cada usurio,


12

Programao WEB

JEDITM

recuperar o Cookie apropriado do Browser que contm o Session ID e definir um tempo apropriado para a expirao do Cookie.

Alm dos detalhes acima, um problema com a utilizao de Cookies que alguns usurios desabilitam o suporte a Cookies no Browser por questes de segurana. So necessrias abordagens alternativas. 4.1.2. URL Rewriting (Reescrita de URL) Nesta abordagem, o Browser cliente concatena um Session ID nico ao fim de cada requisio que ele faz ao servidor. Este Session ID pode ento ser lido, e a informao apropriada ao usurio recuperada. Esta outra boa soluo que funciona mesmo se o usurio desabilitar o uso de Cookies. Contudo, existem dois problemas associados com essa abordagem. Primeiro, o servidor deve assegurar que cada Session ID que ele fornece seja nico. Segundo, a aplicao completa deve ser escrita de forma que o Session ID concatenado a todos os Links/URLs apontem para a aplicao. Qualquer requisio que no inclua o Session ID no seria considerada parte da sesso e no teria acesso s informaes especficas da sesso. 4.1.3. Campos ocultos no fomulrio Nesta abordagem, um campo oculto no formulrio introduzido nos formulrios HTML com o valor sendo definido a uma sesso particular. Entretanto, este mtodo muito limitado pelo fato de que somente pode ser utilizando quando h um formulrio na pgina que o cliente esteja utilizando.

4.2. Rastreabilidade de Sesso em Servlets


A especificao de Servlets oferece uma API de alto nvel para fornecer acesso ao rastreamento de sesso: a API HttpSession. Ao utilizar esta API, o desenvolvedor no precisa se preocupar com muitos dos detalhes mencionados acima: reconhecimento do Session ID, detalhes da manipulao de Cookies e detalhes da extrao de informaes da URL. Estes detalhes so transparentes ao desenvolvedor. E, alm disso, o desenvolvedor conta com um local apropriado conveniente para armazenar os dados de uma sesso para o usurio. O uso correto da API HttpSession tambm permite aplicao trocar para o mtodo de reescrita de URL caso seja detectado que o suporte a Cookies no Browser cliente esteja desabilitado. 4.2.1. Obtendo uma instncia do objeto HttpSession O objeto HttpSession representa os dados da sesso associados a uma dada requisio por um cliente, este pode ser obtido chamando o mtodo getSession() do objeto HttpServletRequest. O continer ento responsvel por ler os dados do cliente (ou dos Cookies ou da reescrita de URL), e criar uma instncia do objeto HttpSession. Passando um valor booleano para o mtodo getSession() (ex., getSession(true)), possvel especificar ao servidor se um novo objeto HttpSession deve ser automaticamente criado no caso de um usurio no ter uma sesso. Um cdigo de exemplo mostrando como obter uma instncia do objeto HttpSession apresentado a seguir: public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { .... HttpSession session = request.getSession(); 4.2.2. Armazenando e recuperando dados em uma sesso Atravs da classe javax.servlet.http.HttpSession, os desenvolvedores no precisam mais gerenciar objetos explicitamente para armazenar dados em uma sesso de usurio, basta utilizar um dos seguintes mtodos:

Programao WEB

13

JEDITM

public void setAttribute(String key, Object value) public Object getAttribute(String key) Este so os mesmos mtodos que encontramos durante nossa discusso sobre diferentes escopos de objetos. Na verdade, os objetos HttpSession que estamos trabalhando agora representam o escopo de sesso discutido previamente. Outro exemplo de como salvar e recuperar objetos no escopo de sesses apresentado abaixo: public class LoginServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { User user = authenticateUser(); ... HttpSession session = request.getSession(); session.setAttribute("userObject", user); ... } } O trecho de cdigo acima mostra o tratamento de uma entrada do usurio atravs de uma Servlet. Uma atividade comum realizada por tais tratamentos, alm da autenticao de usurios, a armazenagem de um Objeto tipo user que representa o usurio no escopo da sesso. Este objeto pode ser recuperado por outras Servlets que precisarem de informaes sobre o usurio atual, tais como: public class InfoServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); User user = (User)session.getAttribute("userObject"); // implementar aqui as operaes necessrias sobre o objeto "user" } } 4.2.3. Removendo dados armazenados na sesso do usurio Para remover dados armazenados no escopo de sesso, chame o mtodo removeAttribute() e passe a chave (tipo String) associada ao valor em questo. Um exemplo de servlet realizando tal remoo apresentado abaixo. Neste cenrio imaginrio, a aplicao armazenou um valor temporrio dentro da sesso associado chave "tempData". Aps ter realizado todas as operaes necessrias com os valores associados a esta chave, o cdigo remove o dado da sesso. public class InfoProcessingServlet extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); session.removeAttribute("tempData"); // redirecionar a resposta para a prxima pgina web response.sendRedirect("next.html"); } } 4.2.4. Encerrando a sesso Encerramento Automtico atravs de timeout Sesses so automaticamente encerradas aps um intervalo pr-determinado de tempo (diz-se que a sesso expira). Este intervalo pode ser inspecionado e configurado no descritor de distribuio da aplicao (deployment descriptor). O descritor de distribuio para o exemplo FirstServlet apresentado abaixo para que possamos revis-lo novamente. ...
Programao WEB 14

JEDITM

</servlet-mapping> <session-config> <session-timeout> 30 </session-timeout> </session-config> <welcome-file-list> ... O valor 30 do elemento <session-timeout> indica que o servidor deve esperar pelo menos 30 minutos de inatividade do usurio antes de encerrar uma sesso. Aps este perodo, todos os objetos contidos no escopo de sesso sero removidos e o objeto HttpSession se tornar invlido. Forar o encerramento da sesso atravs de cdigo (encerramento programtico) Alm do perodo de time-out, uma sesso pode ser terminada programaticamente atravs do mtodo invalidate() da classe HttpSession. O uso deste mtodo recomendado para situaes onde o usurio no precisa mais fazer parte de uma sesso, como por exemplo quando realizamos a sada da aplicao. Encerrar uma sesso programaticamente, ao invs de esperar o time-out, tambm uma forma de liberar os recursos mais rapidamente. Isso tambm garante que qualquer informao sigilosa armazenada na sesso seja descarregada do escopo de sesso imediatamente, dificultando que tais informaes sejam acessadas por outras pessoas. Um exemplo de tratamento de logout por uma Servlet apresentado abaixo: public class LogoutServlet extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); // realizar aqui outras tarefas do logout // invalidar a sesso do usurio session.invalidate(); // redirecionar o usurio para a pgina de login response.sendRedirect("login.jsp"); } } 4.2.5. Realizando Redirecionamento de URL (URL-Rewriting) Por default, objetos HttpSession usam Cookies para manter o escopo de sesses. Entretanto, devemos desenvolver nossas aplicaes adicionando suporte para redirecionamento de URLs, permitindo que a aplicao rode igualmente bem em navegadores que no suportam Cookies. Podemos adicionar suporte a redirecionamento de URLs usando o mtodo encodeURL() encontrado na interface javax.servlet.http.HttpServletResponse. Esse mtodo recebe como parmetro uma String representando um caminho (path) ou uma URL. O mtodo, ento, verifica se o suporte a Cookies est habilitado no navegador do usurio. Se o suporte a Cookies est habilitado, o mtodo retorna a String recebida como parmetro. Caso contrrio, habilita o redirecionamento de URLs incluindo a identificao da sesso (Session ID) como um dos parmetros da URL. O cdigo abaixo um exemplo de como usar o mtodo encodeURL: ... String encodedURL = response.encodeURL("/welcome.jsp"); out.println("<A HREF='" + encodedURL + "'>Clique aqui para continuar</A>"); ... Para fornecer a funcionalidade de redirecionamento de URLs em nossa aplicao WEB, devemos substituir todas as URLs exibidas ao usurio, como hyperlinks, por alguma pgina passada com o mtodo encodeURL. Caminhos (paths) repassados ao mtodo sendRedirect, discutido anteriormente, tambm devem ser novamente codificados desta vez, usando o mtodo encodeRedirectURL().

Programao WEB

15

JEDITM

5. Filtros (Filter)
Filtros so componentes WEB avanados, introduzidos desde a especificao Serlvet 2.3. So componentes que se interpem entre uma requisio do cliente e um determinado recurso. Qualquer tentativa de recuperar o recurso deve passar pelo filtro. Um recurso pode ser qualquer contedo esttico ou dinmico (HTML, JSP, GIF, etc.). Filtros funcionam interceptando as requisies do cliente ao servidor atravs de um encadeamento de filtros. Ou seja, existe uma srie de filtros, atravs dos quais uma requisio passa, antes de, finalmente, acessar um determinado recurso. Quando a requisio passa pelo filtro, esse filtro pode processar os dados contidos na requisio e tambm decidir sobre o prximo passo da requisio que pode ser encaminhada para um outro filtro (caso o filtro atual no seja o ltimo da cadeia de filtros), acessar o recurso diretamente ou impedir que o usurio acesse o recurso desejado.

Figura 3: Ilustrao de requisio de passagem por filtros

A figura acima apresenta a maneira pela qual as requisies passam atravs de filtros, antes de acessar seu ponto final (EndPoint) um recurso. Filtros so componentes teis, visto que fornecem ao desenvolvedor uma forma simples de incluir processamento adicional, antes que os recursos de uma aplicao WEB sejam acessados. Esse tipo de funcionalidade tambm possvel de ser implementado atravs do redirecionamento de Servlets e requisies. Entretanto, o uso de redirecionamento bem menos elegante, porque exige que o encadeamento dos processos seja programado diretamente no cdigo das Servlets que compem a aplicao e cada vez que esse encadeamento mudar, sero necessrias modificaes no cdigo das Servlets para reconfigurar o encadeamento. Filtros, por sua vez, no sofrem essa limitao, pois o continer que gerencia a seqncia de componentes a serem chamados, antes que uma determinada requisio acesse um recurso. Eventualmente, o continer pode ser reconfigurado alterando-se a quantidade e a ordem dos filtros, sem que haja necessidade de alteraes no cdigo-fonte da aplicao.

5.1. Criando um Filtro


Para criar um filtro, os desenvolvedores devem criar uma classe que implemente a interface javax.servlet.Filter. Essa interface define os seguintes mtodos:

void init(FilterConfig config) throws ServletException esse mtodo chamado pelo continer durante a primeira vez que o filtro carregado na memria. Cdigos de inicializao devem ser colocados aqui, incluindo o uso de parmetros de inicializao contidos no arquivo web.xml recebidos no parmetro FilterConfig. void destroy esse mtodo chamado pelo continer quando o filtro descarregado da memria. Isso ocorre normalmente quando a aplicao WEB encerrada. O cdigo de

Programao WEB

16

JEDITM

liberao de recursos utilizados pelo filtro deve ser inseridos aqui o encerramento de uma conexo ao banco de dados, por exemplo.

void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException esse mtodo contm toda a funcionalidade do filtro, ou seja, as regras que devem ser verificadas, antes que uma requisio possa continuar seu caminho at um recurso. Esse mtodo chamado pelo continer quando o servidor decide que o filtro deve interceptar uma determinada requisio ou resposta ao usurio. Os parmetros passados para esse mtodo so instncias das classes ServletRequest e ServletResponse do pacote javax.servlet.http e da classe FilterChain do pacote javax.servlet. Se o filtro estiver sendo usado por uma aplicao web (o caso mais comum), o desenvolvedor pode realizar o casting entre esses objetos para instncias das classes HttpServletRequest e HttpServletResponse do pacote javax.servlet.http, respectivamente. Isso permite a recuperao de informaes especficas do protocolo HTTP.

Assim como um servlet, o continer ir criar uma nica instncia da classe Filter e usar processamento multi-tarefa (multi-threading), para lidar com as requisies concorrentes de vrios clientes. Isso significa que esse mtodo deve ser programado no modo thread-safe. Um exemplo de classe implementando um filtro apresentado abaixo. Esse filtro usa o recurso de entrada disponvel na classe ServletContext, para registrar todas as requisies do usurio que passam pelo filtro. import import import import import import import import import java.io.IOException; java.util.logging.Filter; java.util.logging.LogRecord; javax.servlet.FilterChain; javax.servlet.FilterConfig; javax.servlet.ServletContext; javax.servlet.ServletException; javax.servlet.ServletRequest; javax.servlet.ServletResponse;

public class LoggingFilter implements Filter { private FilterConfig config; public void init(FilterConfig config) { this.config = config; } public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { // recupera o objeto ServletContext que sera usado para realizar o logging ServletContext context = config.getServletContext(); // cria um registro da URL acessada pelo usurio String logEntry = request.getServerName() + ":" + request.getServerPort(); logEntry += "/" + request.getLocalAddr() + "/" + request.getLocalName(); logEntry += "--> acessado pelo usurio em " + new java.util.Date(); // utilizando o recurso de logging disponvel na classe ServletContext context.log(logEntry); // chama o prximo filtro na cadeia de filtros chain.doFilter(request, response);

} public void destroy() {} public boolean isLoggable(LogRecord arg0) { throw new UnsupportedOperationException("Not supported yet."); }

5.2. Encadeamento de Filtros (Filter Chains)


O encadeamento de filtros permite que filtros sejam aplicados a um recurso obedecendo a uma seqncia pr-determinada. A caracterstica de encadeamento dos filtros permite uma lgica diferenciada no uso destes componentes. O encadeamento a diferena bsica entre os filtros e
Programao WEB 17

JEDITM

os servlets. O encadeamento de filtros permite uma separao clara entre as diversas camadas de processamento de requisies. Se, por exemplo, novas funcionalidades precisarem ser implementadas antes do processamento de uma requisio, basta criar um novo filtro. Uma vez que o filtro estiver configurado, basta adicion-lo cadeia de filtros aplicados requisio antes que ela atinja o seu ponto final (um recurso). Isso no interfere em nenhum processamento que j estivesse sendo realizado sobre a requisio, a menos que o cdigo do filtro tenha sido projetado para isso. A seqncia da cadeia de filtros determinada pela localizao da declarao de um filtro no descritor de distribuio (deployment descriptor) e obedece ordem crescente dos elementos <filter-mapping>. Esses elementos representam o mapeamento entre cada filtro e um recurso. Conforme dito anteriormente, a classe javax.servlet.FilterChain representa a seqncia de filtros que sero chamados antes de uma requisio atingir seu ponto final. O nico controle que o desenvolvedor tem sobre essa seqncia o mtodo doFilter da classe FilterChain: esse mtodo chama o prximo filtro da seqncia ou diretamente o recurso, se o filtro for o ltimo da seqncia. Esse mtodo requer objetos das classes ServletRequest e ServletResponse, do pacote javax.servlet, como parmetros. Novamente, como no h necessidade do programador se preocupar com o prximo filtro do encadeamento, ele pode se concentrar apenas na lgica da classe que est sendo produzida. Se um desenvolvedor esquecer de chamar o mtodo doFilter, o resto da cadeia de filtros (e eventualmente o recurso final) nunca ser acessada. Se essa no for a funcionalidade desejada, deve-se ter ateno no momento de programar o cdigo do filtro para garantir a chamada do mtodo. Entretanto, existem casos em que desejamos realmente interromper a cadeia de filtros. Um bom exemplo um filtro de segurana que evita o acesso indevido a recursos de uma aplicao caso alguns critrios no sejam obedecidos (senha invlida, etc.). Um exemplo desse filtro apresentado abaixo. O cdigo descreve um filtro de segurana que verifica a existncia de informaes sobre o usurio armazenadas no escopo da sesso. Se no encontrar tais informaes o filtro assume que o usurio no est mais logado ou ento que a sua sesso expirou. Em qualquer um desses casos, o filtro responde requisio, redirecionando o usurio pgina de login. import import import import import import import import import import import import import java.io.IOException; java.io.PrintWriter; java.util.logging.Filter; java.util.logging.LogRecord; javax.servlet.FilterChain; javax.servlet.FilterConfig; javax.servlet.RequestDispatcher; javax.servlet.ServletException; javax.servlet.ServletRequest; javax.servlet.ServletResponse; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; javax.servlet.http.HttpSession;

public class SecurityFilter implements Filter { private FilterConfig config; public void init(FilterConfig config) { this.config = config; } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { HttpServletRequest httpRequest = (HttpServletRequest)request; HttpServletResponse httpResponse = (HttpServletResponse)response; HttpSession session = httpRequest.getSession(); User user = (User) session.getAttribute("userObject"); if (user != null) {
Programao WEB 18

JEDITM

} public void destroy() {} public boolean isLoggable(LogRecord arg0) { throw new UnsupportedOperationException("Not supported yet."); }

// se o usurio atender a certas condies, permitir o acesso aos recursos chain.doFilter(request, response); } else { PrintWriter out = response.getWriter(); out.println("Bem-vindo, por favor, " + "faa o login antes de continuar utilizando a aplicao."); RequestDispatcher rd = request.getRequestDispatcher("login.jsp"); rd.include(request, response); }

5.3. Configurao de filtros


A configurao de filtros muito parecida com a configurao de Servlets. Existe uma sesso necessria para configurar cada filtro utilizado na aplicao bem como sesses para configurar o mapeamento entre os filtros e os padres de URLs aos quais as cadeias de filtros sero aplicadas. Um exemplo de configurao de filtro apresentado abaixo: ... </context-param> <filter> <filter-name>LoggingFilter</filter-name> <filter-class>jedi.filters.LoggingFilter</filter-class> </filter> <filter-mapping> <filter-name>LoggingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> Dado que a interpretao do arquivo web.xml sofre influncia da ordem em que os elementos so declarados, recomendamos a declarao dos filtros aps os elementos <context-param> e antes de qualquer definio sobre servlets. Tambm cuide para colocar os elementos <filtermapping> aps a definio dos filtros. Por default, filtros no so aplicados a componentes web (outros servlets, JSP, etc.) acessados pela classe RequestDispatcher atravs de chamadas include ou forward. Filtros so aplicados apenas a requisies feitas diretamente pelo cliente. Esse comportamento, entretanto, pode ser modificado, incluindo-se um ou mais elementos <dispatch> ao mapeamento do filtro. ... </context-param> <filter> <filter-name>LoggingFilter</filter-name> <filter-class>jedi.filters.LoggingFilter</filter-class> </filter> <filter-mapping> <filter-name>LoggingFilter</filter-name> <url-pattern>/*</url-pattern> <dispatch>REQUEST</dispatch> <dispatch>INCLUDE</dispatch> </filter-mapping> Elementos <dispatch> possuem um dos seguintes valores: REQUEST, INCLUDE, FORWARD e ERROR. Isso indica quando um filtro deve ser aplicado apenas a requisies do cliente, apenas em includes, apenas em requisies, apenas em caso de erro ou na combinao desses quatro valores.

Programao WEB

19

JEDITM

6. Exerccios
6.1. Exerccios sobre redirecionamento de respostas
1) Quais so as duas formas de se realizar redirecionamento na API Servlet? 2) Qual a diferena entre utilizar o mtodo include e o mtodo forward no objeto RequestDispatcher? 3) Qual a diferena entre utilizar o mtodo forward do objeto RequestDispatcher e o mtodo sendRedirect utilizando o objeto HttpServletResponse?

6.2. Exerccios sobre escopo


1) Quais so os diferentes escopos disponveis em uma aplicao WEB nos quais um objeto pode ser armazenado? 2) Qual objeto associado ao escopo de aplicao? E ao escopo de sesso? 3) Qual o tempo de vida/visibilidade dos objetos colocados no escopo de sesso? E no escopo de requisio? 4) Dado o cdigo abaixo: public class SenderServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String message = "Can you hear me?"; request.setAttribute("messageKey", message); response.sendRedirect("ReceiverServlet"); } } Se houvesse uma ReceiverServlet mapeada para o local indicado dentro do mtodo sendRedirect, seria possvel recuperar a mensagem? Justifique? 5) Crie uma implementao de ReceiverServlet que tente recuperar a mensagem armazenada dentro do escopo de requisio pela classe SenderServlet dada no exerccio anterior.

6.3. Exerccios sobre rastreabilidade


1) A classe HttpSession fornecida pela Servlet API utiliza Cookies para controlar o escopo de sesso de usurio. Qual a desvantagem dessa forma de controlar sesses de usurios? 2) Como um desenvolvedor pode recuperar uma instncia da classe HttpSession? 3) Considere o seguinte cdigo: public class InfoBean { private String nome; private String numero; // mtodos get(...) e set(...) } Se uma instncia dessa classe foi armazenada em uma sesso sob a chave "infoBean", crie uma Servlet que recupere a instncia e exiba os valores dos atributos nome e nmero.

6.4. Exerccios sobre filtros


1) Quais so os trs mtodos definidos na interface Filter que devem ser implementados em classes de filtro? 2) Quando configuramos um filtro no descritor de aplicaes WEB, essa configurao deve vir antes ou depois da definio das Servlets? 3) Aps um filtro ter realizado sua funcionalidade, como ele chama o prximo filtro da cadeia de filtros ou o recurso desejado?
Programao WEB 20

JEDITM

4) Considere o seguinte cenrio: Temos uma aplicao WEB com funcionalidades administrativas que podem ser disponibilizadas aos seus usurios comuns. Se todos os recursos necessrios a essas funcionalidades administrativas esto localizados no diretrio admin de nossa aplicao, como configurar um filtro chamado AdminFilter tal que todas as requisies a recursos administrativos passem por esse filtro? 5) Crie uma classe que implementa o AdminFilter descrito acima. O filtro deve ser capaz de determinar quando um usurio autorizado ou no a recuperar um valor lgico armazenado no escopo de sesso. O nome da chave usada para armazenar o valor lgico isAdmin. Se o valor for true, o usurio est autorizado a acessar os recursos administrativos. Caso contrrio, o usurio deve ser redirecionado pgina de entrada, com uma mensagem informando que ele no tem as credenciais necessrias para acessar a parte administrativa do sistema.

Programao WEB

21

JEDITM

Parceiros que tornaram JEDITM possvel

Instituto CTS Patrocinador do DFJUG. Sun Microsystems Fornecimento de servidor de dados para o armazenamento dos vdeo-aulas. Java Research and Development Center da Universidade das Filipinas Criador da Iniciativa JEDITM. DFJUG Detentor dos direitos do JEDITM nos pases de lngua portuguesa. Banco do Brasil Disponibilizao de seus telecentros para abrigar e difundir a Iniciativa JEDITM. Politec Suporte e apoio financeiro e logstico a todo o processo. Borland Apoio internacional para que possamos alcanar os outros pases de lngua portuguesa. Instituto Gaudium/CNBB Fornecimento da sua infra-estrutura de hardware de seus servidores para que os milhares de alunos possam acessar o material do curso simultaneamente.

Programao WEB

22