Padrões JEE – Parte 1

Olá a todos!

Neste primeiro post, estou publicando a primeira parte de uma série de artigos que tratarão de um assunto que, apesar de nem sempre estar presente em provas de concurso, vez por outra aparece em alguns editais de grandes concursos (apareceu, por exemplo, no edital do TCU 2009).  Além disso, é um tema interessante também para aplicação no trabalho cotidiano de quem lida com desenvolvimento na plataforma JEE (antes chamada de J2EE), além de ser cobrado, por exemplo, na prova de certificação SCEA (Sun Certified Enterprise Architect).  Trata-se do catálogo de padrões de projeto para aplicações baseadas na plataforma Java Enterprise Edition (JEE), apresentado em detalhes no livro Core J2EE Patterns – Best Practices and Design Strategies, 2ª. Edição [1], cuja versão resumida encontra-se no site [2].  As figuras aqui apresentadas foram baseadas na versão online do catálogo.

O objetivo aqui é apresentar um resumo sobre essa categoria de padrões
, de modo semelhante ao publicado pelo colega Fernando Pedrosa, que resumiu em uma ótima série de artigos os padrões GoF (Gang of Four).  Nesta primeira parte, falarei sobre padrões da camada de apresentação, em particular, sobre os padrões Intercepting Filter, Front Controller, Context Object e Application Controller.

Antes de darmos início à explicação sobre os quatro padrões acima citados, vamos revisar a listagem de padrões agrupados por camada:

  • Padrões da Camada de Apresentação (Presentation Tier Patterns):
    • Intercepting Filter
    • Front Controller
    • Context Object
    • Application Controller
    • View Helper
    • Composite View
    • Service to Worker
    • Dispatcher View
  • Padrões da Camada de Negócio (Business Tier Patterns)
    • Business Delegate
    • Service Locator
    • Session Façade
    • Application Service
    • Business Object
    • Composite Entity
    • Transfer Object
    • Transfer Object Assembler
    • Value List Handler
  • Padrões da Camada de Integração (Integration Tier Patterns)
    • Data Access Object
    • Service Activator
    • Domain Store
    • Web Service Broker

A plataforma JEE atualmente está na versão 6 e, desde a época em que a 2ª. edição do catálogo de padrões foi publicada, a tecnologia evoluiu de tal forma que alguns dos padrões tornaram-se obsoletos.  Além disso, vários deles – especialmente aqueles pertencentes à camada de apresentação – hoje já se encontram embutidos em frameworks de desenvolvimento, tais como Struts, Spring, etc.  Alguns inclusive são implementados “nativamente’’ na API padrão do JEE.  Com isso, facilita-se a vida do desenvolvedor, que faz uso de boas práticas muitas vezes sem sequer tomar conhecimento.  Também vale ressaltar que alguns padrões JEE foram criados pela Sun para suprir deficiências da própria plataforma JEE, e por isso devem ser encarados mais como workarounds do que como “padrões de projeto” de fato.

Bem, deixando as discussões introdutórias de lado, vamos enfim ao resumo dos padrões JEE analisados neste post.

Intercepting Filter

Problema: interceptar e manipular uma requisição e uma resposta antes e depois que a requisição é processada.

Solução: utilizar um Intercepting Filter como um filtro plugável para pré e/ou pós-processar requisições e respostas dessas requisições.  Dessa forma, filtros fracamente acoplados são combinados de forma encadeada, podendo ser adicionados, removidos e recombinados a qualquer momento.

Estrutura:

Diagrama de sequência:


Participantes e responsabilidades:

  • Client: entidade que envia a requisição.
  • FilterManager: gerencia o processamento dos filtros, instanciando o FilterChain – uma lista encadeada de filtros – com os filtros apropriados, na ordem correta, e inicia o processamento.
  • FilterChain: coleção ordenada de filtros independentes entre si.
  • FilterOne, FilterTwo: filtros individuais, cada um sendo responsável por uma tarefa específica (ex.: autenticação, autorização, logging, etc.)

Exemplos de aplicabilidade:

Imagine uma situação em que cada requisição do cliente deve ser interceptada para fins de autenticação e/ou controle de acesso, registro (logging), abertura de um contexto transacional ou qualquer outra funcionalidade que seja mais ou menos genérica.  Uma opção seria replicar essa lógica em todas as páginas ou todos os servlets da aplicação. Mas isso seria um desastre do ponto de vista de manutenibilidade e robustez do código, uma vez que haveria replicação de código e nenhuma garantia de que o processamento necessário seria de fato invocado.  Daí a necessidade de um mecanismo que reúna as seguintes vantagens:

  • Processamento centralizado, genérico e não invasivo, independente da lógica de negócio da aplicação.
  • Possibilidade de pré-processar uma requisição, alterando-a, por exemplo, para fins de conversão de dados.
  • Possibilidade de pós-processamento da resposta de uma requisição para alterá-la, converter dados para apresentação, etc.
  • Flexibilidade para adicionar e/ou remover lógica de pré ou pós-processamento sem interferir no core da aplicação.

O padrão Intercepting Filter é um exemplo de padrão suportado nativamente pela plataforma JEE, por meio da interface javax.servlet.Filter. Abaixo, temos um exemplo de código:

A lógica de pré-processamento pode, por exemplo, verificar se existe um usuário autenticado na sessão, caso o recurso alvo exija autenticação para ser acessado. Em caso afirmativo, a requisição é repassada para o alvo ou para o próximo filtro (linha 18).  Caso contrário, esse repasse não deve ser feito e o código deve retornar imediatamente, fazendo com que a linha 18 não seja executada.

Um exemplo comum de lógica de pós-processamento é o controle de transação.  Caso nenhuma exceção tenha sido gerada, a transação atual é confirmada (commit).  Caso contrário, é feito o rollback.  Não mostrei no código acima nenhuma lógica de controle de transação porque, na prática, esta deveria estar presente em outro filtro, por questões de modularidade.

Para que o filtro acima definido seja ativado, é preciso configurá-lo no deployment descriptor da aplicação, também conhecido como arquivo web.xml.  No código abaixo, a classe br.timasters. MeuFiltro é configurada para interceptar todas as requisições a páginas JSP da aplicação (*.jsp):

Front Controller

Problema: Deseja-se um ponto de acesso centralizado para tratamento de requisições à camada de apresentação.

Solução: Usar um Front Controller como o ponto inicial de contato para tratar um determinado conjunto de requisições.  Tal conjunto pode englobar todas as possíveis requisições para a aplicação, ou apenas as requisições relacionadas a uma determinada funcionalidade, permitindo respectivamente a existência de um único controlador para toda a aplicação ou mesmo um controlador por funcionalidade. O Front Controller centraliza lógica de controle que de outra forma estaria replicada, e gerencia as principais atividades relacionadas com o tratamento de requisições.

Estrutura:


Diagrama de sequência:


Participantes e responsabilidades:

  • Front Controller: ponto de contato inicial para tratar requisições ao sistema.  Opcionalmente, delega o processamento para um Application Controller (ver mais adiante o padrão Application Controller).
  • Application Controller: Responsável pela lógica de redirecionar o processamento para as ações especificas que deverão servir à requisição, bem como redirecionar para a view (ex.: página) apropriada.
  • Command: Objeto que realiza a ação de tratamento propriamente dito da requisição (ex.: lógica de um determinado caso de uso).
  • View: representa a interface (UI) retornada para o cliente (ex.: página HTML/JSP).

Exemplos de aplicabilidade:

Atualmente, o papel desempenhado pelo Front Controller costuma ser encapsulado por frameworks de mercado como Struts, Java Server Faces e vários outros.  Em geral, o Front Controller é implementado como uma servlet que centraliza a lógica comum ao processamento de todas as requisições e em seguida redireciona o processamento da requisição para o controlador mais adequado.

Context Object

Problema: Deseja-se evitar o uso de informações de sistema específicas de um protocolo fora de seu contexto.

Solução: Usar um Context Object para encapsular informações de estado de forma independente de protocolo, para que possa ser compartilhada por todas a aplicação.

Estrutura:


Diagrama de Sequência:


Participantes e responsabilidades:

  • Cliente:  Cria um objeto com a interface ProtocolInterface.
  • ProtocolInterface:  Um objeto que expõe detalhes específicos de um protocolo ou de uma camada (ex.: HttpServletRequest).
  • ContextFactory:  Cria um ContextObject.
  • ContextoObject: Objeto genérico usado para compartilhar estado, de forma independente de protocolo ou de camada.

Exemplos de aplicabilidade:

O código abaixo mostra um ContextObject que encapsula informações de sistema relativas à sessão do usuário, tais como os dados do usuário logado, o idioma utilizado, etc.  Veja que, embora tais informações tenham sido obtidas da requisição e da sessão HTTP, elas podem ser acessadas a partir de qualquer camada da aplicação sem que para isso seja necessário interagir com a API relativa ao protocolo HTTP, tais como as classes HttpServletRequest ou HttpSession.

Finalmente, se no futuro houver a necessidade da aplicação empregar uma camada de aplicação que não seja Web, mas sim baseada em desktop ou mesmo em sistemas móveis (ex.: celulares, palms, etc.), a lógica de negócio que fizer uso da API oferecido pelo Context Object continuará funcionando normalmente.  A única modificação é a forma como o objeto ContextObject será populado.

Application Controller

Problema: Deseja-se centralizar e modularizar o gerenciamento de ações e visões.

Solução: Utilizar um Application Controller para centralizar a recuperação e invocação de componentes responsáveis pelo processamento de requisições, tais como comandos (commands)  e visões (views).

Estrutura:


Diagrama de Sequência:


Participantes e responsabilidades:

  • Client:  Invoca o Application Controller.  Na camada de apresentação, pode ser por exemplo, um Front Controller ou um Intercepting Filter.
  • ApplicationController:  Utiliza Mapper para delegar e/ou redirecionar uma requisição para a ação e/ou visão apropriada.
  • Mapper:  Usa um mapeamento para traduzir requisições nas ações e visões apropriadas.
  • Map:  Armazena referências para os recursos-alvo.
  • Target:  Um recurso que atua no processamento de uma requisição particular.  Exemplo: commands, views e style sheets.

Exemplos de aplicabilidade:

Um exemplo típico de implementação do padrão Application Controller pode ser encontrado no framework Struts.  Vou apresentar aqui um exemplo baseado nas primeiras versões do Struts, onde fica mais clara a utilização deste padrão JEE.  O exemplo aqui apresentado foi adaptado do livro Core J2EE Patterns – 2ª. Edição.

Vejamos inicialmente um exemplo de cliente implementado como Front Controller – no exemplo específico, uma servlet que atua como primeiro ponto de contato da requisição com a aplicação:

Código (parcial) do Application Controller:

A aplicação é configurada de forma declarativa por meio de um arquivo de configuração com conteúdo semelhante ao do exemplo abaixo:

Exemplo de implementação da ação (Command):

Na parte 2 desta série de posts, continuarei a tratar de padrões da camada de apresentação, analisando os padrões View Helper, Composite View, Service to Worker e Dispatcher View.

Referências:

[1] Core J2EE Patterns – Best Practices and Design Strategies, 2nd Edition.  Depak Alur, John Crupi e Dan Malks.  2003.

[2] Catálogo online de padrões: http://java.sun.com/blueprints/patterns/catalog.html

»crosslinked«

Monique Monteiro

Sou Arquiteta de Software (embora já tenha atuado também como Gerente de Projetos), MSc em Ciência da Computação e sou de Recife, mas moro atualmente em Brasília. Estou envolvida na área de TI (mais especificamente desenvolvimento de software) há cerca de 10 anos (contando o período da faculdade, é claro :)), e de lá pra cá sempre gostei de aprender coisas novas relacionadas ao estado da arte em desenvolvimento e Engenharia de Software em geral! Desde dezembro de 2009 estou trabalhando no Tribunal de Contas da União (TCU), como Auditora Federal de Controle Externo.

Você pode gostar...

8 Resultados

  1. Claudio Maia disse:

    Excelente Artigo. Parabens!!

  2. roger disse:

    ola, parabens pela postagem
    na parte referente ao padrão contextObject, vc menciona q algumas informacoes, como usuario logado, idioma..podem ser obtidas via http..
    como, se o http eh um procolo stateless, não mantendo informações de estado do usuario? alguem explica?

    • Monique disse:

      @Roger,

        o protocolo HTTP, apesar de ser stateless no sentido de não ser um protocolo orientado a conexão, utiliza o conceito de sessão e cookies para simular informações que precisem ser armazenadas entre diferentes requisições.  São as informações que estão na sessão que podem ser obtidas via HTTP.

        Existem outras formas (proprietárias) de simulação de estado, como por exemplo escopo de conversão.  Mas isso é outra estória…

  3. Wandembergh Nunes disse:

    Parabéns pelo artigo!!!
    Gostaria de mais detalhes sobre o padrão de projetos Service-to-Work, e onde eu posso implementá-lo na minha aplicação.
    Pode enviar os materiais para o meu e-mail, desde já agradeço muito a atenção e estarei no aguardo.

    • Monique disse:

      O pattern Service To Worker é muito encontrado em frameworks Web MVC, como Spring MVC e Struts.  Este último tem sido menos utilizado.

      De fato existem poucas referências acerca desse pattern.  Não existe uma receita padrão e normalmente ele é encapsulado na própria infra dos frameworks.  Aconselho dar uma olhada no Spring MVC.

  4. Pinheiro disse:

    Primeiramente, parabéns pelo artigo.  Uma dúvida:  O Front Controller possui as mesmas funções do Controller do MVC?? Se não, qual a diferença? Obrigado, Pinheiro

  5. walter cunha disse:

    @Fernando: finalmente a Monique aceitou o convite para ser autora do Blog! \o/

  6. Fernando Pedrosa disse:

    Excelente, Monique. A comunidade estava precisando de um resumo desse (complicado) assunto.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *