Você está na página 1de 391

INTRODUO AO DEMOISELLE FRAMEWORK

Uma abordagem comparativa de aplicaes Web em Java orientada ao reuso Flvio Gomes da Silva Lisboa
com a colaborao de Luciana Campos Mota

Esta obra utiliza a licena Creative Commons Attribution-NonCommercial-ShareAlike License

Lisboa, Flvio Gomes da Silva Introduo ao Demoiselle Framework: Uma abordagem comparativa de Utilizao do padro MVC para o desenvolvimento de aplicaes Web em Java orientada ao reuso. Braslia. SERPRO, 2010. III Congresso Internacional Software Livre e Governo Eletrnico. 1.Framework 2.Java 3.Reuso. 4.Web

Dedicatria
Este livro dedicado a Cleonisse Cintra da Silva, para que seu nome nunca seja esquecido. Viveu pelos outros, cuidou de todos e nunca recebeu recompensa. Onde estiver agora, que tenha seu descanso merecido.

Sumrio
Dedicatria..............................................................................................................................3 Agradecimentos.......................................................................................................................8 Sobre o autor...........................................................................................................................9 Prefcio.................................................................................................................................10 Introduo.............................................................................................................................12 1.1 A Arte da Guerra no Desenvolvimento de Software..................................................13 1.2 Frameworks................................................................................................................15 1.2 O Desafio dos Frameworks........................................................................................17 A loja virtual de livros...........................................................................................................19 2.1 Levantamento de requisitos........................................................................................19 2.2 O Sonho de Nabucodonosor.......................................................................................24 Modelagem............................................................................................................................26 3.1 Descrevendo os Casos de Uso....................................................................................26 3.1.1 Caso de Uso Adicionar Item ao Carrinho...........................................................27 3.1.2 Caso de Uso Editar Item do Carrinho.................................................................28 3.1.3 Caso de Uso Excluir Item do Carrinho...............................................................28 3.1.4 Caso de Uso Buscar Livro..................................................................................29 3.1.5 Caso de Uso Fechar Pedido................................................................................29 3.1.6 Caso de Uso Cadastrar Cliente...........................................................................30 3.1.7 Caso de Uso Manter Cadastro............................................................................31 3.1.8 Caso de Uso Autenticar Usurio.........................................................................31 3.1.9 Caso de Uso Verificar Permisso de Funcionrio..............................................32 3.1.10 Caso de Uso Gerenciar Carrinho......................................................................33 3.1.11 Caso de Uso Gerar Relatrios...........................................................................33 3.1.12 Diagramas de Casos de Uso..............................................................................34 3.3 Diagrama Entidade Relacionamento..........................................................................35 3.4 Diagrama de Classes...................................................................................................36 3.5 A Implementao........................................................................................................36 Livraria com JSP e JDBC.....................................................................................................38 4.1 Servlets.......................................................................................................................38 4.2 JSP..............................................................................................................................43 4.3 Ambiente de desenvolvimento...................................................................................46 4.4 Configurando o servidor no Eclipse...........................................................................46 4.5 Criando um projeto Web............................................................................................50 4.6 Estrutura do projeto Web............................................................................................52 4.7 MVC...........................................................................................................................53 4.8 Camada de Persistncia..............................................................................................55 4.8.1 Criando os Modelos............................................................................................55 4.8.2. Criando os DAOs...............................................................................................72 4.8.3 Testando a Camada de Persistncia..................................................................108 4.8.4 Classes e Arquivos Auxiliares da Camada de Persistncia..............................111 4.9.Camada de Controle.................................................................................................112 4

4.9.1 Servlet de Autenticao....................................................................................115 4.9.2 Classe Abstrata para Servlets Autenticados......................................................118 4.9.3 Servlet de Gravao..........................................................................................119 4.9.3.1 Classe de Controle de Acesso...................................................................132 4.9.3.2 Constantes com os Papis.........................................................................134 4.9.3.3 Arquivo com os Papis dos Usurios........................................................134 4.9.3.4 Constantes com os Nomes dos Cadastros.................................................135 4.9.4 Servlet de Remoo..........................................................................................135 4.10 Camada de Viso....................................................................................................143 4.10.1 Pginas JSP.....................................................................................................143 4.10.2 Classes Auxiliares da Camada de Viso.........................................................157 4.11 Concluses..............................................................................................................183 Livraria com JSF e Hibernate.............................................................................................186 5.1 Hibernate..................................................................................................................186 5.2 JSF ...........................................................................................................................186 5.3 Configurao do Web Page Editor...........................................................................187 5.4 Criando um Projeto JavaServer Faces......................................................................188 5.5 Instalando e Usando JBoss Tools para Configurar o Hibernate...............................192 5.6 Camada de Persistncia............................................................................................198 5.6.1 Criando Modelos com Anotaes.....................................................................198 5.6.2 Criando DAOs sem JDBC................................................................................218 5.6.3 Testando a Camada de Persistncia..................................................................235 5.6.4 Classes e Arquivos Auxiliares da Camada de Persistncia..............................236 5.7 Camada de Controle.................................................................................................237 5.7.1 Generalizao....................................................................................................237 5.7.2 ManagedBeans..................................................................................................244 5.7.3 Registro no faces-config.xml............................................................................262 5.7.4 Classes Auxiliares da Camada de Controle......................................................265 5.8 Camada de Viso......................................................................................................268 5.8.1 Criando as Pginas JSF.....................................................................................268 5.8.2 Pginas de Cadastro..........................................................................................273 5.8.3 Pginas de Edio.............................................................................................279 5.8.4 Pginas de Listagem.........................................................................................291 5.9 Executando a Aplicao...........................................................................................305 5.10 Concluses..............................................................................................................306 Livraria com Demoiselle Framework.................................................................................308 6.1 Demoiselle Framework............................................................................................308 6.2 Demoiselle Infra.......................................................................................................309 6.3 Criao do Projeto Demoiselle Framework.............................................................309 6.4 Camada de Persistncia............................................................................................312 6.4.1 Criando os Modelos .........................................................................................312 6.4.2 Criando os DAOs..............................................................................................315 6.4.3 Testando a Camada de Persistncia..................................................................316 6.4.4 Classes e Arquivos Auxilares da Camada de Persistncia...............................317 6.5 Camada de Negcio..................................................................................................321 5

6.5.1 Controle de Acesso...........................................................................................322 6.6 Camada de Controle e Viso....................................................................................323 6.6.1 Autenticao.....................................................................................................326 6.7 Concluso.................................................................................................................326 Demoiselle: Framework de Arquitetura..............................................................................328 7.1 Fundamentos.............................................................................................................328 7.1.1 Diversidade.......................................................................................................328 7.1.2 Elementos de deciso........................................................................................329 7.1.3 Estratgia para a rea de tecnologia..................................................................329 7.1.4 Diretivas da arquitetura tecnolgica.................................................................331 7.1.4.1 Computao distribuda............................................................................331 7.1.4.2 Aplicaes baseadas em componentes......................................................332 7.1.4.3 Processos orientados a eventos.................................................................333 7.1.4.4 Acoplamento fraco de funes de negcio...............................................333 7.1.4.5 Infraestrutura para suporte a decises.......................................................333 7.1.4.6 Automao de processos...........................................................................334 7.1.4.7 Acesso por Internet...................................................................................334 7.1.4.8 Software Livre...........................................................................................335 7.1.5 Demoiselle com Desenvolvimento Colaborativo............................................335 7.1.6 Orientao a Especificaes.............................................................................338 7.1.6.1 JAAS.........................................................................................................339 7.1.6.2 JCA e JCE.................................................................................................340 7.1.6.3 Servlet.......................................................................................................341 7.1.6.4 JSF.............................................................................................................342 7.2 Estrutura do Projeto Demoiselle...............................................................................343 7.3 Arquitetura................................................................................................................346 7.3.1 Objetivos e Restries Arquiteturais ...............................................................348 7.3.1.1 Extensibilidade..........................................................................................348 7.3.1.2 Reusabilidade............................................................................................349 7.3.1.3 Manutenibilidade......................................................................................350 7.3.1.4 Desempenho..............................................................................................350 7.3.1.5 Estabilidade e Confiabilidade...................................................................350 7.3.2 Perspectiva Estrutural da Soluo.....................................................................351 7.3.2.1 Mdulo Core.............................................................................................351 7.3.2.1.1 Integrao entre Camadas.................................................................351 7.3.2.1.2 Contexto de Mensagens.....................................................................354 7.3.2.1.3 Exceo Padronizada.........................................................................355 7.3.2.1.4 Contexto de Segurana......................................................................356 7.3.2.1.5 Entidades...........................................................................................357 7.3.2.1.6 Contexto de Transao......................................................................357 7.3.2.1.7 Acionadores.......................................................................................358 7.3.2.1.8 Localizador de Contextos..................................................................359 7.3.2.2 Mdulo Util...............................................................................................360 7.3.2.2.1 Carregamento de Configurao.........................................................360 7.3.2.2.2 Paginao de Dados...........................................................................362 6

7.3.2.3 Mdulo Web.............................................................................................363 7.3.2.3.1 Contexto de Segurana......................................................................364 7.3.2.3.2 Contexto de Mensagens.....................................................................364 7.3.2.3.3 Integrao entre Camadas.................................................................365 7.3.2.3.4 Contexto de Transao......................................................................367 7.3.2.3.5 Inicializao do Ambiente.................................................................368 7.3.2.3.6 Redirecionamento Baseado em URL................................................369 7.3.2.3.7 Injeo de Dependncias com Aspectos...........................................372 7.3.2.4 Mdulo Persistence...................................................................................375 7.3.2.5 Mdulo View............................................................................................384 7.3.2.3 Modelo de Arquitetura em Camadas do Demoiselle................................386 7.4 Concluso ................................................................................................................389 Demoiselle Wizard..............................................................................................................391 Script para criao do banco de dados................................................................................392 Script para apagar as tabelas...............................................................................................399 Driver JDBC para PostgreSQL...........................................................................................400 Referncias Bibliogrficas..................................................................................................401

Agradecimentos
O primeiro agradecimento para Deus, que criou o Universo. Sem o Universo seria complicado escrever o livro. O segundo agradecimento para Jos Maria Leocdio, coordenador da CETEC, que colocou este livro como meta para 2010. O terceiro agradecimento para Antonio Carlos Tiboni, que acreditou neste livro. Os demais agradecimentos so para os funcionrios dos Centros de Documentao e Informao do Serpro, que forneceram a bibliografia necessria para a redao do livro e renovaram os livros com prestatividade at que o trabalho estivesse concludo:

Jussara Justino Jos Fonseca Lisania Medianeira Mathias Costas Mrcia Zago Marina Costacurta Falavinha Marilza Fernandes Trindade Salvador Fernandes de Azevedo

Muito obrigado a todos!

Sobre o autor
Flvio Gomes da Silva Lisboa bacharel em Cincia da Computao com ps-graduao em Aplicaes Corporativas usando Orientao a Objetos e Tecnologia Java pela Universidade Tecnolgica Federal do Paran. Atuou como programador em empresas privadas de automao comercial e servios de informtica, e foi funcionrio de carreira do Banco do Brasil, onde chegou a analista na diretoria internacional. Atualmente analista de desenvolvimento de sistemas da Coordenao Estratgica de Tecnologia do Servio Federal de Processamento de Dados (Serpro). membro do time oficial de traduo do Zend Framework. Tem experincia na rea de Cincia da Computao, com nfase em Software Livre, atuando principalmente nos seguintes temas: Java, PHP, padres, frameworks, MVC e objetos.

Prefcio
Este livro traz uma introduo ao Demoiselle Framework. Ele no pressupe um domnio de JEE, e tenta explicar de maneira prtica qual a necessidade do uso de frameworks para desenvolvimento. O principal objetivo deste livro ensinar a criar aplicaes com uma arquitetura que permita o reuso de componentes e facilite sua manuteno. Iremos progredir de uma programao com preocupao mais imediatista at uma que seja orientada a resolver problemas mais genricos. Para tanto, utilizaremos uma abstrao de um problema real. A soluo do problema ter trs implementaes. A primeira ser feita com Java puro, sem o auxlio de frameworks. A segunda utilizar frameworks JSF e Hibernate para a persistncia de dados. A terceira utilizar o framework Demoiselle. A inteno aprender como desacoplar produtos especficos da aplicao por meio de uma camada de alto nvel baseada em especificaes. Essa ltima frase complexa significa o seguinte: como conseguir reaproveitar cdigo entre aplicaes e gastar menos, ao evitar modificaes no cdigo fonte. A metodologia deste deste livro consiste em: 1. Desenvolver uma aplicao (ou mais precisamente uma parte dela) de duas formas diferentes, e compar-las de modo a perceber quais as vantagens e desvantagens que cada uma apresenta. 2. Mostrar o caminho para criar a mesma aplicao usando Demoiselle Framework. Ou seja, este livro o pr-Demoiselle Framework. No objetivo aqui oferecer uma referncia completa sobre o Demoiselle Framework, mas sim dar ao programador a base para que ele comece a utilizar a plataforma. O maior propsito deste livro incluir o leitor no time dos capacitados a iniciar a utilizao do Demoiselle Framework. Antes de partir para a apresentao do problema, iremos fazer uma pequena introduo ao assunto que justifica esse livro, a manuteno de software. Os demais conceitos necessrios sero passados no momento em que eles forem utilizados na codificao. Este livro se baseia na verso 5 de Java, o que no impede que o cdigo aqui exposto funcione para verses superiores, apenas o requisito mnimo. Este livro tambm pressupe conhecimentos bsicos de linguagem Java, orientao a objetos e HTML. Ele

10

contm o necessrio para programadores que no conhecem Servlets, JSP, JSF, Hibernate e muito menos Demoiselle Framework.

11

Introduo
No vale a pena criar um projeto rgido e difcil de manter em um esforo de economizar tempo e dinheiro no incio, se voc continuamente for forado a reservar recursos de desenvolvimento para manter o projeto no futuro. Duane Fields e Mark Kolb.

Neste captulo, introduziremos o problema da manuteno dentro do contexto do desenvolvimento de software. Em seguida, falaremos como o uso de frameworks pode resolver esse problema e, finalmente, como frameworks podem se tornar um problema. Nos primrdios da computao eletrnica, a palavra software referia-se somente a uma sequncia de instrues a serem seguidas e/ou executadas por uma mquina denominada hardware (o computador propriamente dito), na manipulao, redirecionamento ou modificao de um dado/informao ou acontecimento. Mas esse conceito sofreu uma modificao, pois a crescente indstria de software verificou que seu produto final no estava acompanhando a evoluo do hardware. Hoje, o termo software abrange um conjunto de produtos desenvolvidos durante um processo contnuo de construo, que inclui no somente o programa de computador, mas tambm manuais, especificaes, planos de teste e quaisquer outras formas de documentao referentes ao projeto de software. Segundo McConnel(2005), o desenvolvimento de software de computador pode ser considerado um processo complexo; nos ltimos 25 anos, pesquisadores da rea identificaram diversas atividades distintas relacionadas a essa prtica. Entre elas, esto:

Definio do problema; Desenvolvimento dos requisitos; Planejamento da construo; Arquitetura do software ou projeto de alto nvel; Projeto detalhado; Codificao e depurao; Testes unitrios; Testes de integrao; Integrao;

12

Testes de sistema; Manuteno corretiva.

Alm disso, Grohs(2007, p.6) coloca mais quatro questes especficas, dentro do contexto de sistemas multiplataformas e baseados em software livre, que hoje possuem uma grande base instalada: 1. Como aumentar a complexidade das solues, sem deix-las difceis de serem mantidas no futuro (por demandas corretivas ou evolutivas)? 2. Como desenvolver sistemas multiplataformas baseados em software livre? 3. Como controlar os dados (sem abrir mo de eficincia) que vem aumentando em termos de complexidade de estrutura e em termos de volume? 4. Como atender necessidade de aumento de complexidade nos dados sem tornar a interface de entrada dos mesmos mais complexa? As respostas a essas questes precisam ser dadas em um tempo realizvel para a empresa e aceitvel pelo cliente. necessrio dar conta de todas as atividades pertinentes ao processo de desenvolvimento de software no menor tempo possvel, dado que a demanda por implementaes e mudanas s tende a crescer (a ltima mais que a primeira). Alguns defendem que a criao de software uma arte, como Donald Knuth, na obra The Art of Computer Programming. claro que a acepo de software dele limitada, refere-se mais a um contexto matemtico dominante nos primrdios da programao de computadores. O conceito de software, aps Pressman (2006), de um produto de engenharia. Se existe algo de arte no software, podemos dizer que uma Arte da Guerra.

1.1 A Arte da Guerra no Desenvolvimento de Software


J disse Sun Tzu: a velocidade a essncia da guerra. Projetos de software, assim como quaisquer outros projetos, so esforos temporrios, com incio e fim definidos. Eles so planejados, executados e controlados, e entregam produtos, servios ou resultados exclusivos. So desenvolvidos em etapas e continuam por incremento com uma elaborao progressiva. So realizados por pessoas (pessoas comuns, no entidades csmicas, seres imortais ou deuses) e o mais importante: contam com recursos limitados. Sun Tzu aconselha: na guerra, preze pela vitria rpida e evite as operaes prolongadas. Segundo ele, o tempo prolongado ir desgastar as armas, desmoralizar suas tropas, exaurir suas foras e consumir todos os recursos disponveis.

13

Projetos tm de ser os mais curtos possveis, porque s assim sero realizveis. Da mesma forma que na guerra, quanto mais tempo os desenvolvedores demorarem para terminar o projeto, menos eles acreditaro que conseguiro faz-lo. O oramento tambm limitado, pelo cliente, e pelo capital alocado antes que o mesmo efetue o pagamento pelo servio. O tempo no reutilizvel. Depois que ele passou, o que foi consumido em recursos j se perdeu. No como no seriado Brimstone, onde o detetive Ezekiel Stone acorda toda manh com os mesmos 36 dlares e 27 centavos que tinha quando morreu. O conhecedor dos terrveis e devastadores efeitos e dos perigos de empreender uma guerra, est profundamente consciente de como aproveit-la da melhor maneira e lev-la com rapidez a seu trmino. Da mesma forma, o desenvolvedor de software deve utilizar os meios necessrios para obter um rpido desenvolvimento. Porque assim como pode haver uma nova guerra, pode haver um novo projeto. E da mesma forma que um exrcito pode se ver confrontado por dois oponentes, uma equipe de desenvolvimento pode se ver dividida em dois projetos. Ou mais. Quando a Primeira Guerra Mundial comeou, a Alemanha tinha um grave problema. O falecido chanceler Bismarck havia tentado por todos os meios tecer uma rede de alianas que favorecesse o Imprio Alemo no caso de um conflito armado no continente, mas teve que assistir decepcionado aliana entre a repblica da Frana e o Imprio Russo. Isso deixava o exrcito alemo com a possibilidade de uma guerra em duas frentes. E o que os militares germnicos mais temiam terminou por ocorrer. Quando o Imprio Austro-Hngaro declarou guerra Srvia, culpando-a pelo assassinato do arquiduque Francisco Ferdinando, a Alemanha fez o mesmo, por ser aliada dos austracos. Mas a Rssia era aliada da Srvia, e assim declarou guerra ustria e Alemanha. E como a Frana era aliada da Rssia, declarou guerra Alemanha. Concluso: os alemes teriam que combater dois exrcitos ao mesmo tempo. O exrcito alemo tentou repetir o sucesso do general Helmuth Von Moltke, que em apenas quatro meses invadiu e derrotou a Frana em 1870. Os generais germnicos pensavam em derrotar rapidamente os franceses para poder voltar e se concentrar nos russos. Mas infelizmente, os britnicos vieram em auxlio dos franceses e atrasaram o avano alemo. Nesse nterim, o lado leste do Imprio Alemo foi atacado pelos russos. Isso obrigou os germnicos a deslocarem tropas que estavam planejadas para lutar na frente ocidental. A Alemanha acabou tendo que dividir constantemente seus recursos em duas frentes. Apesar da Rssia se render em 1917, no houve tempo para os alemes se reorganizarem, e a entrada dos norte-americanos no conflito nesse mesmo ano terminou por esgotar os recursos do Imprio Alemo. Longe de ser apenas um evento blico, a guerra em duas frentes uma realidade no desenvolvimento de software. E, assim como os alemes, os gerentes e lderes de

14

projeto tm de tentar evitar a sustentao simultnea de dois projetos por um tempo longo. Claro que aqui estamos tratando de projetos grandes, com escopos bem diferentes, os quais so anlogos a dois adversrios que atacam por lados diferentes. H a situao em que os projetos possuem uma certa convergncia, similaridade, o que pode ser metaforizado na situao blica de atacar dois exrcitos em uma s frente.

1.2 Frameworks
De acordo com Martin(1995), para conseguir um rpido desenvolvimento, novos sistemas devem ser construdos a partir de classes que j existam e que possam ser adaptadas s circunstncias. Um desenvolvimento baseado em repositrios necessrio com ferramentas automatizadas. Estas ferramentas devem tornar rpido e fcil o trabalho de se personalizar uma interface grfica padro. Sistemas devem ser construdos de forma que possam ser mudados rpida e facilmente, sem os problemas de manuteno do passado.
Em consonncia com essa afirmao, o principal propsito de um framework ajudar no processo de desenvolvimento de aplicaes. Ele permite que as aplicaes sejam desenvolvidas mais rapidamente e mais facilmente, e deve resultar em uma aplicao de qualidade superior. A figura 1 mostra uma hierarquia tpica de uma aplicao Java web baseada em frameworks. Segundo Fayad (1997), "framework um conjunto de classes que colaboram para realizar uma responsabilidade para um domnio de um subsistema da aplicao." A necessidade de construir software de forma cada vez mais gil e a exigncia da criao de produtos com mais qualidade fazem com que o processo de desenvolvimento de software seja apoiado pelo reuso de estruturas pr-existentes, por exemplo, frameworks. Vrios frameworks podem ser usados na construo de um nico aplicativo de software. Para facilitar a escolha e o uso de vrios frameworks durante o desenvolvimento de software, e garantir a integrao, evoluo e manuteno dos mesmos, Macias (2008) prope uma estrutura chamada Framework Integrador.

15

Figura 1: Arquitetura de uma aplicao Java web com framework

De acordo com Macias, um framework define parmetros de projeto; a forma como realizada a diviso em classes e objetos e suas responsabilidades; a maneira como colaboram entre si, e o fluxo de controle, ditando, assim, a arquitetura de software das aplicaes que os utilizam. Alm disso, fornece padres de projetos - estruturas essenciais para o desenvolvimento de projetos de aplicaes de software - uma espinha dorsal e o continente para os componentes criados nas aplicaes e que iro funcionar dentro delas. Como os frameworks absorvem as decises de projeto que so comuns ao seu domnio de aplicao, eles priorizam a reutilizao de projetos ao invs da reutilizao de cdigo, apesar de inclurem classes concretas que podem ser imediatamente utilizadas. O uso de frameworks e a reutilizao em nvel de projeto implicam em uma inverso de controle entre um cdigo especfico de aplicao e o software na qual ela se baseia. No caso de aplicaes que no usam frameworks e sim bibliotecas ou DLLs (Dynamiclink library), o cdigo principal construdo na aplicao que realiza chamadas ao trecho que se deseja utilizar. J no caso de aplicaes que utilizam frameworks, o trecho principal reutilizvel est nele, que chama o cdigo escrito pelo desenvolvedor, como mostrado na figura 2.1.

16

1.2 O Desafio dos Frameworks


Erich Gamma (Venners, 2005) define framework como o mais alto nvel de reuso. Considerando isso, construir um novo framework, em vez de usar um existente, seria ignorar o objetivo de alcanar mxima reusabilidade. Alm disso, h um conflito entre a mirade de caractersticas oferecida por cada framework, especfico para certos espaos de problemas, e a necessidade de uma empresa. Finalmente, h o problema de gerenciar a obsolescncia dos produtos atuais e absorver novas tecnologias. Um framework genrico no pode pensar em ser mais uma implementao que competir com as existentes, mas um middleware que integre as solues existentes. Isso resolveria o problema de gerenciar diferentes solues para produzir software. Mas permanece ainda a questo da obsolescncia e da inovao. O software nunca um produto acabado. Dessa forma, temos que responder a questo de como uma infraestrutura para construir software pode acompanhar o desenvolvimento tecnolgico sem criar estruturas que aprisionem o desenvolvedor. A resposta, nesse caso, criar uma interface baseada em especificaes tcnicas, e no em implementaes. As Java Specification Requests (JSRs) so especificaes escritas para padronizar a tecnologia Java. JSRs estabelecem padres para a implementao de produtos, e sempre disponibilizam uma implementao de referncia. Diferentes distribuidores podem ter diferentes produtos que seguem as mesmas JSRs, e sua API se comunica com as aplicaes de modo indistinguvel. Sendo assim, um framework que pretenda ser genrico para a criao de aplicaes na tecnologia Java deve ser baseada nas JSRs, e no em produtos de software especficos. Neste livro, tentaremos convenc-lo da necessidade de usar um framework, comeando por um exemplo em que no usamos nenhum. Em seguida tentaremos convenc-lo de que no suficiente usar um framework (pois h vrios) e que no basta juntar vrios frameworks de qualquer modo. No prximo captulo, introduziremos o problema que serve de insumo para nossas implementaes.

17

CAPTULO 2 A loja virtual de livros


Neste captulo iremos simular, de forma bastante simplificada, o incio de um processo de desenvolvimento de software.

2.1 Levantamento de requisitos


McConnel (2005) diz que o problema de software um problema perverso porque voc precisa resolv-lo uma vez para defini-lo claramente, e ento resolv-lo mais uma vez para criar uma soluo que funcione. Que funcione apenas, no que funcione da melhor forma. De forma mais simples, o que ele quer dizer que o cliente e o fornecedor de software no tem, a princpio, o mesmo entendimento sobre o produto a ser desenvolvido. Isso na verdade um reflexo da dificuldade de levantar requisitos junto ao cliente. Para ilustrar essa dificuldade, iremos recorrer a uma analogia com um episdio do livro Alice no Pas das Maravilhas. Aps deixar a casa da Duquesa, Alice encontra uma bifurcao. Nesse ponto, o Gato de Cheshire aparece no galho de uma rvore. Alice pergunta qual caminho ela deve tomar. O gato responde que isso depende onde ela quer chegar. Alice responde que no sabe. Ento o gato diz que, nesse caso, qualquer caminho serve. Apesar desse dilogo parecer tolo, ele na verdade j ocorreu muitas vezes e ainda ocorre no processo de desenvolvimento de software. O cliente quer algo, mas no sabe exatamente o qu. Teoricamente, neste caso, qualquer coisa produzida o atenderia. Mas certamente o cliente, por mais que no saiba o que quer, no aceitar qualquer coisa, pois ele saber muito bem o que no quer. Sendo assim, necessrio um processo de desenvolvimento bem definido e estruturado, que garanta que se chegue a um produto de software que atenda as necessidades do cliente. Ns estamos considerando um processo de desenvolvimento com quatro fases: concepo, anlise e projeto, construo e encerramento.

18

Figura 2: Alice e o Gato de Cheshire (ilustrao de John Tenniel)

19

A concepo a fase na qual identificamos as necessidades do cliente e analisamos se o projeto vivel. Esta a hora certa para desistir de um projeto de software. Qualquer deciso posterior custar caro. A primeira coisa a ser feita identificar as pessoas envolvidas no projeto. Vamos supor que uma empresa de desenvolvimento chamada Laele contatada por uma livraria chamada Alexandria. Essa livraria nova, e tem dificuldade de concorrer com gigantes do mercado, por isso quer comercializar seus produtos pela Internet. Se o retorno for maior do que as vendas presenciais, o dono, seu Omar, ir fechar a loja fsica e trabalhar apenas virtualmente. O analista de negcios da Laele, Tio, faz uma entrevista com o dono da Alexandria e alguns de seus funcionrios. A partir da ele obtm uma lista simplificada de requisitos: 1. O sistema da livraria compreende duas interfaces: uma para o cliente e outra para o funcionrio da loja; 2. A interface do cliente a padro, e deve ser apresentada se nada em contrrio for especificado; 3. A interface do cliente dever apresentar na pgina inicial uma relao aleatria de livros; 4. Essa relao dever apresentar a imagem da capa do livro, o ttulo, o(s) autor(es), o preo e um boto para colocar o livro em um carrinho de compras. 5. O carrinho de compras criado quando o cliente seleciona o primeiro livro. Ele no precisa estar autenticado para fazer isso. 6. O cliente pode alterar a quantidade de exemplares de um livro selecionado. 7. O cliente pode excluir qualquer livro do carrinho, a qualquer momento, antes de finalizar a compra. 8. A pgina inicial tambm dever apresentar uma caixa de busca, que permita a recuperao de livros pelo ISBN, ttulo, autor e editora. 9. O resultado das buscas, se exceder um determinado limite de livros, dever ser distribudo em vrias pginas. O limite padro de livros a serem visualizados quatro. 10. A interface dever apresentar um boto para fechar o pedido de venda em todas as pginas, assim como um link para ver o contedo do carrinho de compras. O boto de fechamento do pedido dever levar o cliente para uma pgina onde ele

20

escolher a forma de pagamento, dentre quatro: depsito em conta, dbito automtico, carto de crdito e boleto bancrio. 11. Aps confirmar a forma de pagamento, o cliente dever obrigatoriamente se autenticar, se j no estiver autenticado. 12. A autenticao feita com o apelido ou CPF e senha do cliente. 13. O cliente pode se autenticar a qualquer momento. Para isso, o sistema dever apresentar um link chamado Conectar. Se o cliente estiver autenticado, dever ser apresentado em seu lugar um link chamado Desconectar. 14. Se o cliente no tiver cadastro, ele pode se cadastrar a qualquer momento. Para isso, deve haver um link chamado Cadastrar. Ele s pode estar disponvel se o cliente estiver desconectado. 15. O link Cadastrar apresentar um formulrio onde o cliente registrar seu CPF, um nome, um apelido, seu e-mail e uma senha de 8 nmeros ou letras. 16. Com a confirmao da compra pelo cliente, deve ser gerado um pedido de venda. 17. Com a gerao do pedido de venda, o carrinho de compras deve ser esvaziado. 18. A interface do funcionrio apresenta opes para incluir, alterar e excluir registros das tabelas do sistema. 19. O sistema possui controle de acesso, pois os funcionrios tm acesso privilgios limitados. e

20. H um funcionrio administrador, que tem acesso a tudo. O administrador quem define os acessos e privilgios. 21. A interface do funcionrio tambm gera um relatrio de pedidos de um determinado perodo (dia, ms, ano). Todos esses requisitos so funcionais, ou, de acordo com Sommerville (2007, p. 80), so requisitos que descrevem o que o sistema deve fazer. Para no tornar o exemplo complexo demais, descartaremos requisitos no funcionais.

2.2 O Sonho de Nabucodonosor


Voc deve ter percebido que faltam algumas coisas nos requisitos do sistema de livraria que vemos em qualquer sistema de livraria na Internet. claro que no temos a pretenso de criar neste livro um sistema de software real, mas apenas um exemplo que permita explorar as principais caractersticas de aplicaes web em Java.

21

Mas oportuno salientar a importncia de um bom levantamento de requisitos em um projeto de software. Segundo Blaschek (apud Fraga Filho e Reis, 2005, p. 2), os principais problemas do desenvolvimento de software esto associados aos requisitos. Isso ocorre porque falhas nos requisitos tem um impacto crescente nas demais fases de um processo de desenvolvimento. Um requisito incorreto produz uma anlise incorreta, que produz um projeto incorreto, que por sua vez produz uma implementao incorreta. E os testes sero realizados sobre falsas premissas, o que os tornar invlidos. Finalmente, o pior caso chegar-se concluso do projeto com um produto que no atende os requisitos. Segundo Pinho (2010), para minimizar os problemas relacionados ao levantamento de requisitos, vrias tcnicas foram desenvolvidas. A entrevista, usada no exemplo, uma tcnica tradicional, cuja eficincia depende da experincia do entrevistador e tem mais utilidade quando as partes interessadas tem muitos conhecimentos subjetivos (conceitos estritamente ligados ao seu negcio) e esto dispostos a serem entrevistados. A academia e o mercado de TI tm reconhecido a importncia da Engenharia de Requisitos, tanto que j existe grande literatura sobre o assunto, eventos especficos e produtos de software para auxiliar essa disciplina. O engenheiro de requisitos um profissional que precisa ter um conhecimento tcnico abrangente e ao mesmo tempo uma capacidade de relacionamento pessoal que ajude a extrair as informaes necessrias e relevantes para a elaborao de um projeto de software. A escolha das tcnicas mais adequadas de levantamento de requisitos para um projeto de suma importncia. Mas to importante conseguir estabelecer um bom entendimento com o cliente, para que ele tambm fique ciente do quo importante que tudo que ele deseja esteja claro para o fornecedor de software. Uma analogia exagerada de como pode se sentir um engenheiro de requisitos diante das incertezas do cliente pode ser encontrada na histria de Nabucodonosor, o fundador do segundo imprio babilnico, relatada na Bblia (Daniel 2:1-5). Ele teve um sonho estranho uma noite e acordou perturbado. Mandou chamar os sbios e magos e pediu que eles interpretassem o sonho. Eles perguntaram qual era o sonho, para poderem interpret-lo. O rei disse que no se lembrava, mas se eles no interpretassem o sonho, iria mandar mat-los. algo similar a mandar criar um sistema, mas no saber ao certo o que ele tem de fazer, e ainda ameaar o desenvolvedor com um processo judicial.

22

CAPTULO 3 Modelagem
(colaborao de Luciana Campos Mota)

Este captulo tratar da formalizao de requisitos e da modelagem do sistema de livraria virtual. A partir da lista de requisitos do captulo anterior, sero criados os casos uso e os diagramas de classe.

3.1 Descrevendo os Casos de Uso


Segundo Sommerville (2007, p. 102), casos de uso constituem uma tcnica baseada em cenrios para levantamento de requisitos. De acordo com Booch et al (1998, p. 222) um caso de uso uma descrio de um conjunto de sequncias de aes, incluindo variantes, que um sistema executa e que produzem um resultado de valor observvel para um ator. Um caso de uso pode descrever um nico objetivo e as possveis coisas que podem ocorrer at que o usurio alcance o objetivo proposto. A lista de requisitos que colhemos at agora nos apresenta uma viso superficial do que o que cliente deseja. Precisamos refinar o entendimento do problema, e obter um insumo mais detalhado que sirva para a fase de elaborao do software. Sommerville (p. 103) afirma que casos de uso identificam as interaes individuais com o sistema. Ele define o contedo de um caso de uso como tendo:

Uma hiptese inicial; Uma descrio passo a passo do fluxo normal de eventos; Uma descrio passo a passo do tratamento de erros; Uma descrio passo a passo de atividades alternativas; Qual o estado do sistema aps o trmino.

Esse contedo, com algumas variaes, pode ser encontrado em vrios autores de Engenharia de Software. Os casos de uso podem ser representados graficamente por diagramas de casos de uso. As interaes descritas nos casos de uso podem ser representadas por diagramas de sequncia.

23

Vamos criar os casos de uso de nosso sistema, a partir da lista inicial de requisitos. O objetivo

3.1.1 Caso de Uso Adicionar Item ao Carrinho

Hiptese inicial: O cliente est visualizando a pgina inicial do sistema, com a lista de livros. A lista pode ser aleatria ou resultado de uma busca; Fluxo normal de eventos: 1. O cliente clica no boto Comprar localizado abaixo da imagem do livro. 2. O livro adicionado ao carrinho de compras. 3. Ele direcionado para uma pgina que exibe o contedo do carrinho de compras, com a soma dos valores dos itens, um boto Fechar Pedido e um boto Continuar Comprando. 4. Ele clica no boto Continuar Comprando e redirecionado para a pgina inicial do sistema.

Tratamento de erros:

No caso de alguma pgina no ser encontrada, o cliente deve ser direcionado para uma pgina de erro padro, e a exceo deve ser gravada em log.

Atividades alternativas: 1. Quando estiver na pgina de contedo do carrinho, o cliente pode editar qualquer um dos itens, alterando sua quantidade - caso de uso 3.1.2 - ou removendo-o - caso de uso 3.1.3. 2. A pgina do carrinho tambm deve exibir a caixa de busca, permitindo que o usurio procure por outros livros sem ter de voltar para a pgina inicial.

Estado do sistema aps o trmino: item adicionado ao carrinho de compras.

3.1.2 Caso de Uso Editar Item do Carrinho

Hiptese inicial: O cliente j est autenticado no sistema e clica sobre o carrinho de compras para modificar um item. Fluxo normal de eventos: 1. O cliente seleciona um item. 2. O cliente altera sua quantidade. 3. Ele clica no boto Continuar Comprando e redirecionado para a pgina inicial do sistema.

24

Tratamento de erros:

No caso de alguma pgina no ser encontrada, o cliente deve ser direcionado para uma pgina de erro padro, e a exceo deve ser gravada em log.

Atividades alternativas: 1. O cliente pode remover um item do carrinho caso de uso 3.1.3. 2. A pgina do carrinho tambm deve exibir a caixa de busca, permitindo que o usurio procure por outros livros sem ter de voltar para a pgina inicial.

Estado do sistema aps o trmino: contedo do carrinho de compras modificado.

3.1.3 Caso de Uso Excluir Item do Carrinho

Hiptese inicial: O cliente j est autenticado no sistema e clica sobre o carrinho de compras para excluir um item. Fluxo normal de eventos: 1. O cliente clica sobre o carrinho de compras. 2. O cliente exclui um item do carrinho.

3. Ele clica no boto Continuar Comprando e redirecionado para a pgina inicial do sistema.

Tratamento de erros:

No caso de alguma pgina no ser encontrada, o cliente deve ser direcionado para uma pgina de erro padro, e a exceo deve ser gravada em log.

Atividades alternativas: 1. O cliente executa o caso de uso 3.1.5. - Fechar Pedido.

2. A pgina do carrinho tambm deve exibir a caixa de busca, permitindo que o usurio procure por outros livros sem ter de voltar para a pgina inicial.

Estado do sistema aps o trmino: item excludo do carrinho de compras.

3.1.4 Caso de Uso Buscar Livro

Hiptese inicial: O cliente est na pgina inicial, preenche a caixa de texto de busca, seleciona um critrio de busca e clica sobre o boto Buscar. Fluxo normal de eventos: 1. O cliente preenche a caixa de busca com as informaes do livro.

25

2. O cliente seleciona o critrio de busca desejado (nome do livro, nome do autor ou ISBN) 3. O cliente clica no boto Buscar Livro. 4. O sistema apresenta uma pgina com os livros que atendem ao critrio selecionado.

Tratamento de erros:

No caso de alguma pgina no ser encontrada, ou houver algum problema de conexo com o banco de dados, o cliente deve ser direcionado para uma pgina de erro padro, e a exceo deve ser gravada em log.

Atividades alternativas: O cliente encerra o caso de uso

Estado do sistema aps o trmino: apresentao de uma listagem de livros.

3.1.5 Caso de Uso Fechar Pedido

Hiptese inicial: O cliente est na pgina do carrinho e clica sobre o boto Fechar Pedido. Fluxo normal de eventos: 1. O carrinho de compras travado. Se o cliente abrir o site do sistema por meio de uma outra aba ou um outro navegador, no conseguir adicionar mais itens. 2. O cliente direcionado para uma pgina onde escolhe uma forma de pagamento dentre quatro: depsito em conta, dbito automtico, carto de crdito e boleto bancrio. 3. Aps escolher a forma de pagamento, o cliente confirma o pedido. 4. O sistema grava o pedido de venda e informa o nmero do pedido. O cliente pode voltar a tela inicial do sistema.

Tratamento de erros:

No caso de alguma pgina no ser encontrada, ou houver algum problema de conexo com o banco de dados, o cliente deve ser direcionado para uma pgina de erro padro, e a exceo deve ser gravada em log.

Atividades alternativas: No h.

26

Estado do sistema aps o trmino: pedido de venda gravado.

3.1.6 Caso de Uso Cadastrar Cliente


Hiptese inicial: O cliente clicou no boto Cadastrar na pgina inicial. Fluxo normal de eventos: 1. O sistema exibe um formulrio pedindo nome, apelido, e-mail e senha. 2. O cliente preenche os dados e confirma a gravao. 3. O sistema grava os dados no banco. 4. O cliente redirecionado para a pgina onde se encontrava anteriormente.

Tratamento de erros:

No caso de alguma pgina no ser encontrada, ou houver algum problema de conexo com o banco de dados, o cliente deve ser direcionado para uma pgina de erro padro, e a exceo deve ser gravada em log.

Atividades alternativas:

A partir de 2, se os dados no forem validados, o formulrio pode ser exibido novamente com mensagem indicando quais so os problemas.

Estado do sistema aps o trmino: cadastro de cliente com registro adicionado.

3.1.7 Caso de Uso Manter Cadastro

Hiptese inicial: Um funcionrio se autenticou no mdulo administrativo do sistema e deseja realizar uma operao em um cadastro. Fluxo normal de eventos: 1. O funcionrio seleciona um cadastro. 2. O funcionrio edita o registro. 3. O funcionrio grava as alteraes. 5. O funcionrio volta para o menu principal do sistema.

Tratamento de erros:

No caso de alguma pgina no ser encontrada, ou houver algum problema de conexo com o banco de dados, o funcionrio deve ser direcionado para uma pgina de erro padro, e a exceo deve ser gravada em log.

Atividades alternativas:

27

A partir de 1, o funcionrio pode procurar um registro. A partir de 2, o funcionrio pode incluir um registro. A partir de 2, o funcionrio pode remover um registro. A partir de 2, o funcionrio pode pesquisar um registro. A realizao de qualquer operao depende de permisso.

Estado do sistema aps o trmino: cadastro com registro modificado.

3.1.8 Caso de Uso Autenticar Usurio


Hiptese inicial: O usurio est na pgina de autenticao. Fluxo normal de eventos: 1. O usurio preenche os dados de login (apelido e senha). 2. O usurio clica sobre o boto Autenticar. 3. O sistema valida os dados. 4. O usurio direcionado para a tela correspondente dependendo de seu perfil (cliente, funcionrio).

Tratamento de erros:

No caso de alguma pgina no ser encontrada, ou houver algum problema de conexo com o banco de dados, o funcionrio deve ser direcionado para uma pgina de erro padro, e a exceo deve ser gravada em log.

Atividades alternativas:

A partir de 3, se os dados no forem vlidos, o funcionrio ser redirecionado para o formulrio de autenticao.

Estado do sistema aps o trmino: usurio autenticado no sistema.

3.1.9 Caso de Uso Verificar Permisso de Funcionrio

Hiptese inicial: O funcionrio solicita acesso a um recurso do mdulo administrativo. Fluxo normal de eventos: 1. O sistema verifica as permisses do funcionrio. 2. O sistema direciona o funcionrio para a pgina responsvel pela interao com o recurso solicitado e registra o acesso no log.

28

Tratamento de erros:

No caso de alguma pgina no ser encontrada, ou houver algum problema de conexo com o banco de dados, o funcionrio deve ser direcionado para uma pgina de erro padro, e a exceo deve ser gravada em log.

Atividades alternativas:

A partir de 1, se o funcionrio no tiver permisso para manipular o recurso, ele ser redirecionado para a pgina do menu principal, com mensagem avisando que ele no tem permisso. A tentativa acessar um recurso no permitido ser gravada em log.

Estado do sistema aps o trmino: registro adicionado no log do sistema.

3.1.10 Caso de Uso Gerenciar Carrinho

Hiptese inicial: O usurio do tipo cliente j est autenticado no sistema e clica sobre o carrinho de compras. Fluxo normal de eventos: 1. O cliente verifica o contedo do carrinho. 2. Ele clica no boto Continuar Comprando e redirecionado para a pgina inicial do sistema.

Tratamento de erros:

No caso de alguma pgina no ser encontrada, o cliente deve ser direcionado para uma pgina de erro padro, e a exceo deve ser gravada em log.

Atividades alternativas: 1. O cliente pode executar o caso de uso 3.1.1 (Adicionar item ao carrinho) 2. O cliente pode executar o caso de uso 3.1.2 (Editar item do carrinho) 3. O cliente pode executar o caso de uso 3.1.3 (Excluir item do carrinho) 4. A pgina do carrinho tambm deve exibir a caixa de busca, permitindo que o usurio procure por outros livros sem ter de voltar para a pgina inicial.

Estado do sistema aps o trmino: atualizao dos itens do carrinho.

3.1.11 Caso de Uso Gerar Relatrios

Hiptese inicial: O usurio (do tipo funcionrio) deseja gerar um relatrio de pedidos de determinado dia/ms/ano. Fluxo normal de eventos:

29

1. O usurio(funcionrio) se autentica no sistema. 2. No mdulo administrativo, ele clica no boto Relatrios. 3. Na pgina de relatrios, ser solicitado para que ele indique o perodo desejado, data incio e data fim. 4. Aps informar o perodo, ele clica em Gerar Relatrio. 5. O relatrio ser gerado e impresso na tela.

Tratamento de erros:

No caso de alguma pgina no ser encontrada, o cliente deve ser direcionado para uma pgina de erro padro, e a exceo deve ser gravada em log.

Atividades alternativas: 1. O usurio pode imprimir o relatrio na impressora ou em arquivo.

Estado do sistema aps o trmino: relatrios gerados.

30

3.1.12 Diagramas de Casos de Uso

Figura 3: Casos de Uso da Aplicao


A figura 3 faz a representao dos casos de uso descritos anteriormente, envolvendo os atores e todas as funcionalidades do sistema. Conforme Booch et al (1998, p. 226), uma generalizao uma relao de herana direta entre classes. A generalizao pode ser usada quando dois ou mais casos de uso possuem comportamento, estrutura e finalidades comuns. Sendo assim, possvel descrever as partes compartilhadas em um novo caso de uso, especializado pelos casos de uso filho. A figura 3.2 demonstra uma generalizao do caso de uso Gerenciar Carrinho, onde os casos de uso Excluir Item do Carrinho, Adicionar Item ao Carrinho e Editar Item do Carrinho so especializaes do Caso de uso (pai) Gerenciar Carrinhho.

31

Figura 4: Exemplo de generalizao do Caso de uso Gerenciar Carrinho

3.3 Diagrama Entidade Relacionamento


Uma informao importante se o cliente j possui uma base de dados, para ser utilizada com a aplicao. Se ele j possui, necessrio analisar a documentao dela, ou criar uma se no existir. No nosso exemplo, a livraria j tem uma base de dados. E ao ser questionado sobre isso, o seu Omar diz que tem que usar essa base, porque todos os livros j esto cadastrados, alm dos dados de clientes e funcionrios. Essa base foi construda por um ex-funcionrio, que criou um pequeno sistema para a loja, para atendimento presencial, mas no o concluiu. O sistema atual se resume apenas a fazer a busca de livros. Assim, antes de modelarmos as classes do sistema, precisamos saber qual a estrutura da base de dados. Para isso, usamos um diagrama entidade-relacionamento. Segundo Silberschatz et (1999, p. 21), o modelo entidade-relacionamento (E-R) foi desenvolvido para facilitar o projeto do banco de dados, permitindo a especificao do esquema da empresa, que representa toda a estrutura lgica do banco de dados. Eles ainda acrescentam que o modelo E-R um dos modelos com maior capacidade semntica; os aspectos semnticos do modelo se referem tentativa de representar o significado dos dados. Finalmente, eles afirmam que o modelo E-R extremamente til para mapear, sobre um esquema conceitual, o significado e interaes das empresas reais. A figura 5 mostra as tabelas do banco de dados mantido pela livraria:

32

Figura 5: Diagrama Entidade-Relacionamento da livraria


Esse diagrama omite o nome dos relacionamentos, mostrando apenas a cardinalidade dos mesmos. Na verdade, o nome do relacionamento, para a aplicao, indiferente. O fato de coloc-lo no diagrama tem um propsito de utilidade: verificar as regras de negcio com o cliente.

3.4 Diagrama de Classes


Booch et al (1998, p. 105) afirma que os diagramas de classe so os diagramas mais comuns encontrados nos sistemas de modelagem objeto-relacional. Conforme o autor, um diagrama deste tipo deve mostrar um conjunto de classes, interfaces e colaboraes e os relacionamentos entre eles. O diagrama de classes da figura 6 uma consequncia do levantamento de requisitos apontado no captulo 2, da definio de casos de usos e das informaes obtidas a partir do diagrama entidade-relacionamento. Classes contm atributos e mtodos, mas neste momento, vamos nos concentrar nos dados a serem manipulados.

3.5 A Implementao
A modelagem feita neste captulo teve por objetivo principal oferecer uma viso completa do sistema, mas no realizaremos sua implementao completa. Um motivo que iremos fazer trs implementaes diferentes, e desenvolver uma aplicao completa trs vezes tornaria este livro muito extenso. Outro motivo que o propsito deste livro to somente ensinar prticas de reuso que facilitem a manuteno de aplicaes Java Web, e no apresentar uma aplicao para ser vendida. A aplicao aqui o meio de ensino, e no o fim. Iremos nos restringir a alguns casos de uso que sero suficientes para realizar a comparao entre trs alternativas de desenvolvimento Java: sem frameworks, com JSF

33

e Hibernate e com Demoiselle. Desenvolver todos os casos de uso no acrescentaria em nada ao objetivo aqui almejado, apenas traria repeties desnecessrias. Por isso, nos captulos a seguir, sero implementados apenas os casos de uso Manter Cadastro, Autenticar Usurio e Verificar Permisso de Funcionrio, que compem grande parte da metade administrativa da aplicao.

Figura 6: Diagrama de classes do Sistema Livraria Virtual

34

CAPTULO 4 Livraria com JSP e JDBC


Neste captulo, faremos a implementao de alguns casos de uso descritos no captulo anterior, usando a tecnologia JavaServer Pages (JSP). JSP uma evoluo dos servlets Java, baseada em linguagens de scripts largamente utilizadas, como ASP e PHP. Faremos uma pequena introduo aos servlets e JSP, para em seguida iniciar a implementao da parte administrativa da livraria. Para acompanhar este captulo, voc precisa ter instalado o JDK 6.

4.1 Servlets
Servlets so aplicaes Java executadas em servidores web. Eles so consequncia de uma demanda por tecnologias de contedo dinmico. Nesta seo iremos apresentar o contexto da criao dos servlets. Um servidor web um dos terminais da arquitetura cliente-servidor proposta pelo protocolo HTTP. O protocolo HTTP roda no topo do TCP/IP e define uma comunicao entre um cliente e um servidor. Essa comunicao , a princpio, assncrona. O cliente faz uma requisio ao servidor e este envia uma resposta. O cliente no precisa esperar pela resposta para enviar outra requisio. Por outro lado, o servidor no envia resposta alguma se no receber uma requisio. O objeto requisitado sempre um arquivo de texto. O protocolo TCP responsvel por garantir que o arquivo enviado de um n da rede para outro chegue ntegro ao seu destino, ainda que o arquivo esteja dividido em blocos no momento do envio (Basham, 2005, p. 6). J o protocolo IP se encarrega de sustentar a transferncia e roteamento dos blocos, ou pacotes, de um hospedeiro para outro at que eles cheguem ao seu destino. A estrutura bsica do protocolo HTTP atende bem ao servio de pginas estticas. Um computador que faz o papel de cliente envia uma requisio de um arquivo (geralmente uma pgina HTML) e o servidor web a devolve. Um software chamado navegador interpreta o contedo do arquivo e exibe algo interessante para o usurio final.

35

Esse servio de pginas estticas foi o princpio da utilizao da web, mas somente um conjunto de pginas HTML no permite criar uma aplicao de software, em que haja interao com o usurio final. Uma aplicao no deve somente prover texto prdefinido, mas processar dados fornecidos pelo usurio e reagir a eventos. Com o crescimento do uso comercial da Internet, surgiu a necessidade do servidor web fazer algum processamento adicional, de modo a prover contedo dinmico. Em vez de uma resposta fixa, um sistema web dinmico oferece respostas personalizadas, com base em parmetros e eventos disparados pela pgina. Alm disso, para que um conjunto de pginas web possa funcionar como uma aplicao, preciso de mecanismos que mantenham estados entre requisies. O protocolo HTTP no mantm estado, assim necessrio uma aplicao no servidor que consiga fazer isso. Segundo Fields e Kolb (2000, p. 3), o primeiro padro para contedo de web dinmico se baseava na Common Gateway Interface, ou CGI. O CGI especifica como servidores web passam informaes de requisies para programas externos. Esses programas externos, rodados pelo servidor, geram respostas em tempo de execuo. Para o cliente, no muda nada, ele continua recebendo uma pgina web. O que muda que no servidor essa pgina no existia originalmente (e no existir mais depois do envio da resposta). No CGI, ao receber uma requisio, o servidor web verifica se ela se refere a um arquivo esttico (pgina HTML) ou a um arquivo associado a uma aplicao. Essa associao deve estar configurada no servidor. Ao identificar que o arquivo solicitado deve ser processado por uma aplicao externa, o servidor gera um processo para executar a aplicao, e recebe a sada desta. Ao receb-la, ele simplesmente a envia para o cliente, como faria com o contedo de qualquer arquivo ordinrio gravado em disco. O problema do CGI que ele cria um novo processo para cada nova requisio, pois os programas de CGI rodam fora do software servidor da web. Isso torna sua aplicabilidade limitada para uso em grande escala de aplicaes baseadas na web. Em 1996, a Sun Introduziu os servlets. Servlets so aplicaes Java, como dissemos no incio da seo. A diferena entre eles e os programas tradicionais de CGI (incluindo programas Java padro), que todos os servlets associados com um servidor da Web rodam dentro de um nico processo. A JVM cria uma thread para cada requisio. Como as threads em Java tm muito menos overhead que os processos completos, e so executados dentro da memria do processador (j alocada pela JVM), a execuo de um servlet muito mais eficiente do que o processamento de um programa CGI.

36

Apresentaremos um pequeno exemplo de servlet que servir para explicar porque no o utilizamos diretamente, ou melhor, porque no utilizamos somente servlets para criar aplicaes web em Java. Para um servlet funcionar, ele precisa de um Container Servlet. Um Container Servlet um componente de software que pode ser executado como um processo especial do servidor web, dedicado a tratar da execuo de servlets, ou pode ser invocado diretamente pelo cliente. No primeiro caso, um servidor web pode ter um Container Servlet embutido ou pode direcionar as requisies para um Container externo. Para o nosso primeiro exemplo, no utilizaremos um servidor web, mas somente um Container Servlet. Nosso Container ser o Apache Tomcat, verso 6.x. Ele pode ser obtido em http://tomcat.apache.org. Baixe a distribuio binria e descompacte em um diretrio de sua preferncia. Para executar o Tomcat, entre no subdiretrio bin de sua instalao e execute o arquivo startup.bat (windows) ou startup.sh (linux). O Tomcat executado na porta 8080 de TCP, para evitar conflitos com servidores web padro que usam a porta 80. Para parar o Tomcat, basta executar o arquivo shutdown.sh (linux). shutdown.bat (windows) ou

Vamos criar um projeto de servlet. Escolha um local (qualquer um menos o diretrio do Tomcat) e crie uma pasta chamada ExemploServlet. Dentro dessa pasta crie trs subpastas: src, classes e etc. A pasta src conter os arquivos de cdigo-fonte (.java); A pasta classes conter os arquivos de bytecode (.class); A pasta etc conter a configurao dos servlets (arquivo web.xml). A estrutura de pastas ficar assim:
ExemploServlet classes etc src

Dentro da pasta src, crie a classe AloMundoServlet, com este cdigo:


import javax.servlet.*; import javax.servlet.http.*; import java.io.*;

37

public class AloMundoServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { PrintWriter out = response.getWriter(); out.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Strict//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">"); out.println("<html>"); out.println("<head>"); out.println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">"); out.println("<title>Al Mundo</title>"); out.println("</head>"); out.println("<body>"); out.println("Al Mundo"); out.println("</body>"); out.println("</html>"); } }

O mtodo doGet executado em resposta a uma requisio HTTP GET. Nesse mtodo, criamos um objeto que encapsula a sada para o cliente. No diretrio etc, iremos criar o arquivo web.xml. Esse arquivo um deployment descriptor (DD), e cada aplicao web em Java precisa ter um. Um DD pode declarar vrios servlets (que compem a aplicao). O cdigo ficar assim:
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <servlet> <servlet-name>AloMundo</servlet-name> <servlet-class>AloMundoServlet</servlet-class> </servlet>

38

<servlet-mapping> <servlet-name>AloMundo</servlet-name> <url-pattern>/alomundo</url-pattern> </servlet-mapping> </web-app>

A tag servlet-name um apelido que serve para fazer a ligao entre a url invocada e o servlet a ser executado. Essa estrutura permite que vrias requisies sejam direcionadas para um mesmo servlet. Compile o servlet com o seguinte comando:
javac -cp [diretrio do tomcat]/lib/servlet-api.jar -d classes

src/AloMundoServlet.java

No diretrio do Tomcat, h uma subpasta chamada webapps. Dentro dela, crie um diretrio com o nome da aplicao web. No nosso caso, ser exemploservlet. Dentro desse diretrio, crie o subdiretrio WEB-INF e copie o arquivo web.xml para dentro dele. Tambm crie dentro de WEB-INF o subdiretrio classes e copie para dentro dele o AloMundoServlet.class. Voc vai ter uma estrutura assim:
webapps exemploservlet WEB-INF web.xml classes AloMundoServlet.class

Inicie o Tomcat e digite no seu navegador a seguinte URL: http://localhost:8080/exemploservlet/alomundo Em comparao com uma linguagem de script, como ASP ou PHP, tivemos muito trabalho s para escrever Al Mundo na tela do navegador. Sem contar que voc pode ter visto um smbolo estranho no lugar da letra acentuada dependendo da codificao de seu navegador. O uso exclusivo de servlets para criar aplicaes web cria dificuldades de lidar com a camada de apresentao. Todo o texto HTML a ser enviado para o navegador teria de ser colocado como argumento do mtodo println. A formatao do HTML dentro de uma

39

String literal o torna ilegvel para o webdesigner. Sem contar que exige que ele conhea Java. claro que aqui fizemos tudo manualmente. O uso de um ambiente integrado de desenvolvimento facilitaria a tarefa, mas no resolveria o problema da mistura de cdigo HTML com Java.

4.2 JSP
De acordo com Fields e Kolb (2000, p. 9), a desvantagem potencial de usar servlets que todo o contedo de documentos, tanto esttico quanto dinmico, reside no cdigo fonte do programa. Como resultado, qualquer modificao em tal documento necessita de interveno de um programador. Para resolver este, problema, segundo Gonalves (2007, p. 115), a Sun Microsystems criou uma tecnologia baseada em servlets chamada JavaServer Pages (JSP), que permite separar o cdigo HTML de Java. Essa separao evita que o programador tenha de inserir muito cdigo para produzir apresentao e no obriga o webdesigner a conhecer (pelo menos no profundamente) a linguagem Java. Faremos uma rpida introduo ao JSP reescrevendo o exemplo da seo anterior. No nos deteremos aqui com muitas explicaes porque o intuito deste livro, citando Silveira et al (2005, p. 1) ensinar de maneira elegante, mostrando apenas o que necessrio no momento correto e poupando o leitor de assuntos que no costumam ser de seu interesse em determinadas fases do aprendizado. Vamos criar um projeto de servlet. Escolha um local (qualquer um menos o diretrio do Tomcat) e crie uma pasta chamada ExemploServlet. Dentro dessa pasta crie trs subpastas: src, classes e etc. A pasta src conter os arquivos de cdigo-fonte (.java); A pasta classes conter os arquivos de bytecode (.class); A pasta etc conter a configurao dos servlets (arquivo web.xml). A estrutura de pastas ficar assim:
ExemploJsp classes etc src

S que na raiz do projeto, criaremos um arquivo chamado index.jsp. Nesse arquivo teremos o seguinte cdigo:
<%@page language="java" contentType="text/html" pageEncoding="UTF-8"

40

import="java.util.*" import="java.text.SimpleDateFormat" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Al Mundo</title> </head> Hoje dia <%= (new SimpleDateFormat("dd/MM/yy")).format(new Date())%> <body> <form action="/exemplojsp/alomundo" method="get"> <input type="submit" value="Diga alguma coisa"/> </form> </body> </html>

Arquivos com extenso .jsp so interpretados pelo Container Java. No arquivo criado anteriormente, temos uma parte dinmica na pgina, a data. Ela gerada por duas classes Java, importadas no incio do arquivo. Alm disso, temos uma chamada a um Servlet por meio de uma requisio HTTP GET feita pelo formulrio HTML. Dentro da pasta src, crie a classe ControllerAloMundoServlet, com este cdigo:
import javax.servlet.*; import javax.servlet.http.*; import java.io.*;

public class ControllerAloMundoServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { PrintWriter out = response.getWriter(); out.println("Al Mundo"); }

41

Como pode perceber, esse Servlet idntico ao anterior, exceto pelo fato de que no envia as tags HTML que formam a pgina. Como no exemplo anterior, iremos criar o arquivo web.xml no diretrio etc. O cdigo este:
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <servlet> <servlet-name>ControllerAloMundo</servlet-name> <servlet-class>ControllerAloMundoServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ControllerAloMundo</servlet-name> <url-pattern>/alomundo</url-pattern> </servlet-mapping> </web-app>

Compile o servlet com o seguinte comando:


javac -cp [diretrio do tomcat]/lib/servlet-api.jar -d classes

src/ControllerAloMundoServlet.java

Crie um diretrio dentro da subpasta webapps do Tomcat com o nome de exemplojsp. Copie para dentro dele o arquivo index.jsp. Dentro de exemplojsp, crie o subdiretrio WEB-INF e copie o arquivo web.xml para dentro dele. Tambm crie dentro de WEB-INF o subdiretrio classes e copie para dentro dele o ControllerAloMundoServlet.class. Voc vai ter uma estrutura assim:
webapps exemplojsp index.jsp WEB-INF web.xml

42

classes ControllerAloMundoServlet.class

Inicie o Tomcat e digite no seu navegador a seguinte URL: http://localhost:8080/exemplojsp Apesar de simples, este exemplo mostra como JSP permite manter as vantagens obtidas pelos servlets em relao a programas CGI, ao mesmo tempo em que promove uma clara diviso do trabalho entre webdesigner e programador. Aps essa introduo a servlets e JSP, vamos dar incio a implementao do nosso projeto.

4.3 Ambiente de desenvolvimento


Para ter produtividade e controle no desenvolvimento de nossa aplicao, iremos utilizar o Eclipse IDE for Java EE Developers. Ele servir para criar as trs verses de nossa aplicao. Ele est disponvel no endereo http://www.eclipse.org/downloads, em distribuies para Windows, Mac e Linux. Neste livro, iremos utilizar a verso Galileo. Se tiver dvidas com relao a instalao e inicializao do Eclipse, consulte os apndices.

4.4 Configurando o servidor no Eclipse


Durante o desenvolvimento de uma aplicao Web, ns precisamos de um servidor para testar, depurar e rodar nosso projeto. E precisamos de uma forma automatizada de fazer isso, para termos produtividade. J vimos como trabalhoso ter de mover os arquivos do projeto de um servlet para o ambiente de execuo do servidor (o processo chamado de publicao). Iremos utilizar o ambiente integrado do Eclipse para no s criar nosso projeto, como tambm distribuir a aplicao para o servidor e execut-la de forma simples e rpida. Utilizaremos o Tomcat como nosso servidor. Para fazer isso, entre no menu Window>Preferences. Procure o item Server, no quadro esquerda. Abra-o, e selecione o item Runtime Environments, conforme mostra a figura 7.

43

Figura 7: Configurao do ambiente de servidor


Clique no boto Add, no quadro direita, para adicionar um ambiente de tempo de execuo para servidor Web. Esse ambiente no o servidor propriamente dito, mas sim o ambiente, bibliotecas e infraestrutura que um servidor precisa. Como estamos usando o Apache Tomcat 6.0, este que selecionaremos na lista de ambientes para servidores disponveis, conforme a figura 8. A lista de ambientes fornecida, assim como toda a configurao de servidores, faz parte do plugin WTP (Web Tools Platform), que consiste em um conjunto de ferramentas e APIs para o desenvolvimento de aplicaes Web. O ambiente de servidor para Apache Tomcat do Eclipse prov a habilidade de executar a aplicao de dentro do projeto sem a necessidade de public-los no servidor. Na fase de desenvolvimento, isso extremamente produtivo. Aps selecionar a marca e verso do servidor, precisamos indicar onde ele est instalado, para que o Eclipse possa inici-lo e interromp-lo. Clique no boto Next, e na tela seguinte, conforme mostra a figura 9, indique o diretrio onde o Tomcat est instalado. Voc pode controlar vrios servidores Web por meio do Eclipse. Mas sua aplicao s poder estar associada a um deles por vez.

44

Figura 8: Seleo do servidor Web JEE

45

Figura 9: Indicao do diretrio do servidor Web

46

4.5 Criando um projeto Web


Agora vamos criar o projeto Web. Acesse o menu File->New->Project. Na lista de tipos de projeto abra a opo Web, e dentro dela, selecione Dynamic Web Project, conforme mostra a figura 10.

Figura 10: Criao de uma projeto Web JEE


Na tela seguinte (figura 11), fazemos a configurao do projeto. O nome ser livrariajsp. O campo Target runtime se refere a qual ambiente ser usado em tempo de execuo da aplicao. Usaremos o ambiente do Apache Tomcat que configuramos anteriormente. O campo Dynamic web module version verso da especificao de servlets. Utilizaremos a verso 2.5.

47

Figura 11: Configurao do projeto Web JEE 48

4.6 Estrutura do projeto Web


Aps a criao do projeto, voc pode visualizar sua estrutura por meio da viso Project Explorer (figura 12).

Figura 12: Estrutura do projeto na viso Project Explorer


Nessa viso, os servlets ficam dentro de Java Resources:src e as pginas JSP ficam dentro de WebContent. Mas usaremos outra viso para trabalhar com nosso projeto. Entre no menu Window->Show View->Other. Selecione a viso Package Explorer, dentro de Java, conforme mostra a figura 13. O Eclipse deve provavelmente abrir a viso Package Explorer na parte inferior direita da tela. Voc pode arrast-la com o mouse pela barra de ttulo at a parte esquerda da tela, para que fique na mesma posio que Project Explorer. A estrutura do projeto deve ficar como mostra a figura 4.8. A viso Package Explorer mais adequada para trabalhar com Java, pois mostra a hierarquia de pacotes em uma estrutura em rvore. Obviamente, mesmo com essa viso, conforme o projeto cresce, a localizao dos arquivos fica mais complicada. Para

49

procurar um arquivo qualquer do projeto, inclusive oculto pelo sistema operacional, voc pode usar a combinao de teclas CTRL+SHIFT+R. Na viso Package Explorer, a pasta src equivale a Java Resources:src de Project Explorer.

Figura 13: Selecionando a viso Package Explorer

4.7 MVC
O primeiro caso de uso que implementaremos ser o Manter Cadastro. O motivo muito simples, os demais dependem dele. No adianta autenticar um usurio se ele no tem nada para fazer. Tambm no possvel verificar permisso se no h recurso definido. A aplicao precisa de um ponto de partida. Por isso, vamos criar a pgina inicial do sistema. Ela ser gerada pelo arquivo index.jsp que ser criando dentro da pasta WebContent. Selecione essa pasta e acesse o menu File->New->Other. Procure o item Web e o abra. Dentro dele est o wizard para JSP, conforme a figura 14.

50

Figura 14: Criao de pgina JSP


Conforme j vimos, o nome do arquivo ser index.jsp. O wizard cria um esqueleto de pgina, que temos de preencher. Como no ser implementada a interface com o cliente da livraria, apenas o mdulo de administrao, esse arquivo ter somente um hyperlink para a pgina do menu de administrao do sistema.
<a href="admin.jsp">Administrao</a>

Ainda no nos preocupamos em definir uma arquitetura para a aplicao, mas teramos de ter feito isso antes de partir para a implementao. Antes de fazer algo mais substancial, vamos pensar na arquitetura. Neste momento, vamos introduzir um padro de projeto para dividir as responsabilidades de nossa aplicao em trs camadas: Modelo, Controlador e Viso. Esse o padro de projeto MVC, descrito por Fowler (2006, p. 315-317).

O Modelo ir se encarregar dos dados e da lgica de negcio.

51

O Controlador ir se encarregar de capturar as requisies, invocar os Modelos e enviar a sada para a Viso. A Viso ir exibir os dados para o usurio. a camada onde esto os arquivos JSP.

Este padro de projeto um padro de alto nvel, ou seja, ele trata a aplicao como um todo. Com relao camada de Modelo, faz-se necessria ainda uma separao entre o armazenamento dos dados em memria para manipulao e as operaes de persistncia no banco de dados. Por isso, iremos utilizar, em nossa aplicao, uma variao do MVC. Em vez da camada de Modelo, utilizaremos uma camada de Persistncia. Essa, por sua vez, ser subdividida em duas camadas: Modelo e DAO.

4.8 Camada de Persistncia 4.8.1 Criando os Modelos


Os Modelos, de uma forma simples e aplicada ao nosso exemplo, so as classes que iro representar as tabelas do banco de dados. A criao dos modelos na camada de fonte de dados segue uma orientao de Fowler (2006, p. 53), o qual afirma que sbio separar o acesso SQL da lgica de domnio e coloc-la em classes separadas. Ele diz que uma boa maneira de organizar essas classes base-las na estrutura da tabela do banco de dados de modo que tenhamos uma classe por tabela. O que ir diferenciar essas classes das demais para a aplicao? Nada, se no utilizarmos algo que as relacione entre si. A pergunta , como a aplicao poder saber, a qualquer momento, que uma classe um modelo? Existem duas respostas. A primeira criar uma superclasse da qual todos os modelos iro herdar. Mas isso s vale a pena se existem comportamentos genricos (mtodos implementados) que possam ser herdados. E nossos modelos iro seguir o padro POJO, criado por Martin Fowler, Rebecca Parsons e John Mackenzie. Esse padro especifica classes que possuem apenas atributos e mtodos para acess-los. A segunda resposta criar uma interface que todos os modelos implementem. Uma interface serve, a princpio, para obrigar classes a implementarem mtodos com uma determinada assinatura. A interface uma maneira de imitar herana mltipla, pois uma classe pode implementar vrias interfaces. Aqui a interface servir, alm disso, como uma identificao. Assim, no pacote models.generic, criaremos a interface IModel:

IModel

52

public interface IModel { public Integer getId(); public String getPrimaryKey(); }

O objetivo dos mtodos de IModel obrigar as classes que a implementarem a retornar o nome do campo na tabela que a chave primria (getPrimaryKey) e o valor para o registro corrente (getId). Temos sempre que tentar identificar caractersticas e comportamentos similares, de modo a criar cdigo centralizado e fcil de manter. Por isso, vamos criar algumas classes abstratas no pacote models.generic, baseando-nos em algumas observaes do diagrama de classes do captulo 3. As classes que implementarem IModel devero ter os atributos id e primaryKey, e pares de mtodos para esses atributos (um para ler e outro para gravar). Para que repetir isso em cada classe? Vamos criar uma classe abstrata que j traga os atributos e os mtodos. Ns a chamaremos de AbstractModel. Ela implementa IModel, de forma que as subclasses no tenham de fazer isso.

AbstractModel
public abstract class AbstractModel implements IModel{ protected Integer id; protected String primaryKey;

public String getPrimaryKey() { return primaryKey; }

public Integer getId() { return id; }

public void setId(Integer id) { this.id = id; }

53

Algumas classes (como Autor e Editora) tem mais em comum do que apenas o id. Elas tambm compartilham um atributo nome. Para evitar replicao de cdigo, podemos criar uma classe abstrata que estenda AbstractModel. Ela se chamar AbstractOnlyName.

AbstractOnlyName
public abstract class AbstractOnlyName extends AbstractModel{ protected String nome; public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; }

As classes Cliente e Funcionario tem muitos atributos em comum. Essas com certeza merecem uma superclasse abstrata. Ns a chamaremos de AbstractUsuario.

AbstractUsuario
public abstract class AbstractUsuario extends AbstractModel{ protected String nome; protected String apelido; protected String senha; protected String email; protected Set<Telefone> telefones = new HashSet<Telefone>(); public String getNome() { return nome; } public void setNome(String nome) {

54

this.nome = nome; } public String getApelido() { return apelido; } public void setApelido(String apelido) { this.apelido = apelido; } public String getSenha() { return senha; } public void setSenha(String senha) { this.senha = senha; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Set<Telefone> getTelefones() { return telefones; } public void setTelefones(Set<Telefone> telefones) { this.telefones = telefones; }

Mais adiante, veremos duas classes que representam os relacionamentos entre as classes Cliente, Funcionario e Telefone. Para evitar ao mximo a replicao de cdigo, criaremos uma classe abstrata para manipular um atributo do tipo Telefone: AbstractTelefone.

55

AbstractTelefone
public abstract class AbstractTelefone implements IModel{ protected Telefone telefone; public Telefone getTelefone() { return telefone; } public void setTelefone(Telefone telefone) { this.telefone = telefone; }

Com essas pequenas generalizaes, podemos enfim criar os modelos, na raiz do pacote models.

Autor
public class Autor extends AbstractOnlyName implements Comparator<Autor> { private String sobrenome;

public Autor() { this.primaryKey = "id_autor"; }

public String getSobrenome() { return sobrenome; }

public void setSobrenome(String sobrenome) { this.sobrenome = sobrenome; }

public boolean equals(AutorLivro autorLivro) { if (getId() == autorLivro.getAutor().getId()) {

56

return true; } return false; }

public int compare(Autor autor1, Autor autor2) { return (autor2.getSobrenome().compareTo(autor1.getSobrenome())); }

No construtor do modelo Autor, assim como nos demais que veremos adiante, temos a inicializao do atributo primaryKey, que o nome da chave primria na tabela mapeada. Essa classe Autor em especial implementa a interface Comparator, para que posteriormente possamos fazer a ordenao de uma coleo de Autores pelo sobrenome.

Cliente
public class Cliente extends AbstractUsuario {

public Cliente() { this.primaryKey = "id_cliente"; }

private String cpf;

public String getCpf() { return cpf; }

public void setCpf(String cpf) {

57

this.cpf = cpf; }

Funcionario
public class Funcionario extends AbstractUsuario { private String matricula;

public Funcionario() { this.primaryKey = "id_usuario"; }

public String getMatricula() { return matricula; }

public void setMatricula(String matricula) { this.matricula = matricula; }

Editora
public class Editora extends AbstractOnlyName {

public Editora() { this.primaryKey = "id_editora"; }

58

Local
public class Local extends AbstractOnlyName {

public Local() { this.primaryKey = "id_local"; }

Livro
public class Livro extends AbstractModel { private String isbn; private String titulo; private Local local; private Editora editora; private Integer ano; private Float preco; private Set<Autor> autores = new HashSet<Autor>();

public Livro() { this.primaryKey = "id_livro"; }

public Set<Autor> getAutores() { return autores; }

public void setAutores(Set<Autor> autores) { this.autores = autores; }

59

public String getIsbn() { return isbn; }

public void setIsbn(String isbn) { this.isbn = isbn; }

public String getTitulo() { return titulo; }

public void setTitulo(String titulo) { this.titulo = titulo; }

public Local getLocal() { return local; }

public void setLocal(Local local) { this.local = local; }

public Editora getEditora() { return editora; }

public void setEditora(Editora editora) { this.editora = editora; }

60

public Integer getAno() { return ano; }

public void setAno(Integer ano) { this.ano = ano; }

public Float getPreco() { return preco; }

public void setPreco(Float preco) { this.preco = preco; }

Pedido
public class Pedido implements IModel { private Integer numeroPedido; private GregorianCalendar dataPedido; private Cliente cliente; private Set<ItemPedido> items = new HashSet<ItemPedido>(); protected String primaryKey;

public Pedido() { this.primaryKey = "numero_pedido"; }

61

public Set<ItemPedido> getItems() { return items; }

public void setItems(Set<ItemPedido> items) { this.items = items; }

public Integer getNumeroPedido() { return numeroPedido; }

public void setNumeroPedido(Integer numeroPedido) { this.numeroPedido = numeroPedido; }

public GregorianCalendar getDataPedido() { return dataPedido; }

public void setDataPedido(GregorianCalendar dataPedido) { this.dataPedido = dataPedido; }

public Cliente getCliente() { return this.cliente; }

public void setCliente(Cliente cliente) { this.cliente = cliente; }

62

public String getPrimaryKey() { return this.primaryKey; }

public Integer getId() { return this.numeroPedido; }

ItemPedido
public class ItemPedido extends AbstractModel { private Pedido pedido; private Livro livro; private Float preco; private Integer quantidade;

public ItemPedido() { this.primaryKey = "id_item"; }

public Pedido getPedido() { return pedido; }

public void setPedido(Pedido pedido) { this.pedido = pedido; }

63

public Livro getLivro() { return livro; }

public void setLivro(Livro livro) { this.livro = livro; }

public Float getPreco() { return preco; }

public void setPreco(Float preco) { this.preco = preco; }

public Integer getQuantidade() { return quantidade; }

public void setQuantidade(Integer quantidade) { this.quantidade = quantidade; }

Telefone
public class Telefone extends AbstractModel { private String numero; private String tipo;

64

public Telefone() { this.primaryKey = "id_telefone"; }

public String getNumero() { return numero; }

public void setNumero(String numero) { this.numero = numero; }

public String getTipo() { return tipo; }

public void setTipo(String tipo) { this.tipo = tipo; }

Existem alguns relacionamentos muitos-para-muitos entre algumas tabelas. Eles esto refletidos nos atributos que so colees de objetos. Para facilitar o trabalho da prxima categoria de classes que iremos construir, vamos criar algumas classes que representam os relacionamentos.

AutorLivro
public class AutorLivro implements IModel, Comparator<AutorLivro> { private Autor autor; private Livro livro;

65

private Integer ordem;

public Autor getAutor() { return autor; }

public void setAutor(Autor autor) { this.autor = autor; }

public Livro getLivro() { return livro; }

public void setLivro(Livro livro) { this.livro = livro; }

public Integer getOrdem() { return ordem; }

public void setOrdem(Integer ordem) { this.ordem = ordem; }

public boolean equals(AutorLivro autorLivro) { if (getAutor().getId() == autorLivro.getAutor().getId() && getLivro().getId() == autorLivro.getLivro().getId()) { return true; }

66

return false; }

public int compare(AutorLivro autorLivro1, AutorLivro autorLivro2) { return (autorLivro2.getAutor().getSobrenome().compareTo(autorLivro1 .getAutor().getSobrenome())); }

public String getPrimaryKey() { return null; }

public Integer getId() { return null; }

A classe AutorLivro implementa a interface Comparator, para que posteriormente possamos fazer a ordenao de uma coleo de Autores pelo sobrenome.

TelefoneCliente
public class TelefoneCliente extends AbstractTelefone {

private Cliente cliente;

public Cliente getCliente() { return cliente; }

67

public void setCliente(Cliente cliente) { this.cliente = cliente; }

public String getPrimaryKey() { return null; }

public Integer getId() { return null; }

TelefoneFuncionario
public class TelefoneFuncionario extends AbstractTelefone { private Funcionario funcionario;

public Funcionario getFuncionario() { return funcionario; }

public void setFuncionario(Funcionario funcionario) { this.funcionario = funcionario; }

68

public String getPrimaryKey() { return null; }

public Integer getId() { return null; }

4.8.2. Criando os DAOs


Os modelos servem to somente para que nossa aplicao consiga manipular dados das tabelas na forma de objetos. Mas algum tem que levar os dados das tabelas do banco de dados para os objetos em memria. Para isso, iremos utilizar um padro de projeto do Core J2EE, chamado DAO. Esse padro define uma separao entre os dados e os mtodos de acesso a eles. Criaremos um pacote chamado dao. Dentro dele iremos criar uma classe para carregar (e persistir) os dados de cada modelo. Mas antes disso, iremos identificar alguns comportamentos genricos para evitar replicao de cdigo. Essa generalizao ficar no pacote dao.generic. O primeiro alvo de generalizao a SQL. Em vez de colocar comandos SQL diretamente em cada classe DAO, podemos centralizar a construo de comandos SQL em uma nica classe. Isso possvel porque as operaes de banco de dados so as mesmas para todos os DAOs, precisamos apenas indicar sobre qual tabela e quais registros estamos operando em determinado momento. Sendo assim, criaremos uma classe chamada DAOEngine, cujo propsito executar comandos SQL.

DAOEngine
public class DAOEngine { private static String url; private static String username; private static String password; private static String driver;

69

private static Connection connection = null; private static final byte NAME = 0; private static final byte VALUE = 1; private static Statement statement = null;

private static final String ERROR_NO_CONNECTION = "No conseguiu estabelecer conexo com o banco de dados";

private DAOEngine() {

public static String getLastException() { return Message.getLastException(); }

O mtodo openConnnection abre uma conexo de banco de dados baseada em configuraes de um arquivo de propriedades chamado connection.properties. Esse arquivo fica na raiz do projeto.
private static boolean openConnnection() { InputStream in = new DAOEngine().getClass().getClassLoader() .getResourceAsStream("connection.properties"); Properties properties = new Properties();

try { properties.load(in); in.close();

driver = properties.getProperty("driver"); url = properties.getProperty("url"); username = properties.getProperty("username"); password = properties.getProperty("password");


} catch (Exception e) {

70

driver = "org.postgresql.Driver"; url = "jdbc:postgresql://localhost:5432/livraria"; username = "postgres"; password = "postgres";


}

try { Class.forName(driver);

connection = DriverManager.getConnection(url, username, password);


return true; } catch (ClassNotFoundException e) {

Message.setLastException(e.getMessage());
e.printStackTrace(); } catch (SQLException e) {

Message.setLastException(e.getMessage());
e.printStackTrace(); } return false; }

O mtodo isConnected diz se h uma conexo aberta.


private static boolean isConnected() { return (connection != null); }

O mtodo insert faz o encapsulamento da instruo SQL INSERT. Ele ser usado pelas classes DAO para incluir registros em uma tabela.
public static boolean insert(String table, String[][] fields) { String names = ""; String values = ""; String sql = "INSERT INTO " + table + "(";

for (int i = 0; i < fields.length; i++) {

71

names = names + fields[i][NAME] + ","; values = values + fields[i][VALUE] + ","; }

if (names.substring(names.length() - 1).equals(",")) names = names.substring(0, names.length() - 1);

if (values.substring(values.length() - 1).equals(",")) values = values.substring(0, values.length() - 1);

sql = sql + names + ") VALUES (" + values + ")";

return executeSQL(sql); }

A execuo propriamente dita do comando SQL feita pelo mtodo executeSQL. Isso porque esse trecho de cdigo comum para os mtodos de incluso, alterao e remoo de registros.
private static boolean executeSQL(String sql) { if (!connectionEstablished()) return false;

try {

statement = connection.createStatement();
boolean result = statement.execute(sql);

statement.close(); connection.close(); connection = null;


return result;

} catch (SQLException e) {

Message.setLastException(e.getMessage());

72

connection = null;
}

return false;

A atualizao de registros feita pelo mtodo update, que encapsula a instruo SQL UPDATE.
public static boolean update(String table, String[][] fields, String where) { String settings = ""; String sql = "UPDATE " + table + " SET ";

for (int i = 0; i < fields.length; i++) { settings = settings + fields[i][NAME] + " = " + fields[i][VALUE] + ","; }

if (settings.substring(settings.length() - 1).equals(",")) settings = settings.substring(0, settings.length() - 1);

sql = sql + settings + " where " + where;

return executeSQL(sql); }

O mtodo delete encapsula o comando SQL DELETE.

public static boolean delete(String table, String where) { String sql = "DELETE FROM " + table + "";

sql = sql + " where " + where;

73

return executeSQL(sql); }

O mtodo fetchAll obtm um conjunto de registros de uma tabela baseado em uma restrio (where). Esse conjunto de registros pode estar ordenados (order), e serem um subconjunto dos que atendem a restrio (limit e offset).
public static ResultSet fetchAll(String table, String where, String order, Integer limit, Integer offset) { String sql;

if (connection != null) try {

connection.close(); connection = null;


} catch (SQLException e1) {

connection = null;
}

if (!openConnnection()) return null;

sql = "SELECT * FROM " + table; sql = sql + (where == null ? "" : " WHERE " + where); sql = sql + (order == null ? "" : " ORDER BY " + order); sql = sql + (limit == null ? "" : " LIMIT " + limit); sql = sql + (offset == null ? "" : " OFFSET " + offset);

try {

statement = connection.createStatement();
ResultSet rs = statement.executeQuery(sql); return rs; } catch (SQLException e) {

74

Message.setLastException(e.getMessage());
} return null; }

O mtodo connectionEstablished verifica se a conexo com o banco de dados est aberta. Caso no esteja, tenta se conectar. Em caso de falha, armazena uma mensagem padro em uma classe preparada especificamente para isso.
private static boolean connectionEstablished() { if (!isConnected()) if (!openConnnection()) {

Message.setLastException(ERROR_NO_CONNECTION);
return false; } return true; }

O mtodo lastValue obtm o ltimo valor gravado em um campo do tipo inteiro. A sua finalidade recuperar o contedo de campos gerados automaticamente pela banco de dados.
public static Integer lastValue(String table, String field) { String sql;

if (!connectionEstablished()) return null;

sql = "SELECT * FROM " + table + " ORDER BY " + field + " DESC";

try {

statement = connection.createStatement();
ResultSet rs = statement.executeQuery(sql);

if (rs.next()) {

75

return rs.getInt(field); } } catch (SQLException e) {

Message.setLastException(e.getMessage());
} return null; }

Esta classe isola o gerenciamento de SQL. Observe que ela faz uso de um arquivo de propriedades para abrir a conexo com o banco. Isso importante, porque se for necessrio alterar os dados de conexo, no preciso modificar a classe, mas to somente o arquivo. Modificar a classe significa ter de recompil-la e redistribu-la. Editar um arquivo de texto algo mais simples. A interface em Java padroniza comportamentos entre classes. Todas as nossas classes DAOs iro executar as mesmas operaes, sobre tabelas diferentes. Assim, vamos garantir que as assinaturas dos mtodos sejam as mesmas.

IDAO
public interface IDAO { public boolean insert(IModel model); public boolean update(IModel model); public boolean delete(IModel model); public IModel fetchOne(IModel model); public List<? extends IModel> fetchAll(String where, String order, Integer limit, Integer offset);

A interface IDAO define assinaturas para os mtodos de incluso (insert), atualizao (update) e remoo (delete) de registros. O mtodo fetchOne serve para retornar um objeto nico, correspondente a um registro da tabela. Ele recebe e retorna uma implementao de IModel. O mtodo fetchAll retorna uma coleo de objetos a partir de um critrio de consulta, que a expresso utilizada pela clusula WHERE da expresso SQL INSERT. Observe que usamos um tipo List, da API Collections de Java. O curinga ? usado para permitir

76

que as classes que implementam esse mtodo definam para a List um tipo de classe, em vez de usar a interface. Isso evita a necessidade de casting. Isso ficar mais claro quando implementarmos as classes DAO utilizando essa interface. A ltima generalizao ser criar uma classe abstrata que implemente os mtodos de incluso, atualizao e remoo definidos por IDAO. Contudo, essa classe no ir implementar diretamente a interface, pois os mtodos de consulta ficaro a cargo de cada DAO. A superclasse dos DAOs de nossa aplicao se chamar AbstractDAO.

AbstractDAO
public abstract class AbstractDAO { protected String table;

public String getTable() { return table; }

public boolean insert(IModel model) { String[][] fields = this.getFields(model);

return DAOEngine.insert(this.table, fields); }

public boolean update(IModel model) { String[][] fields = this.getFields(model);

return DAOEngine .update(this.table, fields, this.getDefaultWhere(model)); }

public boolean delete(IModel model) { return DAOEngine.delete(this.table, this.getDefaultWhere(model));

77

public String getDefaultWhere(IModel model) { return model.getPrimaryKey()+" = "+model.getId(); }

public abstract String[][] getFields(IModel model);

O mtodo getDefaultWhere retorna uma condio padro, usada para busca de objetos nicos. O mtodo getFields retorna um array com os campos editveis da tabela e os valores a serem gravados. Com essas generalizaes, nossas classes DAO, a princpio, s precisaro implementar os mtodos de busca, e os que fornecem os nomes de campos da tabela e critrios de consulta.

AutorDAO
public class AutorDAO extends AbstractDAO implements IDAO {

public AutorDAO() { this.table = "autores"; }

public List<Autor> fetchAll(String where, String order, Integer limit, Integer offset) { List<Autor> list = new ArrayList<Autor>(); ResultSet rs = DAOEngine.fetchAll(this.table, where, order, limit, offset);

try {

78

while (rs.next()) { Autor autor = new Autor(); autor.setId(rs.getInt("id_autor")); autor.setNome(rs.getString("nome")); autor.setSobrenome(rs.getString("sobrenome")); list.add(autor); } return list; } catch (SQLException e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<Autor> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; }

@Override public String[][] getFields(IModel model) { Autor autor = (Autor) model;

String[][] fields = new String[2][2];

79

fields[0][0] = "nome"; fields[0][1] = "'" + autor.getNome() + "'"; fields[1][0] = "sobrenome"; fields[1][1] = "'" + autor.getSobrenome() + "'";

return fields; }

AutorLivroDAO
public class AutorLivroDAO extends AbstractDAO implements IDAO {

public AutorLivroDAO() { this.table = "autores_livro"; }

@Override public String getDefaultWhere(IModel model) { return "id_autor = " + ((AutorLivro) model).getAutor().getId() + " and id_livro = " + ((AutorLivro) model).getLivro().getId(); }

@Override public String[][] getFields(IModel model) { AutorLivro autorLivro = (AutorLivro) model;

String[][] fields = new String[3][2];

fields[0][0] = "id_autor";

80

fields[0][1] = autorLivro.getAutor().getId().toString(); fields[1][0] = "id_livro"; fields[1][1] = autorLivro.getLivro().getId().toString(); fields[2][0] = "ordem"; fields[2][1] = autorLivro.getOrdem().toString();

return fields; }

public List<AutorLivro> fetchAll(String where, String order, Integer limit, Integer offset) { List<AutorLivro> list = new ArrayList<AutorLivro>(); ResultSet rs = DAOEngine.fetchAll(this.table, where, order, limit, offset);

try { while (rs.next()) { AutorLivro autorLivro = new AutorLivro();

Autor autor = new Autor(); autor.setId(rs.getInt("id_autor")); autor = (Autor) new AutorDAO().fetchOne(autor); autorLivro.setAutor(autor);

Livro livro = new Livro(); livro.setId(rs.getInt("id_livro")); livro = (Livro) new LivroDAO().fetchOne(livro); autorLivro.setLivro(livro);

autorLivro.setOrdem(rs.getInt("ordem")); list.add(autorLivro);

81

} return list; } catch (SQLException e) { e.printStackTrace(); }

return null; }

public Set<Autor> fetchAll(String where) { Set<Autor> set = new HashSet<Autor>(); ResultSet rs = DAOEngine.fetchAll(this.table, where, null, null, null);

try { AutorDAO dao = new AutorDAO(); while (rs.next()) { Autor autor = new Autor(); autor.setId(rs.getInt("id_autor")); autor = (Autor) dao.fetchOne(autor); set.add(autor); } return set; } catch (SQLException e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

82

List<AutorLivro> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; }

ClienteDAO
public class ClienteDAO extends AbstractDAO implements IDAO{ public ClienteDAO() { this.table = "clientes"; }

public List<Cliente> fetchAll(String where) { List<Cliente> list = new ArrayList<Cliente>(); ResultSet rs = DAOEngine.fetchAll(this.table,where); try { while (rs.next()) { Cliente cliente = new Cliente(); cliente.setId(rs.getInt("id_cliente")); cliente.setCpf(rs.getString("cpf")); cliente.setNome(rs.getString("nome")); cliente.setApelido(rs.getString("apelido")); cliente.setSenha(rs.getString("senha")); cliente.setEmail(rs.getString("email")); Set<Telefone> telefones = new HashSet<Telefone>();

83

List<TelefoneCliente> telefonesCliente = new TelefoneClienteDAO().fetchAll("id_cliente = "+cliente.getId()); for (Iterator<TelefoneCliente> iterator = telefonesCliente.iterator(); iterator .hasNext();) { TelefoneCliente telefoneFuncionario = (TelefoneCliente) iterator .next(); telefones.add(telefoneFuncionario.getTelefone()); } list.add(cliente); } return list; } catch (SQLException e) { e.printStackTrace(); } return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model); List<Cliente> list = this.fetchAll(where); if (list != null && list.size()>0) return list.get(0); else return null; } @Override public String[][] getFields(IModel model) { Cliente cliente = (Cliente) model; String[][] fields = new String[5][2]; fields[0][0] = "cpf"; fields[0][1] = "'" + cliente.getCpf() + "'";

84

fields[1][0] = "nome"; fields[1][1] = "'" + cliente.getNome() + "'"; fields[2][0] = "apelido"; fields[2][1] = "'" + cliente.getApelido() + "'"; fields[3][0] = "senha"; fields[3][1] = "'" + cliente.getSenha() + "'"; fields[4][0] = "email"; fields[4][1] = "'" + cliente.getEmail() + "'"; return fields; } @Override public String getDefaultWhere(IModel model) { return "id_cliente = "+((Cliente)model).getId(); } }

EditoraDAO
public class EditoraDAO extends AbstractDAO implements IDAO {

public EditoraDAO() { this.table = "editoras"; }

public List<Editora> fetchAll(String where, String order, Integer limit, Integer offset) { List<Editora> list = new ArrayList<Editora>(); ResultSet rs = DAOEngine.fetchAll(this.table, where, order, limit, offset);

try {

85

while (rs.next()) { Editora Editora = new Editora(); Editora.setId(rs.getInt("id_editora")); Editora.setNome(rs.getString("nome")); list.add(Editora); } return list; } catch (SQLException e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<Editora> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; }

@Override public String[][] getFields(IModel model) { Editora editora = (Editora) model;

String[][] fields = new String[1][2];

86

fields[0][0] = "nome"; fields[0][1] = "'" + editora.getNome() + "'";

return fields; }

FuncionarioDAO
public class FuncionarioDAO extends AbstractDAO implements IDAO {

public FuncionarioDAO() { this.table = "funcionarios"; }

public List<Funcionario> fetchAll(String where, String order, Integer limit, Integer offset) { List<Funcionario> list = new ArrayList<Funcionario>(); ResultSet rs = DAOEngine.fetchAll(this.table, where, order, limit, offset);

try { while (rs.next()) { Funcionario funcionario = new Funcionario(); funcionario.setId(rs.getInt("id_usuario")); funcionario.setMatricula(rs.getString("matricula")); funcionario.setNome(rs.getString("nome")); funcionario.setApelido(rs.getString("apelido")); funcionario.setSenha(rs.getString("senha")); funcionario.setEmail(rs.getString("email"));

87

list.add(funcionario); } return list; } catch (SQLException e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<Funcionario> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; }

@Override public String[][] getFields(IModel model) { Funcionario Funcionario = (Funcionario) model;

String[][] fields = new String[5][2];

fields[0][0] = "matricula"; fields[0][1] = "'" + Funcionario.getMatricula() + "'"; fields[1][0] = "nome";

88

fields[1][1] = "'" + Funcionario.getNome() + "'"; fields[2][0] = "apelido"; fields[2][1] = "'" + Funcionario.getApelido() + "'"; fields[3][0] = "senha"; fields[3][1] = "'" + Funcionario.getSenha() + "'"; fields[4][0] = "email"; fields[4][1] = "'" + Funcionario.getEmail() + "'";

return fields; }

ItemPedidoDAO
public class ItemPedidoDAO extends AbstractDAO implements IDAO {

@Override public String[][] getFields(IModel model) { ItemPedido itemPedido = (ItemPedido) model;

String[][] fields = new String[4][2];

fields[0][0] = "id_pedido"; fields[0][1] = itemPedido.getPedido().getNumeroPedido().toString(); fields[1][0] = "id_livro"; fields[1][1] = itemPedido.getLivro().getId().toString(); fields[2][0] = "preco"; fields[2][1] = itemPedido.getPreco().toString(); fields[3][0] = "quantidade"; fields[3][1] = itemPedido.getQuantidade().toString();

89

return fields; }

public List<ItemPedido> fetchAll(String where, String order, Integer limit, Integer offset) { List<ItemPedido> list = new ArrayList<ItemPedido>(); ResultSet rs = DAOEngine.fetchAll(this.table, where, order, limit, offset);

try { while (rs.next()) { ItemPedido itemPedido = new ItemPedido(); itemPedido.setId(rs.getInt("id_item"));

Pedido pedido = new Pedido(); pedido.setNumeroPedido(rs.getInt("id_pedido")); pedido = (Pedido) new PedidoDAO().fetchOne(pedido); itemPedido.setPedido(pedido);

Livro livro = new Livro(); livro.setId(rs.getInt("id_livro")); livro = (Livro) new LivroDAO().fetchOne(livro); itemPedido.setLivro(livro);

itemPedido.setPreco(rs.getFloat("preco")); itemPedido.setQuantidade(rs.getInt("quantidade"));

list.add(itemPedido); } return list;

90

} catch (SQLException e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<ItemPedido> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; }

LivroDAO
public class LivroDAO extends AbstractDAO implements IDAO {

public LivroDAO() { this.table = "livros"; }

public List<Livro> fetchAll(String where, String order, Integer limit, Integer offset) { List<Livro> list = new ArrayList<Livro>();

91

ResultSet rs = DAOEngine.fetchAll(this.table, where, order, limit, offset);

try { while (rs.next()) { Livro livro = new Livro(); livro.setId(rs.getInt("id_livro")); livro.setIsbn(rs.getString("isbn")); livro.setTitulo(rs.getString("titulo"));

Local local = new Local(); local.setId(rs.getInt("id_local")); local = (Local) (new LocalDAO()).fetchOne(local); livro.setLocal(local);

Editora editora = new Editora(); editora.setId(rs.getInt("id_editora")); editora = (Editora) (new EditoraDAO()).fetchOne(editora); livro.setEditora(editora);

livro.setAno(rs.getInt("ano"));

String preco = rs.getString("preco");

livro.setPreco(formataPreco(preco));

livro.setAutores(new AutorLivroDAO().fetchAll("id_livro = " + livro.getId()));

list.add(livro); }

92

return list; } catch (SQLException e) { e.printStackTrace(); }

return null; }

private Float formataPreco(String preco) { int i;

for (i = 0; i < preco.length(); i++) { if (Character.isDigit(preco.charAt(i))) { break; } }

preco = preco.substring(i);

preco = preco.replace(',', '.');

return Float.parseFloat(preco); }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<Livro> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0);

93

else return null; }

@Override public String[][] getFields(IModel model) { Livro livro = (Livro) model;

String[][] fields = new String[6][2];

fields[0][0] = "isbn"; fields[0][1] = "'" + livro.getIsbn() + "'"; fields[1][0] = "titulo"; fields[1][1] = "'" + livro.getTitulo() + "'"; fields[2][0] = "id_editora"; fields[2][1] = livro.getEditora().getId().toString(); fields[3][0] = "id_local"; fields[3][1] = livro.getLocal().getId().toString(); fields[4][0] = "ano"; fields[4][1] = livro.getAno().toString(); fields[5][0] = "preco"; fields[5][1] = "'" + livro.getPreco().toString() + "'";

return fields; } }

LocalDAO
public class LocalDAO extends AbstractDAO implements IDAO {

public LocalDAO() {

94

this.table = "locais"; }

public List<Local> fetchAll(String where, String order, Integer limit, Integer offset) { List<Local> list = new ArrayList<Local>(); ResultSet rs = DAOEngine.fetchAll(this.table, where, order, limit, offset);

try { while (rs.next()) { Local local = new Local(); local.setId(rs.getInt("id_local")); local.setNome(rs.getString("nome")); list.add(local); } return list; } catch (SQLException e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<Local> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0)

95

return list.get(0); else return null; }

@Override public String[][] getFields(IModel model) { Local local = (Local) model;

String[][] fields = new String[1][2];

fields[0][0] = "nome"; fields[0][1] = "'" + local.getNome() + "'";

return fields; } }

PedidoDAO
public class PedidoDAO extends AbstractDAO implements IDAO {

@Override public String[][] getFields(IModel model) { Pedido pedido = (Pedido) model;

String[][] fields = new String[2][2];

fields[0][0] = "data_pedido"; fields[0][1] = pedido.getDataPedido().toString(); fields[1][0] = "id_cliente"; fields[1][1] = pedido.getCliente().getId().toString();

96

return fields; }

public List<Pedido> fetchAll(String where, String order, Integer limit, Integer offset) { List<Pedido> list = new ArrayList<Pedido>(); ResultSet rs = DAOEngine.fetchAll(this.table, where, order, limit, offset);

try { while (rs.next()) { Pedido pedido = new Pedido(); pedido.setNumeroPedido(rs.getInt("numero_pedido")); Date date = rs.getDate("data_pedido"); GregorianCalendar calendar = new GregorianCalendar(); calendar.setTime(date); pedido.setDataPedido(calendar); list.add(pedido); } return list; } catch (SQLException e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) {

97

String where = this.getDefaultWhere(model);

List<Pedido> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; }

public Integer ultimoNumeroPedido() { return new Integer(DAOEngine.lastValue("pedido", "numero_pedido")); }

TelefoneClienteDAO
public class TelefoneClienteDAO extends AbstractDAO implements IDAO {

public TelefoneClienteDAO() { this.table = "telefones_cliente"; }

@Override public String getDefaultWhere(IModel model) { return "id_cliente = " + ((TelefoneCliente) model).getCliente().getId() + " and id_telefone = " + ((TelefoneCliente) model).getTelefone().getId(); }

@Override public String[][] getFields(IModel model) {

98

TelefoneCliente telefoneCliente = (TelefoneCliente) model;

String[][] fields = new String[2][2];

fields[0][0] = "id_cliente"; fields[0][1] = telefoneCliente.getCliente().getId().toString(); fields[1][0] = "id_telefone"; fields[1][1] = telefoneCliente.getTelefone().getId().toString();

return fields; }

public List<TelefoneCliente> fetchAll(String where, String order, Integer limit, Integer offset) { List<TelefoneCliente> list = new ArrayList<TelefoneCliente>(); ResultSet rs = DAOEngine.fetchAll(this.table, where, order, limit, offset);

try { while (rs.next()) { TelefoneCliente telefoneCliente = new TelefoneCliente();

Cliente cliente = new Cliente(); cliente.setId(rs.getInt("id_cliente")); cliente = (Cliente) new ClienteDAO().fetchOne(cliente); telefoneCliente.setCliente(cliente);

Telefone telefone = new Telefone(); telefone.setId(rs.getInt("id_telefone")); telefone = (Telefone) new TelefoneDAO().fetchOne(telefone);

99

telefoneCliente.setTelefone(telefone);

list.add(telefoneCliente); } return list; } catch (SQLException e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<TelefoneCliente> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; }

TelefoneDAO
public class TelefoneDAO extends AbstractDAO implements IDAO {

public TelefoneDAO() { this.table = "telefones"; }

100

@Override public String getDefaultWhere(IModel model) { return "id_telefone = " + ((Telefone) model).getId(); }

@Override public String[][] getFields(IModel model) { Telefone telefone = (Telefone) model;

String[][] fields = new String[2][2];

fields[0][0] = "numero"; fields[0][1] = "'" + telefone.getNumero() + "'"; fields[1][0] = "tipo"; fields[1][1] = "'" + telefone.getTipo().toString() + "'";

return fields; }

public List<Telefone> fetchAll(String where, String order, Integer limit, Integer offset) { List<Telefone> list = new ArrayList<Telefone>(); ResultSet rs = DAOEngine.fetchAll(this.table, where, order, limit, offset);

try { while (rs.next()) { Telefone telefone = new Telefone(); telefone.setId(rs.getInt("id_telefone"));

101

telefone.setNumero(rs.getString("numero")); telefone.setTipo(rs.getString("tipo")); list.add(telefone); } return list; } catch (SQLException e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<Telefone> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; }

TelefoneFuncionarioDAO
public class TelefoneFuncionarioDAO extends AbstractDAO implements IDAO {

public TelefoneFuncionarioDAO() { this.table = "telefones_funcionario"; }

102

@Override public String getDefaultWhere(IModel model) { return "id_funcionario = " + ((TelefoneFuncionario) model).getFuncionario().getId() + " and id_telefone = " + ((TelefoneFuncionario) model).getTelefone().getId(); }

@Override public String[][] getFields(IModel model) { TelefoneFuncionario telefoneFuncionario = (TelefoneFuncionario) model;

String[][] fields = new String[2][2];

fields[0][0] = "id_funcionario"; fields[0][1] = telefoneFuncionario.getFuncionario().getId().toString(); fields[1][0] = "id_telefone"; fields[1][1] = telefoneFuncionario.getTelefone().getId().toString();

return fields; }

public List<TelefoneFuncionario> fetchAll(String where, String order, Integer limit, Integer offset) { List<TelefoneFuncionario> list = new ArrayList<TelefoneFuncionario>(); ResultSet rs = DAOEngine.fetchAll(this.table, where, order, limit, offset);

try { while (rs.next()) {

103

TelefoneFuncionario telefoneFuncionario = new TelefoneFuncionario();

Funcionario funcionario = new Funcionario(); funcionario.setId(rs.getInt("id_funcionario")); funcionario = (Funcionario) new FuncionarioDAO() .fetchOne(funcionario); telefoneFuncionario.setFuncionario(funcionario);

Telefone telefone = new Telefone(); telefone.setId(rs.getInt("id_telefone")); telefone = (Telefone) new TelefoneDAO().fetchOne(telefone); telefoneFuncionario.setTelefone(telefone);

list.add(telefoneFuncionario); } return list; } catch (SQLException e) { e.printStackTrace(); } return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<TelefoneFuncionario> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; }

104

4.8.3 Testando a Camada de Persistncia


No podemos esperar que a aplicao esteja pronta pra saber se tudo est funcionando. Dessa forma, ns precisamos testar cada unidade funcional da aplicao para garantir que ela funcione separadamente, para depois partir para os testes de integrao (que so as implementaes dos casos de testes descritos no captulo 3). JUnit um framework para criao de testes automatizados. O Eclipse facilita no s a criao como a execuo e depurao de testes escritos com esse framework. Para criar um teste unitrio, basta entrar acessar o menu File->New->Other e dentro de Java procurar o item JUnit, exibido na figura 15.

Figura 15: Criao de caso de teste em JUnit


O correto seria criarmos um teste unitrio, para saber se a camada de persistncia funciona de forma isolada. Mas para isso, teramos de criar um simulacro do banco de dados. A criao de simulacros, denominados geralmente de mocks, um assunto parte. Como o tema testes aqui no o foco principal, em vez de fazer testes unitrios iremos criar testes de integrao.

105

Um teste de integrao um teste que verifica o funcionamento de duas partes independentes de um sistema de software. No caso, o banco de dados e a camada de persistncia poderiam ser testados de forma isolada cada um, mas aqui vamos testar ambos simultaneamente. Como exemplo, iremos criar um teste de integrao para a persistncia do modelo Autor. Temos de criar mtodos de teste que consigam verificar todas as funcionalidades presentes nas classes envolvidas. Seguindo o padro do JUnit, a classe teste se chamar TestAutorDAO.

TestAutorDAO
public class TestAutorDAO extends TestCase { private static Autor autor; private static AutorDAO autorDAO = new AutorDAO(); public void testInsert() { TestAutorDAO.autor = new Autor(); TestAutorDAO.autor.setNome("Maurcio"); TestAutorDAO.autor.setSobrenome("de Sousa");

TestAutorDAO.autorDAO.insert(autor); Autor autor = TestAutorDAO.autorDAO.fetchAll("nome = 'Maurcio' and sobrenome = 'de Sousa'").get(0);

assertNotNull(autor);
if (autor!=null) { TestAutorDAO.autor = autor; } System.out.println(autor); } public void testUpdate() { TestAutorDAO.autor.setNome("Carlos"); TestAutorDAO.autor.setSobrenome("Gomes");

106

TestAutorDAO.autorDAO.update(autor); Autor autor = (Autor) new AutorDAO().fetchOne(TestAutorDAO.autor);

assertEquals(TestAutorDAO.autor.getId(), autor.getId());
System.out.println(autor); } public void testDelete() { TestAutorDAO.autorDAO.delete(TestAutorDAO.autor); Autor autor = (Autor) new AutorDAO().fetchOne(TestAutorDAO.autor);

assertNull(autor);
} }

Observe que com trs mtodos de teste conseguimos cobrir todas as funcionalidades presentes no modelo e no DAO.

4.8.4 Classes e Arquivos Auxiliares da Camada de Persistncia


A classe DAOEngine cria uma conexo com base em um arquivo chamado connection.properties. Mostramos a seguir qual seria o contedo desse arquivo.

connection.properties
# configurao do banco de dados driver = org.postgresql.Driver username = postgres password = postgres url = jdbc:postgresql://localhost:5432/livraria

A classe DAOEngine tambm utiliza uma classe para guardar mensagens de exceo. a classe Message, que fica no pacote messages. Ela na verdade servir a todas as camadas da aplicao. Seu cdigo segue adiante.

Message
public class Message { private static String lastException = ""; private static String lastInfo = "";

107

private Message(){};

public static String getLastException() { String message = lastException;

lastException = null;
return message; }

public static String getLastInfo() { String message = lastInfo;

lastInfo = "";
return message; }

public static boolean isException() { return !lastException.equals(""); }

public static boolean isInfo() { return !lastInfo.equals(""); }

public static void setLastException(String lastException) { Message.lastException = lastException; }

public static void setLastInfo(String lastInfo) { Message.lastInfo = lastInfo; }

108

4.9.Camada de Controle
O controle da aplicao ser feito por servlets. Nossa aplicao ter quatro servlets de controle. Um, chamado GravarServlet, ser responsvel por operaes de gravao (incluso e alterao de registros). Outro, chamado RemoverServlet, ser responsvel pela excluso de registros. O terceiro, chamado AutenticarServlet, ser responsvel pela autenticao do usurio e pela sua sada do sistema. Os dois primeiros servlets iro herdar de AuthServlet, que ir encapsular a verificao da autenticao do usurio. Para criar um servlet no Eclipse, basta acessar o menu File->New->Other. Abra o item Web e selecione Servlet, conforme mostra a figura 16. O Eclipse, alm de criar o esqueleto da classe Servlet, tambm cria as entradas no arquivo web.xml. Mas a URL padro o prprio nome do servlet. Iremos alterar para um padro de nome com letras minsculas. No arquivo web.xml, dentro de WebContent/WEB-INF, edite a configurao dos servlets para a seguinte:
<servlet> <description></description> <display-name>GravarServlet</display-name> <servlet-name>GravarServlet</servlet-name> <servlet-class>controllers.GravarServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>GravarServlet</servlet-name> <url-pattern>/gravar</url-pattern> </servlet-mapping> <servlet> <description></description> <display-name>RemoverServlet</display-name> <servlet-name>RemoverServlet</servlet-name> <servlet-class>controllers.RemoverServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>RemoverServlet</servlet-name> <url-pattern>/remover</url-pattern> </servlet-mapping>

109

<servlet> <description></description> <display-name>AutenticarServlet</display-name> <servlet-name>AutenticarServlet</servlet-name> <servlet-class>controllers.AutenticarServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>AutenticarServlet</servlet-name> <url-pattern>/autenticar</url-pattern> </servlet-mapping> <servlet> <description></description> <display-name>AuthServlet</display-name> <servlet-name>AuthServlet</servlet-name> <servlet-class>controllers.AuthServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>AuthServlet</servlet-name> <url-pattern>/AuthServlet</url-pattern> </servlet-mapping>

110

Figura 16: Criando um servlet no Eclipse


Vamos agora editar os Servlets.

4.9.1 Servlet de Autenticao


O servlet de autenticao responsvel por identificar o usurio perante o sistema e lhe dar o acesso primrio. Acesso primrio porque a autenticao a primeira condio para o usurio realizar operaes na parte administrativa do sistema. A segunda ter a permisso requerida para uma determinada operao.
public class AutenticarServlet extends HttpServlet { private static final long serialVersionUID = 1L;

111

public AutenticarServlet() { super(); }

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); }

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

String operacao = request.getParameter("operacao");

if (operacao.equals(Operacoes.LOGIN)) { login(request, response); } if (operacao.equals(Operacoes.LOGOUT)) { logout(request, response); }

private void logout(HttpServletRequest request, HttpServletResponse response) { getServletContext().removeAttribute("funcionario"); try { response.sendRedirect("login.jsp"); } catch (IOException e) { tratarErro(response, e); }

112

private void login(HttpServletRequest request, HttpServletResponse response) { String apelido = request.getParameter("apelido"); String senha = request.getParameter("senha");

FuncionarioDAO dao = new FuncionarioDAO();

try {

List<Funcionario> funcionarios = dao.fetchAll("apelido = '" + apelido + "' and senha ='" + senha + "'", null, null, null);

if (funcionarios != null && funcionarios.size() == 1) { getServletContext().setAttribute("funcionario", funcionarios.get(0)); response.sendRedirect("admin.jsp"); } else {

Message.setLastInfo("Apelido ou senha invlidos!");


response.sendRedirect("login.jsp"); }

} catch (Exception e) {

Message.setLastException(e.getMessage());
tratarErro(response, e); }

113

private void tratarErro(HttpServletResponse response, Exception e) { try { response.sendRedirect("erro.jsp?mensagem=" + e.getMessage()); } catch (IOException e1) { e1.printStackTrace(); } }

Esse servlet faz uso de uma classe de constantes chamada Operacoes, que fica no pacote constants:
public class Operacoes { public final static String LOGIN = "login"; public final static String LOGOUT = "logout";

4.9.2 Classe Abstrata para Servlets Autenticados


Esta a classe que encapsula a lgica de verificao da autenticao do usurio. Em vez de cada classe servlet fazer a verificao por conta prpria, criando cdigo replicado, elas simplesmente herdam de AuthServlet. Como a verificao de autenticao est no mtodo service, que executado antes de doGet e doPost, garantimos que nenhuma operao ser executada se o usurio no estiver autenticado.
public abstract class AuthServlet extends HttpServlet { private static final long serialVersionUID = 1L;

@Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

if (getServletContext().getAttribute("funcionario") == null) {

Message.setLastInfo("Voc precisa estar autenticado para usar o recurso!");


response.sendRedirect("login.jsp");

114

} else { super.service(request, response); } }

public AuthServlet() { super(); }

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { }

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { }

4.9.3 Servlet de Gravao


O servlet de gravao responsvel por recepcionar o envio de formulrios por HTTP POST e providenciar a incluso ou alterao de registro na respectiva tabela. Por isso, a lgica central est no mtodo doPost. O mtodo doPost invoca uma instncia nica de AuthorizationController, classe responsvel pelas informaes de permisso a recursos. Se o usurio autenticado tem os papis necessrios para executar a operao, executado o mtodo de gravao apropriado. Caso contrrio, o usurio redirecionado para a pgina do menu administrativo.
public class GravarServlet extends AuthServlet { private static final long serialVersionUID = 1L;

public GravarServlet() { super();

115

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { }

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

Funcionario funcionario = (Funcionario) getServletContext().getAttribute("funcionario");

AuthorizationController ac = AuthorizationController.getInstance(funcionario.getApelido());

if (!ac.hasRole(new String[]{Papeis.GRAVADOR,Papeis.ADMINISTRADOR})) {

Message.setLastInfo("Voc no tem permisso para usar este recurso!");


response.sendRedirect("admin.jsp"); return; }

String cadastro = request.getParameter("cadastro");

String retornar = request.getParameter("retornar");

if (retornar != null) { response.sendRedirect("cadastro.jsp?cadastro=" + cadastro); return; }

if (request.getCharacterEncoding() == null) request.setCharacterEncoding("UTF-8");

116

if (cadastro.equals(Cadastros.AUTOR)) { gravarAutor(request, response);return; } if (cadastro.equals(Cadastros.CLIENTE)) { gravarCliente(request, response);return; } if (cadastro.equals(Cadastros.EDITORA)) { gravarEditora(request, response);return; } if (cadastro.equals(Cadastros.FUNCIONARIO)) { gravarFuncionario(request, response);return; } if (cadastro.equals(Cadastros.LIVRO)) { gravarLivro(request, response);return; } if (cadastro.equals(Cadastros.LOCAL)) { gravarLocal(request, response);return; } if (cadastro.equals(Cadastros.PEDIDO)) { gravarPedido(request, response);return; } if (cadastro.equals(Cadastros.TELEFONE)) { gravarTelefone(request, response);return; } if (cadastro.equals(Cadastros.AUTOR_LIVRO)) { gravarAutorLivro(request, response);return; } if (cadastro.equals(Cadastros.TELEFONE_CLIENTE)) { gravarTelefoneCliente(request, response);return; }

117

if (cadastro.equals(Cadastros.TELEFONE_FUNCIONARIO)) { gravarTelefoneFuncionario(request, response);return; }

private void gravarTelefoneFuncionario(HttpServletRequest request, HttpServletResponse response) { Funcionario funcionario = new Funcionario(); funcionario.setId(Integer.parseInt(request.getParameter("id_funcionario")));

Telefone telefone = new Telefone();

telefone.setNumero(request.getParameter("numero")); telefone.setTipo(request.getParameter("tipo"));

TelefoneDAO telefoneDAO = new TelefoneDAO(); telefoneDAO.insert(telefone);

telefone.setId(DAOEngine.lastValue(telefoneDAO.getTable(), "id_telefone"));

TelefoneFuncionario telefoneFuncionario = new TelefoneFuncionario(); telefoneFuncionario.setFuncionario(funcionario); telefoneFuncionario.setTelefone(telefone); new TelefoneFuncionarioDAO().insert(telefoneFuncionario);

try { response.sendRedirect("edicao-funcionario.jsp?id=" + request.getParameter("id_funcionario")); } catch (IOException e) {

118

tratarErro(response, e); } }

private void gravarTelefoneCliente(HttpServletRequest request, HttpServletResponse response) {

Cliente cliente = new Cliente(); cliente.setId(Integer.parseInt(request.getParameter("id_cliente")));

Telefone telefone = new Telefone();

telefone.setNumero(request.getParameter("numero")); telefone.setTipo(request.getParameter("tipo"));

TelefoneDAO telefoneDAO = new TelefoneDAO(); telefoneDAO.insert(telefone);

telefone.setId(DAOEngine.lastValue(telefoneDAO.getTable(), "id_telefone"));

TelefoneCliente telefoneCliente = new TelefoneCliente(); telefoneCliente.setCliente(cliente); telefoneCliente.setTelefone(telefone); new TelefoneClienteDAO().insert(telefoneCliente);

try { response.sendRedirect("edicao-cliente.jsp?id=" + request.getParameter("id_cliente")); } catch (IOException e) { tratarErro(response, e);

119

} }

private void gravarAutorLivro(HttpServletRequest request, HttpServletResponse response) {

AutorLivroDAO dao = new AutorLivroDAO();

AutorLivro autorLivro = new AutorLivro();

autorLivro.setAutor(new Autor()); autorLivro.getAutor().setId( Integer.parseInt(request.getParameter("id_autor")));

autorLivro.setLivro(new Livro()); autorLivro.getLivro().setId( Integer.parseInt(request.getParameter("id_livro")));

AutorLivro autorLivroExistente = (AutorLivro) dao.fetchOne(autorLivro);

if (autorLivroExistente == null) { List<AutorLivro> autoresLivro = new ArrayList<AutorLivro>(); autoresLivro = dao.fetchAll("id_livro = " + autorLivro.getLivro().getId(), "ordem", null, null);

Integer ordem = autoresLivro == null ? 1 : autoresLivro.size() + 1;

autorLivro.setOrdem(ordem);

dao.insert(autorLivro); }

120

try { response.sendRedirect("edicao-livro.jsp?id=" + autorLivro.getLivro().getId()); } catch (IOException e) { tratarErro(response, e); } }

private void gravarPedido(HttpServletRequest request, HttpServletResponse response) { Pedido pedido = new Pedido();

GregorianCalendar calendar = new GregorianCalendar(); calendar.setTimeInMillis(System.currentTimeMillis()); pedido.setDataPedido(calendar); pedido.setCliente(new Cliente()); pedido.getCliente().setId(Integer.parseInt(request.getSession().getAttribute( "id_cliente").toString())); PedidoDAO dao = new PedidoDAO(); dao.insert(pedido); pedido.setNumeroPedido(dao.ultimoNumeroPedido()); pedido = (Pedido) dao.fetchOne(pedido); request.getSession().setAttribute("ultimo_pedido", pedido.getNumeroPedido());

try { response.sendRedirect("fechamento.jsp"); } catch (IOException e) { tratarErro(response, e); }

121

private void gravarTelefone(HttpServletRequest request, HttpServletResponse response) { Telefone telefone = new Telefone();

telefone = (Telefone) trataId(request, telefone);

telefone.setNumero(request.getParameter("numero")); telefone.setTipo(request.getParameter("tipo"));

TelefoneDAO dao = new TelefoneDAO(); if (telefone.getId() == null) { dao.insert(telefone); } else { dao.update(telefone); }

try { response.sendRedirect("cadastro.jsp?cadastro=telefone"); } catch (IOException e) { tratarErro(response, e); } }

private void gravarCliente(HttpServletRequest request, HttpServletResponse response) { Cliente cliente = new Cliente();

cliente = (Cliente) trataId(request, cliente);

122

cliente.setApelido(request.getParameter("apelido")); cliente.setEmail(request.getParameter("email")); cliente.setCpf(request.getParameter("cpf")); cliente.setNome(request.getParameter("nome")); cliente.setSenha(request.getParameter("senha"));

ClienteDAO dao = new ClienteDAO(); if (cliente.getId() == null) { dao.insert(cliente); } else { dao.update(cliente); }

try { response.sendRedirect("cadastro.jsp?cadastro=cliente"); } catch (IOException e) { tratarErro(response, e); }

private void gravarLocal(HttpServletRequest request, HttpServletResponse response) { Local local = new Local();

local = (Local) trataId(request, local);

local.setNome(request.getParameter("nome"));

LocalDAO dao = new LocalDAO(); if (local.getId() == null) {

123

dao.insert(local); } else { dao.update(local); }

try { response.sendRedirect("cadastro.jsp?cadastro=local"); } catch (IOException e) { tratarErro(response, e); }

private void gravarLivro(HttpServletRequest request, HttpServletResponse response) { Livro livro = new Livro();

livro = (Livro) trataId(request, livro);

livro.setAno(Integer.parseInt((request.getParameter("ano"))));

Editora editora = new Editora(); editora.setId(Integer.parseInt(request.getParameter("id_editora"))); editora = (Editora) new EditoraDAO().fetchOne(editora); livro.setEditora(editora);

livro.setIsbn(request.getParameter("isbn"));

Local local = new Local(); local.setId(Integer.parseInt(request.getParameter("id_local"))); local = (Local) new LocalDAO().fetchOne(local);

124

livro.setLocal(local);

livro.setPreco(Float.parseFloat(request.getParameter("preco").replace( ',', '.'))); livro.setTitulo(request.getParameter("titulo"));

LivroDAO dao = new LivroDAO(); if (livro.getId() == null) { dao.insert(livro); livro.setId(DAOEngine.lastValue(dao.getTable(), "id_livro")); } else { dao.update(livro); }

try { response.sendRedirect("edicao-livro.jsp?id=" + livro.getId()); } catch (IOException e) { tratarErro(response, e); } }

private void gravarFuncionario(HttpServletRequest request, HttpServletResponse response) { Funcionario funcionario = new Funcionario();

funcionario = (Funcionario) trataId(request, funcionario);

funcionario.setApelido(request.getParameter("apelido")); funcionario.setEmail(request.getParameter("email")); funcionario.setMatricula(request.getParameter("matricula")); funcionario.setNome(request.getParameter("nome"));

125

funcionario.setSenha(request.getParameter("senha"));

FuncionarioDAO dao = new FuncionarioDAO(); if (funcionario.getId() == null) { dao.insert(funcionario); } else { dao.update(funcionario); }

try { response.sendRedirect("cadastro.jsp?cadastro=funcionario"); } catch (IOException e) { tratarErro(response, e); } }

private void gravarAutor(HttpServletRequest request, HttpServletResponse response) { Autor autor = new Autor();

autor = (Autor) trataId(request, autor);

autor.setNome(request.getParameter("nome")); autor.setSobrenome(request.getParameter("sobrenome"));

AutorDAO dao = new AutorDAO(); if (autor.getId() == null) { dao.insert(autor); } else { dao.update(autor); }

126

try { response.sendRedirect("cadastro.jsp?cadastro=autor"); } catch (IOException e) { tratarErro(response, e); } }

private void gravarEditora(HttpServletRequest request, HttpServletResponse response) {

Editora editora = new Editora();

editora = (Editora) trataId(request, editora);

editora.setNome(request.getParameter("nome"));

EditoraDAO dao = new EditoraDAO(); if (editora.getId() == null) { dao.insert(editora); } else { dao.update(editora); }

try { response.sendRedirect("cadastro.jsp?cadastro=editora"); } catch (IOException e) { tratarErro(response, e); }

127

private IModel trataId(HttpServletRequest request, AbstractModel model) { if (request.getParameter("id") != null && !request.getParameter("id").equals("null")) { model.setId(Integer.parseInt(request.getParameter("id"))); } return model; }

private void tratarErro(HttpServletResponse response, Exception e) { try { response.sendRedirect("erro.jsp?mensagem=" + e.getMessage()); } catch (IOException e1) { e1.printStackTrace(); } }

4.9.3.1 Classe de Controle de Acesso


GravarServlet faz uso de uma classe chamada AuthorizationController. Essa classe contm a lgica que recupera os papis do usurio autenticado. AuthorizationController implementa o padro de projeto Singleton, no permitindo que mais de uma instncia seja criada.
public class AuthorizationController { private static AuthorizationController instance = null; private static Set<String> roles = new HashSet<String>();

private AuthorizationController(String user) { }

128

public static AuthorizationController getInstance(String user) { if (instance == null) {

instance = new AuthorizationController(user);


}

instance.updateRoles(user);
return instance; }

private void updateRoles(String user) { InputStream in = this.getClass().getClassLoader().getResourceAsStream("authorization.properties"); Properties properties = new Properties();

try {

roles.clear();
properties.load(in); in.close(); String[] papeisDoUsuario = properties.getProperty(user).split(",", -1); for (int i=0;i<papeisDoUsuario.length;i++) {

roles.add(papeisDoUsuario[i]);
} } catch (Exception e) {

Message.setLastException(e.getMessage());
} }

129

public boolean hasRole(String[] userRoles) { for (int i=0;i<userRoles.length;i++) { if (roles.contains(userRoles[i])) return true; }

return false; }

4.9.3.2 Constantes com os Papis


O uso de constantes recomendado para o teste de controle de acesso, pois padroniza os nomes para os programadores e evita erros de digitao.
public class Papeis { public static final String ADMINISTRADOR = "administrador"; public static final String GRAVADOR = "gravador"; public static final String REMOVEDOR = "removedor"; public static final String LEITOR = "leitor"; }

4.9.3.3 Arquivo com os Papis dos Usurios


A classe AuthorizationController faz uso de um arquivo de configurao, onde colocamos quais so os papis dos usurios. A seguir mostramos um exemplo de como pode ser o contedo desse arquivo.

authorization.properties
# papeis dos usuarios

hugo = leitor jose = leitor,gravador luis = leitor, gravar, removedor

130

patricia = administrador

4.9.3.4 Constantes com os Nomes dos Cadastros


public class Cadastros { public static final String AUTOR = "autor"; public static final String EDITORA = "editora"; public static final String CLIENTE = "cliente"; public static final String FUNCIONARIO = "funcionario"; public static final String LIVRO = "livro"; public static final String LOCAL = "local"; public static final String TELEFONE = "telefone"; public static final String PEDIDO = "pedido"; public static final String AUTOR_LIVRO = "autor_livro"; public static final String TELEFONE_CLIENTE = "telefone_cliente"; public static final String TELEFONE_FUNCIONARIO = "telefone_funcionario"; }

4.9.4 Servlet de Remoo


public class RemoverServlet extends AuthServlet { private static final long serialVersionUID = 1L;

public RemoverServlet() { super(); }

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

Funcionario funcionario = (Funcionario) getServletContext() .getAttribute("funcionario");

131

AuthorizationController ac = AuthorizationController .getInstance(funcionario.getApelido());

if (!ac .hasRole(new String[] { Papeis.REMOVEDOR, Papeis.ADMINISTRADOR })) {

Message.setLastInfo("Voc no tem permisso para usar este recurso!");


response.sendRedirect("admin.jsp"); return; }

String cadastro = request.getParameter("cadastro");

String paramId = request.getParameter("id"); Integer id = null;

if (paramId != null) { id = Integer.parseInt(paramId); }

if (cadastro.equals(Cadastros.AUTOR)) { removerAutor(response, id); return; } if (cadastro.equals(Cadastros.CLIENTE)) { removerCliente(response, id); return; } if (cadastro.equals(Cadastros.EDITORA)) { removerEditora(response, id); return; }

132

if (cadastro.equals(Cadastros.FUNCIONARIO)) { removerFuncionario(response, id); return; } if (cadastro.equals(Cadastros.LIVRO)) { removerLivro(response, id); return; } if (cadastro.equals(Cadastros.LOCAL)) { removerLocal(response, id); return; } if (cadastro.equals(Cadastros.TELEFONE)) { removerTelefone(response, id); return; } if (cadastro.equals(Cadastros.AUTOR_LIVRO)) { removerAutorLivro(response, Integer.parseInt(request .getParameter("id_autor")), Integer.parseInt(request .getParameter("id_livro"))); return; } if (cadastro.equals(Cadastros.TELEFONE_CLIENTE)) { removerTelefoneCliente(response, Integer.parseInt(request .getParameter("id_cliente")), Integer.parseInt(request .getParameter("id_telefone"))); return; } if (cadastro.equals(Cadastros.TELEFONE_FUNCIONARIO)) { removerTelefoneFucionario(response, Integer.parseInt(request .getParameter("id_funcionario")), Integer.parseInt(request

133

.getParameter("id_telefone"))); return; }

private void removerTelefoneFucionario(HttpServletResponse response, Integer idFuncionario, int idTelefone) { TelefoneFuncionario telefoneFuncionario = new TelefoneFuncionario(); telefoneFuncionario.setFuncionario(new Funcionario()); telefoneFuncionario.setTelefone(new Telefone());

telefoneFuncionario.getFuncionario().setId(idFuncionario); telefoneFuncionario.getTelefone().setId(idTelefone);

new TelefoneFuncionarioDAO().delete(telefoneFuncionario);

new TelefoneDAO().delete(telefoneFuncionario.getTelefone()); try { response.sendRedirect("edicao-funcionario.jsp?id=" + idFuncionario); } catch (IOException e) { tratarErro(response, e); }

private void removerTelefoneCliente(HttpServletResponse response, Integer idCliente, Integer idTelefone) { TelefoneCliente telefoneCliente = new TelefoneCliente(); telefoneCliente.setCliente(new Cliente()); telefoneCliente.setTelefone(new Telefone());

134

telefoneCliente.getCliente().setId(idCliente); telefoneCliente.getTelefone().setId(idTelefone);

new TelefoneClienteDAO().delete(telefoneCliente);

new TelefoneDAO().delete(telefoneCliente.getTelefone()); try { response.sendRedirect("edicao-cliente.jsp?id=" + idCliente); } catch (IOException e) { tratarErro(response, e); } }

private void removerAutorLivro(HttpServletResponse response, Integer idAutor, Integer idLivro) { AutorLivro autorLivro = new AutorLivro(); autorLivro.setAutor(new Autor()); autorLivro.setLivro(new Livro());

autorLivro.getAutor().setId(idAutor); autorLivro.getLivro().setId(idLivro);

new AutorLivroDAO().delete(autorLivro); try { response.sendRedirect("edicao-livro.jsp?id=" + idLivro); } catch (IOException e) { tratarErro(response, e); e.printStackTrace(); } }

135

private void removerTelefone(HttpServletResponse response, Integer id) { Telefone telefone = new Telefone(); telefone.setId(id); new TelefoneDAO().delete(telefone); try { response.sendRedirect("cadastro.jsp?cadastro=telefone"); } catch (IOException e) { tratarErro(response, e); } }

private void removerLocal(HttpServletResponse response, Integer id) { Local local = new Local(); local.setId(id); new LocalDAO().delete(local); try { response.sendRedirect("cadastro.jsp?cadastro=local"); } catch (IOException e) { tratarErro(response, e); } }

private void removerLivro(HttpServletResponse response, Integer id) { Livro livro = new Livro(); livro.setId(id); new LivroDAO().delete(livro); try { response.sendRedirect("cadastro.jsp?cadastro=livro"); } catch (IOException e) { tratarErro(response, e);

136

} }

private void removerFuncionario(HttpServletResponse response, Integer id) { Funcionario funcionario = new Funcionario(); funcionario.setId(id); new FuncionarioDAO().delete(funcionario); try { response.sendRedirect("cadastro.jsp?cadastro=funcionario"); } catch (IOException e) { tratarErro(response, e); } }

private void removerEditora(HttpServletResponse response, Integer id) { Editora editora = new Editora(); editora.setId(id); new EditoraDAO().delete(editora); try { response.sendRedirect("cadastro.jsp?cadastro=editora"); } catch (IOException e) { tratarErro(response, e); } }

private void removerCliente(HttpServletResponse response, Integer id) { Cliente cliente = new Cliente(); cliente.setId(id); new ClienteDAO().delete(cliente); try { response.sendRedirect("cadastro.jsp?cadastro=cliente");

137

} catch (IOException e) { tratarErro(response, e); } }

private void removerAutor(HttpServletResponse response, Integer id) { Autor autor = new Autor(); autor.setId(id); new AutorDAO().delete(autor); try { response.sendRedirect("cadastro.jsp?cadastro=autor"); } catch (IOException e) { tratarErro(response, e); } }

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }

private void tratarErro(HttpServletResponse response, Exception e) { try { response.sendRedirect("erro.jsp?mensagem=" + e.getMessage()); } catch (IOException e1) { e1.printStackTrace(); } }

138

4.10 Camada de Viso


A camada de Viso ser composta por pginas HTML e classes Java auxiliares para a gerao de contedo dinmico. As classes auxiliares so necessrias para que as pginas JSP evitem conter cdigo de processamento e tentem se limitar apresentao dos dados. A pgina admin.jsp contm uma estrutura de deciso que verifica se o usurio est autenticado. Caso no esteja, ele redirecionado para a pgina de autenticao (login.jsp). Esse mesmo procedimento feito em todas as pginas JSP, exceto a de autenticao. Essa pgina contm os links para os cadastros mantidos pelo sistema. Lembrando que todas as pginas JSP ficam dentro de WebContent.

4.10.1 Pginas JSP


admin.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%> <%@page import="messages.Message"%> <jsp:useBean id="view" class="view.ViewController"></jsp:useBean> <%if (getServletContext().getAttribute("funcionario") == null) response.sendRedirect("login.jsp");%> <!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=UTF-8"> <title>Mdulo Administrativo</title> </head> <body> <h1>Manuteno de Cadastros</h1> <h2><%=Message.getLastInfo()%></h2> <table border="0"> <tr><td><a href="/livrariajsp/cadastro.jsp?cadastro=autor">Autores</a></td></tr> <tr><td><a href="/livrariajsp/cadastro.jsp?cadastro=cliente">Clientes</a></td></tr> <tr><td><a href="/livrariajsp/cadastro.jsp?cadastro=editora">Editora</a></td></tr> <tr><td><a href="/livrariajsp/cadastro.jsp?cadastro=funcionario">Funcionrios</a></td></tr>

139

<tr><td><a href="/livrariajsp/cadastro.jsp?cadastro=livro">Livros</a></td></tr> <tr><td><a href="/livrariajsp/cadastro.jsp?cadastro=local">Locais</a></td></tr> <tr><td><a href="/livrariajsp/autenticar?operacao=logout">Sair</a></td></tr> </table> </body> </html>

login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <jsp:useBean id="view" class="view.ViewController"></jsp:useBean> <%if (getServletContext().getAttribute("funcionario") != null) response.sendRedirect("admin.jsp");%> <!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=UTF-8"> <title>Autenticao</title> </head> <body> <form action="/livrariajsp/autenticar?operacao=login" method="post"> <h1><%=view.getMessage(null)%></h1> <table border="0"> <tr> <td>Apelido:</td> <td><input type="text" name="apelido"></td> </tr> <tr> <td>Senha:</td> <td><input type="password" name="senha"></td> </tr> </table>

140

<input type="submit" value="entrar"> </form> </body>

</html>

Todas as pginas de listagem dos cadastros so iguais. Por isso no precisamos criar um arquivo para cada uma. O arquivo cadastro.jsp faz a exibio de qualquer cadastro por meio de parmetro passado por HTTP GET.

cadastro.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="constants.Papeis" %> <%@ page import="models.Funcionario" %> <jsp:useBean id="view" class="view.ViewController"></jsp:useBean> <%if (getServletContext().getAttribute("funcionario") == null) {response.sendRedirect("login.jsp");} else{ if (!view.hasRole((Funcionario)getServletContext().getAttribute("funcionario"),Papeis.LEITOR)) {response.sendRedirect("admin.jsp");} else{ %> <!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=UTF-8"> <title>Cadastro</title> </head> <body> <a href="/livrariajsp/edicao-<%=request.getParameter("cadastro")%>.jsp">Incluir</a> <form action="/livrariajsp/cadastro.jsp?cadastro=<%=request.getParameter("cadastro")%>" method="post"> Busca: <input type="text" name="valorprocurado"> <select name="campoprocurado"> <%=view.getOpcoesDeBusca(request.getParameter("cadastro"))%>

141

</select> <input type="submit" value="OK"> </form> <%Integer pagina = request.getParameter("pagina") == null ? null : Integer.parseInt(request.getParameter("pagina"));%> < %=view.getLista(request.getParameter("cadastro"),request.getParameter("campoprocurado"),request.getParameter("valor procurado"),request.getParameter("ordem"),pagina)%> <p align="center"><a href="/livrariajsp/admin.jsp">Mdulo Administrativo</a></p> </body> </html> <%}}%>

As pginas de edio j contm peculiaridades que ficam difceis de se generalizar apenas com os recursos de JSP.

edicao-autor.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="constants.Papeis" %> <%@ page import="models.Funcionario" %> <jsp:useBean id="view" class="view.ViewController"></jsp:useBean> <%if (getServletContext().getAttribute("funcionario") == null) {response.sendRedirect("login.jsp");} else{ if (!view.hasRole((Funcionario)getServletContext().getAttribute("funcionario"),Papeis.LEITOR)) {response.sendRedirect("admin.jsp");} else{ %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@ page import="models.Autor"%> <%@ page import="dao.AutorDAO"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

142

<jsp:useBean id="model" class="models.Autor"></jsp:useBean> <jsp:setProperty property="id" name="model" value="<%=request.getParameter("id") == null ? null : Integer.parseInt(request.getParameter("id"))%>"/> <title><%= model.getId() == null ? "Incluso" : "Alterao"%></title> </head> <body> <h1>Cadastro de Autores</h1> <form action="/livrariajsp/gravar?cadastro=autor" method="post"> <%model = (Autor) view.getModel(model);%> Nome: <input type="text" name="nome" value="<%=model.getNome()%>"><br/> Sobrenome: <input type="text" name="sobrenome" value="<%=model.getSobrenome()%>"><br/> <input type="hidden" name="id" value="<%=request.getParameter("id")%>"> <input type="hidden" name="cadastro" value="autor"> <input type="submit" value="Gravar"> <input type="submit" name="retornar" value="Retornar"> </form> </body> </html> <%}}%>

edicao-cliente.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="constants.Papeis" %> <%@ page import="models.Funcionario" %> <jsp:useBean id="view" class="view.ViewController"></jsp:useBean> <%if (getServletContext().getAttribute("funcionario") == null) {response.sendRedirect("login.jsp");} else{ if (!view.hasRole((Funcionario)getServletContext().getAttribute("funcionario"),Papeis.LEITOR)) {response.sendRedirect("admin.jsp");}

143

else{ %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@ page import="models.Cliente"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <jsp:useBean id="model" class="models.Cliente"></jsp:useBean> <jsp:setProperty property="id" name="model" value="<%=request.getParameter("id") == null ? null : Integer.parseInt(request.getParameter("id"))%>"/> <title><%= model.getId() == null ? "Incluso" : "Alterao"%></title> </head> <body> <h1>Cadastro de Clientes</h1> <table border="0"> <tr> <td> <h2>Dados Bsicos</h2> <form action="/livrariajsp/gravar?cadastro=cliente" method="post"> <%model = (Cliente) view.getModel(model);%> CPF: <input type="text" name="cpf" value="<%=model.getCpf()%>"><br/> Nome: <input type="text" name="nome" value="<%=model.getNome()%>"><br/> Apelido: <input type="text" name="apelido" value="<%=model.getApelido()%>"><br/> Senha: <input type="password" name="senha" value="<%=model.getSenha()%>"><br/> e-mail: <input type="text" name="email" value="<%=model.getEmail()%>"><br/> <input type="hidden" name="id" value="<%=request.getParameter("id")%>">

144

<input type="hidden" name="cadastro" value="cliente"> <input type="submit" value="Gravar"> <input type="submit" name="retornar" value="Retornar"> </form> </td> <td> <%if (request.getParameter("id") != null){%> <h2>Telefones</h2> <form action="/livrariajsp/gravar?cadastro=telefone_cliente" method="post"> Telefone: <input type="text" name="numero"><br/> Tipo: <select name="tipo"> <%=view.getTiposTelefone()%> </select> <input type="submit" id="adicionar" value="Adicionar telefone"> <input type="hidden" name="id_cliente" value="<%=request.getParameter("id")%>"> </form> <form action="/livrariajsp/remover?cadastro=telefone_cliente" method="post"> <select name="id_telefone"> <%=view.getTelefonesCliente(request.getParameter("id"))%> </select> <input type="submit" id="remover" value="Remover telefone"> <input type="hidden" name="id_cliente" value="<%=request.getParameter("id")%>"> </form> <%}%> </td> </tr> </table> </body> </html>

145

<%}}%>

edicao-editora.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="constants.Papeis" %> <%@ page import="models.Funcionario" %> <jsp:useBean id="view" class="view.ViewController"></jsp:useBean> <%if (getServletContext().getAttribute("funcionario") == null) {response.sendRedirect("login.jsp");} else{ if (!view.hasRole((Funcionario)getServletContext().getAttribute("funcionario"),Papeis.LEITOR)) {response.sendRedirect("admin.jsp");} else{ %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@ page import="models.Editora"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <jsp:useBean id="model" class="models.Editora"></jsp:useBean> <jsp:setProperty property="id" name="model" value="<%=request.getParameter("id") == null ? null : Integer.parseInt(request.getParameter("id"))%>"/> <title><%= model.getId() == null ? "Incluso" : "Alterao"%></title> </head> <body> <h1>Cadastro de Editoras</h1> <form action="/livrariajsp/gravar?cadastro=editora" method="post"> <%model = (Editora) view.getModel(model);%> Nome: <input type="text" name="nome" value="<%=model.getNome()%>"><br/> <input type="hidden" name="id" value="<%=request.getParameter("id")%>"> <input type="hidden" name="cadastro" value="editora">

146

<input type="submit" value="Gravar"> <input type="submit" name="retornar" value="Retornar"> </form> </body> </html>

<%}}%>

edicao-funcionario.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="constants.Papeis" %> <%@ page import="models.Funcionario" %> <jsp:useBean id="view" class="view.ViewController"></jsp:useBean> <%if (getServletContext().getAttribute("funcionario") == null) {response.sendRedirect("login.jsp");} else{ if (!view.hasRole((Funcionario)getServletContext().getAttribute("funcionario"),Papeis.LEITOR)) {response.sendRedirect("admin.jsp");} else{ %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@ page import="models.Funcionario"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <jsp:useBean id="model" class="models.Funcionario"></jsp:useBean> <jsp:setProperty property="id" name="model" value="<%=request.getParameter("id") == null ? null : Integer.parseInt(request.getParameter("id"))%>"/> <title><%= model.getId() == null ? "Incluso" : "Alterao"%></title> </head> <body> <h1>Cadastro de Funcionrios</h1> <table border="0">

147

<tr> <td> <form action="/livrariajsp/gravar?cadastro=funcionario" method="post"> <%model = (Funcionario) view.getModel(model);%> Matrcula: <input type="text" name="matricula" value="<%=model.getMatricula()%>"><br/> Nome: <input type="text" name="nome" value="<%=model.getNome()%>"><br/> Apelido: <input type="text" name="apelido" value="<%=model.getApelido()%>"><br/> Senha: <input type="password" name="senha" value="<%=model.getSenha()%>"><br/> e-mail: <input type="text" name="email" value="<%=model.getEmail()%>"><br/> <input type="hidden" name="id" value="<%=request.getParameter("id")%>"> <input type="hidden" name="cadastro" value="funcionario"> <input type="submit" value="Gravar"> <input type="submit" name="retornar" value="Retornar"> </form> </td> <td> <%if (request.getParameter("id") != null){%> <h2>Telefones</h2> <form action="/livrariajsp/gravar?cadastro=telefone_funcionario" method="post"> Telefone: <input type="text" name="numero"><br/> Tipo: <select name="tipo"> <%=view.getTiposTelefone()%> </select> <input type="submit" id="adicionar" value="Adicionar telefone">

148

<input type="hidden" name="id_funcionario" value="<%=request.getParameter("id")%>"> </form> <form action="/livrariajsp/remover?cadastro=telefone_funcionario" method="post"> <select name="id_telefone"> <%=view.getTelefonesFuncionario(request.getParameter("id"))%> </select> <input type="submit" id="remover" value="Remover telefone"> <input type="hidden" name="id_funcionario" value="<%=request.getParameter("id")%>"> </form> <%}%> </td> </tr> </table> </body> </html> <%}}%>

edicao-livro.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="constants.Papeis" %> <%@ page import="models.Funcionario" %> <jsp:useBean id="view" class="view.ViewController"></jsp:useBean> <%if (getServletContext().getAttribute("funcionario") == null) {response.sendRedirect("login.jsp");} else{ if (!view.hasRole((Funcionario)getServletContext().getAttribute("funcionario"),Papeis.LEITOR)) {response.sendRedirect("admin.jsp");} else{ %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@ page import="models.Livro"%> <html>

149

<head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <jsp:useBean id="model" class="models.Livro"></jsp:useBean> <jsp:setProperty property="id" name="model" value="<%=request.getParameter("id") == null ? null : Integer.parseInt(request.getParameter("id"))%>"/> <title><%= model.getId() == null ? "Incluso" : "Alterao"%></title> </head> <body> <h1>Cadastro de Livros</h1> <table border="0"> <tr> <td> <h2>Dados Bsicos</h2> <form action="/livrariajsp/gravar?cadastro=livro" method="post"> <%model = (Livro) view.getModel(model);%> ISBN: <input type="text" name="isbn" value="<%=model.getIsbn()%>"><br/> Ttulo: <input type="text" name="titulo" value="<%=model.getTitulo()%>"><br/> Local: <select name="id_local"> <%=view.getOpcoesRelacionadas("local",model.getLocal().getId())%> </select><br/> Editora: <select name="id_editora"> <%=view.getOpcoesRelacionadas("editora",model.getEditora().getId())%> </select><br/> Ano: <input type="text" name="ano" value="<%=model.getAno()%>"><br/> Preo: <input type="text" name="preco" value="<%=String.valueOf(model.getPreco()).replace('.',',')%>"><br/>

150

<input type="hidden" name="id" value="<%=request.getParameter("id")%>"> <input type="hidden" name="cadastro" value="Livro"> <input type="submit" value="Gravar"> <input type="submit" name="retornar" value="Retornar"> </form> </td> <td> <%if (request.getParameter("id") != null){%> <h2>Autores</h2> <form action="/livrariajsp/gravar?cadastro=autor_livro" method="post"> <select name="id_autor"> <%=view.getOpcoesAutores()%> </select> <input type="submit" id="adicionar" value="Adicionar autor"> <input type="hidden" name="id_livro" value="<%=request.getParameter("id")%>"> </form> <form action="/livrariajsp/remover?cadastro=autor_livro" method="post"> <select name="id_autor"> <%=view.getOpcoesAutores(request.getParameter("id"))%> </select> <input type="submit" id="remover" value="Remover autor"> <input type="hidden" name="id_livro" value="<%=request.getParameter("id")%>"> </form> <%}%> </td> </tr> </table> </body> </html> <%}}%>

151

edicao-local.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="constants.Papeis" %> <%@ page import="models.Funcionario" %> <jsp:useBean id="view" class="view.ViewController"></jsp:useBean> <%if (getServletContext().getAttribute("funcionario") == null) {response.sendRedirect("login.jsp");} else{ if (!view.hasRole((Funcionario)getServletContext().getAttribute("funcionario"),Papeis.LEITOR)) {response.sendRedirect("admin.jsp");} else{ %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@ page import="models.Local"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <jsp:useBean id="model" class="models.Local"></jsp:useBean> <jsp:setProperty property="id" name="model" value="<%=request.getParameter("id") == null ? null : Integer.parseInt(request.getParameter("id"))%>"/> <title><%= model.getId() == null ? "Incluso" : "Alterao"%></title> </head> <body> <h1>Cadastro de Locais</h1> <form action="/livrariajsp/gravar?cadastro=local" method="post"> <%model = (Local) view.getModel(model);%> Nome: <input type="text" name="nome" value="<%=model.getNome()%>"><br/> <input type="hidden" name="id" value="<%=request.getParameter("id")%>"> <input type="hidden" name="cadastro" value="local"> <input type="submit" value="Gravar">

152

<input type="submit" name="retornar" value="Retornar"> </form> </body> </html> <%}}%>

4.10.2 Classes Auxiliares da Camada de Viso


Como se pde perceber, todas as pginas JSP de nossa aplicao fazem referncia a uma classe chamada ViewController. Essa classe fornece a infraestrutura de processamento para as pginas JSP.

ViewController
enum TipoMensagem {EXCEPTION, INFO};

public class ViewController { private ModelFactory modelFactory = new ModelFactory(); private ListaFactory listaFactory = new ListaFactory(); private OpcoesFactory opcoesFactory = new OpcoesFactory();

public IModel getModel(IModel model) { if (model instanceof Autor) { return modelFactory.getAutor((Autor)model); } if (model instanceof Cliente) { return modelFactory.getCliente((Cliente)model); } if (model instanceof Editora) { return modelFactory.getEditora((Editora)model);

153

} if (model instanceof Funcionario) { return modelFactory.getFuncionario((Funcionario)model); } if (model instanceof Livro) { return modelFactory.getLivro((Livro)model); } if (model instanceof Local) { return modelFactory.getLocal((Local)model); } if (model instanceof Telefone) { return modelFactory.getTelefone((Telefone)model); } return null; }

public String getLista(String cadastro, String campoProcurado, String valorProcurado, String ordem, Integer pagina) { return listaFactory.getLista(cadastro,campoProcurado,valorProcurado,ordem,pagina); }

public String getOpcoesDeBusca(String cadastro) { return opcoesFactory.getOpcoesDeBusca(cadastro);

154

public String getOpcoesRelacionadas(String cadastro) { return getOpcoesRelacionadas(cadastro, null); }

public String getOpcoesRelacionadas(String cadastro,Integer selecionado) { return opcoesFactory.getOpcoesRelacionadas(cadastro,selecionado); }

public String getOpcoesAutores() { return opcoesFactory.getOpcoesAutores(null); }

public String getOpcoesAutores(String StringId) { if (StringId == null) return opcoesFactory.getOpcoesAutores(-1); else return opcoesFactory.getOpcoesAutores(Integer.parseInt(StringId)); }

public String getTiposTelefone() { return opcoesFactory.getTiposTelefone(); }

public String getTelefonesCliente(String paramId)

155

{ Integer id = Integer.parseInt(paramId);

return opcoesFactory.getTelefonesCliente(id); }

public String getTelefonesFuncionario(String paramId) { Integer id = Integer.parseInt(paramId);

return opcoesFactory.getTelefonesFuncionario(id); }

public String getOpcoesFuncionarios(Integer idFuncionario) { return opcoesFactory.getOpcoesFuncionarios(idFuncionario); }

public String getMessage(TipoMensagem tipo) { if (tipo == null) { return Message.isException() ? Message.getLastException() : (Message.isInfo() ? Message.getLastInfo() : ""); } if (tipo == TipoMensagem.EXCEPTION) { return Message.getLastException(); } if (tipo == TipoMensagem.INFO) {

156

return Message.getLastInfo(); } return ""; }

public boolean hasRole(Funcionario funcionario,String papel) { if (funcionario == null) return false;

AuthorizationController ac = AuthorizationController.getInstance(funcionario.getApelido());

if (!ac.hasRole(new String[]{papel})) {

Message.setLastInfo("Voc no tem permisso para usar este recurso!");


return false; }

return true; } }

ViewController faz uso de trs classes especializadas para prover contedo dinmico para as pginas: ListaFactory, ModelFactory e OpcoesFactory. ListaFactory tem por objetivo prover mtodos para a criao das listagens dos cadastros e dos campos do formulrio de pesquisa.

ListaFactory
public class ListaFactory extends ModelFactory { private Integer registrosPorPagina = 20;

public void setRegistrosPorPagina(Integer registrosPorPagina) { this.registrosPorPagina = registrosPorPagina;

157

public String getLista(String cadastro, String where, String order, Integer pagina) { String tabela = "<table border=\"1\">";

Integer numeroDeDegistros = pagina == null ? null : registrosPorPagina;

if (cadastro.equals(Cadastros.AUTOR)) { tabela = tabela + getListaAutor(where, order, numeroDeDegistros, pagina); } if (cadastro.equals(Cadastros.CLIENTE)) { tabela = tabela + getListaCliente(where, order, numeroDeDegistros, pagina); } if (cadastro.equals(Cadastros.EDITORA)) { tabela = tabela + getListaEditora(where, order, numeroDeDegistros, pagina); } if (cadastro.equals(Cadastros.FUNCIONARIO)) { tabela = tabela + getListaFuncionario(where, order, numeroDeDegistros, pagina); } if (cadastro.equals(Cadastros.LIVRO)) { tabela = tabela + getListaLivro(where, order, numeroDeDegistros, pagina); } if (cadastro.equals(Cadastros.LOCAL)) { tabela = tabela

158

+ getListaLocal(where, order, numeroDeDegistros, pagina); } if (cadastro.equals(Cadastros.TELEFONE)) { tabela = tabela + getListaTelefone(where, order, numeroDeDegistros, pagina); }

tabela = tabela + "</table>";

return tabela; }

private String getListaTelefone(String where, String order, Integer numeroDeDegistros, Integer pagina) { String tabela = "";

List<Telefone> lista = new TelefoneDAO().fetchAll(where, order, numeroDeDegistros, pagina);

String cadastro = "telefone";

tabela = tabela + "<thead>"; tabela = tabela + "<th>Id</th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=numero\">Nmero</a></th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=tipo\">Tipo</a></th>"; tabela = tabela + "<th>Excluir</th>"; tabela = tabela + "</thead>";

int i = 0;

159

for (Iterator<Telefone> iterator = lista.iterator(); iterator.hasNext();) { Telefone telefone = (Telefone) iterator.next();

tabela = tabela + "<tr>"; tabela = tabela + "<td><a href=\"/livrariajsp/edicao-" + cadastro + ".jsp?id=" + telefone.getId() + "\">" + telefone.getId() + "</a></td>"; tabela = tabela + "<td>" + telefone.getNumero() + "</td>"; tabela = tabela + "<td>" + telefone.getTipo() + "</td>"; tabela = tabela + "<td><a href=\"/livrariajsp/remover?cadastro=" + cadastro + "&id=" + telefone.getId() + "\">X</a></td>"; tabela = tabela + "</tr>"; i++; } return tabela;

private String getListaLocal(String where, String order, Integer numeroDeDegistros, Integer pagina) { String tabela = "";

List<Local> lista = new LocalDAO().fetchAll(where, order, numeroDeDegistros, pagina);

String cadastro = "local";

tabela = tabela + "<thead>"; tabela = tabela + "<th>Id</th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=nome\">Nome</a></th>";

160

tabela = tabela + "<th>Excluir</th>"; tabela = tabela + "</thead>";

int i = 0; for (Iterator<Local> iterator = lista.iterator(); iterator.hasNext();) { Local local = (Local) iterator.next();

tabela = tabela + "<tr>"; tabela = tabela + "<td><a href=\"/livrariajsp/edicao-" + cadastro + ".jsp?id=" + local.getId() + "\">" + local.getId() + "</a></td>"; tabela = tabela + "<td>" + local.getNome() + "</td>"; tabela = tabela + "<td><a href=\"/livrariajsp/remover?cadastro=" + cadastro + "&id=" + local.getId() + "\">X</a></td>"; tabela = tabela + "</tr>"; i++; } return tabela; }

private String getListaLivro(String where, String order, Integer numeroDeDegistros, Integer pagina) { String tabela = "";

List<Livro> lista = new LivroDAO().fetchAll(where, order, numeroDeDegistros, pagina);

String cadastro = "livro";

tabela = tabela + "<thead>"; tabela = tabela + "<th>Id</th>";

161

tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=isbn\">ISBN</a></th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=titulo\">Ttulo</a></th>"; tabela = tabela + "<th>Local</th>"; tabela = tabela + "<th>Editora</th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=ano\">Ano</a></th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=preco\">Preo</a></th>"; tabela = tabela + "<th>Excluir</th>"; tabela = tabela + "</thead>";

int i = 0; for (Iterator<Livro> iterator = lista.iterator(); iterator.hasNext();) { Livro livro = (Livro) iterator.next();

tabela = tabela + "<tr>"; tabela = tabela + "<td><a href=\"/livrariajsp/edicao-" + cadastro + ".jsp?id=" + livro.getId() + "\">" + livro.getId() + "</a></td>"; tabela = tabela + "<td>" + livro.getIsbn() + "</a></td>"; tabela = tabela + "<td>" + livro.getTitulo() + "</a></td>"; tabela = tabela + "<td>" + livro.getLocal().getNome() + "</td>"; tabela = tabela + "<td>" + livro.getEditora().getNome() + "</td>"; tabela = tabela + "<td>" + livro.getAno() + "</td>"; tabela = tabela + "<td>" + livro.getPreco().toString().replace('.', ',') + "</td>"; tabela = tabela + "<td><a href=\"/livrariajsp/remover?cadastro=" + cadastro + "&id=" + livro.getId() + "\">X</a></td>"; tabela = tabela + "</tr>";

162

i++; } return tabela; }

private String getListaFuncionario(String where, String order, Integer numeroDeDegistros, Integer pagina) { String tabela = "";

List<Funcionario> lista = new FuncionarioDAO().fetchAll(where, order, numeroDeDegistros, pagina);

String cadastro = "funcionario";

tabela = tabela + "<thead>"; tabela = tabela + "<th>Id</th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=matricula\">Matrcula</a></th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=nome\">Nome</a></th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=apelido\">Apelido</a></th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=email\">e-mail</a></th>"; tabela = tabela + "<th>Excluir</th>"; tabela = tabela + "</thead>";

int i = 0; for (Iterator<Funcionario> iterator = lista.iterator(); iterator .hasNext();) { Funcionario funcionario = (Funcionario) iterator.next();

163

tabela = tabela + "<tr>"; tabela = tabela + "<td><a href=\"/livrariajsp/edicao-" + cadastro + ".jsp?id=" + funcionario.getId() + "\">" + funcionario.getId() + "</a></td>"; tabela = tabela + "<td>" + funcionario.getMatricula() + "</a></td>"; tabela = tabela + "<td>" + funcionario.getNome() + "</td>"; tabela = tabela + "<td>" + funcionario.getApelido() + "</td>"; tabela = tabela + "<td>" + funcionario.getEmail() + "</td>"; tabela = tabela + "<td><a href=\"/livrariajsp/remover?cadastro=" + cadastro + "&id=" + funcionario.getId() + "\">X</a></td>"; tabela = tabela + "</tr>"; i++; } return tabela; }

private String getListaCliente(String where, String order, Integer numeroDeDegistros, Integer pagina) { String tabela = "";

List<Cliente> lista = new ClienteDAO().fetchAll(where, order, numeroDeDegistros, pagina);

String cadastro = "cliente";

tabela = tabela + "<thead>"; tabela = tabela + "<th>Id</th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=cpf\">CPF</a></th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro="

164

+ cadastro + "&ordem=nome\">Nome</a></th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=apelido\">Apelido</a></th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=email\">e-mail</a></th>"; tabela = tabela + "<th>Excluir</th>"; tabela = tabela + "</thead>";

int i = 0; for (Iterator<Cliente> iterator = lista.iterator(); iterator.hasNext();) { Cliente cliente = (Cliente) iterator.next();

tabela = tabela + "<tr>"; tabela = tabela + "<td><a href=\"/livrariajsp/edicao-" + cadastro + ".jsp?id=" + cliente.getId() + "\">" + cliente.getId() + "</td>"; tabela = tabela + "<td>" + cliente.getCpf() + "</td>"; tabela = tabela + "<td>" + cliente.getNome() + "</td>"; tabela = tabela + "<td>" + cliente.getApelido() + "</td>"; tabela = tabela + "<td>" + cliente.getEmail() + "</td>"; tabela = tabela + "<td><a href=\"/livrariajsp/remover?cadastro=" + cadastro + "&id=" + cliente.getId() + "\">X</a></td>"; tabela = tabela + "</tr>"; i++; } return tabela; }

public String getLista(String cadastro) { return getLista(cadastro, null, null, null, null); }

165

private String getListaEditora(String where, String order, Integer limit, Integer offset) { String tabela = "";

List<Editora> lista = new EditoraDAO().fetchAll(where, order, limit, offset);

String cadastro = "editora";

tabela = tabela + "<thead>"; tabela = tabela + "<th>Id</th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=nome\">Nome</a></th>"; tabela = tabela + "<th>Excluir</th>"; tabela = tabela + "</thead>";

int i = 0; for (Iterator<Editora> iterator = lista.iterator(); iterator.hasNext();) { Editora editora = (Editora) iterator.next();

tabela = tabela + "<tr>"; tabela = tabela + "<td><a href=\"/livrariajsp/edicao-" + cadastro + ".jsp?id=" + editora.getId() + "\">" + editora.getId() + "</a></td>"; tabela = tabela + "<td>" + editora.getNome() + "</a></td>"; tabela = tabela + "<td><a href=\"/livrariajsp/remover?cadastro=" + cadastro + "&id=" + editora.getId() + "\">X</a></td>"; tabela = tabela + "</tr>"; i++; }

166

return tabela; }

private String getListaAutor(String where, String order, Integer limit, Integer offset) { String tabela = "";

List<Autor> lista = new AutorDAO() .fetchAll(where, order, limit, offset);

String cadastro = "autor";

tabela = tabela + "<thead>"; tabela = tabela + "<th>Id</th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=nome\">Nome</a></th>"; tabela = tabela + "<th><a href=\"/livrariajsp/cadastro.jsp?cadastro=" + cadastro + "&ordem=sobrenome\">Sobrenome</a></th>"; tabela = tabela + "<th>Excluir</th>"; tabela = tabela + "</thead>";

int i = 0; for (Iterator<Autor> iterator = lista.iterator(); iterator.hasNext();) { Autor autor = (Autor) iterator.next();

tabela = tabela + "<tr>"; tabela = tabela + "<td><a href=\"/livrariajsp/edicao-" + cadastro + ".jsp?id=" + autor.getId() + "\">" + autor.getId() + "</a></td>"; tabela = tabela + "<td>" + autor.getNome() + "</td>"; tabela = tabela + "<td>" + autor.getSobrenome() + "</td>";

167

tabela = tabela + "<td><a href=\"/livrariajsp/remover?cadastro=" + cadastro + "&id=" + autor.getId() + "\">X</a></td>"; tabela = tabela + "</tr>"; i++; } return tabela; }

public String getLista(String cadastro, String campoProcurado, String valorProcurado, String order, Integer pagina) { String where = null;

if (campoProcurado == null || valorProcurado == null) return getLista(cadastro, null, order, pagina);

if (cadastro.equals(Cadastros.AUTOR)) { where = campoProcurado + " LIKE '%" + valorProcurado + "%'"; } if (cadastro.equals(Cadastros.CLIENTE)) { where = campoProcurado + " LIKE '%" + valorProcurado + "%'"; } if (cadastro.equals(Cadastros.EDITORA)) { where = campoProcurado + " LIKE '%" + valorProcurado + "%'"; } if (cadastro.equals(Cadastros.FUNCIONARIO)) { where = campoProcurado + " LIKE '%" + valorProcurado + "%'"; } if (cadastro.equals(Cadastros.LIVRO)) { where = campoProcurado + " LIKE '%" + valorProcurado + "%'"; } if (cadastro.equals(Cadastros.LOCAL)) {

168

where = campoProcurado + " LIKE '%" + valorProcurado + "%'"; } if (cadastro.equals(Cadastros.TELEFONE)) { where = campoProcurado + " LIKE '%" + valorProcurado + "%'"; }

return getLista(cadastro, where, order, pagina); } }

A finalidade da classe ModelFactory prover mtodos que retornem modelos para as pginas de edio. Esses modelos podem ser vazios se for uma incluso. ModelFactory
public class ModelFactory { public Autor getAutor(Autor model) { AutorDAO dao = new AutorDAO();

model = (Autor) dao.fetchOne(model);

if (model == null) { model = new Autor(); model.setNome(""); model.setSobrenome(""); } return model; }

public Editora getEditora(Editora model) { EditoraDAO dao = new EditoraDAO();

model = (Editora) dao.fetchOne(model);

169

if (model == null) { model = new Editora(); model.setNome(""); } return model; }

public IModel getLocal(Local model) { LocalDAO dao = new LocalDAO();

model = (Local) dao.fetchOne(model);

if (model == null) { model = new Local(); model.setNome(""); } return model; }

public IModel getCliente(Cliente model) { ClienteDAO dao = new ClienteDAO();

model = (Cliente) dao.fetchOne(model);

if (model == null) { model = new Cliente(); model.setApelido(""); model.setCpf(""); model.setEmail(""); model.setNome(""); model.setSenha("");

170

} return model; }

public IModel getFuncionario(Funcionario model) { FuncionarioDAO dao = new FuncionarioDAO();

model = (Funcionario) dao.fetchOne(model);

if (model == null) { model = new Funcionario(); model.setApelido(""); model.setEmail(""); model.setMatricula(""); model.setNome(""); model.setSenha(""); } return model; }

public IModel getTelefone(Telefone model) { TelefoneDAO dao = new TelefoneDAO();

model = (Telefone) dao.fetchOne(model);

if (model == null) { model = new Telefone(); model.setNumero(""); model.setTipo(Telefones.RESIDENCIAL); } return model;

171

public IModel getLivro(Livro model) { LivroDAO dao = new LivroDAO();

model = (Livro) dao.fetchOne(model);

if (model == null) { model = new Livro(); GregorianCalendar calendar = new GregorianCalendar(); calendar.setTimeInMillis(System.currentTimeMillis()); model.setAno(calendar.get(Calendar.YEAR)); model.setIsbn(""); model.setPreco(0.0f); model.setTitulo(""); model.setEditora(new Editora()); model.setLocal(new Local()); } return model; }

A classe OpcoesFactory serve para prover mtodos que preencham caixas de seleo de formulrios.

OpcoesFactory
public class OpcoesFactory {

public String getOpcoesDeBusca(String cadastro) { String opcoes = "";

172

if (cadastro.equals(Cadastros.AUTOR)) { opcoes = opcoes + "<option value=\"nome\">Nome</option>"; opcoes = opcoes + "<option value=\"sobrenome\">Sobrenome</option>"; } if (cadastro.equals(Cadastros.CLIENTE)) { opcoes = opcoes + "<option value=\"cpf\">CPF</option>"; opcoes = opcoes + "<option value=\"nome\">Nome</option>"; opcoes = opcoes + "<option value=\"apelido\">Apelido</option>"; opcoes = opcoes + "<option value=\"email\">e-mail</option>"; } if (cadastro.equals(Cadastros.EDITORA)) { opcoes = opcoes + "<option value=\"nome\">Nome</option>"; } if (cadastro.equals(Cadastros.FUNCIONARIO)) { opcoes = opcoes + "<option value=\"matricula\">Matrcula</option>"; opcoes = opcoes + "<option value=\"nome\">Nome</option>"; opcoes = opcoes + "<option value=\"apelido\">Apelido</option>"; opcoes = opcoes + "<option value=\"email\">e-mail</option>"; } if (cadastro.equals(Cadastros.LIVRO)) { opcoes = opcoes + "<option value=\"isbn\">ISBN</option>"; opcoes = opcoes + "<option value=\"titulo\">Ttulo</option>"; opcoes = opcoes + "<option value=\"ano\">Ano</option>"; } if (cadastro.equals(Cadastros.LOCAL)) { opcoes = opcoes + "<option value=\"nome\">Local</option>"; } if (cadastro.equals(Cadastros.TELEFONE)) { opcoes = opcoes + "<option value=\"numero\">Nmero</option>"; opcoes = opcoes + "<option value=\"tipo\">Tipo</option>"; }

173

return opcoes; }

public String getOpcoesRelacionadas(String cadastro, Integer selecionado) { String opcoes = "";

if (cadastro.equals(Cadastros.LOCAL)) { List<Local> locais = new LocalDAO().fetchAll(null, "nome", null, null);

for (Iterator<Local> iterator = locais.iterator(); iterator .hasNext();) { Local local = (Local) iterator.next(); opcoes = opcoes + "<option value=\"" + local.getId() + "\" " + (selecionado == null ? "" : (local.getId() == selecionado ? "selected" : "")) + ">" + local.getNome() + "</option>"; } } if (cadastro.equals(Cadastros.EDITORA)) { List<Editora> editoras = new EditoraDAO().fetchAll(null, "nome", null, null);

for (Iterator<Editora> iterator = editoras.iterator(); iterator .hasNext();) { Editora editora = (Editora) iterator.next();

174

opcoes = opcoes + "<option value=\"" + editora.getId() + "\" " + (selecionado == null ? "" : (editora.getId() == selecionado ? "selected" : "")) + ">" + editora.getNome() + "</option>"; } }

return opcoes; }

public String getOpcoesAutores(Integer id) { String opcoes = "";

String where = (id == null ? null : "id_livro = " + id);

if (where == null) { List<Autor> autores = new AutorDAO().fetchAll(null, null, null, null);

Collections.sort(autores, new Autor());

for (Iterator<Autor> iterator = autores.iterator(); iterator .hasNext();) { Autor autor = (Autor) iterator.next();

opcoes = opcoes + "<option value=\"" + autor.getId() + "\">" + autor.getSobrenome() + "," + autor.getNome()

175

+ "</option>"; } } else { List<AutorLivro> autoresLivro = new AutorLivroDAO().fetchAll(where, null, null, null);

Collections.sort(autoresLivro, new AutorLivro());

for (Iterator<AutorLivro> iterator = autoresLivro.iterator(); iterator .hasNext();) { AutorLivro autorLivro = (AutorLivro) iterator.next();

opcoes = opcoes + "<option value=\"" + autorLivro.getAutor().getId() + "\">" + autorLivro.getAutor().getSobrenome() + "," + autorLivro.getAutor().getNome() + "</option>"; } } return opcoes; }

public String getTiposTelefone() { String opcoes = ""; Field[] tipos = Telefones.class.getFields();

for (int i = 0; i < tipos.length; i++) { Field field = tipos[i]; String tipo = ""; try { tipo = (String) field.get(null); } catch (IllegalArgumentException e) {

176

} catch (IllegalAccessException e) { } opcoes = opcoes + "<option value=\"" + tipo + "\">" + tipo + "</option>"; }

return opcoes; }

public String getTelefonesCliente(Integer id) { String opcoes = ""; TelefoneClienteDAO dao = new TelefoneClienteDAO();

List<TelefoneCliente> telefones = dao.fetchAll("id_cliente = " + id, null, null, null);

for (Iterator<TelefoneCliente> iterator = telefones.iterator(); iterator .hasNext();) { TelefoneCliente telefoneCliente = (TelefoneCliente) iterator.next(); opcoes = opcoes + "<option value=\"" + telefoneCliente.getTelefone().getId() + "\">" + telefoneCliente.getTelefone().getNumero() + " - " + telefoneCliente.getTelefone().getTipo() + "</option>";

} return opcoes; }

public String getTelefonesFuncionario(Integer id) { String opcoes = ""; TelefoneFuncionarioDAO dao = new TelefoneFuncionarioDAO();

177

TelefoneDAO telefoneDao = new TelefoneDAO(); Telefone telefone = new Telefone();

List<TelefoneFuncionario> telefones = dao.fetchAll("id_funcionario = " + id, null, null, null);

for (Iterator<TelefoneFuncionario> iterator = telefones.iterator(); iterator .hasNext();) { TelefoneFuncionario telefoneFuncionario = (TelefoneFuncionario) iterator .next(); telefone.setId(telefoneFuncionario.getTelefone().getId()); telefone = (Telefone) telefoneDao.fetchOne(telefone); opcoes = opcoes + "<option value=\"" + telefone.getId() + "\">" + telefone.getNumero() + " - " + telefone.getTipo() + "</option>";

} return opcoes; }

public String getOpcoesFuncionarios(Integer idFuncionario) { String opcoes = "";

FuncionarioDAO dao = new FuncionarioDAO();

List<Funcionario> funcionarios = dao.fetchAll(null, "nome", null, null);

for (Iterator<Funcionario> iterator = funcionarios.iterator(); iterator .hasNext();) { Funcionario funcionario = (Funcionario) iterator.next(); opcoes = opcoes + "<option value=\"" + funcionario.getId() + "\">"

178

+ funcionario.getNome() + " - " + funcionario.getMatricula() + "</option>"; }

return opcoes; }

4.11 Concluses
Terminamos assim a implementao das trs camadas propostas na seo 4.7: Persistncia, Controle e Viso. A estrutura final de pacotes da aplicao pode ser vista na figura 17.

Figura 17: Estrutura de pacotes da aplicao livrariajsp 179

Essa implementao torna funcionais os casos de uso Manter Cadastro, Autenticar Usuario e Verificar Permisso de Funcionrio. A arquitetura adotada procurou reutilizar o mximo de estruturas, para facilitar a manuteno futura e permitir que o sistema cresa. Contudo, percebe-se que a maior parte do cdigo que implementamos no o que realmente interessa para o cliente, mas sim o necessrio para a aplicao funcionar. E apesar de tentarmos generalizar diversas pores de cdigo, ainda h muita repetio. O prximo captulo mostra como Hibernate e JSF j trazem prontas funcionalidades que tivemos de implementar neste captulo. Uma nica observao. A figura 17 mostra um pacote util, que no foi tratado aqui. Sua finalidade armazenar classes utilitrias que sejam usadas por todas as camadas. Como no implementamos todos os casos de uso, ele terminou por ficar vazio.

180

CAPTULO 5 Livraria com JSF e Hibernate


Neste captulo, faremos a implementao dos mesmos casos de uso tratados no captulo anterior, usando a tecnologia JavaServer Pages (JSF) para a camada de viso e Hibernate para a camada de persistncia. Faremos uma pequena introduo a JSF e Hibernate, para em seguida iniciar a implementao da parte administrativa da livraria. Para acompanhar este captulo, voc precisa ter instalado o Eclipse Galileo for JEE Developers.

5.1 Hibernate
Segundo Bauer e King (2007, p. 31), Hibernate uma ferramenta de mapeamento objeto relacional [ORM] completa que fornece todos os benefcios de um ORM. Esses benefcios so: produtividade, manutenibilidade, performance e independncia de fornecedor. Ainda segundo os autores, o Hibernate Core o servio bsico para a persistncia. Ele faz mapeamento utilizando arquivos XML e possui uma linguagem de consulta chamada HQL, assim como interfaces de consulta programtica para consultas do tipo Criteria e Example. A partir de JDK 5.0, Hibernate criou uma nova maneira de definir o mapeamento objeto-relacional usando anotaes. O pacote Hibernate Annotations, usado em cima do Core, reduz significativamente a quantidade de linhas de cdigo necessrias para fazer ORM. Por isso, utilizaremos Hibernate Annotations em nossa implementao. Os conceitos necessrios para utilizao do Hibernate sero vistos conforme criarmos a camada de Persistncia. A verso do Hibernate a ser utilizada aqui a 3.3.1.

5.2 JSF
Segundo Kurniawan (2004, p. XIII), JavaServer Faces (JSF) uma tecnologia nova para construo de aplicativos Web em Java, cuja especificao foi desenvolvida pelo grupo de peritos JSR-127 sob a superviso do Java Community Process.

181

JSF baseada nas tecnologias Servlet e JavaServer Pages. Um framework que implementa JSF realiza muito do trabalho que o programador teria de fazer manualmente se utilizasse somente servlets e JSP. De acordo com Geary e Horstmann (2007, p. 3), JSF define um conjunto de componentes pr-fabricados de interface de usurio, um modelo de programao orientado a eventos e um modelo de componentes que permite a adio de novos componentes por desenvolvedores independentes. O funcionamento de JSF se baseia no redirecionamento das requisies para um servlet chamado FacesServlet. Esse redirecionamento feito no arquivo web.xml. FacesServlet cria um objeto chamado FacesContext, que por sua vez contm os objetos ServletContext, ServletRequest e ServletResponse, que lhe so passados pelo continer Web. Em seguida, FacesServlet cria o objeto Lyfecycle, que processa FacesContext em seis fases. So elas:

Reconstituio da rvore de componentes; Aplicao dos valores da requisio; Processamento de validaes; Atualizao de valores de modelos; Invocao do aplicativo; Renderizao da resposta.

JSF permite que o programador crie ouvidores (listeners) que so verificados entre quaisquer duas fases do ciclo de vida de processamento da requisio. Esses ouvidores podem inclusive alterar o curso do fluxo de processamento. A utilizao de JSF ser vista durante a implementao do projeto deste captulo. A verso da especificao a ser utilizada aqui a 1.2.

5.3 Configurao do Web Page Editor


Nossa primeira tarefa ser configurar o Web Page Editor como editor padro de pginas JSP. Isso necessrio porque esse editor, ao contrrio do JSP Editor, possui funcionalidades para edio de JSF. Para mudar o editor padro de JSP, acesse o menu Window->Preferences. No item General, procure Editors, e dentro deste, File Associations. Procure na caixa de listagem a extenso *.jsp. Ao selecion-la, sero exibidos na listagem abaixo os editores associados. Selecione Web Page Editor, conforme mostra a figura 18, e clique em Default.

182

Figura 18: Alterao do editor de pginas JSP

5.4 Criando um Projeto JavaServer Faces


Vamos criar um projeto JavaServer Faces no Eclipse. Para isso, acesse o menu File>New->Project e selecione o item Web. Dentro dele, escolha Dynamic Project Web. At aqui o mesmo procedimento que fizemos para o projeto anterior. Aps escolher o tipo de projeto, somos levados a janela de configurao. O nome do projeto ser livrariajsf. Como j configuramos um servidor de aplicao, podemos selecionar Apache Tomcat v6.0 na caixa Target runtime. Agora vem a parte nova. Na caixa de seleo Configuration, selecione o item JavaServer Faces v1.2 Project. A tela dever estar como mostra a figura 19. Aps isso, clique em Next at chegar tela JSF Capabilities, onde iremos selecionar a implementao JSF a ser utilizada. Voc pode usar (teoricamente) qualquer implementao de JSF. Aqui ns iremos utilizar a implementao de referncia, um subprojeto do GlassFish chamado Mojarra.

183

Figura 19: Criao de um projeto JSF


Toda especificao do JCP tem uma implementao de referncia livre e um kit de compatibilidade de tecnologia. Isso ajuda os fornecedores de software a criarem suas implementaes de uma determinada JSR e verificar se ela est de acordo com o que foi especificado.

184

A implementao de referncia no o melhor produto de software que pde ser produzido a partir da especificao, mas sim aquele que est totalmente de acordo com ela e que funciona. A especificao cria um padro e estabelece um mnimo de funcionalidades. Mas isso no impede que cada fornecedor crie uma implementao que possua mais recursos do que os exigidos por uma JSR. Dessa forma, os consumidores ficam protegidos, pois a JSR assegura que todas as implementaes iro operar da mesma maneira. A escolha por uma ou outra implementao no significa aprisionamento de software, desde que, claro, a aplicao crie dependncias apenas para os recursos previstos pela especificao. Os fornecedores de software, por sua vez, podem concorrer entre si oferecendo funcionalidades que extrapolem as definidas na JSR, e criando ferramentas auxiliares. Aps essa defesa do modelo tecnolgico do JCP, vamos incluir as bibliotecas JSF em nossa aplicao.

Figura 20: Download da implementao JSF

185

Selecione User Library na caixa de seleo Type e clique no boto Download libraries... O Eclipse ir fazer uma busca e mostrar uma tela (figura 20), onde voc pode escolher uma biblioteca JSF de sua preferncia. Ns selecionaremos o Mojarra para o nosso projeto. Aps aceitar a licena, basta aguardar o download.

Figura 21: Configurao do JSF para o projeto


Terminado o download, voc deve ter uma tela igual da figura 21. Basta clicar no boto Finish e o projeto estar criado e configurado para trabalhar com JSF.

5.5 Instalando e Usando JBoss Tools para Configurar o Hibernate


Para facilitar nosso trabalho, iremos utilizar um plugin Eclipse chamado JBoss Tools, que entre outras coisas, oferece suporte para Hibernate. Ele pode ser obtido no site

186

http://www.jboss.org/tools/download. A verso utilizada aqui a 3.1, para o Eclipse 3.5.2. A instalao de plug-ins no Eclipse torna-se bem simples quando se usa update sites. Por meio do menu Help->Install New Software, possvel indicar uma URL a partir da qual o Eclipse ir baixar e instalar um plug-in. Os update sites do JBoss Tools esto disponveis na pgina de downloads, j citada anteriormente. Aps instalar JBoss Tools, vamos selecionar o projeto livrariajsf e acessar o menu New->Other. Localize o item Hibernate. Abra-o e selecione Hibernate Console Configuration, conforme mostra a figura 22.

Figura 22: Configurao do Hibernate no Eclipse 187

Esse item ir abrir uma tela que nos ajudar a criar os arquivos de configurao do Hibernate. Primeiro temos de selecionar o tipo de configurao. Iremos usar anotaes nas classes para fazer o mapeamento objeto-relacional, por isso selecionaremos no campo Type a opo Annotations (jdk 1.5+). Precisamos indicar uma conexo com banco de dados. Isso feito no frame Database Connection. Se j no houver uma conexo criada, use o boto New para criar uma. possvel testar facilmente a nova conexo por meio de um boto da tela de dados de conexo. No frame Property file, criaremos o arquivo de propriedades do Hibernate. Basta clicar no boto Setup desse frame e escolher a opo Create new. Tome cuidado para criar o arquivo dentro do diretrio src do projeto, que est no classpath. No frame Configuration File, criaremos o arquivo de configurao do Hibernate. Clique no boto Setup e ele abrir um formulrio no qual colocaremos os dados de configurao, conforme mostra a figura 23. O campo Session factory name no obrigatrio. Vamos preeench-lo apenas para mostrar no arquivo de configurao o que gerado. O imprescindvel no formulrio o preenchimento dos campos Database dialect, Username e Password. No campo Database dialect selecionamos qual dialeto SQL ser utilizado. Neste caso, ser PostgreSQL. A escolha do dialeto provoca o preenchimento dos campos Driver class e Connection URL. Este ltimo traz o modelo da URL de conexo, preciso complet-lo com o nome do banco de dados. Aps preencher o formulrio do arquivo de configurao, devemos ter uma tela igual da figura 24. Observe que os dois arquivos de configurao esto no diretrio src do projeto, para serem localizados Basta clicar em Finish e os arquivos hibernate.cfg.xml e hibernate.properties sero criados na raiz do projeto. Isso configura o Hibernate, mas no o instala. O modo ideal de fazer a instalao do Hibernate usado Maven, mas este assunto ficar para o prximo captulo. Por ora, vamos baixar manualmente o Hibernate e configurar o Build Path do projeto para localizar as bibliotecas. necessrio baixar dois arquivos a partir de http://sourceforge.net/projects/hibernate/files, um contendo o ncleo do Hibernate e outro que contm o suporte a anotaes. O primeiro est na pasta hibernate3, e o segundo na pasta hibernate-annotations. Iremos baixar a verso 3.3.1GA de ambos. Faa o download dos arquivos e os descompacte em um diretrio de sua preferncia. Depois, selecione o projeto livrariajsf, entre no menu popup Build Path->Configure Build Path. Na aba Libraries, clique em Add External jars e importe todos os arquivos .jar do Hibernate.

188

Tome cuidado, porque h arquivos .jar na raiz das instalaes e dentro do diretrio lib de cada uma. No caso do Hibernate Core, inclua os .jar dos subdiretrios required e bytecode. Do subdiretrio optional, inclua o jar de ehcache.

189

Figura 23: Configurao do arquivo hibernate.cfg.xml

190

Figura 24: Console de configurao do Hibernate no Eclipse

191

Um grande problema da linguagem Java que ela sozinha no faz nada. Para fazer aplicaes teis, voc precisa de APIs que usam outras APIs, que por sua vez usam outras APIs. Esse controle de quem depende de quem algo muito complexo, que se for feito sem uma ferramenta adequada pode causar muita dor de cabea. Ns faremos a incluso manual das dependncias neste projeto para deixar clara a dificuldade. O meio mais elegante para fazer gesto de dependncias ser mostrado no prximo captulo. O Hibernate tem algumas dependncias de APIs de terceiros. So elas: SLF4, Log4J e Commons Logging. Elas podem ser obtidas, respectivamente nos seguintes endereos:

http://www.slf4j.org/dist http://archive.apache.org/dist/logging/log4j/1.2.14 Logging: http://commons.apache.org/logging/download_logging.cgi

As verses necessrias para o Hibernate aqui utilizado so: SLF4 1.5.2, Log4J 1.2.14 e Commons Logging 1.1.1. Aps descompactar essas bibliotecas em um diretrio de sua preferncia, selecione o projeto livrariajsf e entre no menu popup Build Path->Configure Build Path. Na aba Libraries, clique em Add External jars e importe todos os arquivos .jar das trs APIs citadas. Para ter certeza de que no falta nada, listamos a seguir os arquivos .jar necessrios para o funcionamento do Hibernate, com o caminho diretrio completo da instalao:

hibernate-distribution-3.3.1.GA/hibernate3.jar hibernate-distribution-3.3.1.GA/lib/required/antlr-2.7.6.jar hibernate-distribution-3.3.1.GA/lib/required/commons-collections-3.1.jar hibernate-distribution-3.3.1.GA/lib/required/dom4j-1.6.1.jar hibernate-distribution-3.3.1.GA/lib/required/javassist-3.4.GA.jar hibernate-distribution-3.3.1.GA/lib/required/jta-1.1.jar hibernate-distribution-3.3.1.GA/lib/required/slf4j-api-1.5.2.jar hibernate-distribution-3.3.1.GA/hibernate-testing.jar hibernate-annotations-3.3.1.GA/hibernate-annotations.jar hibernate-annotations-3.3.1.GA/lib/ejb3-persistence.jar hibernate-annotations-3.3.1.GA/lib/hibernate-commons-annotations.jar

192

hibernate-distribution-3.3.1.GA/lib/bytecode/cglib/hibernate-cglib-repack2.1_3.jar hibernate-distribution-3.3.1.GA/lib/optional/ehcache/ehcache-1.2.3.jar slf4j-1.5.2/slf4j-log4j12-1.5.2.jar logging-log4j-1.2.14/dist/lib/log4j-1.2.14.jar commons-logging-1.1.1/commons-logging-1.1.1.jar commons-logging-1.1.1/commons-logging-adapters-1.1.1.jar commons-logging-1.1.1/commons-logging-api-1.1.1.jar commons-logging-1.1.1/commons-logging-tests.jar

Com esses procedimentos, agora podemos configurar os modelos de nossa aplicao.

5.6 Camada de Persistncia 5.6.1 Criando Modelos com Anotaes


Iremos copiar os pacotes models e models.generic do projeto livrariajsp para o livrariajsf e fazer as alteraes para que eles utilizem o Hibernate. A configurao do atributo primaryKey no construtor no mais necessria. Na verdade, o atributo primaryKey no mais necessrio, nem seus mtodos de leitura e gravao, por isso podemos remov-los da classe AbstractModel e da interface IModel. A prpria classe AbstractModel ser eliminada, pois como cada entidade ter um gerador de sequncia diferente para seu campo id, no ser possvel manter o atributo correspondente genrico. A interface IModel permanece, pois os mtodos de acesso e modificao (getId e setId) so utilizados por AbstractDAO. Os construtores dos modelos faro a inicializao dos atributos agora, para serem manipulados pelo JSF. A classe AbstractOnlyName agora no herda mais de AbstractModel, que foi eliminada. Ela implementa IModel diretamente. Alm disso, essa classe agora recebe uma anotao @MappedSuperclass do pacote javax.persistence. Essa anotao informa ao Hibernate que os campos desta classe devem ser considerados para a criao da tabela mapeada pela classe. AbstractOnlyName define um atributo genrico chamado nome. Usamos a anotao @Column de javax.persistence para informar ao Hibernate que esse atributo ser um

193

campo na tabela mapeada pela classe concreta que estende AbstractOnlyName. Com o parmetro length definimos o comprimento do campo.

AbstractOnlyName
@MappedSuperclass public abstract class AbstractOnlyName implements IModel { @Column(name = "nome", length = 30) protected String nome; public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } }

A classe AbstractUsuario agora estende AbstractOnlyName e tambm utiliza as anotaes @MappedSuperclass e @Column.

AbstractUsuario
@MappedSuperclass public abstract class AbstractUsuario extends AbstractOnlyName { @Column(name = "apelido", length = 10) protected String apelido;

@Column(name = "senha", length = 8) protected String senha;

@Column(name = "email", length = 40) protected String email;

194

public String getApelido() { return apelido; }

public void setApelido(String apelido) { this.apelido = apelido; }

public String getSenha() { return senha; }

public void setSenha(String senha) { this.senha = senha; }

public String getEmail() { return email; }

public void setEmail(String email) { this.email = email; } }

J tivemos uma reduo de duas classes, em relao aplicao anterior. E ao contrrio dela, construda com JDBC, desta vez no precisaremos de uma classe abstrata para definir o atributo telefone. O motivo que no haver necessidade de classes auxiliares para definir os relacionamentos das tabelas, porque o Hibernate faz isso com o uso de anotaes, que so metadados que afetam o modo pelo qual os programas Java so tratados por ferramentas e bibliotecas.

195

Iremos daqui para frente mostrar como ficam os modelos usando anotaes. Aps a apresentao do cdigo-fonte, sero discutidas as anotaes utilizadas na respectiva classe. Todas as anotaes utilizadas doravante so do pacote javax.persistence. Comecemos pelo modelo Autor. A nica modificao, alm das anotaes, no construtor. Todos os atributos, exceto o que mapeia a chave primria, devem ser inicializados, para que objeto possa ser manipulado pelo JSF.

Autor
@Entity @Table(name = "autores") @SequenceGenerator(name = "AutorSequence", sequenceName = "autores_id_autor_seq") public class Autor extends AbstractOnlyName implements Comparator<Autor> {

@Id @GeneratedValue(generator = "AutorSequence", strategy = GenerationType.SEQUENCE) @Column(name = "id_autor", columnDefinition = "serial") private Integer id;

@Column(name = "sobrenome", length = 20) private String sobrenome;

public Autor() { this.nome = ""; this.sobrenome = ""; }

public String getSobrenome() { return sobrenome; } public void setSobrenome(String sobrenome) {

196

this.sobrenome = sobrenome; } public int compare(Autor autor1, Autor autor2) { return (autor2.getSobrenome().compareTo(autor1.getSobrenome())); } public void setNome(String nome) { this.nome = nome; } public String getNome() { return nome; } public void setId(Integer id) { this.id = id; }

public Integer getId() { return id; } }

A anotao @Entity identifica essa classe como uma entidade, ou seja, os seus dados so provenientes de uma entidade do banco de dados, de uma tabela. A anotao @Table, por meio do parmetro name, identifica o nome da tabela no banco de dados. A anotao @SequenceGenerator define uma sequncia, um elemento do banco de dados responsvel pela gerao de sries numricas baseadas em uma regra. O parmetro name cria um nome para ser utilizado pela classe. O parmetro @sequenceName leva o nome da sequncia no banco de dados. A anotao @Id identifica qual atributo est mapeando a chave primria da tabela. Conforme j vimos, @Column identifica os atributos que mapeiam campos de uma tabela. A anotao @GeneratedValue indica ao Hibernate que o atributo em questo ter seus valores gerados automaticamente. A fonte dos valores definida pelo parmetro generator, que neste caso AutorSequence, especificado por @SequenceGenerator. O parmetro strategy indica como o valor ser criado pelo gerador.

197

A anotao @columnDefinition serve para forarmos o Hibernate a criar um campo exatamente da maneira como queremos. No caso, no queremos que o Hibernate crie um campo do tipo inteiro (o que ele vai fazer baseado no tipo de dados Java), mas sim um campo do tipo serial do Postgresql. O campo serial tambm inteiro, mas tem uma sequncia associada a ele. Vamos agora para o prximo modelo, Cliente. Cliente
@Entity @Table(name = "clientes") @SequenceGenerator(name = "ClienteSequence", sequenceName = "clientes_id_cliente_seq") public class Cliente extends AbstractUsuario { @Id @GeneratedValue(generator = "ClienteSequence", strategy = GenerationType.SEQUENCE) @Column(name = "id_cliente", columnDefinition = "serial") private Integer id;

@Column(name = "cpf", length = 11) private String cpf;

@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinTable(name = "telefones_cliente", joinColumns = @JoinColumn(name = "id_cliente", columnDefinition = "integer NOT NULL"), inverseJoinColumns = @JoinColumn(name = "id_telefone", columnDefinition = "integer NOT NULL")) protected Set<Telefone> telefones = new HashSet<Telefone>();

public Cliente() { this.apelido = ""; this.cpf = ""; this.email = ""; this.nome = ""; this.senha = ""; this.telefones = new HashSet<Telefone>(); }

198

public String getCpf() { return cpf; } public void setCpf(String cpf) { this.cpf = cpf; } public void setId(Integer id) { this.id = id; } public Integer getId() { return id; } public Set<Telefone> getTelefones() { return telefones; } public void setTelefones(Set<Telefone> telefones) { this.telefones = telefones; } }

A anotao @ManyToMany indica que o atributo representa um relacionamento de muitos-para-muitos. O argumento cascade configura as operaes em cascata, ou seja, quais operaes sobre a tabela principal tero repercusso na tabela relacionada. A constante CascadeType.ALL informa que todas as operaes na tabela principal, incluindo atualizao e remoo, sero propagadas para as tabelas dependentes. Neste caso, se um cliente for removido, todos os seus telefones tambm sero removidos. O argumento fetch informa ao Hibernate como ser a recuperao dos dados das tabelas dependentes. Voc pode carregar todos os dados relacionados de uma vez, ou busc-los sob demanda. A constante FetchType.LAZY informa que a busca dos registros dependentes s ser feita quando o atributo for lido. Ou seja, para este caso, o atributo telefones no ser imediatamente populado quando um objeto Cliente for recuperado, mas apenas quando for invocado seu mtodo de leitura.

199

A anotao @JoinTable complementa @ManyToMany, trazendo as sobre a tabela que realiza o relacionamento. O argumento name define o nome da tabela de relacionamento. O argumento joinColumns define quais sero os campos na tabela de relacionamento que sero a chave primria da tabela principal (a tabela da classe que est definindo o relacionamento). A anotao @JoinColumn, similar a a @Column, permite informar todos os detalhes sobre um campo, incluindo nome e tipo de dados. O argumento name dessa anotao indica o nome da chave estrangeira. O argumento inverseJoinColumns define quais sero os campos na tabela de relacionamento que sero a chave primria da tabela dependente. As anotaes da classe Funcionario so exatamente as mesmas de cliente.

Funcionario
@Entity @Table(name = "funcionarios") @SequenceGenerator(name = "FuncionarioSequence", sequenceName = "funcionarios_id_usuario_seq") public class Funcionario extends AbstractUsuario { @Id @GeneratedValue(generator = "FuncionarioSequence", strategy = GenerationType.SEQUENCE) @Column(name = "id_usuario", columnDefinition = "serial") private Integer id;

@Column(name = "matricula", length = 8) private String matricula;

@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinTable(name = "telefones_funcionario", joinColumns = @JoinColumn(name = "id_cliente", columnDefinition = "integer NOT NULL"), inverseJoinColumns = @JoinColumn(name = "id_funcionario", columnDefinition = "integer NOT NULL")) protected Set<Telefone> telefones = new HashSet<Telefone>();

public Funcionario() {

200

this.apelido = ""; this.email = ""; this.matricula = ""; this.nome = ""; this.senha = ""; this.telefones = new HashSet<Telefone>(); }

public String getMatricula() { return matricula; }

public void setMatricula(String matricula) { this.matricula = matricula; }

public void setId(Integer id) { this.id = id; }

public Integer getId() { return id; }

public Set<Telefone> getTelefones() { return telefones; }

public void setTelefones(Set<Telefone> telefones) { this.telefones = telefones; }

201

Editora
@Entity @Table(name = "editoras") @SequenceGenerator(name = "EditoraSequence", sequenceName = "editoras_id_editora_seq") public class Editora extends AbstractOnlyName { @Id @GeneratedValue(generator = "EditoraSequence", strategy = GenerationType.SEQUENCE) @Column(name = "id_editora", columnDefinition = "serial") private Integer id;

public Editora() { this.nome = ""; }

public void setId(Integer id) { this.id = id; }

public Integer getId() { return id; } }

Local
@Entity @Table(name = "locais") @SequenceGenerator(name = "LocalSequence", sequenceName = "locais_id_local_seq") public class Local extends AbstractOnlyName { @Id @GeneratedValue(generator = "LocalSequence", strategy = GenerationType.SEQUENCE)

202

@Column(name = "id_local", columnDefinition = "serial") private Integer id;

public Local() { this.nome = ""; }

public void setId(Integer id) { this.id = id; }

public Integer getId() { return id; } }

Livro
@Entity @Table(name = "livros") @SequenceGenerator(name = "LivroSequence", sequenceName = "livros_id_livro_seq") public class Livro implements IModel {

@Id @GeneratedValue(generator = "LivroSequence", strategy = GenerationType.SEQUENCE) @Column(name = "id_livro", columnDefinition = "serial") protected Integer id;

@Column(name = "isbn", length = 13) private String isbn;

@Column(name = "titulo", length = 255)

203

private String titulo;

@OneToOne @JoinColumn(name = "id_local", referencedColumnName = "id_local", columnDefinition = "integer NOT NULL") private Local local;

@OneToOne @JoinColumn(name = "id_editora", referencedColumnName = "id_editora", columnDefinition = "integer NOT NULL") private Editora editora;

@Column(name = "ano") private Integer ano;

@Column(name = "preco") private Float preco;

@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinTable(name = "autores_livro", joinColumns = @JoinColumn(name = "id_autor", columnDefinition = "integer NOT NULL"), inverseJoinColumns = @JoinColumn(name = "id_livro", columnDefinition = "integer NOT NULL")) private Set<Autor> autores = new HashSet<Autor>();

public Livro() { this.ano = 0; this.autores = new HashSet<Autor>(); this.editora = new Editora(); this.isbn = ""; this.local = new Local(); this.preco = 0.0f; this.titulo = ""; }

204

public Set<Autor> getAutores() { return autores; }

public void setAutores(Set<Autor> autores) { this.autores = autores; }

public String getIsbn() { return isbn; }

public void setIsbn(String isbn) { this.isbn = isbn; }

public String getTitulo() { return titulo; }

public void setTitulo(String titulo) { this.titulo = titulo; }

public Local getLocal() { return local; }

public void setLocal(Local local) { this.local = local;

205

public Editora getEditora() { return editora; }

public void setEditora(Editora editora) { this.editora = editora; }

public Integer getAno() { return ano; }

public void setAno(Integer ano) { this.ano = ano; }

public Float getPreco() { return preco; }

public void setPreco(Float preco) { this.preco = preco; }

public Integer getId() { return this.id; }

public void setId(Integer id) {

206

this.id = id; } }

A anotao @OneToOne define um relacionamento de um-para-um. As informaes sobre o relacionamento so dadas pela anotao @JoinColumn, j vista anteriormente. Aqui necessrio configurar o argumento referencedColumnName, que o nome da chave primria na tabela dependente.

Pedido
@Entity @Table(name = "pedidos") public class Pedido implements IModel { @Id @Column(name = "numero_pedido") private Integer numeroPedido;

@Column(name = "data_pedido") @Temporal(TemporalType.DATE) private Calendar dataPedido;

@OneToOne @JoinColumn(name = "id_cliente", referencedColumnName = "id_cliente", columnDefinition = "integer NOT NULL") private Cliente cliente;

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, targetEntity = ItemPedido.class) private Set<ItemPedido> items = new HashSet<ItemPedido>();

public Pedido() { this.cliente = new Cliente(); this.dataPedido = Calendar.getInstance(); this.items = new HashSet<ItemPedido>();

207

this.numeroPedido = 0; }

public Set<ItemPedido> getItems() { return items; }

public void setItems(Set<ItemPedido> items) { this.items = items; }

public Integer getNumeroPedido() { return numeroPedido; }

public void setNumeroPedido(Integer numeroPedido) { this.numeroPedido = numeroPedido; }

public Calendar getDataPedido() { return dataPedido; }

public void setDataPedido(Calendar dataPedido) { this.dataPedido = dataPedido; }

public Cliente getCliente() { return this.cliente; }

208

public void setCliente(Cliente cliente) { this.cliente = cliente; }

public Integer getId() { return this.getNumeroPedido(); }

public void setId(Integer id) { this.setNumeroPedido(id); } }

A anotao @Temporal especfica para tratar campos de data e hora. A constante TemporalType.DATE indica que o campo ter o tipo de dados de data padro do banco de dados utilizado. A anotao @OneToMany indica um relacionamento de um-para-muitos. O argumento targetEntity configura a classe que mapeia a tabela dependente.

ItemPedido
@Entity @Table(name = "itens_pedido") @SequenceGenerator(name = "ItemPedidoSequence", sequenceName = "itens_pedido_id_item_seq", allocationSize = 1) public class ItemPedido implements IModel { @Id @GeneratedValue(generator = "ItemPedidoSequence", strategy = GenerationType.SEQUENCE) @Column(name = "id_item", columnDefinition = "serial") private Integer id;

@OneToOne @JoinColumn(name = "id_pedido", referencedColumnName = "numero_pedido", columnDefinition = "integer NOT NULL") private Pedido pedido;

209

@OneToOne @JoinColumn(name = "id_livro", referencedColumnName = "id_livro", columnDefinition = "integer NOT NULL") private Livro livro;

@Column(name = "preco") private Float preco;

@Column(name = "quantidade") private Integer quantidade;

public ItemPedido() { this.livro = new Livro(); this.pedido = new Pedido(); this.preco = 0.0f; this.quantidade = 0; }

public Livro getLivro() { return livro; }

public void setLivro(Livro livro) { this.livro = livro; }

public Float getPreco() { return preco; }

public void setPreco(Float preco) {

210

this.preco = preco; }

public Integer getQuantidade() { return quantidade; }

public void setQuantidade(Integer quantidade) { this.quantidade = quantidade; }

public Integer getId() { return this.id; }

public void setId(Integer id) { this.id = id; }

public void setPedido(Pedido pedido) { this.pedido = pedido; }

public Pedido getPedido() { return pedido; } }

Telefone
@Entity @Table(name = "telefones")

211

@SequenceGenerator(name = "TelefoneSequence", sequenceName = "telefones_id_telefone_seq") public class Telefone implements IModel {

@Id @GeneratedValue(generator = "TelefoneSequence", strategy = GenerationType.SEQUENCE) @Column(name = "id_telefone", columnDefinition = "serial") private Integer id;

@Column(name = "numero", length = 16) private String numero;

@Column(name = "tipo", length = 20) private String tipo;

public Telefone() { this.numero = ""; this.tipo = ""; }

public String getNumero() { return numero; }

public void setNumero(String numero) { this.numero = numero; }

public String getTipo() { return tipo; }

212

public void setTipo(String tipo) { this.tipo = tipo; }

public Integer getId() { return this.id; }

public void setId(Integer id) { this.id = id; } }

Como os relacionamentos foram definidos por meio de anotaes, os trs modelos auxiliares criados na aplicao anterior so desnecessrios. E assim, eliminamos mais trs classes.

5.6.2 Criando DAOs sem JDBC


Em relao ao captulo anterior, teremos uma grande modificao no que diz respeito a camada de DAOs. A primeira se refere classe que encapsula os comandos SQL. Como o Hibernate faz isso, ela no mais necessria. Em seu lugar, utilizaremos uma classe que cria, recupera e fecha a sesso com o banco de dados via API do Hibernate. a classe HibernateUtil, que ficar no pacote dao.generic HibernateUtil
public class HibernateUtil { public static final SessionFactory sessionFactory; static { try { // Cria SessionFactory a partir de hibernate.cfg.xml

sessionFactory = new AnnotationConfiguration().configure()


.buildSessionFactory(); } catch (Throwable ex) { // A mensagem de erro deve ser gravada em log, em uma aplicao real System.err.println("Initial SessionFactory creation failed." + ex);

213

throw new ExceptionInInitializerError(ex); } } public static final ThreadLocal<Session> session = new ThreadLocal<Session>();

public static Session currentSession() { Session s; try { s = (Session) session.get(); if (s == null) { s = sessionFactory.openSession(); // Armazena na varivel ThreadLocal

session.set(s);
} } catch (HibernateException e) { SessionFactory exceptionFactory = new AnnotationConfiguration() .configure().buildSessionFactory(); s = exceptionFactory.openSession();

session.set(s);
}

// Abre uma nova Session, se esta thread ainda no tem nenhuma return s; }

public static void closeSession() throws HibernateException { Session s = (Session) session.get(); if (s != null) s.close();

session.set(null);
}

214

O mtodo ultimoNumeroDoPedido de DAOEngine no ser mais necessrio, porque o Hibernate atualiza automaticamente o atributo id do objeto Pedido com o valor criado no registro aps a incluso. A interface IDAO ser mantida, sem modificaes: IDAO
public interface IDAO { public boolean insert(IModel model); public boolean update(IModel model); public boolean delete(IModel model); public IModel fetchOne(IModel model); public List<? extends IModel> fetchAll(String where, String order, Integer limit, Integer offset); }

Desta vez, a classe AbstractDAO implementa a interface IDAO, o que faz com que as classes DAO precisem apenas herdar da primeira. No mais necessrio um atributo para guardar o nome da tabela (nem um mtodo para recuper-lo), pois essa informao est no modelo, por meio de anotao. Agora possvel definir um mtodo genrico de busca, utilizando a linguagem de consulta orientada a objetos do Hibernate, o HQL. Tambm no mais necessrio um mtodo para recuperar os nomes dos campos (getFields), pois o Hibernate cuida disso.

AbstractDAO
public abstract class AbstractDAO implements IDAO {

/** * Mtodo padro para incluir registros * * @param model */ public boolean insert(IModel model) { return save(model); }

215

/** * Mtodo padro para atualizar registros * * @param model */ public boolean update(IModel model) { return save(model); }

private boolean save(IModel model) { Session session = HibernateUtil.currentSession(); Transaction tx = session.beginTransaction(); try { session.saveOrUpdate(model); session.flush(); tx.commit(); return true; } catch (Exception e) { Message.setLastException(e.getMessage()); tx.rollback(); return false; }

/** * Mtodo padro para remover registros * * @param model */ public boolean delete(IModel model) {

216

Session session = HibernateUtil.currentSession(); Transaction tx = session.beginTransaction(); try { session.delete(model); session.flush(); session.evict(model); tx.commit(); return true; } catch (Exception e) { Message.setLastException(e.getMessage()); tx.rollback(); return false; } }

/** * Mtodo para obter a condio padro para consultas * * @param model * @return */ public String getDefaultWhere(IModel model) { return "id=" + model.getId(); }

public List<?> fetchAll(String entity, String where, String order, Integer limit, Integer offset) { if (where == null) { where = ""; } else { where = " where " + where;

217

if (order == null) { order = ""; } else { order = " order by " + order; }

Query hqlQuery = HibernateUtil.currentSession().createQuery( "from " + entity + where + order);

if (limit != null) { hqlQuery.setMaxResults(limit); }

if (offset != null) { hqlQuery.setFirstResult(offset); }

return hqlQuery.list(); } }

As classes DAO agora ficam muito mais simples, porque precisam implementar apenas dois mtodos, sendo que o mtodo fetchOne uma extrao de dados de fetchAll, e este ltimo apenas invoca o mtodo de consulta da superclasse com o argumento do nome do modelo.

AutorDAO
public class AutorDAO extends AbstractDAO { @SuppressWarnings("unchecked")

218

public List<Autor> fetchAll(String where, String order, Integer limit, Integer offset) {

try { return (List<Autor>) super.fetchAll("Autor",where, order, limit, offset); } catch (Exception e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<Autor> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; } }

219

ClienteDAO
public class ClienteDAO extends AbstractDAO { @SuppressWarnings("unchecked") public List<Cliente> fetchAll(String where, String order, Integer limit, Integer offset) { try { return (List<Cliente>) super.fetchAll("Cliente", where, order, limit, offset); } catch (Exception e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<Cliente> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; } }

220

EditoraDAO
public class EditoraDAO extends AbstractDAO { public EditoraDAO() { }

@SuppressWarnings("unchecked") public List<Editora> fetchAll(String where, String order, Integer limit, Integer offset) { try { return (List<Editora>) super.fetchAll("Editora", where, order, limit, offset); } catch (Exception e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<Editora> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; } }

221

FuncionarioDAO
public class FuncionarioDAO extends AbstractDAO { @SuppressWarnings("unchecked") public List<Funcionario> fetchAll(String where, String order, Integer limit, Integer offset) { try { return (List<Funcionario>) super.fetchAll("Funcionario", where, order, limit, offset); } catch (Exception e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<Funcionario> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; } }

222

223

ItemPedidoDAO
public class ItemPedidoDAO extends AbstractDAO { @SuppressWarnings("unchecked") public List<ItemPedido> fetchAll(String where, String order, Integer limit, Integer offset) { try { return (List<ItemPedido>) super.fetchAll("ItemPedido", where, order, limit, offset); } catch (Exception e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<ItemPedido> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; }

224

LivroDAO
public class LivroDAO extends AbstractDAO { @SuppressWarnings("unchecked") public List<Livro> fetchAll(String where, String order, Integer limit, Integer offset) { try { return (List<Livro>) super.fetchAll("Livro", where, order, limit, offset); } catch (Exception e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<Livro> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; } }

225

LocalDAO
public class LocalDAO extends AbstractDAO { @SuppressWarnings("unchecked") public List<Local> fetchAll(String where, String order, Integer limit, Integer offset) { try { return (List<Local>) super.fetchAll("Local", where, order, limit, offset); } catch (Exception e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<Local> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; } }

226

PedidoDAO
public class PedidoDAO extends AbstractDAO { public String getDefaultWhere(IModel model) { return "numeroPedido=" + model.getId(); } @SuppressWarnings("unchecked") public List<Pedido> fetchAll(String where, String order, Integer limit, Integer offset) { try { return (List<Pedido>) super.fetchAll("Pedido", where, order, limit, offset); } catch (Exception e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<Pedido> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; } }

227

TelefoneDAO
public class TelefoneDAO extends AbstractDAO { @SuppressWarnings("unchecked") public List<Telefone> fetchAll(String where, String order, Integer limit, Integer offset) { try { return (List<Telefone>) super.fetchAll("Telefone", where, order, limit, offset); } catch (Exception e) { e.printStackTrace(); }

return null; }

public IModel fetchOne(IModel model) { String where = this.getDefaultWhere(model);

List<Telefone> list = this.fetchAll(where, null, null, null); if (list != null && list.size() > 0) return list.get(0); else return null; } }

No precisamos mais de DAOs para tratar os relacionamentos, pois estes so tratados dentro dos DAOs dos modelos principais, que os definem com anotaes. Assim, eliminamos mais trs classes.

228

5.6.3 Testando a Camada de Persistncia


Iremos refazer o exemplo de teste de integrao da classe AutorDAO, para mostrar como fica com o uso de Hibernate.

TestAutorDAO
public class TestAutorDAO extends TestCase { private static Autor autor; private static Autor autorRecuperado; private static AutorDAO autorDAO = new AutorDAO();

/** * Testa se um registro includo com sucesso */ public void testInsert() {

autor = new Autor(); autor.setNome("Maurcio"); autor.setSobrenome("de Sousa");

TestAutorDAO.autorDAO.insert(autor);

Autor autorRecuperado = (Autor) TestAutorDAO.autorDAO.fetchOne(autor);

assertNotNull(autorRecuperado.getId());

System.out.println(autor);

/** * Testa se um registro atualizado com sucesso

229

*/ public void testUpdate() {

autor.setNome("Carlos"); autor.setSobrenome("Gomes");

autorDAO.update(autor);

autorRecuperado = (Autor) autorDAO.fetchOne(autor);

assertEquals(autor.getId(), autorRecuperado.getId());

System.out.println(autor); }

/** * Teste se um registro apagado com sucesso */ public void testDelete() {

autorDAO.delete(autor);

autorRecuperado = (Autor) autorDAO.fetchOne(autor);

assertNull(autorRecuperado);
}

5.6.4 Classes e Arquivos Auxiliares da Camada de Persistncia


O arquivo connection.properties utilizado no captulo anterior no mais necessrio, porque as informaes sobre a conexo com o banco esto no arquivo hibernate.cfg.xml. A classe Message do pacote messages pode ser totalmente reaproveitada, sem nenhuma modificao.

230

5.7 Camada de Controle 5.7.1 Generalizao


O controle da aplicao ser feito por classes ManagedBean, de acordo com a arquitetura do JSF, que cuida das camadas de controle e viso. Teremos um ManagedBean para cada cada modelo cujos dados constiturem um cadastro. Esses ManagedBeans tero trs operaes comuns: listar dados, gravar dados e remover dados. Por estabelecer um padro, criaremos uma interface para esses ManagedBeans, com mtodos correspondentes a essas operaes:

IManagedBean
public interface IManagedBean { public String gravar(); public String remover(); public ArrayList<? extends IModel> getLista(); }

Como j sabemos que teremos de verificar a autenticao do usurio, e isso feito na camada de controle, vamos criar uma classe abstrata para os ManagedBeans que faa essa verificao.

AuthController
public abstract class AuthController {

public AuthController(boolean checkUser) { if (checkUser) if (!isAuthenticated()) { throw new SecurityException("Usurio no autenticado"); } }

protected boolean isAuthenticated() {

231

return getSession().getAttribute("funcionario") != null; }

@SuppressWarnings("static-access") protected HttpSession getSession() { FacesContext facesContext = FacesContext.getCurrentInstance();

HttpServletRequest request = (HttpServletRequest) facesContext .getCurrentInstance().getExternalContext().getRequest();

HttpSession session = request.getSession(); return session; } }

O construtor invoca o mtodo isAuthenticated se receber um valor verdadeiro, indicado que deve ser verificada a autenticao. Caso o usurio no esteja autenticado, lanada uma exceo. O mtodo isAuthenticated recupera os dados do usurio da sesso, por meio da classe de contexto do JSF (FacesContext). Agora podemos criar uma classe abstrata para os ManagedBeans que implemente a interface ImanagedBean e herde AuthController.

AbstractManagedBean
public abstract class AbstractManagedBean extends AuthController implements IManagedBean { protected IModel bean = null; protected IDAO dao = null; protected String order = null; protected String where = null; protected String searchKey = null;

public AbstractManagedBean(boolean checkUser) { super(checkUser);

232

public abstract ArrayList<? extends IModel> getLista();

public String gravar() { if (this.bean.getId() == null) { this.dao.insert(this.bean); } else { this.dao.update(this.bean); } try { this.bean = bean.getClass().newInstance(); } catch (InstantiationException e) { Message.setLastException(e.getMessage()); this.bean = null; } catch (IllegalAccessException e) { Message.setLastException(e.getMessage()); this.bean = null; } return new CadastroMB().getCadastro(); }

public String remover() { try { this.dao.delete(this.bean); this.bean = bean.getClass().newInstance(); } catch (InstantiationException e) { Message.setLastException(e.getMessage()); } catch (IllegalAccessException e) { Message.setLastException(e.getMessage()); } catch (Exception e) {

233

Message.setLastException(e.getMessage()); } return new CadastroMB().getCadastro(); }

public IModel getBean() { return bean; }

public void setBean(IModel bean) { this.bean = bean; }

public IDAO getDao() { return dao; }

public void setDao(IDAO dao) { this.dao = dao; }

public String getOrder() { return order; }

public void setOrder(String order) { this.order = order; }

public String getWhere() { return where;

234

public void setWhere(String where) { this.where = where; }

public String getSearchKey() { return searchKey; }

public void setSearchKey(String searchKey) { this.searchKey = searchKey; }

protected void prepareWhere() { this.where = this.where == null ? null : this.where+" like '%"+this.searchKey+"%'"; }

protected void cleanWhereAndOrder() { this.where = null; this.order = null; }

Perceba, comparativamente, que essa classe AbstractManagedBean muito mais simples do que os servlets GravarSelect e RemoverServlet. S que os ManagedBeans no herdaro diretamente de AbstractManagedBean. Devemos lembrar tambm que precisamos fazer o controle de acesso aos recursos da

235

aplicao. Por isso, iremos definir uma classe que contenha a verificao das permisses. A classe AcessControllerMB estende AbstractManagedBean e aplica o controle de acesso aos mtodos de gravao e remoo. Ela reutiliza a classe AuthorizationController, criada na aplicao anterior. Mas aqui ns movemos essa classe para o pacote controllers.generic, por entender que ela faz parta da infraestrutura genrica dos ManagedBeans.

AccessControllerMB
public abstract class AccessControllerMB extends AbstractManagedBean { protected AuthorizationController ac;

public AccessControllerMB(boolean checkUser) { super(checkUser);

Funcionario funcionario = (Funcionario) getSession().getAttribute("funcionario");

this.ac = AuthorizationController.getInstance(funcionario.getApelido());

public String gravar() { if (!ac.hasRole(new String[] {Papeis.GRAVADOR,Papeis.ADMINISTRADOR})) { throw new SecurityException("O usurio no tem acesso a este recurso [gravar]"); } return super.gravar(); }

public String remover() {

236

if (!ac.hasRole(new String[] {Papeis.REMOVEDOR,Papeis.ADMINISTRADOR})) { throw new SecurityException("O usurio no tem acesso a este recurso [remover]"); } return super.remover(); } }

Especificamente para as classes que possuem o atributo telefone, ser necessrio um mtodo que faa a recuperao dos tipos de telefone. Para isso, criamos uma classe abstrata que retorne uma lista das constantes da classe Telefone.

AbstractUsuarioMB
public abstract class AbstractUsuarioMB extends AccessControllerMB{ public AbstractUsuarioMB(boolean checkUser) { super(checkUser); }

public List<SelectItem> getTiposTelefone() { List<SelectItem> items = new ArrayList<SelectItem>(); Field[] tipos = Telefones.class.getFields();

for (int i = 0; i < tipos.length; i++) { Field field = tipos[i]; String tipo = ""; try { tipo = (String) field.get(null); } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } items.add(new SelectItem(tipo, tipo)); }

237

return items; }

Agora podemos criar os ManagedBeans da aplicao.

5.7.2 ManagedBeans
AutorMB
public class AutorMB extends AccessControllerMB{

public AutorMB() { super(true); this.bean = new Autor(); this.dao = new AutorDAO(); }

public Autor getAutor() { return (Autor) bean; }

public void setAutor(Autor autor) { this.bean = autor; }

@SuppressWarnings("unchecked") public ArrayList<Autor> getLista() { if (!ac.hasRole(new String[] {Papeis.LEITOR,Papeis.ADMINISTRADOR})) { throw new SecurityException("O usurio no tem acesso a este recurso [listar]"); }

238

this.prepareWhere(); ArrayList<Autor> lista = (ArrayList<Autor>) this.dao.fetchAll(this.where,this.order, null, null); this.cleanWhereAndOrder(); return lista; } }

ClienteMB
public class ClienteMB extends AbstractUsuarioMB { private TelefoneDAO telefoneDAO = null; private Telefone telefone = null;

public ClienteMB() { super(true); this.bean = new Cliente(); this.dao = new ClienteDAO(); this.telefoneDAO = new TelefoneDAO(); this.setTelefone(new Telefone()); }

public void setCliente(Cliente cliente) { this.bean = cliente; }

public Cliente getCliente() { return (Cliente) bean; }

public void setTelefone(Telefone telefone) { this.telefone = telefone; }

239

public Telefone getTelefone() { return telefone; }

public String adicionarTelefone() { Set<Telefone> telefones = new HashSet<Telefone>();

this.telefoneDAO.insert(telefone); telefone = (Telefone) telefoneDAO.fetchOne(telefone); telefones.add(telefone);

for (Iterator<Telefone> iterator = ((Cliente) this.bean).getTelefones() .iterator(); iterator.hasNext();) { Telefone telefone = (Telefone) iterator.next(); telefone = (Telefone) telefoneDAO.fetchOne(telefone); telefones.add(telefone); } ((Cliente) this.bean).setTelefones(telefones); this.dao.update(bean);

this.telefone = new Telefone(); return AliasNavigationRules.EDITAR_CLIENTE; }

public String removerTelefone() { this.telefone = (Telefone) telefoneDAO.fetchOne(this.telefone);

((Cliente) this.bean).getTelefones().remove(this.telefone); this.dao.update(this.bean);

240

telefoneDAO.delete(this.telefone); this.telefone = new Telefone(); return AliasNavigationRules.EDITAR_CLIENTE; }

@SuppressWarnings("unchecked") public List<SelectItem> getTelefonesCliente() { List<SelectItem> items = new ArrayList<SelectItem>();

for (Iterator iterator = ((Cliente) this.bean).getTelefones().iterator(); iterator .hasNext();) { Telefone telefone = (Telefone) iterator.next(); items.add(new SelectItem(telefone.getId(), telefone.getNumero()+" - "+telefone.getTipo())); }

return items; }

@SuppressWarnings("unchecked") public ArrayList<Cliente> getLista() { if (!ac.hasRole(new String[] {Papeis.LEITOR,Papeis.ADMINISTRADOR})) { throw new SecurityException("O usurio no tem acesso a este recurso [listar]"); } this.prepareWhere(); ArrayList<Cliente> lista = (ArrayList<Cliente>) this.dao.fetchAll(this.where, this.order, null, null); this.cleanWhereAndOrder(); return lista; } }

241

EditoraMB
public class EditoraMB extends AccessControllerMB{

public EditoraMB() { super(true); this.bean = new Editora(); this.dao = new EditoraDAO(); }

public Editora getEditora() { return (Editora) bean; }

public void setEditora(Editora editora) { this.bean = editora; }

@SuppressWarnings("unchecked") public ArrayList<Editora> getLista() { if (!ac.hasRole(new String[] {Papeis.LEITOR,Papeis.ADMINISTRADOR})) { throw new SecurityException("O usurio no tem acesso a este recurso [listar]"); } this.prepareWhere(); ArrayList<Editora> lista = (ArrayList<Editora>) this.dao.fetchAll(this.where, this.order, null, null); this.cleanWhereAndOrder(); return lista; }

242

FuncionarioMB
public class FuncionarioMB extends AbstractUsuarioMB{ private Telefone telefone = null;

public FuncionarioMB() { super(true); this.bean = new Funcionario(); this.dao = new FuncionarioDAO(); this.telefone = new Telefone(); }

public void setFuncionario(Funcionario funcionario) { this.bean = funcionario; }

public Funcionario getFuncionario() { return (Funcionario) bean; }

public void setTelefone(Telefone telefone) { this.telefone = telefone; }

public Telefone getTelefone() { return telefone; }

public String adicionarTelefone()

243

{ return AliasNavigationRules.EDITAR_CLIENTE; }

public String removerTelefone() { return AliasNavigationRules.EDITAR_CLIENTE; }

@SuppressWarnings("unchecked") public ArrayList<Funcionario> getLista() { if (!ac.hasRole(new String[] {Papeis.LEITOR,Papeis.ADMINISTRADOR})) { throw new SecurityException("O usurio no tem acesso a este recurso [listar]"); } this.prepareWhere(); ArrayList<Funcionario> lista = (ArrayList<Funcionario>) this.dao.fetchAll(this.where, this.order, null, null); this.cleanWhereAndOrder(); return lista; }

@SuppressWarnings("unchecked") public List<SelectItem> getTelefonesFuncionario() { List<SelectItem> items = new ArrayList<SelectItem>();

for (Iterator iterator = ((Funcionario) this.bean).getTelefones().iterator(); iterator .hasNext();) { Telefone telefone = (Telefone) iterator.next(); items.add(new SelectItem(telefone.getId(), telefone.getNumero()+" - "+telefone.getTipo())); }

244

return items; } }

LivroMB
public class LivroMB extends AccessControllerMB { private Autor autor = null; private AutorDAO autorDAO = null; private EditoraDAO editoraDAO = null; private LocalDAO localDAO = null;

public LivroMB() { super(true); this.bean = new Livro(); ((Livro) this.bean).setEditora(new Editora()); ((Livro) this.bean).setLocal(new Local()); this.dao = new LivroDAO(); this.autor = new Autor(); this.autorDAO = new AutorDAO(); this.editoraDAO = new EditoraDAO(); this.localDAO = new LocalDAO(); }

public Livro getLivro() { return (Livro) bean; }

public void setLivro(Livro livro) { this.bean = livro; }

245

@SuppressWarnings("unchecked") public ArrayList<Livro> getLista() { if (!ac.hasRole(new String[] {Papeis.LEITOR,Papeis.ADMINISTRADOR})) { throw new SecurityException("O usurio no tem acesso a este recurso [listar]"); } this.prepareWhere(); ArrayList<Livro> lista = (ArrayList<Livro>) this.dao.fetchAll(this.where, this.order, null, null); this.cleanWhereAndOrder(); return lista; }

public String adicionarAutor() { Set<Autor> autores = new HashSet<Autor>();

autor = (Autor) autorDAO.fetchOne(autor); autores.add(autor);

for (Iterator<Autor> iterator = ((Livro) this.bean).getAutores() .iterator(); iterator.hasNext();) { Autor autor = (Autor) iterator.next(); autor = (Autor) autorDAO.fetchOne(autor); autores.add(autor); } ((Livro) this.bean).setAutores(autores); this.dao.update(bean);

this.autor = new Autor(); return AliasNavigationRules.EDITAR_LIVRO; }

246

public String removerAutor() { this.autor = (Autor) autorDAO.fetchOne(this.autor);

((Livro) this.bean).getAutores().remove(this.autor); this.dao.update(this.bean);

this.autor = new Autor(); return AliasNavigationRules.EDITAR_LIVRO; }

@SuppressWarnings("unchecked") public List<SelectItem> getAutoresLivro() { List<SelectItem> items = new ArrayList<SelectItem>();

for (Iterator iterator = ((Livro) this.bean).getAutores().iterator(); iterator .hasNext();) { Autor autor = (Autor) iterator.next(); items.add(new SelectItem(autor.getId(), autor.getSobrenome() + ", " + autor.getNome())); }

return items; }

@SuppressWarnings("unchecked") public List<SelectItem> getAutores() { List<SelectItem> items = new ArrayList<SelectItem>();

List<Autor> lista = this.autorDAO.fetchAll(null, null, null, null);

247

Collections.sort(lista, new Autor());

for (Iterator iterator = lista .iterator(); iterator.hasNext();) { Autor autor = (Autor) iterator.next(); items.add(new SelectItem(autor.getId(), autor.getSobrenome() + ", " + autor.getNome())); }

return items; }

@SuppressWarnings("unchecked") public List<SelectItem> getEditoras() { List<SelectItem> items = new ArrayList<SelectItem>();

for (Iterator iterator = this.editoraDAO.fetchAll(null, null, null, null).iterator(); iterator.hasNext();) { Editora editora = (Editora) iterator.next(); items.add(new SelectItem(editora.getId(), editora.getNome())); }

return items; }

@SuppressWarnings("unchecked") public List<SelectItem> getLocais() { List<SelectItem> items = new ArrayList<SelectItem>();

for (Iterator iterator = this.localDAO.fetchAll(null, null, null, null) .iterator(); iterator.hasNext();) {

248

Local local = (Local) iterator.next(); items.add(new SelectItem(local.getId(), local.getNome())); }

return items; }

public Autor getAutor() { return autor; }

public void setAutor(Autor autor) { this.autor = autor; }

public AutorDAO getAutorDAO() { return autorDAO; }

public void setAutorDAO(AutorDAO autorDAO) { this.autorDAO = autorDAO; }

public String gravar() { String uri = super.gravar(); ((Livro) this.bean).setEditora(new Editora()); ((Livro) this.bean).setLocal(new Local()); return uri; }

249

public String remover() { String uri = super.remover(); ((Livro) this.bean).setEditora(new Editora()); ((Livro) this.bean).setLocal(new Local()); return uri; }

LocalMB
public class LocalMB extends AccessControllerMB{

public LocalMB() { super(true); this.bean = new Local(); this.dao = new LocalDAO(); }

public Local getLocal() { return (Local) bean; }

public void setLocal(Local local) { this.bean = local; }

@SuppressWarnings("unchecked") public ArrayList<Local> getLista()

250

{ if (!ac.hasRole(new String[] {Papeis.LEITOR,Papeis.ADMINISTRADOR})) { throw new SecurityException("O usurio no tem acesso a este recurso [listar]"); } this.prepareWhere(); ArrayList<Local> lista = (ArrayList<Local>) this.dao.fetchAll(this.where, this.order, null, null); this.cleanWhereAndOrder(); return lista; } }

Um ManagedBean especfico ir lidar com o controle do menu principal do mdulo administrativo. Ele herdar diretamente de AuthController, porque para ter acesso a ele, basta estar autenticado. CadastroMB
public class CadastroMB extends AuthController { private static String cadastro = null;

public CadastroMB() { super(true); }

public String autores() { this.setCadastro(Cadastros.AUTOR); return this.getCadastro(); }

public String clientes() { this.setCadastro(Cadastros.CLIENTE); return this.getCadastro(); }

251

public String editoras() { this.setCadastro(Cadastros.EDITORA); return this.getCadastro(); }

public String funcionarios() { this.setCadastro(Cadastros.FUNCIONARIO); return this.getCadastro(); }

public String livros() { this.setCadastro(Cadastros.LIVRO); return this.getCadastro(); }

public String locais() { this.setCadastro(Cadastros.LOCAL); return this.getCadastro(); }

public void setCadastro(String cadastro) { CadastroMB.cadastro = cadastro; }

public String getCadastro() { return CadastroMB.cadastro; }

public String editar() { if (CadastroMB.cadastro.equals(Cadastros.AUTOR)) {

252

return AliasNavigationRules.EDITAR_AUTOR; } if (CadastroMB.cadastro.equals(Cadastros.CLIENTE)) { return AliasNavigationRules.EDITAR_CLIENTE; } if (CadastroMB.cadastro.equals(Cadastros.EDITORA)) { return AliasNavigationRules.EDITAR_EDITORA; } if (CadastroMB.cadastro.equals(Cadastros.FUNCIONARIO)) { return AliasNavigationRules.EDITAR_FUNCIONARIO; } if (CadastroMB.cadastro.equals(Cadastros.LIVRO)) { return AliasNavigationRules.EDITAR_LIVRO; } if (CadastroMB.cadastro.equals(Cadastros.LOCAL)) { return AliasNavigationRules.EDITAR_LOCAL; }

return AliasNavigationRules.ADMINISTRACAO; }

public String listar() { if (CadastroMB.cadastro.equals(Cadastros.AUTOR)) { return Cadastros.LISTA_AUTOR; } if (CadastroMB.cadastro.equals(Cadastros.CLIENTE)) { return Cadastros.LISTA_CLIENTE; } if (CadastroMB.cadastro.equals(Cadastros.EDITORA)) { return Cadastros.LISTA_EDITORA; }

253

if (CadastroMB.cadastro.equals(Cadastros.FUNCIONARIO)) { return Cadastros.LISTA_FUNCIONARIO; } if (CadastroMB.cadastro.equals(Cadastros.LIVRO)) { return Cadastros.LISTA_LIVRO; } if (CadastroMB.cadastro.equals(Cadastros.LOCAL)) { return Cadastros.LISTA_LOCAL; } return ""; }

public String admin() { return AliasNavigationRules.ADMINISTRACAO; }

public String cadastroAtual() { return this.getCadastro(); } }

Um ManagedBean ficar encarregado de controlar a entrada e sada do usurio do mdulo administrativo.

LoginMB
public class LoginMB extends AuthController{ private Funcionario funcionario; private FuncionarioDAO funcionarioDAO;

public void setFuncionario(Funcionario funcionario) { this.funcionario = funcionario; }

254

public Funcionario getFuncionario() { return funcionario; }

public LoginMB() { super(false); this.funcionario = new Funcionario(); this.funcionarioDAO = new FuncionarioDAO(); }

public String login() { ArrayList<Funcionario> lista = (ArrayList<Funcionario>) this.funcionarioDAO .fetchAll("apelido='" + this.funcionario.getApelido() + "' and senha='" + this.funcionario.getSenha() + "'", null, null, null);

if (lista == null || lista.size() == 0) { Message.setLastException("Dados invlidos!"); return AliasNavigationRules.LOGIN; }

HttpSession session = getSession(); session.setAttribute("funcionario", funcionario);

return AliasNavigationRules.ADMINISTRACAO; }

public boolean autenticado() { HttpSession session = getSession(); Funcionario funcionario = (Funcionario) session

255

.getAttribute("funcionario");

return (funcionario != null); }

public String logout() { HttpSession session = getSession(); session.setAttribute("funcionario", null); session.removeAttribute("funcionario"); this.funcionario = new Funcionario(); return AliasNavigationRules.LOGOUT; } }

Finalmente, um ltimo ManagedBean informaes sobre excees lanadas.

ficar

encarregado

de recuperar

as

ExceptionMB
public class ExceptionMB { public String getException() { return Message.getLastException(); } }

5.7.3 Registro no faces-config.xml


preciso registrar os ManagedBeans concretos, os que sero utilizados diretamente nas pginas JSF, no arquivo faces.config.xml. A figura 25 mostra como adicionar ManagedBeans pelo editor grfico.

256

Figura 25: Incluso de Managed Beans no arquivo faces-config.xml


Aps a incluso dos Managed Beans, a tela deve ser igual da figura 26.

Para no haver dvidas, o trecho de cdigo correspondente essa configurao este:


<managed-bean> <managed-bean-name>autorMB</managed-bean-name> <managed-bean-class>controllers.AutorMB</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <managed-bean>

257

<managed-bean-name>cadastroMB</managed-bean-name> <managed-bean-class>controllers.CadastroMB</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <managed-bean> <managed-bean-name>clienteMB</managed-bean-name> <managed-bean-class>controllers.ClienteMB</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <managed-bean> <managed-bean-name>editoraMB</managed-bean-name> <managed-bean-class>controllers.EditoraMB</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <managed-bean> <managed-bean-name>exceptionMB</managed-bean-name> <managed-bean-class>controllers.ExceptionMB</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <managed-bean> <managed-bean-name>funcionarioMB</managed-bean-name> <managed-bean-class>controllers.FuncionarioMB</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <managed-bean> <managed-bean-name>livroMB</managed-bean-name> <managed-bean-class>controllers.LivroMB</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <managed-bean> <managed-bean-name>localMB</managed-bean-name>

258

<managed-bean-class>controllers.LocalMB</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <managed-bean> <managed-bean-name>loginMB</managed-bean-name> <managed-bean-class>controllers.LoginMB</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean>

5.7.4 Classes Auxiliares da Camada de Controle


As classes Cadastros, Papeis e Telefones, do pacote constants da aplicao em JSP sero reaproveitadas. A classe Cadastros ser modificada, recebendo como acrscimo as constantes referentes s pginas de listagem.

Cadastros
public class Cadastros { public static final String AUTOR = "autor"; public static final String EDITORA = "editora"; public static final String CLIENTE = "cliente"; public static final String FUNCIONARIO = "funcionario"; public static final String LIVRO = "livro"; public static final String LOCAL = "local"; public static final String TELEFONE = "telefone"; public static final String PEDIDO = "pedido"; public static final String AUTOR_LIVRO = "autor_livro"; public static final String TELEFONE_CLIENTE = "telefone_cliente"; public static final String TELEFONE_FUNCIONARIO = "telefone_funcionario";

public static final String LISTA_AUTOR = "lista-autor.jsp"; public static final String LISTA_EDITORA = "lista-editora.jsp"; public static final String LISTA_CLIENTE = "lista-cliente.jsp"; public static final String LISTA_FUNCIONARIO = "lista-funcionario.jsp";

259

public static final String LISTA_LIVRO = "lista-livro.jsp"; public static final String LISTA_LOCAL = "lista-local.jsp"; }

No pacote navigation criamos uma classe chamada AliasNavigationRules, que contm os apelidos para pginas JSF definidos no arquivo faces-config.xml.

AliasNavigationRules
public class AliasNavigationRules { public static final String ADMINISTRACAO = "admin"; public static final String EDITAR_AUTOR = "editar-autor"; public static final String EDITAR_CLIENTE = "editar-cliente"; public static final String EDITAR_EDITORA = "editar-editora"; public static final String EDITAR_FUNCIONARIO = "editar-funcionario"; public static final String EDITAR_LIVRO = "editar-livro"; public static final String EDITAR_LOCAL = "editar-local"; public static final String LOGIN = "login"; public static final String LOGOUT = "logout"; }

Uma regra de navegao a definio dos possveis destinos a partir de uma nica origem. Ou seja, especificamos, a partir de uma pgina, para onde o usurio pode ir. Um caso de navegao, por sua vez, define um dos destinos de uma regra de navegao. No nosso caso, teremos apenas uma regra de navegao. As regras e casos de navegao no faces-config.xml podem ser definidos pelo editor grfico, conforme figura 26. O trecho de cdigo corresponde no arquivo este:
<navigation-rule> <navigation-case> <from-outcome>admin</from-outcome> <to-view-id>/admin.jsf</to-view-id> </navigation-case> <navigation-case> <from-outcome>autor</from-outcome> <to-view-id>/cadastro-autor.jsf</to-view-id>

260

</navigation-case> <navigation-case> <from-outcome>cliente</from-outcome> <to-view-id>/cadastro-cliente.jsf</to-view-id> </navigation-case> <navigation-case> <from-outcome>editar-autor</from-outcome> <to-view-id>/edicao-autor.jsf</to-view-id> </navigation-case> <navigation-case> <from-outcome>editar-cliente</from-outcome> <to-view-id>/edicao-cliente.jsf</to-view-id> </navigation-case> <navigation-case> <from-outcome>editar-editora</from-outcome> <to-view-id>/edicao-editora.jsf</to-view-id> </navigation-case> <navigation-case> <from-outcome>editar-funcionario</from-outcome> <to-view-id>/edicao-funcionario.jsf</to-view-id> </navigation-case> <navigation-case> <from-outcome>editar-livro</from-outcome> <to-view-id>/edicao-livro.jsf</to-view-id> </navigation-case> <navigation-case> <from-outcome>editar-local</from-outcome> <to-view-id>/edicao-local.jsf</to-view-id> </navigation-case> <navigation-case> <from-outcome>editora</from-outcome>

261

<to-view-id>/cadastro-editora.jsf</to-view-id> </navigation-case> <navigation-case> <from-outcome>funcionario</from-outcome> <to-view-id>/cadastro-funcionario.jsf</to-view-id> </navigation-case> <navigation-case> <from-outcome>livro</from-outcome> <to-view-id>/cadastro-livro.jsf</to-view-id> </navigation-case> <navigation-case> <from-outcome>local</from-outcome> <to-view-id>/cadastro-local.jsf</to-view-id> </navigation-case> <navigation-case> <from-outcome>login</from-outcome> <to-view-id>/login.jsf</to-view-id> </navigation-case> <navigation-case> <from-outcome>logout</from-outcome> <to-view-id>/index.jsp</to-view-id> </navigation-case> </navigation-rule>

5.8 Camada de Viso 5.8.1 Criando as Pginas JSF


Agora criaremos a camada de viso da aplicao, que ser constituda exclusivamente de pginas JSF. No ser mais necessria a existncia de classes auxiliares como fizemos na aplicao JSP. JSF depende de JSTL (JavaServer Pages Standard Tag Library). Por isso a aplicao precisa da API e de uma implementao dessa especificao. Voc pode obter tanto a API quanto a implementao da JSTL na seguinte URL:

262

https://jstl.dev.java.net/download.html Aqui foi utilizada a verso 1.2. Aps baixar o arquivo jar da biblioteca em um diretrio de sua preferncia, selecione o projeto livrariajsf e entre no menu popup Build Path>Configure Build Path. Na aba Libraries, clique em Add External jars e importe os arquivos jstl-api-1.2.jar e jslt-impl-1.2.jar.

Figura 26: Regras de Navegao no faces-config.xml


A primeira pgina contm apenas o link para a pgina de administrao, ou melhor, para o formulrio de autenticao. index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!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=UTF-8">

263

<title>Sistema de Livraria Virtual</title> </head> <body> <a href="login.jsf">Administrao</a> </body>

</html>

A pgina de login j contm cdigo JSF. Para se referir a uma classe ManagedBean, usamos o identificador do arquivo faces-config.xml. Por exemplo, neste caso, o nome loginMB representa a classe LoginMB. Ao utilizar esse identificador, o JSF se encarrega de criar a instncia dessa classe e capturar a referncia para ter acesso aos mtodos e atributos pblicos. login.jsp
<?xml version="1.0" encoding="UTF-8" ?> <jsp:root version="2.0" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"> <jsp:directive.page contentType="text/html" /> <jsp:output omit-xml-declaration="no" doctype-root-element="html" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" /> <f:view> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Autenticao</title> </head> <body> <h1>Autenticao</h1> <h:form> <h:outputText value="#{exceptionMB.exception}"/> </h:form> <h:form>

264

<table> <tr> <td>Apelido:</td> <td><h:inputText value="#{loginMB.funcionario.apelido}"/></td> </tr> <tr> <td>Senha:</td> <td><h:inputSecret value="#{loginMB.funcionario.senha}"/></td> </tr> <tr> <td><h:commandButton value="Entrar" action="#{loginMB.login}"/></td> </tr> </table> </h:form> </body> </html> </f:view> </jsp:root>

Utilizaremos duas bibliotecas de tags JSF, a core (referenciada pela letra f) e a html (referenciada pela letra h). A tag f:view define a viso propriamente dita, a pgina HTML que ser enviada para o navegador. A tag h:form define um formulrio controlado pelo JSF. A tag h:outputText representa um componente grfico, no caso um texto no editvel pelo usurio. A tag h:inputText, por outro lado, uma caixa de texto para edio. Com o atributo value, configuramos qual atributo do ManagedBean est relacionado com o componente grfico. O JSF recuperar os valores dos atributos da instncia para os componentes grficos. Qualquer alterao dos dados de um componente de entrada implicar na modificao automtica dos respectivos atributos, assim que o formulrio for submetido. A tag h:inputSecret gera um campo especfico para senhas, onde os caracteres digitados no so exibidos.

265

A tag h:commandButton cria um boto de submisso. Este, uma vez acionado, faz a associao dos dados dos componentes grficos com os respectivos atributos dos ManagedBeans e executa o mtodo especificado no argumento action. Aps o login, o usurio tem acesso ao menu de administrao.

admin.jsp
<?xml version="1.0" encoding="UTF-8" ?> <jsp:root version="2.0" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"> <jsp:directive.page contentType="text/html" /> <jsp:output omit-xml-declaration="no" doctype-root-element="html" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" /> <f:view> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Mdulo Administrativo</title> </head> <body> <h1>Manuteno de Cadastros</h1> <h:form> <table> <tr><td><h:commandButton action="#{cadastroMB.autores}" value="Autores" /></td></tr> <tr><td><h:commandButton action="#{cadastroMB.clientes}" value="Clientes" /></td></tr> <tr><td><h:commandButton action="#{cadastroMB.editoras}" value="Editoras" /></td></tr> <tr><td><h:commandButton action="#{cadastroMB.funcionarios}" value="Funcionrios" /></td></tr> <tr><td><h:commandButton action="#{cadastroMB.livros}" value="Livros" /></td></tr> <tr><td><h:commandButton action="#{cadastroMB.locais}" value="Locais" /></td></tr> <tr><td><h:commandButton action="#{loginMB.logout}" value="Sair" /></td></tr> </table>

266

</h:form> </body> </html> </f:view> </jsp:root>

5.8.2 Pginas de Cadastro


Ao contrrio da aplicao anterior, onde havia uma nica pgina para todos os cadastros, aqui utilizaremos uma pgina para cada cadastro. Isso acontece porque temos um ManagedBean para cada cadastro, e ele interage com uma pgina prpria.

cadastro-autor.jsp
<?xml version="1.0" encoding="UTF-8" ?> <jsp:root version="2.0" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:c="http://java.sun.com/jstl/core"> <jsp:directive.page contentType="text/html" /> <jsp:output omit-xml-declaration="no" doctype-root-element="html" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" /> <f:view> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Cadastro de Autores</title> </head> <body> <h1>Cadastro de Autores</h1> <h:form> <h:commandButton action="#{cadastroMB.editar}" value="Incluir" /> </h:form>

267

<f:subview id="listing"> <c:import url="lista-autor.jsp" /> </f:subview> <h:form> <h:commandLink action="#{cadastroMB.admin}">Mdulo Administrativo</h:commandLink> </h:form> </body> </html> </f:view> </jsp:root>

cadastro-cliente.jsp
<?xml version="1.0" encoding="UTF-8" ?> <jsp:root version="2.0" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:c="http://java.sun.com/jstl/core"> <jsp:directive.page contentType="text/html" /> <jsp:output omit-xml-declaration="no" doctype-root-element="html" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" /> <f:view> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Cadastro de Clientes</title> </head> <body> <h1>Cadastro de Clientes</h1> <h:form> <h:commandButton action="#{cadastroMB.editar}" value="Incluir" /> </h:form>

268

<f:subview id="listing"> <c:import url="lista-cliente.jsp" /> </f:subview> <h:form> <h:commandLink action="#{cadastroMB.admin}">Mdulo Administrativo</h:commandLink> </h:form> </body> </html> </f:view> </jsp:root>

cadastro-editora.jsp
<?xml version="1.0" encoding="UTF-8" ?> <jsp:root version="2.0" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:c="http://java.sun.com/jstl/core"> <jsp:directive.page contentType="text/html" /> <jsp:output omit-xml-declaration="no" doctype-root-element="html" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" /> <f:view> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Cadastro</title> </head> <body> <h1>Cadastro de Editoras</h1> <h:form> <h:commandButton action="#{cadastroMB.editar}" value="Incluir" /> </h:form>

269

<f:subview id="listing"> <c:import url="lista-editora.jsp" /> </f:subview> <h:form> <h:commandLink action="#{cadastroMB.admin}">Mdulo Administrativo</h:commandLink> </h:form> </body> </html> </f:view> </jsp:root>

cadastro-funcionario.jsp
<?xml version="1.0" encoding="UTF-8" ?> <jsp:root version="2.0" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:c="http://java.sun.com/jstl/core"> <jsp:directive.page contentType="text/html" /> <jsp:output omit-xml-declaration="no" doctype-root-element="html" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" /> <f:view> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Cadastro de Funcionrios</title> </head> <body> <h1>Cadastro de Funcionrios</h1> <h:form> <h:commandButton action="#{cadastroMB.editar}" value="Incluir" /> </h:form>

270

<f:subview id="listing"> <c:import url="lista-funcionario.jsp" /> </f:subview> <h:form> <h:commandLink action="#{cadastroMB.admin}">Mdulo Administrativo</h:commandLink> </h:form> </body> </html> </f:view> </jsp:root>

cadastro-livro.jsp
<?xml version="1.0" encoding="UTF-8" ?> <jsp:root version="2.0" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:c="http://java.sun.com/jstl/core"> <jsp:directive.page contentType="text/html" /> <jsp:output omit-xml-declaration="no" doctype-root-element="html" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" /> <f:view> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Cadastro de Livros</title> </head> <body> <h1>Cadastro de Livros</h1> <h:form> <h:commandButton action="#{cadastroMB.editar}" value="Incluir" /> </h:form>

271

<f:subview id="listing"> <c:import url="lista-livro.jsp" /> </f:subview> <h:form> <h:commandLink action="#{cadastroMB.admin}">Mdulo Administrativo</h:commandLink> </h:form> </body> </html> </f:view> </jsp:root>

cadastro-local.jsp
<?xml version="1.0" encoding="UTF-8" ?> <jsp:root version="2.0" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:c="http://java.sun.com/jstl/core"> <jsp:directive.page contentType="text/html" /> <jsp:output omit-xml-declaration="no" doctype-root-element="html" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" /> <f:view> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Cadastro de Locais</title> </head> <body> <h1>Cadastro de Locais</h1> <h:form> <h:commandButton action="#{cadastroMB.editar}" value="Incluir" /> </h:form>

272

<f:subview id="listing"> <c:import url="lista-local.jsp" /> </f:subview> <h:form> <h:commandLink action="#{cadastroMB.admin}">Mdulo Administrativo</h:commandLink> </h:form> </body> </html> </f:view> </jsp:root>

As tags f:subview e c:import definem que uma rea ser preenchida com o contedo de outra pgina JSF, importada para a seo indicada. Isso permite dividir as responsabilidades entre pginas. No caso, a rea de listagem criada por uma pgina especfica para isso, e a leitura e compreenso do arquivo fica mais fcil. A tag h:commandLink cria um hiperlink, associado com um mtodo de um ManagedBean.

5.8.3 Pginas de Edio


Cada pgina de cadastro aponta para uma pgina de edio.

edicao-autor.jsp
<?xml version="1.0" encoding="UTF-8" ?> <jsp:root version="2.0" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"> <jsp:directive.page contentType="text/html" /> <jsp:output omit-xml-declaration="no" doctype-root-element="html" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" /> <f:view> <html xmlns="http://www.w3.org/1999/xhtml"> <head>

273

<title>Cadastro de Autores</title> </head> <body> <h1>Cadastro de Autores</h1> <h:form> <table> <tr> <td>Nome:</td> <td><h:inputText value="#{autorMB.bean.nome}"/></td> </tr> <tr> <td>Sobrenome:</td> <td><h:inputText value="#{autorMB.bean.sobrenome}"/></td> </tr> <tr> <td><h:commandButton value="Gravar" action="#{autorMB.gravar}"/></td> <td><h:commandButton value="Retornar" action="#{cadastroMB.cadastroAtual}"/></td> </tr> </table> </h:form> </body> </html> </f:view> </jsp:root>

edicao-cliente.jsp
<?xml version="1.0" encoding="UTF-8" ?> <jsp:root version="2.0" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"> <jsp:directive.page contentType="text/html" />

274

<jsp:output omit-xml-declaration="no" doctype-root-element="html" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" /> <f:view> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Cadastro de Clientes</title> </head> <body> <h1>Cadastro de Clientes</h1> <table border="0"> <tr> <td> <h2>Dados Bsicos</h2> <h:form> <table> <tr> <td>CPF:</td> <td><h:inputText value="#{clienteMB.bean.cpf}" /></td> </tr> <tr> <td>Nome:</td> <td><h:inputText value="#{clienteMB.bean.nome}" /></td> </tr> <tr> <td>Apelido:</td> <td><h:inputText value="#{clienteMB.bean.apelido}" /></td> </tr> <tr> <td>Senha:</td> <td><h:inputSecret value="#{clienteMB.bean.senha}" /></td>

275

</tr> <tr> <td>e-mail:</td> <td><h:inputText value="#{clienteMB.bean.email}" /></td> </tr> <tr> <td><h:commandButton value="Gravar" action="#{clienteMB.gravar}" /></td> <td><h:commandButton value="Retornar" action="#{cadastroMB.cadastroAtual}" /></td> </tr> </table>

</h:form></td> <td> <h2>Telefones</h2> <p> <h:form rendered="#{clienteMB.bean.id != null}"> Telefone: <h:inputText value="#{clienteMB.telefone.numero}" /> <br /> Tipo: <h:selectOneMenu value="#{clienteMB.telefone.tipo}"> <f:selectItems value="#{clienteMB.tiposTelefone}"/> </h:selectOneMenu> <br /> <h:commandButton value="Adicionar telefone" action="#{clienteMB.adicionarTelefone}" /> </h:form> </p> <p>

276

<h:form rendered="#{clienteMB.bean.id != null}"> <h:selectOneMenu value="#{clienteMB.telefone.id}"> <f:selectItems value="#{clienteMB.telefonesCliente}"/> </h:selectOneMenu> <br /> <h:commandButton value="Remover telefone" action="#{clienteMB.removerTelefone}" /> </h:form> </p> </td> </tr> </table> </body> </html> </f:view> </jsp:root>

A tag h:selectOneMenu cria uma caixa de listagem. O item escolhido configura o atributo apontado pelo argumento value. A tag f:selectItems cria as opes da caixa de listagem a partir de uma coleo de objetos SelectItem.

edicao-editora.jsp
<?xml version="1.0" encoding="UTF-8" ?> <jsp:root version="2.0" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"> <jsp:directive.page contentType="text/html" /> <jsp:output omit-xml-declaration="no" doctype-root-element="html" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" /> <f:view>

277

<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Cadastro de Editoras</title> </head> <body> <h1>Cadastro de Editoras</h1> <h:form> <table> <tr> <td>Nome:</td> <td><h:inputText value="#{editoraMB.bean.nome}"/></td> </tr> <tr> <td><h:commandButton value="Gravar" action="#{editoraMB.gravar}"/></td> <td><h:commandButton value="Retornar" action="#{cadastroMB.cadastroAtual}"/></td> </tr> </table> </h:form> </body> </html> </f:view> </jsp:root>

edicao-funcionarios.jsp
<?xml version="1.0" encoding="UTF-8" ?> <jsp:root version="2.0" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"> <jsp:directive.page contentType="text/html" /> <jsp:output omit-xml-declaration="no" doctype-root-element="html" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"

278

doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" /> <f:view> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Cadastro de Funcionrios</title> </head> <body> <h1>Cadastro de Funcionrios</h1> <table border="0"> <tr> <td> <h2>Dados Bsicos</h2> <h:form> <table> <tr> <td>Matrcula:</td> <td><h:inputText value="#{funcionarioMB.funcionario.matricula}" /></td> </tr> <tr> <td>Nome:</td> <td><h:inputText value="#{funcionarioMB.funcionario.nome}" /></td> </tr> <tr> <td>Apelido:</td> <td><h:inputText value="#{funcionarioMB.funcionario.apelido}" /></td> </tr> <tr> <td>Senha:</td> <td><h:inputSecret value="#{funcionarioMB.funcionario.senha}" /></td> </tr> <tr>

279

<td>e-mail:</td> <td><h:inputText value="#{funcionarioMB.funcionario.email}" /></td> </tr> <tr> <td><h:commandButton value="Gravar" action="#{funcionarioMB.gravar}" /></td> <td><h:commandButton value="Retornar" action="#{cadastroMB.cadastroAtual}" /></td> </tr> </table>

</h:form></td> <td> <h2>Telefones</h2> <p> <h:form rendered="#{funcionarioMB.bean.id != null}"> Telefone: <h:inputText value="#{funcionarioMB.telefone.numero}" /> <br /> Tipo: <h:selectOneMenu value="#{funcionarioMB.telefone.tipo}"> <f:selectItems value="#{funcionarioMB.tiposTelefone}"/> </h:selectOneMenu> <br /> <h:commandButton value="Adicionar telefone" action="#{funcionarioMB.adicionarTelefone}" /> </h:form> </p> <p> <h:form rendered="#{funcionarioMB.bean.id != null}"> <h:selectOneMenu value="#{funcionarioMB.telefone.id}">

280

<f:selectItems value="#{funcionarioMB.telefonesFuncionario}"/> </h:selectOneMenu> <br /> <h:commandButton value="Remover telefone" action="#{funcionarioMB.removerTelefone}" /> </h:form> </p> </td> </tr> </table> </body> </html> </f:view> </jsp:root>

edicao-livro.jsp
<?xml version="1.0" encoding="UTF-8" ?> <jsp:root version="2.0" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"> <jsp:directive.page contentType="text/html" /> <jsp:output omit-xml-declaration="no" doctype-root-element="html" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" /> <f:view> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Cadastro de Livros</title> </head> <body> <h1>Cadastro de Livros</h1>

281

<table border="0"> <tr> <td> <h2>Dados Bsicos</h2> <h:form> <table> <tr> <td>ISBN:</td> <td><h:inputText value="#{livroMB.bean.isbn}" /></td> </tr> <tr> <td>Ttulo:</td> <td><h:inputText value="#{livroMB.bean.titulo}" /></td> </tr> <tr> <td>Local:</td> <td> <h:selectOneMenu value="#{livroMB.bean.local.id}"> <f:selectItems value="#{livroMB.locais}"/> </h:selectOneMenu> </td> </tr> <tr> <td>Editora:</td> <td> <h:selectOneMenu value="#{livroMB.bean.editora.id}"> <f:selectItems value="#{livroMB.editoras}"/> </h:selectOneMenu> </td> </tr> <tr>

282

<td>Ano:</td> <td><h:inputText value="#{livroMB.bean.ano}"/></td> </tr> <tr> <td>Preo:</td> <td><h:inputText value="#{livroMB.bean.preco}"/></td> </tr> <tr> <td><h:commandButton value="Gravar" action="#{livroMB.gravar}" /></td> <td><h:commandButton value="Retornar" action="#{cadastroMB.cadastroAtual}" /></td> </tr> </table> </h:form></td> <td> <h2>Autores</h2> <h:form rendered="#{livroMB.bean.id != null}"> Autor: <h:selectOneMenu value="#{livroMB.autor.id}"> <f:selectItems value="#{livroMB.autores}"/> </h:selectOneMenu> <br /> <h:commandButton value="Adicionar autor" action="#{livroMB.adicionarAutor}" /> </h:form> <h:form> <h:selectOneMenu value="#{livroMB.autor.id}"> <f:selectItems value="#{livroMB.autoresLivro}"/> </h:selectOneMenu> <br />

283

<h:commandButton value="Remover autor" action="#{livroMB.removerAutor}" /> </h:form></td>

</tr> </table> </body> </html> </f:view> </jsp:root>

edicao-local.jsp
<?xml version="1.0" encoding="UTF-8" ?> <jsp:root version="2.0" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"> <jsp:directive.page contentType="text/html" /> <jsp:output omit-xml-declaration="no" doctype-root-element="html" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" /> <f:view> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Cadastro de Locais</title> </head> <body> <h1>Cadastro de Locais</h1> <h:form> <table> <tr> <td>Nome:</td>

284

<td><h:inputText value="#{localMB.bean.nome}"/></td> </tr> <tr> <td><h:commandButton value="Gravar" action="#{localMB.gravar}"/></td> <td><h:commandButton value="Retornar" action="#{cadastroMB.cadastroAtual}"/></td> </tr> </table> </h:form> </body> </html> </f:view> </jsp:root>

5.8.4 Pginas de Listagem


Como j vimos, cada pgina de cadastro importa uma pgina de listagem. Vamos ver primeiro uma das pginas para discutir os componentes que ela utiliza.

lista-autor.jsp
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <h:form> Busca <h:selectOneMenu value="#{autorMB.where}"> <f:selectItem itemValue="nome" itemLabel="Nome" /> <f:selectItem itemValue="sobrenome" itemLabel="Sobrenome" /> </h:selectOneMenu> <h:inputText value="#{autorMB.searchKey}" /> <h:commandButton action="#{cadastroMB.autores}" value="OK"> </h:commandButton> <h:outputText value="#{exceptionMB.exception}" /> </h:form> <h:dataTable value="#{autorMB.lista}" var="row" border="1">

285

<h:column> <f:facet name="header"> <h:outputText value="Id" /> </f:facet> <h:form> <h:commandLink action="#{cadastroMB.editar}" value="#{row.id}"> <f:setPropertyActionListener value="#{row}" target="#{autorMB.bean}" /> </h:commandLink> </h:form> </h:column> <h:column> <f:facet name="header"> <h:form> <h:commandLink action="#{cadastroMB.autores}" value="Sobrenome"> <f:setPropertyActionListener value="sobrenome" target="#{autorMB.order}" /> </h:commandLink> </h:form> </f:facet> <h:outputText value="#{row.sobrenome}" /> </h:column> <h:column> <f:facet name="header"> <h:form> <h:commandLink action="#{cadastroMB.autores}" value="Nome"> <f:setPropertyActionListener value="nome" target="#{autorMB.order}" /> </h:commandLink> </h:form> </f:facet> <h:outputText value="#{row.nome}" /> </h:column> <h:column>

286

<f:facet name="header"> <h:outputText value="Remover" /> </f:facet> <h:form> <h:commandButton action="#{autorMB.remover}" value="X"> <f:setPropertyActionListener value="#{row}" target="#{autorMB.bean}" /> </h:commandButton> </h:form> </h:column> </h:dataTable>

O componente h:dataTable constri uma tabela HTML populada com o contedo de uma coleo de dados itervel. O argumento value aponta para o mtodo que retorna a coleo, enquanto row armazena, a cada iterao, o objeto atual da coleo. A tag h:column define uma coluna para a tabela. A tag f:facet cria um cabealho para a coluna. A tag f:setPropertyActionListener atualiza um atributo, definido pelo argumento target, com o valor especificado pelo argumento value. A atualizao feita quando ocorre o componente que contm a tag sofre uma ao.

lista-cliente.jsp
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <h:form> Busca <h:selectOneMenu value="#{clienteMB.where}"> <f:selectItem itemValue="cpf" itemLabel="CPF" /> <f:selectItem itemValue="nome" itemLabel="Nome" /> <f:selectItem itemValue="apelido" itemLabel="Apelido" /> <f:selectItem itemValue="email" itemLabel="e-mail" /> </h:selectOneMenu> <h:inputText value="#{clienteMB.searchKey}" /> <h:commandButton action="#{cadastroMB.clientes}" value="OK">

287

</h:commandButton> <h:outputText value="#{exceptionMB.exception}"/> </h:form> <h:dataTable value="#{clienteMB.lista}" var="row" border="1"> <h:column> <f:facet name="header"> <h:outputText value="Id" /> </f:facet> <h:form> <h:commandLink action="#{cadastroMB.editar}" value="#{row.id}"> <f:setPropertyActionListener value="#{row}" target="#{clienteMB.bean}"/> </h:commandLink> </h:form> </h:column> <h:column> <f:facet name="header"> <h:form> <h:commandLink action="#{cadastroMB.clientes}" value="CPF"> <f:setPropertyActionListener value="cpf" target="#{clienteMB.order}" /> </h:commandLink> </h:form> </f:facet> <h:outputText value="#{row.cpf}" /> </h:column> <h:column> <f:facet name="header"> <h:form> <h:commandLink action="#{cadastroMB.clientes}" value="Nome"> <f:setPropertyActionListener value="nome" target="#{clienteMB.order}" /> </h:commandLink> </h:form>

288

</f:facet> <h:outputText value="#{row.nome}" /> </h:column> <h:column> <f:facet name="header"> <h:form> <h:commandLink action="#{cadastroMB.clientes}" value="Apelido"> <f:setPropertyActionListener value="apelido" target="#{clienteMB.order}" /> </h:commandLink> </h:form> </f:facet> <h:outputText value="#{row.apelido}" /> </h:column> <h:column> <f:facet name="header"> <h:form> <h:commandLink action="#{cadastroMB.clientes}" value="e-mail"> <f:setPropertyActionListener value="email" target="#{clienteMB.order}" /> </h:commandLink> </h:form> </f:facet> <h:outputText value="#{row.email}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Remover" /> </f:facet> <h:form> <h:commandButton action="#{clienteMB.remover}" value="X"> <f:setPropertyActionListener value="#{row}" target="#{clienteMB.bean}"/> </h:commandButton>

289

</h:form> </h:column> </h:dataTable>

lista-editora.jsp
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <h:form> Busca <h:selectOneMenu value="#{editoraMB.where}"> <f:selectItem itemValue="nome" itemLabel="Nome" /> </h:selectOneMenu> <h:inputText value="#{editoraMB.searchKey}" /> <h:commandButton action="#{cadastroMB.editoras}" value="OK"> </h:commandButton> <h:outputText value="#{exceptionMB.exception}"/> </h:form> <h:dataTable value="#{editoraMB.lista}" var="row" border="1"> <h:column> <f:facet name="header"> <h:outputText value="Id" /> </f:facet> <h:form> <h:commandLink action="#{cadastroMB.editar}" value="#{row.id}"> <f:setPropertyActionListener value="#{row}" target="#{editoraMB.bean}"/> </h:commandLink> </h:form> </h:column> <h:column> <f:facet name="header">

290

<h:form> <h:commandLink action="#{cadastroMB.editoras}" value="Nome"> <f:setPropertyActionListener value="nome" target="#{editoraMB.order}" /> </h:commandLink> </h:form> </f:facet> <h:outputText value="#{row.nome}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Remover" /> </f:facet> <h:form> <h:commandButton action="#{editoraMB.remover}" value="X"> <f:setPropertyActionListener value="#{row}" target="#{editoraMB.bean}"/> </h:commandButton> </h:form> </h:column> </h:dataTable>

lista-funcionario.jsp
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <h:form> Busca <h:selectOneMenu value="#{funcionarioMB.where}"> <f:selectItem itemValue="matricula" itemLabel="Matrcula" /> <f:selectItem itemValue="nome" itemLabel="Nome" /> <f:selectItem itemValue="apelido" itemLabel="Apelido" /> <f:selectItem itemValue="email" itemLabel="e-mail" /> </h:selectOneMenu>

291

<h:inputText value="#{funcionarioMB.searchKey}" /> <h:commandButton action="#{cadastroMB.funcionarios}" value="OK"> </h:commandButton> <h:outputText value="#{exceptionMB.exception}"/> </h:form> <h:dataTable value="#{funcionarioMB.lista}" var="row" border="1"> <h:form><h:outputText value="#{cadastroMB.exception}"/></h:form> <h:column> <f:facet name="header"> <h:outputText value="Id" /> </f:facet> <h:form> <h:commandLink action="#{cadastroMB.editar}" value="#{row.id}"> <f:setPropertyActionListener value="#{row}" target="#{funcionarioMB.bean}"/> </h:commandLink> </h:form> </h:column> <h:column> <f:facet name="header"> <h:form> <h:commandLink action="#{cadastroMB.funcionarios}" value="Matrcula"> <f:setPropertyActionListener value="matricula" target="#{funcionarioMB.order}" /> </h:commandLink> </h:form> </f:facet> <h:outputText value="#{row.matricula}" /> </h:column> <h:column> <f:facet name="header"> <h:form> <h:commandLink action="#{cadastroMB.funcionarios}" value="Nome">

292

<f:setPropertyActionListener value="nome" target="#{funcionarioMB.order}" /> </h:commandLink> </h:form> </f:facet> <h:outputText value="#{row.nome}" /> </h:column> <h:column> <f:facet name="header"> <h:form> <h:commandLink action="#{cadastroMB.funcionarios}" value="Apelido"> <f:setPropertyActionListener value="apelido" target="#{funcionarioMB.order}" /> </h:commandLink> </h:form>

</f:facet> <h:outputText value="#{row.apelido}" /> </h:column> <h:column> <f:facet name="header"> <h:form> <h:commandLink action="#{cadastroMB.funcionarios}" value="e-mail"> <f:setPropertyActionListener value="email" target="#{funcionarioMB.order}" /> </h:commandLink> </h:form> </f:facet> <h:outputText value="#{row.email}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Remover" /> </f:facet>

293

<h:form> <h:commandButton action="#{funcionarioMB.remover}" value="X"> <f:setPropertyActionListener value="#{row}" target="#{funcionarioMB.bean}"/> </h:commandButton> </h:form> </h:column> </h:dataTable>

lista-livro.jsp
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <h:form> Busca <h:selectOneMenu value="#{livroMB.where}"> <f:selectItem itemValue="isbn" itemLabel="ISBN" /> <f:selectItem itemValue="titulo" itemLabel="Ttulo" /> <f:selectItem itemValue="editora.nome" itemLabel="Editora" /> <f:selectItem itemValue="local.nome" itemLabel="Local" /> </h:selectOneMenu> <h:inputText value="#{livroMB.searchKey}" /> <h:commandButton action="#{cadastroMB.livros}" value="OK"> </h:commandButton> <h:outputText value="#{exceptionMB.exception}" /> </h:form> <h:dataTable value="#{livroMB.lista}" var="row" border="1"> <h:column> <f:facet name="header"> <h:outputText value="Id" /> </f:facet> <h:form> <h:commandLink action="#{cadastroMB.editar}" value="#{row.id}">

294

<f:setPropertyActionListener value="#{row}" target="#{livroMB.bean}" /> </h:commandLink> </h:form> </h:column> <h:column> <f:facet name="header"> <h:form> <h:commandLink action="#{cadastroMB.livros}" value="ISBN"> <f:setPropertyActionListener value="isbn" target="#{livroMB.order}" /> </h:commandLink> </h:form> </f:facet> <h:outputText value="#{row.isbn}" /> </h:column> <h:column> <f:facet name="header"> <h:form> <h:commandLink action="#{cadastroMB.livros}" value="Ttulo"> <f:setPropertyActionListener value="titulo" target="#{livroMB.order}" /> </h:commandLink> </h:form> </f:facet> <h:outputText value="#{row.titulo}" /> </h:column> <h:column> <f:facet name="header"> <h:form> <h:commandLink action="#{cadastroMB.livros}" value="Local"> <f:setPropertyActionListener value="local.nome" target="#{livroMB.order}" />

295

</h:commandLink> </h:form> </f:facet> <h:outputText value="#{row.local.nome}" /> </h:column> <h:column> <f:facet name="header"> <h:form> <h:commandLink action="#{cadastroMB.livros}" value="Editora"> <f:setPropertyActionListener value="editora.nome" target="#{livroMB.order}" /> </h:commandLink> </h:form>

</f:facet> <h:outputText value="#{row.editora.nome}" /> </h:column> <h:column> <f:facet name="header"> <h:form> <h:commandLink action="#{cadastroMB.livros}" value="Ano"> <f:setPropertyActionListener value="ano" target="#{livroMB.order}" /> </h:commandLink> </h:form> </f:facet> <h:outputText value="#{row.ano}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Preo" /> </f:facet>

296

<h:outputText value="#{row.preco}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Remover" /> </f:facet> <h:form> <h:commandButton action="#{livroMB.remover}" value="X"> <f:setPropertyActionListener value="#{row}" target="#{livroMB.bean}" /> </h:commandButton> </h:form> </h:column> </h:dataTable>

lista-local.jsp
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <h:form> Busca <h:selectOneMenu value="#{localMB.where}"> <f:selectItem itemValue="nome" itemLabel="Nome" /> </h:selectOneMenu> <h:inputText value="#{localMB.searchKey}" /> <h:commandButton action="#{cadastroMB.locais}" value="OK"> </h:commandButton> <h:outputText value="#{exceptionMB.exception}" /> </h:form> <h:dataTable value="#{localMB.lista}" var="row" border="1"> <h:column> <f:facet name="header"> <h:outputText value="Id" />

297

</f:facet> <h:form> <h:commandLink action="#{cadastroMB.editar}" value="#{row.id}"> <f:setPropertyActionListener value="#{row}" target="#{localMB.bean}" /> </h:commandLink> </h:form> </h:column> <h:column> <f:facet name="header"> <h:form> <h:commandLink action="#{cadastroMB.locais}" value="Nome"> <f:setPropertyActionListener value="nome" target="#{localMB.order}" /> </h:commandLink> </h:form> </f:facet> <h:outputText value="#{row.nome}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Remover" /> </f:facet> <h:form> <h:commandButton action="#{localMB.remover}" value="X"> <f:setPropertyActionListener value="#{row}" target="#{localMB.bean}" /> </h:commandButton> </h:form> </h:column> </h:dataTable>

298

5.9 Executando a Aplicao


Lembre-se de que uma aplicao Java uma grande rede de dependncias entre bibliotecas. Ao executar a aplicao com a opo Run/Run on Server, o Eclipse ir tentar publicar a aplicao no servidor selecionado, o que significa que ele vai transferir para o servidor todas as classes compiladas, e APIs necessrias. No processo de desenvolvimento, isso pode falhar com mais frequncia do que se possa imaginar. Ento, se por acaso for lanada uma exceo alertando sobre a ausncia da classe ConfigureListener, copie os arquivos .jar do JSF para o diretrio de bibliotecas do servidor de aplicao. Por exemplo, no nosso caso, copiaramos para o diretrio lib do Tomcat. A complexidade do gerenciamento de dependncias no Java leva uma questo: necessrio uma infraestrutura que ajude a manter as dependncias, garantindo que tudo que foi criado no desenvolvimento passe para o ambiente de produo, e ainda que haja um controle das verses de cada API e biblioteca das quais a aplicao depende.

299

5.10 Concluses
Terminamos assim a implementao da aplicao em trs camadas usando Hibernate e JSF. A estrutura final de pacotes da aplicao pode ser vista na figura 27.

Figura 27: Estrutura de pacotes da aplicao livrariajsf


Iremos comparar agora essa aplicao com a anterior, que utilizava somente Servlets/JSP e JDBC, e fazer nossas consideraes. Com o uso de Hibernate, eliminamos a dependncia da aplicao com a SQL do banco de dados. Alm disso, a classe HibernateUtil muito mais simples do que a DAOEngine, porque todas as funcionalidades que precisamos criar para a ltima j esto disponveis por meio do objeto de sesso da primeira.

300

O Hibernate prov um controle de transao, o que permite que recuperemos o estado do banco em caso de falha. O uso das anotaes do Hibernate para o mapeamento objeto-relacional permitiu a eliminao de cinco classes da camada de modelo. A princpio, pode parecer que a camada de controle ficou mais complexa, porque livrariajsp tinha cinco classes nessa camada, e livrariajsf tem catorze. No entanto, devese considerar que somente duas classes de livrariajsp, GravarServlet e RemoverServlet tinham muitos mtodos, alm de misturar vrias regras de negcio. O uso de ManagedBeans permitiu o estabelecimento de mais pontos de controle por meio de classes mais simples. O que ocorreu na verdade foi que o domnio de cada problema (no caso, um determinado cadastro) foi estabelecido de forma bem definida. As abstraes da camada de controle permitem que o programador tenha vrias vises de alto nvel sobre a camada de controle, focando as funcionalidades gerais, comportamentos genricos entre alguns ManagedBeans, controle de acesso e autenticao. O uso de JSF tornou desnecessrio o pacote view, criado em livrariajsp, porque o ManagedBean prov todo o controle necessrio sobre os dados da camada de viso. Assim, a camada de viso em livrariajsf constituda to somente de pginas Web. As abstraes proporcionadas pelo Hibernate e pela implementao JSF permitiram, para esta aplicao livrariajsf, que o programador ficasse mais focado na implementao de regras de negcio, e menos com questes de infraestrutura. Embora alguns elementos tenham se fragmentado (classes de controle e pginas JSF), a possibilidade de reuso aumentou. No prximo captulo, veremos como fica ainda mais fcil lidar com essas questes de infraestrutura de aplicao com o uso de um framework integrador.

301

CAPTULO 6 Livraria com Demoiselle Framework


Neste captulo, faremos a implementao dos mesmos casos de uso tratados no captulo anterior, usando o Demoiselle Framework. Este captulo se concentrar em mostrar como utilizar o Demoiselle Framework, deixando a fundamentao terica para o captulo seguinte. Para acompanhar este captulo, voc precisa ter instalado o Demoiselle Eclipse 3.5.

6.1 Demoiselle Framework


Por uma questo didtica, e para no sobrecarregar sua mente de forma precipitada, iremos apresentar aqui apenas uma viso geral do que o Demoiselle Framework. O prximo captulo se aprofundar em sua arquitetura. Demoiselle Framework uma integrao de vrias tecnologias de desenvolvimento de software para Java e tambm consiste em uma arquitetura de referncia para aplicaes. Seu objetivo prover uma infraestrutura para a construo de aplicaes Java para Web. Demoiselle Framework prov ao desenvolvedor Java independncia de fornecedores, por meio da adoo de padres aceitos mundialmente. Demoiselle Framework se baseia nas especificaes do JCP, de modo a no ficar aprisionado por implementaes particulares. Podemos destacar quatro caractersticas importantes de aplicaes construdas com o Demoiselle Framework:

As camadas so independentes, porque referncias a objetos so obtidas indiretamente por meio de programao orientada a aspectos (AOP). A aplicao independente da interface, pois utiliza JSF. A aplicao independente de banco de dados, pois utiliza JPA. Os servios consumidos por todas as camadas esto disponveis por meio de contextos.

302

6.2 Demoiselle Infra


O projeto Demoiselle Infra mantm um conjunto de pacotes de software destinados a auxiliar no preparo dos ambientes de desenvolvimento, homologao baseados no Demoiselle Framework. Atualmente esto disponveis pacotes exclusivamente para a plataforma GNU/Linux e distribuies baseadas no Debian como o Ubuntu. Para criar nossa aplicao com Demoiselle Framework, usaremos o Demoiselle Eclipse, que est disponvel como um pacote Debian. O Demoiselle Eclipse inclui o Eclipse Galileo, os plugins .m2 para Maven, AJDT para AspectJ e Demoiselle Wizard. Alm disso, ele j traz todas as dependncias necessrias para uma aplicao Demoiselle Framework. A instalao do ambiente de desenvolvimento do Demoiselle (demoiselle-dev) bastante simples para usurios Debian. O primeiro passo incluir a seguinte linha no arquivo /etc/apt/sources.list:
deb ftp://sagres.c3sl.ufpr.br/demoiselle hardy stable

O segundo passo atualizar os ndices do APT (Advanced Package Tool) por meio do seguinte comando do terminal:
apt-get update

O ltimo passo instalar os pacotes do Demoiselle com o comando a seguir:


apt-get install demoiselle-dev

Isso criar no menu principal da interface grfica um subitem dentro de 'Programao', chamado Demoiselle Eclipse 3.5.

6.3 Criao do Projeto Demoiselle Framework


At agora, tivemos que criar a estrutura dos projetos manualmente. Com Demoiselle Framework, possvel criar um projeto a partir de uma estrutura pr-montada, um arqutipo de aplicao. Isso possvel graas ao Maven, um software para gesto de projetos escrito em Java. O Maven pode recuperar uma estrutura definida por um arqutipo, que nada mais que um arquivo .jar com classes que seguem um padro pr-definido. A partir de um arqutipo, o Maven pode criar pacotes, diretrios e arquivos, com nomes e contedo construdos de acordo com parmetros. Em seu sub-projeto de componentes, o Demoiselle possui um arqutipo para aplicaes Web, que j contm as dependncias para os componentes mais utilizados. o demoiselle-archetype-webapp-sample. Utilizaremos aqui a verso 1.1.0.

303

O primeiro passo criar um projeto Maven. Selecione o projeto Maven no menu File>New->Project, conforme a figura 28.

Figura 28: Criao de projeto Maven


Aps selecionar o tipo de projeto Maven, clique no boto Next. Voc pode ignorar a tela imediatamente seguinte, pois no h nada para ser alterado. Clique em Next novamente. A prxima tela a seleo de arqutipos. Os arqutipos so recuperados por meio de um arquivo chamado archetype-catalog.xml. O campo Catalog informa onde o Eclipse deve procurar por esse arquivo. Escolha a opo Demoiselle, que aponta para o catlogo de arqutipos residente no diretrio do pacote demoiselle-dev. O diretrio padro /opt/demoiselle/tool/maven2-local-repo.

304

Ao selecionar o catlogo, so listados todos os arqutipos registrados nele. Escolha o demoiselle-archetype-webapp-sample 1.1.0, conforme a figura 29.

Figura 29: Seleo do catlogo de arqutipos e arqutipo Maven


Na prxima tela ns configuramos a raiz dos pacotes da aplicao, composta de duas partes, Group Id e Artifact Id, sendo este ltimo o nome do projeto. O nosso Group Id ser samples.web e o Artifact Id ser livrariademoiselle, conforme a figura 30. Aps clicar no boto Finish, basta aguardar enquanto o Maven cria o projeto a partir das definies constantes no arqutipo. Aps a concluso do processo, voc deve ter um projeto com a estrutura apresentada na figura 31. Alm de ter essa funcionalidade de criar projetos a partir de arqutipos, o Maven tambm prov um meio simples e fcil de controlar as dependncias da aplicao. Todas as dependncias so registradas em um arquivo chamado pom.xml. Em vez de ter o trabalho de baixar cada API ou biblioteca para um diretrio do JAVA_HOME, ou adicionar pelo Build Path, basta incluir uma tag nesse arquivo com o site e a verso da dependncia. O prprio Maven se encarregar de baix-la, e manter tudo em um diretrio centralizado. No caso do demoiselle-dev, o diretrio o /opt/demoiselle/tool/maven2-local-repo. A organizao das dependncias em um diretrio padro ajuda os programadores,

305

evitando quebras na distribuio da aplicao por falta de algum arquivo. E tambm permite um controle eficaz dos nmeros de verso de cada API ou biblioteca utilizadas.

Figura 30: Parmetros do arqutipo Maven


Aps a criao do projeto, precisamos configurar a aplicao e criar as classes de cada camada.

6.4 Camada de Persistncia 6.4.1 Criando os Modelos


Iremos utilizar a abstrao do Demoiselle Framework para o Hibernate. Primeiro, Tudo o que fizemos na aplicao livrariajsf para a camada de modelos ser reaproveitado. As nicas mudanas sero os nomes dos pacotes e o fato de que a interface IModel herdar de IPojo, que a interface padro dos modelos no Demoiselle Framework. As generalizaes dos POJOs ficaro no samples.web.livrariademoiselle.bean. Abaixo, a nica interface alterada: pacote

IModel
public interface IModel extends IPojo { public Integer getId();

306

public void setId(Integer id); }

Figura 31: Estrutura de um projeto Demoiselle Framework 307

As classes modelo concretas ficararo samples.web.livrariademoiselle.bean.implementation.

no

pacote

Tambm precisamos incluir a dependncia ao banco PostgreSQL no arquivo pom.xml. Dentro da tag dependencies, inclua o seguinte trecho de cdigo:
<dependency> <groupId>postgresql</groupId> <artifactId>postgresql</artifactId> <version>8.4-701.jdbc3</version> </dependency>

6.4.2 Criando os DAOs


Demoiselle Framework utiliza a especificao JPA para conexo com banco de dados e mapeamento objeto-relacional. Isso confere liberdade de escolha para o programador, porque qualquer implementao de JPA pode ser utilizada na camada de persistncia. Os captulos anteriores trouxeram o fundamento necessrio para a utilizao do Demoiselle. Por isso no iremos agora repetir o que no for realmente necessrio. Iremos mostrar como se cria um DAO no Demoiselle Framework, usando JPA, e voc estar habilitado a criar os demais, pois seguem o mesmo padro. Demoiselle Framework realiza injeo de dependncias entre camadas. Isso significa que classes especficas no so utilizadas diretamente. Em seu lugar so usadas interfaces. As interfaces dizem quais mtodos so esperados, e em tempo de compilao, a implementao adequada 'injetada' na varivel de referncia. Por isso, primeiro criamos uma interface para o DAO, e ento fazemos a classe que a implementa. Vamos utilizar como exemplo o DAO do modelo Autor. A interface a seguinte:

IAutorDAO
public interface IAutorDAO extends IDAO<Autor> { public PagedResult<Autor> listar(Page pagina); public List<Autor> listar(); public PagedResult<Autor> filtrar(Autor Autor, Page pagina); public Autor buscar(Autor Autor); }

308

A classe que implementa essa interface fica assim:

AutorDAO
public class AutorDAO extends JPAExtensionDAO<Autor> implements IAutorDAO {

public Autor buscar(Autor autor) { return findById(autor.getId()); }

public PagedResult<Autor> filtrar(Autor autor, Page pagina) { return findByExample(autor, pagina); }

public PagedResult<Autor> listar(Page pagina) { return findByJPQL("select a FROM Autor a ORDER BY a.nome ASC", pagina); }

public List<Autor> listar() { return findAll(); } }

Basta agora seguir os mesmos passos para criar os demais DAOs.

6.4.3 Testando a Camada de Persistncia


O teste integrado que verifica se a camada de persistncia funciona similar ao que foi feito para a aplicao livrariajsf. Vamos indicar aqui apenas o que diferente. Prosseguindo com o mesmo exemplo, iremos usar o teste de persistncia do modelo Autor. A primeira mudana no atributo esttico do DAO do modelo Autor. No colocaremos mais o construtor da classe AutorDAO. Em vez disso, escreveremos assim:
@Injection

309

private static IAutorDAO autorDAO;

Isso indica que o atributo autorDAO sofrer uma injeo de dependncia, ou seja, a instncia ser atribuda em tempo de compilao. Para que isso ocorra, preciso que a classe de teste implemente uma interface do framework chamada IFacade. Outra mudana a inicializao (e encerramento) do contexto de transao. Como o teste executado fora do framework, precisamos fazer isso explicitamente. Inclumos o cdigo do contexto de transao nos mtodos setUp e tearDown da classe de teste, que, respectivamente, so executados antes e depois de cada mtodo de teste. Eis o cdigo:
public void setUp() { WebTransactionContext.getInstance().init(); } public void tearDown() { WebTransactionContext.getInstance().end(); }

As duas ltimas alteraes so nos nomes dos mtodos utilizados. Em vez de fetchOne, usaremos buscar, pois este ltimo o que foi definido pela interface IAlunoDAO. E em vez do mtodo delete para remover, usaremos remove.

6.4.4 Classes e Arquivos Auxilares da Camada de Persistncia


Estamos utilizando a implementao TopLink do JPA. A seguir, temos o contedo do arquivo persistence.xml, que fica no diretrio META-INF. Esse arquivo tem um propsito similar ao hibernate.cfg.xml do Hibernate. Ele contm a configurao do JPA para a aplicao. Alm da configurao do provedor de persistncia TopLink, o arquivo contm comentada a configurao para o EclipseLink, mostrando como as propriedades so padronizadas.

persistence.xml
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd" version="1.0">

310

<persistence-unit name="LivrariaPU" transaction-type="RESOURCE_LOCAL">

<!-- JPA Provider Definition --> <!-<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> -->

<provider>oracle.toplink.essentials.PersistenceProvider</provider>

<class>samples.web.livrariademoiselle.bean.implementation.Autor</class> <class>samples.web.livrariademoiselle.bean.implementation.Cliente</class> <class>samples.web.livrariademoiselle.bean.implementation.Editora</class> <class>samples.web.livrariademoiselle.bean.implementation.Funcionario</class> <class>samples.web.livrariademoiselle.bean.implementation.ItemPedido</class> <class>samples.web.livrariademoiselle.bean.implementation.Livro</class> <class>samples.web.livrariademoiselle.bean.implementation.Local</class> <class>samples.web.livrariademoiselle.bean.implementation.Pedido</class> <class>samples.web.livrariademoiselle.bean.implementation.Telefone</class>

<!-- EclipseLink JPA Settings --> <!-<properties> <property name="eclipselink.target-database" value="PostgreSQL" /> <property name="eclipselink.logging.level" value="FINE" /> <property name="eclipselink.ddl-generation" value="create-tables" /> <property name="eclipselink.ddl-generation.output-mode" value="database" /> <property name="eclipselink.session.customizer" value="samples.web.livrariademoiselle.persistence.config.EclipseLinkSessionCustomizer" /> <property name="eclipselink.jdbc.driver"

311

value="org.postgresql.Driver" /> <property name="eclipselink.jdbc.url" value="jdbc:postgresql://localhost/postgres" /> <property name="eclipselink.jdbc.user" value="postgres" /> <property name="eclipselink.jdbc.password" value="postgres" /> </properties> -->

<!-- TopLink JPA Settings --> <properties> <property name="toplink.target-database" value="PostgreSQL" /> <property name="toplink.logging.level" value="FINE" /> <property name="toplink.ddl-generation" value="create-tables" /> <property name="toplink.ddl-generation.output-mode" value="database" /> <property name="toplink.session.customizer" value="samples.web.livrariademoiselle.persistence.config.TopLinkSessionCustomizer" /> <property name="toplink.jdbc.driver" value="org.postgresql.Driver" /> <property name="toplink.jdbc.url" value="jdbc:postgresql://localhost/postgres" /> <property name="toplink.jdbc.user" value="postgres" /> <property name="toplink.jdbc.password" value="postgres" /> </properties> </persistence-unit> </persistence>

O nome da unidade de persistncia deve ser definido em uma propriedade do arquivo demoiselle.properties, assim:
framework.demoiselle.persistence.default_persistence_unit=LivrariaPU

preciso incluir no arquivo pom.xml do projeto as dependncias da implementao JPA. Para o caso da TopLink, o seguinte trecho de cdigo deve ser includo dentro da tag dependencies:
<dependency> <groupId>toplink.essentials</groupId> <artifactId>toplink-essentials</artifactId>

312

<version>2.1-60f</version> </dependency> <dependency> <groupId>toplink.essentials</groupId> <artifactId>toplink-essentials-agent</artifactId> <version>2.1-60f</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>3.2.1.ga</version> <scope>provided</scope> </dependency>

Alm disso, especificamente para o Tomcat, necessrio definir uma classe que customize a sesso para o provedor de persistncia. Essa classe est referenciada no arquivo persistence.xml, a TopLinkSessionCustomizer, cujo cdigo o seguinte:
public class TopLinkSessionCustomizer implements SessionCustomizer {

public void customize(Session session) throws Exception { JNDIConnector connector = (JNDIConnector) session.getLogin().getConnector(); connector.setLookupType(JNDIConnector.STRING_LOOKUP);

prepareForPostgreSQL(); }

private void prepareForPostgreSQL() { PostgreSQLPlatform.setShouldIgnoreCaseOnFieldComparisons(true); }

313

6.5 Camada de Negcio


Demoiselle Framework prope uma estrutura diferente para camadas. Em vez de seguir estritamente o MVC, ele introduz uma camada chamada Negcio entre a Persistncia e o Controle. O objetivo dessa camada conter as regras de negcio, de forma a desacopl-las do modelo. Assim, a camada de persistncia se limita a prover os dados, sem armazenar a lgica para trat-los. Assim como foi para com os DAOs, os objetos de negcio so criados por classes que implementam interfaces padronizadas. Vamos usar o modelo Autor como exemplo. As regras de negcio de Autor ficariam em uma classe chamada AutorBC, que implementaria uma classe IAutorBC, herdeira de IBusinessController. A classe de negcio utiliza injeo de dependncia para manipular o DAO de Autor sem ficar preso implementao. IAutorDAO fica no pacote samples.web.livrariademoiselle.business AutorDAO, sua implementao, fica no samples.web.livrariademoiselle.business.implementation. enquanto pacote

IAutorDAO
public interface IAutorBC extends IBusinessController { public void incluir(Autor autor); public void alterar(Autor autor); public void excluir(Autor autor); public Autor buscar(Autor aluno); public PagedResult<Autor> listar(Page pagina); public PagedResult<Autor> filtrar(Autor aluno, Page pagina); }

AutorDAO
public class AutorBC implements IAutorBC { @Injection private IAutorDAO autorDAO;

public void alterar(Autor autor) { autorDAO.insert(autor); }

314

public Autor buscar(Autor autor) { return autorDAO.buscar(autor); }

public void excluir(Autor autor) { autorDAO.remove(autor); }

public PagedResult<Autor> filtrar(Autor autor, Page pagina) { return autorDAO.filtrar(autor, pagina); }

public void incluir(Autor autor) { autorDAO.insert(autor); }

public PagedResult<Autor> listar(Page pagina) { return autorDAO.listar(pagina); }

6.5.1 Controle de Acesso


Demoiselle Framework utiliza a especificao JAAS para fazer controle de permisses baseado em papis. Assim como fizemos na aplicao livrariajsf, podemos ter uma classe de constantes, com os nomes dos papis. Mas em vez de utilizar uma estrutura de deciso do tipo SE... ENTO... SENO..., utilizamos uma anotao. Supondo que tenhamos a classe AliasRole no pacote constant, podemos utiilizar a seguinte anotao para restringir o acesso ao mtodo excluir de AutorBC:
@RequiredRole(roles={AliasRole.ADMINISTRADOR, AliasRole.REMOVEDOR})

315

public void excluir(Autor autor) { autorDAO.remove(autor); }

6.6 Camada de Controle e Viso


A camada de Controle e Viso do Demoiselle Framework totalmente baseada em JSF. Por isso quase tudo o que foi criado na aplicao livrariajsf ser reaproveitado. Assim, s discutiremos as mudanas necessrias. O controle de acesso as pginas no ser realizado com estruturas de deciso SE... ENTO... SENO. Nenhuma pgina, exceto a de login, ser acessvel se o usurio no estiver autenticado. Para isso, todas as pginas JSF que criamos sero movidas para o diretrio src/main/webapp/private/pages. No arquivo faces-config.xml basta acrescentar o prefixo /private/pages/ nas tags <to-view-id>. Os ManagedBeans iro herdar da classe AbstractManagedBean, para que possamos fazer a injeo de dependncia do objeto de negcio. No ser mais possvel ter os mtodos gravar e remover centralizados, por causa do mecanismo de injeo, mas sua implementao ser bem simples. A seguir temos um exemplo do ManagedBean para o modelo Autor.

AutorMB
public class AutorMB extends AbstractManagedBean { @Injection private IAutorBC autorBC; private Autor bean; private PagedResultDataModel<Autor> listAutor;

public AutorMB() { this.bean = new Autor(); this.listAutor = new PagedResultDataModel<Autor>(); }

public void atualizaListaAutor() {

316

Page primeiraPagina = new Page(getRows(), 1); PagedResult<Autor> result = autorBC.listar(primeiraPagina); listAutor.bind(result); }

public void setBean(Autor bean) { this.bean = bean; }

public Autor getBean() { return bean; }

public void setListAutor(PagedResultDataModel<Autor> listAutor) { this.listAutor = listAutor; }

public PagedResultDataModel<Autor> getListAutor() { return listAutor; }

public String gravar() { try { if (this.bean.getId()==null) autorBC.incluir(this.bean); else autorBC.alterar(this.bean); for (IMessage imsg : WebMessageContext.getInstance().getMessages()) {

addMessage(imsg);
} } catch (ApplicationRuntimeException e) {

317

addMessage(e.getObjectMessage(), e);
} WebMessageContext.getInstance().clear(); return AliasNavigationRule.ALIAS_AUTOR_EDITAR; }

public String remover() { try { autorBC.excluir(this.bean); for (IMessage imsg : WebMessageContext.getInstance().getMessages()) {

addMessage(imsg);
} } catch (ApplicationRuntimeException e) {

addMessage(e.getObjectMessage(), e);
} WebMessageContext.getInstance().clear(); return AliasNavigationRule.ALIAS_AUTOR_LISTAR; }

O mtodo addMessage no da classe AbstractManagedBean. Ele importado estaticamente do seguinte pacote: br.gov.framework.demoiselle.view.faces.util.ManagedBeanUtil

6.6.1 Autenticao
Com Demoiselle Framework, no precisamos incluir a lgica de autenticao em nossas classes de controle. Demoiselle utiliza JAAS para autenticao, assim precisamos apenas configurar os usurios e papis no arquivo de configurao do servidor de aplicao. No caso do Apache Tomcat, por exemplo, bastaria incluir as seguintes linhas (para o caso da aplicao livraria) no arquivo tomcat-users.xml:

318

<tomcat-users> <role rolename="leitor"/> <role rolename="gravador"/> <role rolename="removedor"/> <role rolename="administrador"/> <user username="leitor" password="leitor" roles="leitor"/> <user username="gravador" password="gravador" roles="leitor,gravador"/> <user username="admin" password="admin" roles="administrador"/> </tomcat-users>

6.7 Concluso
Com o uso de Demoiselle Framework, conseguimos obter diversas vantagens em nossa aplicao, com relao ao reuso de componentes e independncia de fornecedores. Com o uso de Hibernate na aplicao anterior, j tnhamos conseguido independncia do banco de dados. Agora, com o uso de JPA, ficamos independentes do provedor do mecanismo de persistncia e mapeamento objeto-relacional. Demoiselle Framework introduz a camada de Negcio, removendo tanto do Modelo quanto do Controle a responsabilidade por tratar as regras de negcio da aplicao. Essa na verdade a camada onde deve ser gasto o maior esforo, sendo que as demais devem reaproveitar tudo o que for possvel. Como se pode notar, JSF j havia trazido melhorias com relao ao uso de JSP e Servlets. O Demoiselle Framework reaproveita todas a capacidade das implementaes JSF e ainda adiciona a injeo de dependncia, que torna a camada de Controle e Viso desacoplada das demais, assim como ocorre com a camada de Negcio. As questes relativas segurana da aplicao, como autenticao e autorizao, so facilitadas pelo Demoiselle Framework graas ao uso da especificao JAAS. Por meio do uso de padres, Demoiselle Framework realmente facilita o desenvolvimento de aplicaes Java EE e estimula a reutilizao de cdigo e componentes. O prximo e ltimo captulo trar uma viso geral e profunda sobre as motivaes que levaram criao do Demoiselle Framework, e tambm discorrer de forma mais profunda sobre sua arquitetura. De qualquer modo, para maiores informaes sobre o Demoiselle Framework, o ponto de partida o portal www.frameworkdemoiselle.gov.br.

319

CAPTULO 7 Demoiselle: Framework de Arquitetura


Neste captulo, apresentamos os fundamentos do framework Demoiselle. Inicialmente discutirmos os elementos de diversidade, deciso e a estratgia de governo para a rea de tecnologia que serviram de insumo para o estabelecimento de um projeto de infraestrutura de software que definiu uma arquitetura de referncia para a criao de aplicaes. Ser abordada a caracterstica de desenvolvimento colaborativo do projeto Demoiselle, assim como a questo do reuso de componentes. A estrutura do projeto e suas motivaes sero apresentadas, bem como a arquitetura do framework. Neste ponto, todos os mdulos que o compem sero vistos com detalhes.

7.1 Fundamentos 7.1.1 Diversidade


Segundo Mariaca (2009), a diversidade uma das palavras de ordem na empresa moderna, entendida como o estilo estrutural da organizao que representa alto valor estratgico e elemento de competitividade. O desenvolvimento de tecnologia da informao para governo, como um negcio, envolve diversidade. Os elementos dessa diversidade podem ser: Equipes: desenvolvimento de sistemas, administrao de centro de dados, infraestrutura de redes, logstica, recursos humanos, consultoria jurdica, etc. Clientes: executivo, legislativo, judicirio, ministrios, empresas, autarquias, fundaes, universidades, etc. Plataformas: livres e proprietrias, abertas e fechadas, de grande e pequeno porte, Web, desktop, dispositivos mveis, etc. Demandas: sistemas corporativos, crticos, em tempo real, integrao de sistemas, manuteno do legado, etc. Pessoas: h uma mirade de itens diversificados quando se trata de pessoas, entre formao profissional, experincia de vida, crenas pessoais, vocao, etc.

320

Recursos: a nica certeza em relao aos recursos que eles sero limitados. Fora isso, dependen do da combinao dos elementos anteriores, pode-se ter mais ou menos disponibilidade de recursos.

7.1.2 Elementos de deciso


5 pilares foram escolhidos pelo Serpro para definir a estratgia de tecnologia de tecnologia do governo: os atores institucionais, o conhecimento maduro, a integrao, a escalabilidade e a sustentabilidade. Os atores institucionais so o servidor pblico, que visto como o trabalhador do conhecimento, as firmas e o cidado. A tecnologia da informao deve proporcionar a esses trs globalidade, conexo, mobilidade e facilidade de acesso. O conhecimento maduro prefervel s solues ad hoc. A preocupao em criar com componentes reutilizveis deve permear as decises sobre estratgia tecnolgica. Com relao a integrao, ela se refere a trs aspectos: a eliminao do insulamento de sistemas, a busca e recuperao de informao e a preservao de identidade e privacidade. O crescimento econmico e social se reflete na necessidade do crescimento dos sistemas de informao. O governo no tem condies reais de fazer sua estrutura de atendimento crescer fisicamente na proporo que a populao necessita, e precisa do suporte de sistemas de informao que possibilitem o chamado governo eletrnico. A preocupao do pilar da escalabilidade garantir a manuteno dos servios disponveis por meios eletrnicos e adio de novos sem que haja uma perda de performance que se reflita em um atendimento ruim para o cidado. A estratgia de tecnologia tambm deve ser sustentvel ao longo do tempo, de modo que o Estado no tenha de onerar a populao para manter a qualidade e disponibilidade dos servios.

7.1.3 Estratgia para a rea de tecnologia


Os elementos de deciso abordados anteriormente serviram de base para definir uma estratgia tecnolgica para o governo. Essa estratgia consiste em quatro objetivos: evoluir a cultura de desenvolvimento de aplicaes, criar uma capacidade de manuteno e extenso prpria, definir uma infraestrutura tecnolgica de aplicaes e criar um alinhamento com o movimento de software livre. Com relao a cultura de desenvolvimento de aplicaes, a estratgia do Serpro praticar um desenvolvimento compartilhado, integrado, produtivo e gerencivel, que faa uso preferencial de tecnologias abertas.

321

O governo trabalha com muitas restries de recursos, e no possvel depender de terceiros para manter sistemas de informao ou estender suas funcionalidades. Pois isso a necessidade do governo de ter a capacidade de realizar essas tarefas por conta prpria, por meio dos rgos e empresas desenvolvedores de sistemas. A criao, manuteno e integrao de sistemas um processo contnuo, o que certamente gera experincia e conhecimento. Por outro lado, os aspectos ligados a infraestrutura das aplicaes no interessam ao cliente, mas so alvo de esforo por parte do desenvolvedor. Finalmente, segundo Pacitti (2006, p. 45), o software (...) torna-se cada vez mais complicado, caro, menos confivel, difcil de configur-lo e mant-lo. Em funo disso, a definio de uma infraestrutura mnima para a criao de aplicaes permite que o desenvolvedor ignore os detalhes de baixo nvel, mantendo o foco na implementao das regras de negcio. Conforme os requisitos definidos para o governo eletrnico (www.governoeletronico.gov.br), essa infraestrutura de aplicaes deve ser distribuda, escalvel e habilitada para a Web (mas no restrita mesma), que proporcione alta disponibilidade, seja preparada para contingncia e tenha um baixo custo de propriedade. Por ltimo, mas no menos importante, a estratgia para a rea de tecnologia contempla o alinhamento com o movimento de software livre. Segundo Pacitti (2006, p. 40), o software livre vem ao encontro da necessidade, cada vez maior, de as decises dos governos e da administrao pblica dependerem dos sistemas de software. Ele afirma que a opo de alguns pases desenvolvidos pelo software livre se d pelos aspectos tcnicos, econmicos e de segurana nacional do mesmo. De acordo com Pacitti (2006, p. 41), o software livre proporciona aos governos:

Maior segurana e confiana no sistema de software in house;

Diminuio da dependncia econmica e tecnolgica causada pelo uso de softwares produzidos fora do pas; Economia trazida pelo fato de o software ser produzido por poucos rgos pblicos especializados de excelncia e da poder ser o mesmo software utilizado e aproveitado pelos demais rgos no especializados do mesmo governo.

7.1.4 Diretivas da arquitetura tecnolgica


Para cumprir os objetos estratgicos da seo anterior, fez-se necessria a definio de uma arquitetura de referncia para aplicaes. Segundo Fowler (2006, p. 24), a arquitetura subjetiva, uma compreenso do projeto de um sistema compartilhada pelos desenvolvedores experientes em um projeto. Esta compreenso compartilhada frequentemente se apresenta na forma dos componentes mais importantes do sistema

322

e de como eles interagem. Tambm diz respeito a decises, pois os desenvolvedores gostariam de tomar as decises certas desde o incio, j que elas so vistas como difceis de alterar. A subjetividade pode levar a criao de uma mirade de arquiteturas diferentes, para projetos diferentes de equipes diferentes, que, no entanto, esto em uma mesma estrutura governamental. O reuso e consequentemente a manuteno so prejudicados. Uma arquitetura de referncia d aos desenvolvedores um ponto de partida e induz a uma compreenso uniformizada dos sistemas de informao. A arquitetura de referncia definida para a criao da infraestrutura de aplicaes do governo estabeleceu oito diretivas: 1. Computao distribuda 2. Aplicaes baseadas em componentes 3. Processos orientados a eventos 4. Acoplamento fraco de funes de negcio 5. Infraestrutura para suporte a decises 6. Automao de processos 7. Acesso por Internet 8. Software livre

7.1.4.1 Computao distribuda


Segundo Casetti et al [CaAK93], um sistema distribudo constitui-se de um conjunto de processadores autnomos conectados atravs de um subsistema de comunicao, que cooperam-se atravs da troca de mensagens. Esse tipo de sistema deve apresentar duas caractersticas inerentes: 1) a transparncia na sua utilizao, ou seja, a capacidade de apresentar-se aos seus usurios como uma entidade nica, e 2) o alto grau de tolerncia a faltas (falhas). Ainda segundo o mesmo autor, existem em geral trs aspectos de software que podem estar distribudos: dados, programas e controle. No tocante a distribuio de dados, pode-se ter: sistemas de arquivos distribudos e sistemas de banco de dados distribudos. No que diz respeito a programas, pode-se ter: programas centralizados e programas distribudos. Um programa centralizado aquele que executado em uma arquitetura na qual cada um dos processadores pode executar qualquer instruo desse programa. J um programa distribudo aquele que se encontra espalhado por vrias memrias

323

primrias, sendo que cada uma acessada por um processador diferente, o qual executa a parte do programa que se encontra na memria primria a ele associada. A distribuio do controle est relacionada diretamente com a distribuio do prprio sistema operacional. O que distingue um sistema distribudo de um sistema de arquitetura clssica a distribuio do controle. O controle centralizado quando a execuo de um programa, em qualquer instante, est sob os cuidados de um nico elemento processador. J, quando o controle distribudo, a execuo de um programa est sob os cuidados de mais um elemento processador. A diretiva de computao distribuda da arquitetura de referncia visa estabelecer uma infraestrutura de software escalvel, preparada para o aumento de usurios, para o crescimento dos dados persistentes e para a expanso do escopo de funcionalidades. Ela advm tambm da distribuio geogrfica do governo brasileiro, em um pas de grande extenso territorial. Alm disso, visa criar aplicaes com suporte para diversas tecnologias, baseadas em padres de interoperabilidade e alinhadas com a e-Ping (http://www.governoeletronico.gov.br/acoes-e-projetos/e-ping-padroes-deinteroperabilidade).

7.1.4.2 Aplicaes baseadas em componentes


O esforo de desenvolvimento de software exige diversos recursos, como pessoas e ambiente de desenvolvimento (ferramentas de hardware e de software). Um terceiro recurso torna-se decisivo para diminuir o esforo de desenvolvimento: os componentes de software reusvel. A arquitetura de referncia orienta a prtica da engenharia de software baseada em componentes. Pressman (2006, p. 323) afirma que essa engenharia enfatiza reusabilidade isto , a criao e o reuso de blocos construtivos de software. Esses blocos construtivos, frequentemente chamados componentes, devem, ser catalogados para facilitar a referncia, padronizados para facilitar a aplicao e validados para facilitar a integrao. Deve-se buscar a construo de componentes de experincia plena que, segundo Pressman, so especificaes, projetos, cdigo ou dados de teste existentes desenvolvidos para projetos anteriores, que so similares ao software a ser construdo para o presente projeto. Essa categoria de componentes exige modificaes de risco relativamente baixo.

7.1.4.3 Processos orientados a eventos


Processos orientados a eventos referem-se ao uso de uma arquitetura orientada a servios. Processo, neste caso, um conjunto de tarefas que iniciada por um evento, transforma informao e produz uma sada. Algumas atividades podem ser

324

condicionais, ou alternativas, ou rodar em paralelo, ou precisam ser repetidas; raramento uma simples cadeia (Allen, 2007) A implementao dos processos orientados a evento promove a diminuio do emprego de transferncia de arquivos e filas de entrada, de processos dinmicos e o desenho (projeto) simples de aplicaes.

7.1.4.4 Acoplamento fraco de funes de negcio


Segundo Miller (2009), acoplamento entre classes ou subsistemas uma medida da interconexo entre essas classes ou subsistemas. O acoplamento forte significa que as classes relacionadas precisam conhecer detalhes internos umas das outras, as alteraes se propagam pelo sistema, e o sistema potencialmente mais difcil de entender. O acoplamento fraco, em contrapartida, tem como metas: 1. Tornar o cdigo mais fcil de ler; 2. Tornar as classes mais simples para o consumo de outros desenvolvedores, ocultando a parte "feia" do funcionamento interno em APIs bem projetadas; 3. Isolar possveis alteraes em uma rea pequena do cdigo; 4. Reutilizar classes em contextos completamente novos.

7.1.4.5 Infraestrutura para suporte a decises


O suporte decises significa que a infraestrutura de software deve gerar aplicaes que forneam ao servidor pblico, encarado como um trabalhador do conhecimento, acesso s informaes de que necessita para a tomada de decises. A plataforma de construo de software deve facilitar a recuperao de informaes de situao, excees, registros histricos e qualquer conhecimento relevante ao servidor pblico, usurio do sistema. A infraestrutura deve criar meios para implementao de inteligncia computacional, que capacite as aplicaes a fazerem associaes de dados e predio com base nos mesmos.

7.1.4.6 Automao de processos


Com relao automao de processos, a plataforma de construo de software deve facilitar o gerenciamento de processos de negcio, permitir transaes de longa durao, possibilitar a integrao com barramentos de servios. A plataforma tambm deve permitir a composio de processos de negcio por meio de web services, seja por coreografia ou orquestrao. Segundo Peltz (2003), a orquestrao refere-se a um processo de negcio executvel que pode interagir com Web services internos e externos. A orquestrao descreve

325

como Web services podem interagir em um nvel de mensagem, incluindo a lgica de negcios e a ordem de execuo das interaes. Essas interaes podem abranger aplicaes e/ou organizaes, e resultar em um processo transacional de vida longa. Com a orquestrao, o processo sempre controlado da perspectiva de uma das partes do negcio. Ainda segundo o mesmo autor, a coreografia mais colaborativa em sua natureza, onde cada parte envolvida no processo descreve a parte com quem atua na interao. A coreografia segue uma sequencia de mensagens que pode envolver mltiplas partes e mltiplas fontes. Ela associada com as trocas de mensagem pblicas que ocorrem entre mltiplos Web services. Peltz afirma que a orquestrao difere da coreografia quando descreve um fluxo de processo entre servios, controlado por uma nica parte. Na coreografia nenhuma parte verdadeiramente dona da conversa.

7.1.4.7 Acesso por Internet


Dada a existncia de um enorme legado de aplicaes de governo, sendo que a possibilidade de migrao muito remota, a integrao dos sistemas legados com interfaces Web necessria para permitir melhor navegabilidade, usabilidade e consolidao de dados de fontes diversas, alm do acesso a partir de qualquer lugar, por meio de conexo a Internet e disponibilidade de um navegador. O acesso por Internet tambm faz parte das polticas gerais descritas no Documento de Referncia da e-PING (Brasil, 2008), o qual afirma que todos os sistemas de informao da administrao pblica devero estar alinhados com as principais especificaes usadas na Internet e com a World Wide Web, e ainda que os navegadores (browsers) devem constituir o principal meio de acesso a esses sistemas. O documento diz que todos os sistemas de informao de governo devero ser acessveis, preferencialmente, por meio de tecnologia baseada em browser, sendo que outras interfaces so permitidas em situaes especficas, como em rotinas de atualizao e captao de dados onde no haja alternativa tecnolgica disponvel baseada em navegadores. O acesso por Internet tambm coloca para a infraestrutura de software os desafios de permitir a navegao baseada em semntica, por meio de aplicaes sensveis ao modo de navegao (Web 2.0) e ao contexto (Web 3.0). As aplicaes podem ter interfaces baseadas em navegador, para acesso direto por usurios, ou interfaces de aplicaes (web services) para integrao com outros sistemas.

7.1.4.8 Software Livre


A infraestrutura de software deve ser constituda preferencialmente de software livre e deve ser licenciada como software livre de modo que proporcione:

326

Compartilhamento de solues; Desenvolvimento em rede; Reduo de custos; Simplificao de prticas de segurana; Gerenciamento compartilhado de conhecimento; Estmulo inovao; Sustentabilidade a longo prazo.

7.1.5 Demoiselle com Desenvolvimento Colaborativo


Um das acepes da palavra colaborar, segundo o dicionrio Michaelis, cooperar para a realizao de qualquer coisa. O mesmo dicionrio afirma que cooperar, por sua vez, significa agir ou trabalhar junto com outro ou outros para um fim comum. Nesse entendimento, a princpio, todo desenvolvimento de software que envolva trabalho em equipe colaborativo. No entanto, o termo desenvolvimento colaborativo, como utilizado pelas comunidades de software livre e aberto, tem um significado mais restrito. Para chegar a esse significado, vamos fazer uma breve anlise do desenvolvimento de software, revendo alguns conceitos de captulos anteriores. Pressman (2006, p. 1) afirma que o software de computador um produto. No entanto, o mesmo autor reconhece que o software no fabricado no sentido clssico da engenharia, mas apenas desenvolvido por um processo de engenharia, e no se desgasta com o tempo, apesar de se deteriorar. A deteriorao de software o crescimento da introduo de falhas pela manuteno ao longo do tempo. Sommerville (2007, p. 3) refina o conceito de Pressman, afirmando que o software em si no um produto, pois abstrato e intangvel, no limitado por materiais ou controlado por leis da fsica ou por processos de manufatura. O autor declara que o software gera produtos, que podem ser comercializados, na forma de um sistema de software. Em sua viso (2007, p. 4), um sistema de software consiste geralmente de um conjunto de programas, arquivos de configurao utilizados para configurar esses programas, documentao do sistema, documentao do usurio e stios Web com informaes atualizadas sobre o produto. Os produtos de software podem ser genricos ou feitos sob encomenda. No primeiro caso, a organizao que os desenvolve controla sua especificao. No segundo, a especificao desenvolvida e controlada pelo comprador do sistema de software.

327

Independentemente do tipo de produto de software, Somerville (2007, p. 275) afirma que no final do primeiro milnio da Era Crist e nos anos iniciais do segundo, houve um movimento da indstria de software no sentido de praticar o desenvolvimento baseado em reuso. O autor justifica esse movimento como uma resposta s demandas por menores curtos de produo e manuteno de software, entregas mais rpidas de sistemas e aumento da qualidade do software. Segundo ele, cada vez mais empresas veem seu software como um ativo valioso e esto promovendo o reuso para aumentar seu retorno sobre investimentos em software. Para, Somerville (2007, p. 276), o reuso traz como benefcios o aumento de confiana no software, a reduo do risco de processo, o uso eficiente de especialistas, a conformidade com padres e a acelerao do desenvolvimento. Mas o mesmo autor alerta (Somm07, p. 277) para os problemas que podem advir com o reuso, se no houver planejamento. Vamos destacar alguns deles. Um dos problemas o aumento do custo de manuteno, provocado pela indisponibilidade do cdigo-fonte de um sistema ou componente de software reusvel. Uma soluo para isso a adoo preferencial de softwares livres, que trazem como pressuposto o cdigo-fonte aberto. Outro problema a criao e manuteno de uma biblioteca de componentes reusveis. E aqui tocamos num ponto crucial. Alm das questes que envolvem as tcnicas de classificao, catalogao e recuperao de componentes, e da compreenso e adaptao dos mesmos, est a replicao de componentes. Se uma equipe de uma empresa cria uma biblioteca de componentes reusveis, ela deve ficar disponvel para que todos os desenvolvedores da empresa possam utiliz-la. Alm disso, preciso permitir que os usurios dos componentes possam contribuir com sua evoluo. Se os usurios no puderem ver mudanas de que necessitam implementadas nos componentes existentes, eles criaro novos componentes. A dimenso do problema pode se tornar maior se o cdigo-fonte no estiver disponvel, o que implicar na reescrita de funcionalidades j implementadas. Se o desdobramento de um projeto de componente reusvel em vrios pode ocorrer dentro de uma organizao, que dir entre organizaes distintas. No intuito de assegurar a propriedade do software, algumas companhias competem entre si, criando componentes similares. Outras cooperam no desenvolvimento de componentes comuns, agregando experincias e beneficiando-se da expertise de cada uma. Para que a segunda estratgia tenha xito, um fator importante a motivao dos contribuidores do software. Na viso tradicional da Engenharia de Software, os desenvolvedores criam cdigo por imposio, em seu horrio de trabalho. O modelo de desenvolvimento colaborativo prope uma nova abordagem, onde o desenvolvedor contribui espontaneamente com cdigo, em seu tempo livre. E, uma vez que o software seja livre, esse desenvolvedor no precisa pertencer ao quadro da empresa.

328

Isso abre possibilidades para que uma companhia tenha a sua disposio um nmero maior de desenvolvedores do que poderia manter em uma estrutura formal. E aqui chegamos ao ponto que abrimos no incio desta seo: o significado de desenvolvimento colaborativo para as comunidades de software livre. Os desenvolvedores que contribuem com o software em seu tempo livre e que no fazem parte da empresa no so obrigados a contribuir. Segundo Taurion (2004), eles o fazem por status, satisfao pessoal e benefcios indiretos, como empregabilidade em outras empresas. Segundo pesquisa realizada por Lakhani (2005, p. 27), 44,9% dos contribuidores de comunidades de software livre escrevem cdigo para os projetos porque acham isso intelectualmente estimulante. Mas Fogel (2007, p. 126) afirma que essas razes no constituem toda a verdade. Segundo ele, as pessoas gastam tempo em software livre por razes que excedem um desejo abstrato de produzir bom cdigo. Ele diz que alm dessa motivao, e do desafio com valor educacional de trabalhar em problemas difceis, est o desejo intrnseco dos seres humanos em trabalhar com outros seres humanos, e dar e obter respeito por meio de atividades cooperativas. Dessa forma, para manter o software em comunidade, preciso estabelecer aes que incentivem a colaborao e o compartilhamento do conhecimento. O Demoiselle Framework e seus subprojetos so mantidos em um ambiente de desenvolvimento colaborativo, no Sourceforge, com ferramentas que permitem o controle de verses, o registro e acompanhamento de bugs e novas funcionalidades, a comunicao por meio de listas de discusso, fruns e wikipages e a criao de desdobramentos (ramos) do projeto, como estmulo a inovao.

7.1.6 Orientao a Especificaes


Segundo McLaughlin, Pollice e West (2007, p. 81), a nica constante da anlise e projeto de software, a nica coisa com que se pode contar quando se escreve software, a mudana. De acordo com os autores, no importa se uma aplicao foi maravilhosamente bem projetada, pois com o tempo ela sempre crescer e mudar. Novas solues para problemas sero descobertas, as linguagens de programao evoluiro e os clientes iro aparecer com novos requisitos que obrigaro a alterao do cdigo das aplicaes. Nesse cenrio, criar uma infraestrutura de software para padronizar o desenvolvimento e promover o reuso de componentes torna-se um grande desafio. Como construir algo genrico o suficiente, mas ao mesmo tempo flexvel para administrar a manuteno de software? Tendo em vista essa questo, o projeto Demoiselle tomou como um de seus princpios o fundamento da arquitetura em especificaes tecnolgicas, e no em

329

implementaes especficas de software. As especificaes utilizadas como fundamento para o Demoiselle so as JSRs. Segundo a Apache Foundation (2009), uma JSR (Java Specification Request) um veculo formal pelo qual as tecnologias Java so criadas ou atualizadas. Uma JSR proposta por qualquer membro do JCP (Java Community Process), que ento fica conhecido como lder da especificao. O lder da especificao organiza um grupo de especialistas e esse grupo trabalha para criar a especificao. O grupo de especialistas deve criar tambm uma implementao de referncia assim como um kit de compatibilidade de tecnologia. O JCP a organizao que governa as tecnologias Java. Inicialmente criada pela Sun Microsystems, ela composta de um comit executivo formado por 32 representantes de empresas, indivduos e acadmicos que representam milhares de membros. Por meio do JCP, que as JSRs so criadas. Uma especificao tecnolgica permite independncia de fornecedor, pois sendo aberta, qualquer um pode fazer sua implementao, que dever operar seguindo os mesmos padres. Alm disso, a manuteno de uma especificao por um organismo independente (JCP uma organizao no governamental), garante estabilidade aos padres estabelecidos. A especificao diz o que a tecnologia deve fazer, e no o como. Assim, ela consegue manter um padro ao mesmo tempo que permite a evoluo tecnolgica. Alm das especificaes ditadas pelas JSRs, o Demoiselle se orienta para o uso de APIs que fazem parte da distribuio padro da tecnologia Java, de modo a evitar a dependncia direta de componentes de terceiros. As especificaes e APIs que fundamentam o Demoiselle so JAAS, JCA e JCE, JSF e Servlet.

7.1.6.1 JAAS
O texto a seguir uma traduo livre do guia de referncia do JAAS, disponvel na URL: http://java.sun.com/javase/6/docs/technotes/guides/security/jaas/JAASRefGuide.html. O servio de autenticao e autorizao Java (JAAS) foi introduzido como um pacote opctional (extenso) para o Java 2 SDK, Standard Edition (J2SDK), v 1.3. JAAS foi integrado ao J2SDK 1.4. JAAS pode ser usado para dois propsitos: Para autenticao de usurios, para determinar de modo seguro e confivel quem est atualmente executando o cdugo Java, independente do cdigo estar rodando em uma aplicao, um applet, um bean, ou um servlet; Para autorizao de usurios para garantir que eles tem os direitos de controle de acesso (permisses) requeridas para fazer as aes realizadas.

330

JAAS implementa uma verso Java do framework padro Pluggable Authentication Module (PAM). (...). Tradicionalmente, Java prov controle de acesso baseado em cdigo-fonte (controle de acesso baseado em de onde o cdigo veio e quem assinou o cdigo). Faltava, entretanto, a habilidade adicional de impor controles de acesso baseados em quem executa o cdigo. JAAS provides prov um framework que aumenta a arquitetura de segurana de Java com tal suporte. A autenticao JAAS executada de um modo plugvel. Isso permite que aplicaes permaneam independentes de tecnologias de autenticao subjacentes. Tecnologias de autenticao novas ou atualizadas podem ser plugadas na aplicao sem obrigar modificaes na prpria aplicao. Aplicao habilitam o processo de autenticao pela instanciao de um objeto LoginContext, que por sua vez referencia um Configuration para determinar a(s) tecnologia(s) de autenticao, ou os LoginModule(s), a serem usados para executar a autenticao. LoginModules tpicos devem estar prontos para ler verificar um nome de usurio e senha. Outros podem ler e verificar uma voz ou uma impresso digital, por exemplo. Uma vez que o usurio ou servio executando o cdigo tenha sido autenticado, o componente de autorizao JAAS trabalha em conjunto com o modelo de controle de acesso do Java SE para proteger o acesso a recursos sensveis. Ao contrrio da J2SDK 1.3 e anteriores, onde as decises de controle de acesso so baseadas somente na localidade do cdigo e nos assinantes do cdigo (um objeto CodeSource), na J2SDK 1.4 as decises de controle de acesso so baseadas tanto na execuo de cdigo CoudeSource quanto no usurio ou servio rodando o cdigo, que representado por um objeto Subject. Subject atualizado por um LoginModule com objetos Principals relevantes e credenciais se a autenticao foi bem sucedida. Um objeto CodeSource estende o conceito de um codebase para encapsular no somente a URL, mas tambm os certificados que foram usados para verificar a assinatura de cdigo originria daquela localizao.

7.1.6.2 JCA e JCE


O texto a seguir uma traduo livre do guia de referncia da JCA, disponvel na URL http://java.sun.com/j2se/1.4.2/docs/guide/security/CryptoSpec.html. A API Security uma API central da linguagem de programao Java, construda em torno do pacote java.security (e seus subpacotes). Esta API projetada para permitir que os desenvolvedores incorporem tanto funcionalidades de baixo nvel quanto de alto nvel em seus programas. O primeiro lanamento da API Security na JDK 1.1 introduziu a "Java Cryptography Architecture" (JCA), um framework para acessar e desenvolver funcionalidades

331

criptogrficas para a plataforma Java. Na JDK 1.1, a JCA inclua APIs para assinaturas digitais e sumrios de mensagens. Nos lanamentos sebsequentes, a Java 2 SDK estendeu de forma significativa a Java Cryptography Architecture, como descrito neste documento. Ela tambm atalizou a infraestrutura de gerenciamento de certificado para suportar certificados X.509 v3, e introduziu uma nova Java Security Architecture para controle acesso refinado, altamente configurvel e controle de acesso extensvel. A Java Cryptography Architecture engloba as partes da API Java 2 SDK Security relacionadas a criptografia, assim como um conjunto de convenes e especificaes fornecidas neste documento. Isso inclui um provedor de arquitetura que permite implementaes de criptografia mltiplas e interoperveis. A Java Cryptography Extension (JCE) estende a API JCA para incluir APIs para criptografia, troca de chave, e Message Authentication Code (MAC). Juntas, a JCE e os aspectos de criptografia da SDK fornecem uma API de cripografia completa e independente de plataforma. JCE era originalmente um pacote opcional (extenso) para a Java 2 SDK, Standard Edition, verses 1.2.x e 1.3.x. JCE agora est integrado ao Java 2 SDK, v 1.4.

7.1.6.3 Servlet
O texto a seguir uma traduo livre de excertos da especificao Servlet 2.5, disponvel na URL: http://jcp.org/aboutJava/communityprocess/mrel/jsr154/index.html Essa especificao define os conceitos, arquitetura e padres para servlets e servlet containers. Segundo a especificao JSR 154, um servlet um componente Web baseado em tecnologia Java, gerenciado por um recipiente, que gera contedo dinmico. Como outros componentes baseados em tecnologia Java, servlets so classes Java independentes de plataforma que so compilados para um cdigo de bytes de plataforma neutra que pode ser carregado dinamicamente e executado por um servidor Web habilitado com a tecnologia Java. Containers , s vezes chamado de mecanismos de servlet, so extenses do servidor Web que oferecem funcionalidade de servlet. Servlets interagem com os clientes Web atravs de um paradigma de solicitao/resposta implementado pelo servlet container. A mesma especificao detalha o conceito de servlet container. O servlet container uma parte de um servidor Web ou servidor de aplicao que fornece o servios de rede atravs da qual os pedidos e as respostas so enviadas, decodifica pedidos baseados em MIME, e formata respostas baseadas em MIME. Um servlet container tambm contm e gera servlets atravs do seu ciclo de vida.

332

Um servlet container pode ser construdo em um servidor Web, ou instalado como um componente suplementar do servidor Web atravs dessa API de extenso nativa do servidor API. Servlet con tainers tambm podem ser construdos ou, eventualmente, instalados em servidores de aplicao habilitados para Web. Todos os servlet containers devem suportar HTTP como um protocolo para solicitaes e respostas, mas protocolos adicionais de solicitao/resposta, tais como HTTPS (HTTP sobre SSL) podem ser suportados. As verses exigidas das especificaes HTTP que um container deve implementar so HTTP/1.0 e HTTP/1.1. Porque o container pode ter um mecanismo de cache descrito na RFC2616 (HTTP/1.1), ele pode modificar as solicitaes dos clientes antes de entreg-las ao servlet, pode modificar as respostas produzidas pelos servlets antes de envi-las aos clientes , ou pode responder s solicitaes, sem entreg-las para o servlet de acordo com a RFC2616. Um servlet container pode impor restries de segurana no ambiente em que um servlet executado. Em um ambiente Java 2 Platform, Standard Edition (J2SE, v.1.3 ou acima) ou Java 2 Platform, Enterprise Edition (J2EE, v.1.3 ou superior), estas restries devem ser colocadas usando a arquitetura de permisso definida pela plataforma Java 2. Por exemplo, servidores de aplicao high-end podem limitar a criao de um objeto Thread para garantir que outros componentes do container no sero afetados de forma negativa. J2SE 1.3 a verso mnima da plataforma Java com as quais servlet containers devem ser construdos.

7.1.6.4 JSF
O texto a seguir uma traduo livre da pgina da JSF, disponvel na URL http://java.sun.com/javaee/javaserverfaces. Desenvolvida atravs do Java Community Process sob JSR - 314, tecnologia JavaServer Faces estabelece o padro para a construo de interfaces de usurio do lado servidor. Com as contribuies do grupo de peritos, as APIs JavaServer Faces esto sendo projetadas de modo que possam ser aproveitadas por ferramentas que iro tornar o desenvolvimento de aplicativos web ainda mais fcil. Vrios fornecedores de ferramentas foram respeitados membros do grupo de especialistas da especificao JSR-314, que desenvolveu o JavaServer Faces 1.0. Esses fornecedores esto comprometidos em apoiar a tecnologia JavaServer Faces em suas ferramentas, promovendo a adoo do padro de tecnologia JavaServer Faces. A tecnologia JavaServer Faces inclui:

Um conjunto de APIs para representar os componentes UI e gerenciar o seu estado, a manipulao de eventos e validao de entrada, definio de navegao da pgina, e apoiar a internacionalizao e acessibilidade.

333

Uma biblioteca de tags JavaServer Pages (JSP) personalizada para expressar uma interface JavaServer Faces dentro de uma pgina JSP.

Projetada para ser flexvel, a tecnologia JavaServer Faces aproveita a interface padro web e os conceitos de camada existentes sem limitar os desenvolvedores a uma marca, linguagem, protocolo ou dispositivo cliente particular. As classes de componentes UI includas com a tecnologia JavaServer Faces encapsulam a funcionalidade do componente, e no a apresentao especfica de um cliente, permitindo assim que os componentes JavaServer Faces UI a ser prestado a vrios dispositivos do cliente. Ao combinar a funcionalidade do componente de UI com geradores customizados, que geram atributos para um componente especfico do usurio, os desenvolvedores podem construir tags personalizadas para um dispositivo cliente em particular. Como uma convenincia, a tecnologia JavaServer Faces fornece um gerador personalizado e uma biblioteca de tags JSP personalizadas para processamento para um cliente de HTML, permitindo que os desenvolvedores de aplicativos para Java Platform, Enterprise Edition (Java EE) usem a tecnologia JavaServer Faces em suas aplicaes. Como a facilidade de uso o principal objetivo, a arquitetura do JavaServer Faces define claramente uma separao entre a lgica da aplicao e a apresentao enquanto torna fcil conectar a camada de apresentao com o cdigo do aplicativo. Este projeto permite que cada membro de uma equipe de desenvolvimento de aplicativos web focalize a sua parte do processo de desenvolvimento, e tambm oferece um modelo de programao simples para juntar os partes. Por exemplo, os desenvolvedores de pgina web sem conhecimentos de programao podem usar os componentes de tags UI de JavaServer Faces para ligar o cdigo do aplicativo com uma pgina web sem escrever scripts.

7.2 Estrutura do Projeto Demoiselle


O projeto Demoiselle est estruturado de forma a proporcionar fraco acoplamento de funcionalidades e reuso por meio de componentes.

Figura 32: Projeto Demoiselle Framework e subprojetos

334

O framework, a infraestrutura bsica para criao de aplicaes, o projeto principal. Sua arquitetura ser detalhada no prximo captulo. Em linhas gerais, o framework oferece uma interface que integra e abstrai o uso de vrias tecnologias baseando-se em especificaes. A evoluo das especificaes Java deve manter o framework com um mnimo de implementao, ou at mesmo reduzi-la. As implementaes dos outros subprojetos, por outro lado, tendem a crescer. Para estabelecer padronizao, sem criar impedimentos para a evoluo tecnolgica, o framework concentra-se em definir uma arquitetura de referncia. Ela foi construda a partir do conhecimento e da experincia de um grupo de arquitetos, tendo como base as especificaes de interoperabilidade da e-PING e um direcionamento estratgico do uso de tecnologias. Segundo Hofmeister (2000, p. 8), uma arquitetura de referncia define tipos de elementos de uma arquitetura e como eles interagem. Ela tambm define um mapeamento de funcionalidades para elementos arquiteturais. A arquitetura de referncia uma especificao, portanto. Assim, necessrio um produto de software, que implemente os padres definidos por ela. O framework esse produto. Mas alm de implementar a arquitetura de referncia, o framework tambm serve para evoluir a mesma. A utilizao do framework, ao longo do tempo, gera questionamentos, que so usados para avaliar e manter a arquitetura.

Figura 33: Insumos e produto da arquitetura de referncia


Hofmeister (2000, p. 3) afirma que embora ter uma boa arquitetura de software no garante que um produto atenda seus requisitos, ter uma arquitetura pobremente projetada ou mal definida torna impossvel atender os requisitos do produto. A arquitetura poupa tempo ao desenvolvedor, quando define tecnologias a serem utilizadas, dentro de uma mirade de possibilidades. Ela poupa tempo do projetista, quando oferece a estrutura bsica para uma aplicao. Ela ajuda nas tomadas de decises do projeto, pois cria um escopo bem definido de questes a serem tratadas. E ela cria condies para o reuso ao estabelecer padres de implementao.

335

Figura 34: Produtos da arquitetura


Cinco projetos orbitam ao redor do framework: Demoiselle Components, Demoiselle Wizard, Demoiselle Sample, Demoiselle Process e Demoiselle Infra. Demoiselle Components abriga a construo de componentes fracamente acoplados ao framework. Isso quer dizer que o framework no depende dos componentes. Os componentes, por outro lado, podem ser dependentes do framework, se fizerem uso de seus padres. No possvel obrigar todos os componentes a implementar interfaces e classes abstratas do framework, ou fazer uso de suas anotaes e aspectos, porque nem sempre isso necessrio para prover funcionalidades em nvel mais alto. Isso permite que componentes tambm possam ser utilizados de forma independente do framework, de forma que o reuso de cdigo no dependa exclusivamente da infraestrutura. Demoiselle Wizard consiste na produo de ferramentas que facilitem a criao de aplicaes que implementem os padres Demoiselle por meio da gerao e edio automtica de cdigo. O projeto nasceu com a produo de um plugin especfico para o IDE Eclipse, mas o objetivo que sejam construdas ferramentas que atendam outros ambientes de desenvolvimento para a plataforma Java. O framework no depende de ferramentas de gerao de cdigo, mas como seu foco padronizao, a produtividade alcanada verdadeiramente com o uso de ambientes integrados de desenvolvimento. Demoiselle Sample rene implementaes de referncia do Demoiselle Framework. So aplicaes de exemplo que utilizam os recursos oferecidos pelo framework e servem como ponto de partida para desenvolvedores e estudantes. Demoiselle Process tem por objetivo criar um processo de desenvolvimento de sistemas que seja orientado para a arquitetura de referncia do Demoiselle. A utilizao do framework independe de processo de desenvolvimento, mas a existncia de um que j assuma uma arquitetura padro resulta em mais agilidade na construo de aplicaes.

336

Demoiselle Infra tem como objetivo ajudar desenvolvedores a instalar e configurar o ambiente de desenvolvimento e tcnicos de suporte a criarem e manterem um ambiente de produo.

7.3 Arquitetura
Demoiselle Framework uma soluo para desenvolvimento de aplicaes em Java construda pelo Serpro, para padronizar a construo de suas aplicaes e promover a gerao de componentes de software reutilizveis. Ele consiste em duas partes, um framework arquitetural e as dependncias estruturais desse framework. O foco, neste caso o framework arquitetural, mas apresentaremos uma viso geral dessas duas partes, para justificar a escolha da plataforma utilizada. Um framework pode ser compreendido como um conjunto de classes cooperativas que implementam os mecanismos que so essenciais para um domnio de problemas especficos (Horstmann, 2007, p. 312) e que constroem um projeto reutilizvel para uma determinada categoria de software (Gamma et alli, 2000, p. 41). Gamma et alli (2000, p. 332) ainda afirma que um framework fornece uma melhor orientao arquitetnica do software, atravs do particionamento do projeto em classes abstratas e da definio de suas responsabilidades e colaboraes. Segundo Gamma, o desenvolvedor pode customizar o framework para uma aplicao particular, atravs da especializao e da composio de instncias de suas classes. Demoiselle Framework, alm das definies acima, implementa o conceito de framework integrador (Macias, 2008). Isso ficar mais evidente adiante, quando for tratada a camada dos frameworks especialistas. A estrutura geral do Demoiselle baseada na diviso em camadas, pois, segundo Fowler (2006, p. 37-38), isso permite a compreenso de uma parte do sistema como um todo coerente sem a necessidade de saber muito sobre as demais partes. Alm disso, a utilizao de camadas permite a fcil substituio de implementaes, a minimizao de dependncias entre partes das aplicaes, e a definio de padres que podem gerar cdigo reutilizvel. A camada mais baixa do Demoiselle o sistema operacional. Essa camada no passvel da imposio de padro, porque a escolha do sistema operacional depende de vrios fatores, como os tipos de aplicao que sero executadas, a necessidade de customizao (adaptao do sistema) e a disponibilidade de recursos financeiros (para pagamento de licenas e contrato de suporte) ou humanos (para manuteno do sistema por conta prpria). A imposio de um sistema operacional para um framework voltado ao governo invivel, pois aprisiona o Estado a uma tecnologia e tende a onerar o cidado. Dado isso, as aplicaes devem ser capazes de rodar em qualquer sistema operacional (ou

337

pelo menos na maioria disponvel/usada no mercado). A tecnologia Java permite a portabilidade pela implementao do conceito de mquina virtual, que constitui a segunda camada mais baixa do Demoiselle. A prxima camada mais acima denominada plataforma. Como a implementao atual do Demoiselle est direcionada a construo de aplicaes Web, a camada de plataforma se constitui de servidores de aplicao Web que sigam a especificao Servlets 2.5 (JCP, 2000). A criao de aplicaes que no sejam Web (Desktop, embarcadas em dispositivos mveis) implicar em mudanas nessa camada. Em seus projetos, o Serpro fez uso de JBoss e Tomcat. A prxima camada mais superior, dos frameworks de fundamento, constitui-se da reunio de especificaes da tecnologia Java que norteiam as implementaes de software utilizadas pelo framework. A ideia que as aplicaes no fiquem presas a produtos de software especficos. A adoo dos padres definidos pelas especificaes garante uma certa liberdade na troca de tecnologias especialistas. As tecnologias especialistas, ou melhor, os frameworks especialistas, fazem parte da camada seguinte. Este o ponto de mutao do Demoiselle Framework. Os frameworks especialistas so integrados pela ltima camada no topo, o framework arquitetural, que constitui efetivamente o Demoiselle. O gerenciamento de mudanas deve se concentrar nessas duas camadas superiores, sendo que o framework arquitetural deve permanecer estvel. A ideia proteger as aplicaes do impacto das mudanas, conservando a mesma interface para as classes e mtodos utilizados, mas alterando os componentes que implementam as funcionalidades conforme for necessrio. O intento tirar do desenvolvedor a preocupao com as implementaes de baixo nvel, que constituem a infraestrutura de software. Todas as tecnologias integradas pelo Demoiselle podem ser perfeitamente usadas sem o framework. Porm, nesse caso, o desenvolvedor divide a sua preocupao com diversas estruturas, precisa gerenciar isso por conta prpria e torna as aplicaes dependentes de determinadas tecnologias, fortemente sujeitas mudana. Ao programar para o Demoiselle Framework, o desenvolvedor consegue criar uma estrutura de software reutilizvel, de duas formas. Primeiro, se algum framework especialista tiver de ser substitudo, a aplicao ir ignorar essa mudana, pois sua interface com o framework permanecer inalterada. A mudana ocorrer na implementao do framework que faz a integrao, sendo que o resultado final permanecer o mesmo.

7.3.1 Objetivos e Restries Arquiteturais


Doravante, quando nos referirmos a Demoiselle, estaremos tratando do framework arquitetural. A arquitetura do Demoiselle norteada e restringida por um conjunto de

338

objetivos, a saber, extensibilidade, reusabilidade, manutenibilidade, desempenho, estabilidade e confiabilidade. A arquitetura atual foi desenhada para atender somente aplicaes Web no distribudas.

7.3.1.1 Extensibilidade
Seria absurdo presumir a possibilidade da criao de uma infraestrutura de software que pudesse atender s demandas de todas as aplicaes. Essa uma dificuldade do estabelecimento e aceitao de padres. Tentativas de cercar todos os problemas tendem ao fracasso, pois no possvel prever as funcionalidades necessrias para atender aplicaes futuras. De modo a convergir a padronizao das aplicaes, pr-requisito para o objetivo tratado a seguir, e a capacidade dos sistemas de crescerem, a arquitetura do framework define a existncia de pontos de extenso seja por meio de interfaces, abstraes ou pela utilizao de padres de projetos. As principais interfaces da arquitetura so: IDAO: Interface para as classes que implementam o padro de projetos DAO (Alur et alli, 2002, p. 346), no qual um objeto responsvel por extrair e encapsular todos os acessos origem de dados e gerenciar a conexo com a origem de dados para obter e armazenar dados. Classes que implementam IDAO no acessam outras camadas da aplicao, apenas a de persistncia; IFacade: Interface para classes que implementam o padro Faade (Gamma et alli, p. 179), cujo objetivo unificar subsistemas por meio de uma interface de nvel mais alto e tornar mais fcil o uso dos mesmos; IBusinessController: Interface para classes que definem objetos da camada de negcios (Alur et alli, 2002, p. 50) que acessam a camada de persistncia atravs de classes que implementam a interface IDAO. Objetos que implementam IBusinessController podem acessar funcionalidades de outros sistemas ou mdulos atravs de implementaes de IFacade; IViewController: Interface para classes que fundem os conceitos de viso e controle do MVC (2006, p. 315). Objetos dessas classes tero acesso somente a instncias de classes que implementam IFacade e IBusinessController; Uma caracterstica inerente dos frameworks, citada por Fowler (Fowl05) que os mtodos definidos por um usurio para adaptar o framework s suas necessidades so frequentemente chamados de dentro do prprio framework, em vez do cdigo de aplicao do usurio. O framework frequentemente faz o papel do programa principal na coordenao e sequenciamento de atividades da aplicao. Essa inverso de

339

controle d aos frameworks o poder de servir como esqueletos extensveis. Os mtodos fornecidos pela adaptao do usurio para os algoritmos genricos definidos no framework para uma aplicao particular.

7.3.1.2 Reusabilidade
Segundo Paula Filho (2009, p. 256), quando uma organizao comea a usar processos definidos de desenvolvimento de software, os maiores ganhos iniciais resultam da reduo dos defeitos introduzidos em cada iterao. Isso ocorre por causa da reduo do desperdcio de tempo e dinheiro, principalmente aquele que causada por defeitos de requisitos, anlise e desenho. A partir da, ganhos significativos de produtividade s so conseguidos por meio da reutilizao. Em face disso, a arquitetura de uma infraestrutura de software deve favorecer o reuso, a partir da especificao de artefatos comuns em diversos projetos. O Demoiselle Framework prope dois principais artefatos de reuso, uma arquitetura de referncia e componentes fracamente acoplados. A arquitetura de referncia uma estrutura padro de aplicao em camadas. A partir do padro de projeto MVC (Fowler, 2006, p. 315) e do modelo J2EE (Alur et alli, 2002, p. 114), o Demoiselle prope trs camadas: Viso e Controle, Negcios e Persistncia. Viso e Controle a fuso das camadas homnimas do padro MVC, em um entendimento de que so indissociveis, exceto em aplicaes servidoras de servios. Negcios centraliza a maior parte do processamento de negcios para a aplicao. Persistncia corresponde a camada de Modelo do MVC e de Integrao do J2EE. Camadas podem ser reaproveitadas entre aplicaes, geralmente com adaptaes. O Demoiselle Framework prope a reduo ao mnimo de adaptaes com o uso de injeo de dependncias (Fowler, 2004). Esse um padro cuja ideia bsica consiste em um objeto separado, um montador, que realiza a instanciao da implementao apropriada de uma interface, de modo que uma camada no dependa de classes especficas. A injeo de dependncias no Demoiselle feito com o uso de orientao a aspectos, implementada por AspectJ. A extensibilidade por meio de componentes fracamente acoplados serve tambm a reutilizao. A proposta do Demoiselle que as aplicaes sejam criadas com blocos de cdigo pr-fabricados, que encerrem funcionalidades completas. O desenvolvimento orientado a componentes favorece o framework quando preserva sua extensibilidade, ao mesmo tempo em que acelera o desenvolvimento e aumenta a qualidade do cdigo, ao induzir a construo de aplicaes pela composio de funcionalidades. A criao de componentes para o Demoiselle segue a orientao de McConnell (2005, p. 78), na qual a responsabilidade de cada bloco de construo deve ser bemdefinida. Um bloco de construo deve ter uma rea de responsabilidade e deve saber o

340

mnimo possvel sobre as reas de responsabilidade de outros blocos de construo (fraco acoplamento).

7.3.1.3 Manutenibilidade
A arquitetura divide responsabilidades entre mdulos lgicos, que sero vistos adiante, com o intuito de causar o menor impacto no todo em caso de manuteno das aplicaes. Isso alcanado com duas abordagens: diminuio do acoplamento e foco da manuteno em pontos especficos.

7.3.1.4 Desempenho
O projeto do Demoiselle identificou, com base na experincia das equipes de desenvolvimento do Serpro, pontos crticos de performance, tais como integrao entre camadas e controle de transaes. De modo a diminuir os riscos de perda de desempenho, na manuteno e evoluo de aplicaes, o framework implementa os pontos crticos como funcionalidades, que fazem parte dos pontos especficos de manuteno citados anteriormente.

7.3.1.5 Estabilidade e Confiabilidade


Estabilidade aqui no se refere garantir a execuo das aplicaes, mas sim que seu comportamento continue sendo o esperado aps a realizao de manutenes. Para garantir isso, foi decidido que o framework no dependeria de implementaes especficas de determinadas funcionalidades, e sim que ele seria fundamentado em especificaes tecnolgicas. Desse modo, as aplicaes ficam protegidas de mudanas em produtos de software, pois as implementaes podem ser substitudas por outras que sigam as mesmas especificaes. A estabilidade do framework garante a confiabilidade das aplicaes, pois ao manter as mesmas condies estabelecidas (especificaes), a tendncia que o sistema prossiga normalmente na execuo de suas funes.

7.3.2 Perspectiva Estrutural da Soluo


Apresentaremos aqui uma viso lgica do framework arquitetural, os mdulos lgicos nos quais est dividido e quais os elementos de projeto presentes nesses mdulos. O framework consiste em cinco mdulos: core, util, web, persistence e view. Esses mdulos so bibliotecas de classes Java, disponibilizadas independentemente como arquivos .jar.

7.3.2.1 Mdulo Core


Este o mdulo que contm o conjunto de especificaes que do base estrutural ao framework. Seu objetivo tornar possvel a padronizao, extenso e integrao entre as camadas das aplicaes baseadas no framework.

341

O pacote br.gov.framework.demoiselle.core.layer define as abstraes para os objetos de cada camada. Ele contm as interfaces vistas nos objetivos e restries arquiteturais: IViewController, IBusinessController, IDAO e IFacade. exceo de IDAO, as demais interfaces no contm declarao de mtodos, o que pode parecer estranho, j que interfaces servem para definir comportamentos padronizados por meio de cdigo genrico reusvel. O que ocorre as interfaces do mdulo Core possuem outro propsito: servir para identificar os pontos de injeo de dependncias. Geralmente as aplicaes faro uso das trs primeiras interfaces. IFacade serve para definir uma fachada quando a aplicao trata de integrao entre mdulos ou integrao de subsistemas. O Core no possui nenhuma funcionalidade imediatamente utilizvel. Ele apenas define os padres do framework, de modo que outros mdulos tem de estend-lo para tornar o framework funcional.

7.3.2.1.1 Integrao entre Camadas


O pacote br.gov.framework.demoiselle.core.layer.integration define uma abstrao para o mecanismo de integrao entre camadas.

Figura 35: Pacotes do Core e suas dependncias

342

Figura 36: Padro de Camadas


O mecanismo de integrao atua na camada de viso injetando objetos de negcio por meio de uma fbrica (Gamma et alli, 2000, p. 95) do prprio framework ou alguma fbrica definida pela aplicao. Essa fbrica pode utilizar um proxy (Gamma et alli, 2000, p. 198) do framework ou da aplicao para instanciar objetos de negcio. De forma similar, na camada de regras de negcio, o mecanismo atua injetando objetos de persistncia. Trs interfaces so definidas neste pacote: IFactory, IBusinessControllerFactory e IDAOFactory. IFactory uma abstrao de fbricas de objetos injetados. IBusinessControllerFactory e IDAOFactory so especializaes de IFactory, respectivamente para objetos de negcio e objetos de persistncia. Beneficiando-se das funcionalidades oferecidas pela verso 5 de Java, o framework define no mdulo Core duas anotaes (annotations): Injection e Factory. A primeira uma anotao de propriedade que contm informaes a respeito da injeo de dependncia. A segunda uma anotao de classe ou pacote usada para definir a implementao da fbrica utilizada na injeo de dependncia. A classe InjectionContext responsabiliza-se por manter as informaes necessrias para a fbrica realizar a criao de objetos.

343

O mdulo Core especifica quem trata a injeo de dependncia, mas a forma como a injeo ser realizada deve ser definida pelos mdulos que implementam as abstraes do Core. O mdulo Web que implementa a injeo de dependncia por padro. Isso no impede que ilustremos como se d o fraco acoplamento proporcionado pelo uso desse padro. O cdigo a seguir uma classe que implementa a interface IViewController, que no contm nenhum comportamento definido. Isso to somente funciona como um marcador, ou na linguagem da AOP (Aspect Oriented Programming), um join point. Isso serve para avisar ao compilador da linguagem orientada a aspectos, que executado antes do compilador Java ordinrio, que um aspecto pode ser aplicado neste ponto, ou mais especificamente, nessa classe. Observe que a classe MeuMB define um atributo cujo tipo no uma classe, e sim uma interface. IMeuBC uma extenso de IBusinessController e tambm constitui um join point. Antes do atributo, porm, h uma anotao @Injection. O que vai ocorrer quando da compilao dessa classe, que o compilador de aspectos identificar pela anotao que o atributo precisa receber uma instncia. A ocorre a injeo de cdigo. Na linha imediatamente a seguir ao da declarao includo um pedao de cdigo (advice) que faz a atribuio de uma classe que implementa IMeuBC para meuBC.

public class MeuMB implements IViewController{ @Injection private IMeuBC meuBC; }

A classe que ser instanciada definida pelo mdulo que implementa o Core. Podese induzir que a classe tenha que seguir um padro de nome para ser localizada. E isso pode levar a crer que difcil flexibilizar a aplicao para que determinados atributos instanciem classes fora do padro. Mas facil criar excees regra, pela passagem do parmetro name para a anotao @Injection, como se v na classe MeuMB modifica a seguir.
public class MeuMB implements IViewController{ @Injection (name=br.gov.escola.business.implementation.AlunoBC) private IMeuBC meuBC; }

344

Figura 37: Integrao entre camadas


7.3.2.1.2 Contexto de Mensagens
O pacote br.gov.framework.demoiselle.core.message define uma abstrao de mensagens trocadas durante uma requisio entre as camadas dos sistemas. Essa abstrao permite criar um contexto de mensagens para que todas as camadas definidas pelas arquitetura de referncia possam manipular mensagens. Ela tambm auxilia a exibio das mensagens para o usurio, seja na forma de tela, arquivo texto (log), em banco de dados ou na juno dessas opes. Cada implementao dessa especificao deve prover uma soluo de acesso ao contexto de mensagem. Esse pacote define duas interfaces, IMessage e IMessageContext. A primeira uma abstrao da unidade de mensagem, enquanto a segunda abstrai o contexto de mensagem. O pacote ainda conta com um tipo enumerado chamado Severity, que padroniza as severidades genricas.

345

Figura 38: Contexto de Mensagens


7.3.2.1.3 Exceo Padronizada
O pacote br.gov.framework.demoiselle.core.exception define a classe ApplicationRuntimeException como a exceo padro para ser utilizada pelas aplicaes. Essa classe encapsula uma instncia de IMessage, constituindo uma mensagem de erro padronizada que pode ser tratada facilmente pelos mdulos do framework. ApplicationRuntimeException uma exceo no verificada, portanto no precisa obrigatoriamente ser capturada ou declarada. A seguir temos um exemplo de lanamento da exceo padronizada, com a passagem de uma mensagem definida pelo usurio.
public void MetodoBC(){ if ( /*Condio para lanamento de exceo*/ ){ throw new ApplicationRuntimeException(ErrorMessage.ERRO_01); } }

346

Figura 39: Exceo padronizada


7.3.2.1.4 Contexto de Segurana
O framework especifica uma forma padronizada de acesso aos dados da aplicao com restries de segurana por intermdio de autenticao e autorizada baseada em papis. Cada implementao desta especificao do Core deve prover uma soluo de acesso ao contexto de segurana. A abstrao do contexto de segurana baseada na especificao JAAS, uma API que permite que aplicaes escritas na plataforma J2EE usem servios de controle de autenticao e autorizao sem necessidade de estarem fortemente dependentes desses servios. A seguir temos um exemplo de uso do contexto de segurana:
ISecurityContext contexto = ContextLocator.getInstance().getSecurityContext(); if (contexto.isUserInRole("Administrador")){ ... }

A utilizao do mtodo getInstance() assinala o uso do padro de projeto Singleton (Gamma et alli, 2000, p. 130), o que coerente, visto que as informaes relativas a segurana devem ficar centralizadas. A classe que implementa esse Singleton ser tratada adiante.

7.3.2.1.5 Entidades
O pacote br.gov.framework.demoiselle.core.bean prope uma abstrao para as entidades da aplicao, a interface IPojo, que fora a utilizao do padro Value Object (Alur et alli, 2002, p. 232).

347

Figura 40: Contexto de Segurana

Figura 41: Padro para entidades


7.3.2.1.6 Contexto de Transao
O pacote br.gov.framework.demoiselle.core.transaction especifica o mecanismo de controle transacional e define um contexto de transao que atua no incio e no fim de cada ao. Seu funcionamento depende de um tipo definido pela enumerao TransactionType, que pode ser LOCAL ou JTA (Java Transaction API). LOCAL indica que a aplicao ser responsvel pelo gerenciamento da transao, enquanto JTA indica que a aplicao depender de uma implementao JTA disponvel no continer. Esse pacote possui duas interfaces, ITransactionResource e ITransactionContext. A primeira define um recurso a ser registrado no contexto de transao, enquanto a segunda representa o contexto de transao responsvel por registrar o incio e o fim de cada ao e registrar os recursos transacionais.

7.3.2.1.7 Acionadores
O pacote br.gov.framework.demoiselle.core.action define um mecanismo padronizado de aes a serem executadas pela aplicao. Essas aes so definidas como funes estruturais da aplicao, como carregamento de configurao e inicializao de ambiente. As interfaces desse pacote so IActionManager, ILoaderAction e IAction. A primeira define um padro para classes que gerenciam aes, com mtodos para configurar o

348

carregador da ao (que deve implementer ILoaderAction). O carregador da ao contm uma coleo de tipos IAction, que per sua vez representam aes.

Figura 42: Contexto de Transao


Um exemplo de ao padronizada pode ser visto a seguir:
public class MinhaAplicacaoAction implements IAction { private static Logger log = Logger.getLogger(MinhaAplicacaoAction.class); public void execute() {

log.debug("Lendo arquivos de configurao");


} }

Uma classe que implemente ILoaderAction, por exemplo MeuCarregadorAction, recupera as aes com seu mtodo getActions(), que retorna uma coleo do tipo IAction. Uma implementao de IActionManager, por sua vez, dispara todas as aes pela chamada a seus mtodos execute(), algo extremamente simples para a estrutura for trazida pelo Java 5, que itera sobre colees.

349

Figura 43: Acionadores


7.3.2.1.8 Localizador de Contextos
O pacote br.gov.framework.demoiselle.core.context define uma classe chamada ContextLocator. Essa classe fundamental para que as aplicaes consigam ter um acesso fcil e centralizado aos contextos de Mensagem, Transao e Segurana, e ao mesmo tempo garante que eles tenham, cada um, uma nica instncia, pela aplicao do padro Singleton. As implementaes de cada contexto devem obrigatoriamente utilizar o localizador de contextos como canal de acesso, para que todas as camadas da aplicao possam utilizar os contextos.

Figura 44: Localizador de Contextos

350

7.3.2.2 Mdulo Util


Este mdulo que contm componentes utilitrios da maior amplitude genrica, que visam facilitar o trabalho de outras funcionalidades do framework. Consiste de dois pacotes, um para carregamento de configurao e outro para paginao de dados.

Figura 45: Mdulo Util


7.3.2.2.1 Carregamento de Configurao
O pacote br.gov.framework.demoiselle.util.config define um mecanismo padronizado de carregamento de configurao que permite carregar variveis configuradas no ambiente, arquivos XML ou arquivos de propriedades para um objeto. Esse mecanismo utilizado em vrios outros componentes do framework e pode ser utilizado tambm pelas aplicaes. A classe ConfigurationLoader o utilitrio que executa o carregamento das configuraes nas classes. Uma anotao chamada ConfigKey usada nas classes para identificar os atributos que podem ser carregados a partir de uma configurao. A limitao dos recursos aceitos pelo mecanismo feita pelo tipo enumerado ConfigType. Como srio candidato a excees, o pacote contm uma exceo prpria, ConfigurationException, que herda de RuntimeException, o que a torna tambm no verificvel. O trecho de cdigo a seguir traz exemplos das declaraes de carregamento de configurao possveis:

@ConfigKey (name = "key", type=ConfigType.SYSTEM) private String stringValueSystem;

@ConfigKey (name = "framework.stringValue", type=ConfigType.XML, resourceName="configuration.xml")

351

private String stringValueXML;

@ConfigKey (name = "framework.stringValue", type=ConfigType.PROPERTIES, resourceName="configuration.properties") private String stringValueProperties;

Esses atributos poderiam, por exemplo, pertencer a uma classe chamada MeuConfig. O carregamento e uso da configurao se daria da forma a seguir:
public void meuMetodo() { MeuConfig meuConfig = new MeuConfig(); ConfigurationLoader.load(meuConfig); System.out.print( meuConfig.getMinhaPropriedade()); }

Figura 46: Carregamento de Configurao

352

7.3.2.2.2 Paginao de Dados


As aplicaes geralmente necessitam trafegar resultados entre as camadas de forma paginada garantindo o desempenho da aplicao. Esse mecanismo implementado no pacote br.gov.framework.demoiselle.util.page com um objeto que permite configurar os dados da pgina que ser requisitada (instncia de Page) e um objeto que contm os resultados de forma paginada (instncia de PageResult).

Figura 47: Paginao de dados


7.3.2.3 Mdulo Web
Este mdulo contm implementaes de algumas especificaes do mdulo Core e tambm utilitrios comuns de aplicaes Web no distribudas que facilitam o tratamento de sesses de usurio e suas requisies.

353

Figura 48: Mdulo Web


7.3.2.3.1 Contexto de Segurana
O pacote br.gov.framework.demoiselle.web.security define duas classes para implementar o mecanismo de acesso aos dados com segurana, WebSecurityContext e WebSecurityServletRequestListener. A primeira implementa o contexto de segurana atravs do padro Singleton, alm de gerenciar os dados de segurana vinculados a thread corrente. A segunda responsvel por repassar o objeto request para a instncia da primeira.

354

Figura 49: Contexto de Segurana implementado pelo Mdulo Web


7.3.2.3.2 Contexto de Mensagens
O pacote br.gov.framework.demoiselle.web.security define a classe WebMessageContext para implementar o contexto de mensagens. O cdigo a seguir ilustra o lanamento de mensagens para o contexto:
IMessageContext contextoMsg = ContextLocator.getInstance().getMessageContext(); public class MeuBC implements IBusinessController { public void meuMetodo(){ contextoMsg.addMessage(InfoMessage.Mensagem); } }

O mtodo getMessageContext() devolve uma instncia de WebContextMessage, mas isso no importa para a aplicao, desde que a classe implemente IMessageContext. Isso permite que esse cdigo fique protegido contra mudanas caso o contexto de mensagens seja modificado. A recuperao de mensagens pode ser feita pela chamada ao mtodo getMessages() do contexto de mensagens, que retorna uma coleo de instncias de IMessage.

355

Figura 50: Contexto de Mensagens implementado pelo Mdulo Web


7.3.2.3.3 Integrao entre Camadas
O mdulo Web implementa a especificao de integrao de camadas proposto pelo mdulo Core no pacote br.gov.framework.demoiselle.web.layer.integration. O mecanismo implementado utiliza AOP para detectar os pontos de integrao. Permite que sejam implementadas novas fbricas de acordo com a necessidade da aplicao. Os objetos so fabricados por meio de conveno de nomes entre as interfaces e sua implementao. WebAbstractFactory a abstrao de uma fbrica genrica do mdulo Web, seguindo o padro de projeto Abstract Factory (Gamma, 2000, p. 95). Todas as outras fbricas desse mdulo devem especializar essa classe. WebBusinessControllerFactory e WebDAOFactory implementam respectivamente as interfaces IBusinessController e IDAOFactory, definidas no Core. A classe responsvel pelo mecanismo de injeo de dependncias InjectionManager que faz uso das definies de injeo do Core. InjectionManager chamada quando o aspecto InjectionAspect intercepta instanciaes de classes que implementam IBusinessController, IViewController e Ifacade. O subpacote br.gov.framework.demoiselle.web.layer.integration oferece uma implementao opcional para desenvolver objetos criados pela injeo com um proxy (Gamma et alli, 2000, p. 198). A interface IProxy define o comportamento padro do proxy chamado pela injeo de dependncia (InjectionManager). Sua implementao

356

deve ser registrada no arquivo de configurao do framework e carregada atravs da classe ProxyConfig. A classe WebProxy a implementao bsica da interface IProxy. Uma classe de configurao chamada ProxyConfig diz qual classe implementa a interface IProxy. A injeo de dependncias faz uso do controlador de chamadas de mtodos WebInvocationHandler na hora de envolver o objeto criado em um proxy.

Figura 51: Integrao entre camadas implementada pelo mdulo Web


7.3.2.3.4 Contexto de Transao
O mdulo Web implementa a especificao do contexto transacional proposto no mdulo Core. O mecanismo implementado utiliza AOP para prover um mecanismo transparente de gerenciamento de transao. possvel utilizar o controle transacional do continer (JTA). Para isso deve existir uma implementao de um mecanismo de lookup via JNDI. A interface

357

IJNDITransactionManagerLookup define as informaes para o mecanismo JNDI localizar uma UserTransaction do continer com suporte JTA. O mdulo Web prov uma implementao para essa interface, voltada para o JBoss: JbossTransactionManagerLookup. A implementao padro do contexto transacional a classe WebTransactionContext. A classe WebTransactionAction define a ao de inicializao em aplicaes Web onde o contexto transacional configurado.

WebTransactionActionConfig define as configuraes padro do contexto transacional definido pela aplicao em arquivo externo.
A classe WebTransactionServletRequestListener o controlador do contexto transacional. Ela responsvel por iniciar e finalizar, normalmente ou com erro, o contexto transacional. acionado em todas as requisies Web.

7.3.2.3.5 Inicializao do Ambiente


A inicializao de ambiente implementa a especificao de aes proposta no mdulo Core, essa inicializao ocorre sempre que o continer iniciar a aplicao. O mdulo Web necessita que algumas aes sejam executadas e essas aes esto implementadas no pacote br.gov.framework.demoiselle.web.init. Os componentes e aplicaes baseadas no framework podem implementar outras aes e adicion-las para que sejam executadas na inicializao do ambiente. A interface IinicializationAction define o comportamento de uma ao de inicializao de aplicaes Web. A classe WebInicializationServletContextListener executa todas as aes configuradas ao inicializar o continer web/servlet. A classe WebInicializationLoaderAction carrega todas as classes de aes, baseada nas configuraes representadas pela classe WebInicializationLoaderActionConfig. O cdigo a seguir um exemplo de classe de inicializao do ambiente:
public class MinhaAction implements IInitializationAction { public void execute() {

log.debug("Inicializando minha action");


} public void setServletContext(ServletContext context) { }

358

Figura 52: Contexto de transao implementado pelo mdulo Web O mtodo execute() dessa classe ser invocado automaticamente na inicializao, desde que a classe seja referenciada no arquivo demoiselle.properties, conforme exemplo a seguir:
framework.demoiselle.web.initialization.action=MinhaAction

7.3.2.3.6 Redirecionamento Baseado em URL


O mdulo Web implementa a especificao do contexto transacional proposto no mdulo Core. O mecanismo implementado utiliza AOP para prover um mecanismo transparente de gerenciamento de transao. A implementao do redirecionamento consiste em cinco passos, que ilustraremos a seguir.

359

Figura 53: Inicializao do ambiente


Inicialmente, temos de criar as aes de redirecionamento. Um exemplo a classe adiante, MinhaRedirectAction:
public class MinhaRedirectAction implements IRedirectAction { private ServletReq uest request; private ServletResponse response;

public String getParameter() { return "MinhaActionParameter"; }

public String getValue() { return "MinhaActionValue"; }

public void setRequest(ServletRequest req) { this.request = req; }

360

public void setResponse(ServletResponse resp) { this.response = resp; }

public void execute() { /*Minha execuo*/ } }

Em seguida, necessrio cadastrar as aes no arquivo demoiselle.properties:


# --- Web configuration --framework.demoiselle.web.redirect.action=MinhaRedirectAction01 framework.demoiselle.web.redirect.action=MinhaRedirectAction02 framework.demoiselle.web.redirect.action=MinhaRedirectAction03

Posteriormente, a classe WebRedirectServlet deve ser mapeada no arquivo web.xml:


<servlet> <servlet-name> WebRedirectServlet </servlet-name> <servlet-class> br.gov.framework.demoiselle.web.redirect.WebRedirectServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name> WebRedirectServlet </servlet-name> <url-pattern> /redirect </url-pattern>

361

</servlet-mapping>

Finalmente, na pgina JSP, ou JSF, a ao de redirecionamento chamada desta forma:


<a href="minhaAplicacao/redirect?MinhaActionParameter=MinhaActionValue"> Chamar Minha Action </a>

Figura 54: Implementao do redirecionamento baseado em URL


7.3.2.3.7 Injeo de Dependncias com Aspectos
Martin Fowler (2004) afirma que a ideia bsica da injeo de dependncias ter um objeto separado, um montador, que popula um campo em uma classe com uma implementao apropriada para uma interface. O Demoiselle Framework implementa a injeo de dependncias em seu mdulo Web, por meio de programao orientada a aspectos. Segundo Winck e Goetten Jnior (2006, p. 48) um aspecto o mecanismo disponibilizado pela programao orientada a aspectos para agrupar fragmentos de cdigo referente aos componentes no funcionais em uma unidade no sistema. De acordo com os autores, o principal objetivo da POA [programao orientada a objetos] consiste em separar o cdigo referente ao negcio do sistema dos interesses transversais, de uma forma bem definida e centralizada. Winck e Goetten Jnior afirmam que (2006, p. 43) a orientao a aspectos trabalha em paralelo com outro paradigma. No caso do Demoiselle Framework, a orientao a

362

aspectos utilizada em conjunto com a orientao a objetos, inerente linguagem Java. Segundo os mesmos autores (2006, p. 45), na programao orientada a aspectos (...) os interesses so programados em mdulos separados (...). Aps a programao, ocorre a combinao entre as classes e os aspectos. Eduardo Piveta (2001 apud Winck e Goetten Jnior, 2006) afirma que um sistema que utiliza a programao orientada a aspectos composto por trs componentes: linguagem de componentes, linguagem de aspectos e combinador de aspectos. O Demoiselle Framework utiliza como linguagem de componentes Java, como linguagem de aspectos a AspectJ e como combinador de aspectos o compilador da AspectJ. O mdulo Web contm um aspecto chamado InjectionAspect, cujo cdigo integral exibimos a seguir:
package br.gov.framework.demoiselle.web.layer.integration;

import br.gov.framework.demoiselle.web.layer.integration.InjectionManager;

public aspect InjectionAspect {

pointcut injectionIBusinessController(): execution(public br.gov.framework.demoiselle.core.layer.IBusinessController+.new(..));

pointcut injectionIViewController(): execution(public br.gov.framework.demoiselle.core.layer.IViewController+.new(..));

pointcut injectionIFacade(): execution(public br.gov.framework.demoiselle.core.layer.IFacade+.new(..));

before(): injectionIBusinessController() || injectionIViewController() || injectionIFacade() { InjectionManager manager = new InjectionManager(); manager.execute(thisJoinPoint.getTarget()); }

363

Assim como na linguagem Java a unidade central a classe, na AspectJ a unidade central o aspecto. AspectJ tem sua sintaxe prpria, mas estende a linguagem Java, de modo que todo programa AspectJ um programa Java vlido. Ou melhor, todo aspecto referencia e gera cdigo Java vlido. O aspecto InjectionAspect tem por objetivo interceptar instanciaes de classe que implementem as interfaces IBusinessController, IViewController e IFacade e invocar uma instncia de InjectionManager. Ele faz essas interceptaes por meio da construo pointcut, que um ponto de atuao. Winck e Goetten Jnior (Winck e Goetten Jnior, 2006, p. 56) definem pontos de atuao como elementos do programa usados para definir um ponto de juno, como uma espcie de regra criada pelo programador para especificar eventos que sero considerados como um ponto de juno. Por sua vez, um ponto de juno ou entrada um identificador bem definido na execuo de um programa. Vamos compreender o funcionamento do injectionIBusinessController, que esclarecer os demais:
pointcut injectionIBusinessController(): execution(public br.gov.framework.demoiselle.core.layer.IBusinessController+.new(..));

ponto

de

atuao

A palavra execution refere-se a execuo de um mtodo, o qual se encontra entre os parnteses seguintes. Esse ponto de atuao diz que o aspecto ser disparado sempre que for gerada uma nova instncia de classe que implemente IBusinessController, ou, em outras palavras, quando o mtodo construtor de uma implementao de IBusinessController for executado. Aps a declarao de trs pontos de atuao, o cdigo tem uma construo before. Isso um adendo (advice). Winck e Goetten Jnior (2006, p. 57) definem adendo como um mecanismo similar a um mtodo, usado para declarar o cdigo que deve ser executado a cada ponto de juno em um ponto de atuao. Segundo eles, os adendos so compostos de duas partes, o ponto de atuao, que define as regras de captura dos pontos de juno e o cdigo que ser executado quando ocorrer um ponto de juno (definido pela primeira parte). O programador define em que momento o cdigo ser executado no adendo, em funo do ponto de juno. No caso do adendo before, o cdigo ser executado antes do ponto de juno. Para execut-lo depois usaramos after e para execuo durante o ponto de juno, o identificador around. Vamos analisar o trecho final de cdigo do aspecto, destacado a seguir:
before(): injectionIBusinessController() || injectionIViewController() || injectionIFacade() { InjectionManager manager = new InjectionManager(); manager.execute(thisJoinPoint.getTarget());

364

Esse adendo estabelece que para qualquer dos trs pontos de atuao (injectionIBusinessController, injectionIViewController e injectionFacade), seu cdigo ser executado, antes do ponto de atuao. No caso, uma instncia de InjectionManager ser invocada e chamar seu mtodo execute, passando como argumento o objeto do contexto atual. O mtodo execute de InjectionManager ir verificar todos os atributos do objeto interceptado. Para cada atributo, ele ir verificar a presena da anotao @Injection, definida pelo mdulo Core. Se ela estiver presente, ser passada como argumento para o construtor de InjectionContext, tambm definida pelo Core. O mtodo getFactory de InjectionManager retorna uma implementao do padro de projeto Abstract Factory. Ele verifica se o usurio fez uso da anotao @Factory, especificando uma classe para fabricar os objetos a serem criados. Caso no tenha feito, de acordo com a interface implementada pelo objeto interceptado ele retorna a respectiva classe de fbrica definida pelo mdulo Web. A fbrica de objetos ir retornar uma instncia de acordo com o contexto de injeo, determinado pela anotao. Essa instncia ser injetada no cdigo, mais exatamente, ser associada ao atributo em questo. Dessa forma, no h necessidade de criar instncias de objetos explicitamente, pois o compilador de aspectos ir gerar o cdigo. Isso torna o cdigo-fonte original independente da implementao.

7.3.2.4 Mdulo Persistence


O mdulo Persistence trata as funes de persistncia das aplicaes e sua integrao com outros mdulos. Ele prov a integrao da aplicao sistemas gerenciadores de dados e garante transparncia s demais camadas da aplicao na recuperao, armazenamento e tratamento das informaes. A interface IDAO do mdulo Core, em oposio as outras interfaces do pacote br.gov.framework.demoiselle.core.layer, define quatro operaes. Ela a base para o mdulo de persistncia do framework. A persistncia no Demoiselle Framework enfoca duas abordagens: o acesso direto por JDBC e o mapeamento objeto-relacional. O acesso a sistemas de bancos de dados no-relacionais, geralmente legado, pode ser feito por componentes. Um pacote com trs classes trata do desenvolvimento com drivers JDBC. JDBCGenericDAO implementa alguns mtodos de IDAO, para diminuir o trabalho do desenvolvedor e padronizar o cdigo. A classe JDBCUtil um utilitrio para as

365

configuraes JDBC e tambm a responsvel por inserir uma conexo no controle transacional definido pelo mdulo Core. Finalmente, a classe JDBCTransactionResource representa uma conexo JDBC e pode ser tratada pelo contexto de transao do framework.

Figura 55: Mdulo Persistence


O uso de JDBCUtil para gerenciar conexes pode ser visto neste exemplo de consulta:
public class FuncionarioDAO extends JDBCGenericDAO<Funcionario> implements IFuncionarioDAO { public List<Funcionario> listar() { List<Funcionario> result = new ArrayList<Funcionario>(); PreparedStatement prepStmt = null; Connection con = null; try { con = JDBCUtil.getInstance().getConnection(); prepStmt = con.prepareStatement("SELECT * FROM Funcionario"); ResultSet rs = prepStmt.executeQuery(); while (rs.next()) { long id = rs.getLong("id_funcionario");

366

String nome = rs.getString("nome"); Date nascimento = rs.getDate("nascimento"); String lotacao = rs.getString("lotacao"); result.add(new Funcionario(id, nome, nascimento, lotacao)); } } catch (SQLException e) { throw new ApplicationRuntimeException(ErrorMessage.FUNCIONARIO_005, e); } finally { JDBCUtil.getInstance().closeConnection(); } return result; } }

Para evitar que a troca de banco implique em alterao no cdigo-fonte das classes, a configurao das conexes JDBC feita no arquivo demoiselle.properties, como mostra o exemplo a seguir:
#Configurao para uso de JDBC framework.demoiselle.persistence.jdbc.driver=org.postgresql.Driver framework.demoiselle.persistence.jdbc.url=jdbc:postgresql://localhost/escola framework.demoiselle.persistence.jdbc.user=postgres framework.demoiselle.persistence.jdbc.pass=postgres

Para tratar o mapeamento objeto-relacional, o mdulo Persistence define uma interface chamada IORMDAO, que estende IDAO e define dois mtodos, findByExample() e findById(). possvel integrar qualquer framework especialista de persistncia que use ORM, desde que seja definida uma classe que implemente IORMDAO e outra que seja um recurso transacional. A verso 1.0.x do Demoiselle utiliza o Hibernante como framework de persistncia. O pacote br.gov.framework.demoiselle.persistence.hibernate define a integrao dos frameworks com trs classes: HibernateGenericDAO, HibernateUtil e HibernateTransactionResource. A partir da verso 1.1.x, o JPA foi adotado como padro de persistncia. O pacote br.gov.framework.demoiselle.persistence define a integrao do framework Demoiselle

367

com os provedores de persistncia JPA por meio de trs classes: JPAGenericDAO, EntityManagerProxy e JPATransactionResource.

Figura 56: Persistncia com JDBC


A matria-prima da camada de persistncia so classes Pojo, que representam as entidades da aplicao. Um exemplo a classe Aluno, a seguir:
package br.gov.framework.demoiselle.escola.bean; public class Aluno implements IPojo{ private Long id; public Aluno() {} public Long getId() {

368

return id; } public void setId(Long id) { this.id = id; } }

Figura 57: Persistncia com Hibernate


A arquitetura de referncia define para as aplicaes um pacote br.gov.demoiselle.nomedaaplicacao.persistence, no qual ficam as interfaces que

369

estendem IDAO e as implementaes das mesmas. A classe WebDAOFactory usada por padro para construir os objetos por meio de conveno. A conveno que as interfaces e suas implementaes devem ter a mesma identificao, sendo que as interfaces devem ter o prefixo I e o sufixo DAO, enquanto as implementaes devem omitir o prefixo. Por exemplo, a interface IAlunoDAO deve ser implementada pela classe AlunoDAO. possvel modificar a fbrica que far a injeo de dependncias, estendendo WebDAOFactory e usando o parmetro factory da anotao @Factory, conforme exemplo a seguir:
public class EscolaDAOFactory extends WebDAOFactory { public IDAO create(InjectionContext ctx) { return //Lgica da Fbrica; } }

@Factory(factory=EscolaDAOFactory.class) public class AlunoDAOStubTest implements IFacade{ @Injection private IAlunoDAO alunoDAO; }

As operaes de persistncia fazem uso do contexto de transao, conforme vemos no cdigo seguinte:
public class MinhaClasse { @Injection IMeuDAO meuDao;

public void listar() { WebTransactionContext.getInstance().init(); meuDao.listar(); WebTransactionContext.getInstance().end(); } }

370

A classe HibernateUtil prov um conjunto de implementaes para camada de persistncia baseado no framework Hibernate. Ela integrada ao contexto de transao, de modo que possui um mecanismo transacional completo. O cdigo a seguir ilustra dessa classe para tratar tanto o commit quando o rollback de uma transao:
public class MinhaClasse { @Injection IMeuDAO meuDao;

public void inserir() { WebTransactionContext.getInstance().init(); try{ meuDao.insert(new MeuPojo()); HibernateUtil.getInstance().commit(); }catch (ApplicationRuntimeException e) { HibernateUtil.getInstance().rollback(); } WebTransactionContext.getInstance().end(); } }

A paginao de dados definida pelo mdulo Util usada pelo mdulo Persistence para manter o controle sobre os dados oriundos de uma consulta e recuperar da base apenas as informaes que sero exibidas na viso do usurio. Os benefcios da paginao so a reduo de custos de uso de memria, processamento e rede e a escalabilidade proporcionada. O cdigo a seguir ilustra o uso de paginao. O trecho de cdigo de uma classe herdeira de HibernateGenericDAO:
public void listar() { Page page = new Page(50, 1); listarBean(page); }

public PagedResult<Aluno> listarBean(Page page) { return findHQL("from Bean", page);

371

HibernateGenericDAO implementa um conjunto de funes (consulta, paginao, insero, alterao e excluso) para simplificar a criao de classes IDAO implementadas pela aplicao. Um exemplo de como se fazer consultas com HibernateGenericDAO pode ser visto no cdigo a seguir:
public class DisciplinaDAO extends HibernateGenericDAO<Disciplina> implements IdisciplinaDAO{

public PagedResult<Disciplina> listar(Page page) { return findHQL("from Disciplina order by nome asc", page); }

public Disciplina buscar(Disciplina professor) { List<Disciplina> retorno = find("from Disciplina order by nome asc"); if (retorno != null && retorno.size() > 0 ) return retorno.get(0); return null; }

public PagedResult<Disciplina> filtrar(Disciplina prof, Page page) { return findByExample(prof, page); }

public List<Disciplina> listar() { return findHQL("from Disciplina order by nome asc"); } }

7.3.2.5 Mdulo View


Este mdulo contm implementaes de componentes especficos de interface com usurio baseados na especificao JSF. Uma vez que a especificao JSF define a utilizao de um controlador MVC denominado managed bean, o mdulo View

372

disponibiliza uma implementao padronizada para ser utilizada nas aplicaes. a classe AbstractManagedBean. A classe AbstractManagedBeanConfig representa as configuraes da aplicao do total de linhas e a quantidade de pginas ao paginar dados. Para facilitar as operaes com managed beans, o framework disponibiliza a classe ManagedBeanUtil. O mdulo View tambm prov a classe PagedResultDataModel, um modelo de dados que converte um PagedResult para a representao grfica dos dados paginados.

373

Figura 58: Mdulo View

Figura 59: Controle de viso

Finalmente, o mdulo View define a classe CookieManager, um utilitrio que permite a realizao das operaes bsicas relacionadas a cookies na Web.

374

7.3.2.3 Modelo de Arquitetura em Camadas do Demoiselle


A arquitetura de referncia do Demoiselle Framework prope para as aplicaes uma estrutura baseada na combinao das camadas do padro MVC com as camadas propostas pelos padres da plataforma JEE.

Figura 60: Utilitrios da camada de viso

Figura 61: Manipulador de Cookies


O padro MVC, segundo Fowler (2006, p. 315) considera trs papis. O modelo, a vista e o controlador. De acordo com o autor, o modelo um objeto que representa alguma informao sobre o domnio. um objeto no-visual contendo todos os dados e comportamento que no os usados pela interface de usurio. A vista, por sua vez, representa a exibio do modelo na interface com o usurio. Assim, se nosso modelo for um objeto cliente nossa vista poderia ser um frame cheio de controles para a

375

interface com o usurio ou uma pgina HTML com informaes do modelo. As alteraes nas informaes apresentadas pela vista so manipuladas pelo terceiro membro da trade MVC: o controlador. O controlador recebe a entrada do usurio, manipula o modelo e faz com que a vista seja atualizada apropriadamente. Dessa forma, a interface de usurio uma combinao da vista e do controlador.

Os padres que compem o catlogo JEE (Alur et alli, 2002, p.8), so agrupados em trs camadas, a saber: camada de apresentao, camada de negcios e camada de integrao. A camada de apresentao tem a responsabilidade de interceptar a entrada de dados e filtr-los, de estabelecer um controle nico para a entrada de dados e identificar os responsveis pelo atendimento s requisies de servio, que culminaro na exibio das vises da aplicao. A camada de negcios, segundo Alur et alli (2002, p. 19) trata da principal lgica de negcios da aplicao. Ela fornece as interfaces necessrias aos componentes de servios de negcios subjacentes. Finalmente, temos a camada de integrao, responsvel pelo sistema de informaes da empresa, incluindo os sistemas de banco de dados, o de processamento de transao, os sistemas herdados e os sistemas de planejamento de recurso da empresa. Nessa camada ocorre a integrao com sistemas que no so JEE e com os sistemas herdados.

Figura 62: Camadas do Padro MVC

376

Figura 63: Camadas da plataforma JEE


O modelo de camadas da arquitetura de referncia do Demoiselle combina os modelos anteriores de modo a aproveitar o melhor de cada um. A camada de vista do MVC e de apresentao do JEE so praticamente as mesmas. A camada de controle do MVC pode ser combinada com a camada referente a interface com o usurio, pois a requisio de servio sempre vem por uma interface e o resultado da solicitao tambm exibido por meio de uma. Dentro desse entendimento, o Demoiselle prope para as aplicaes uma camada chamada Controle e Viso. Essa a camada mais superior da arquitetura de referncia. A camada de negcios aproveitada integralmente pelo Demoiselle, como camada de regras de negcio. E as camadas de modelo do MVC e integrao do JEE so combinadas na camada mais inferior da arquitetura de referncia do Demoiselle: a de persistncia.

Figura 64: Camadas de aplicao Demoiselle 377

7.4 Concluso
Um framework direciona o desenvolvedor aos problemas relacionados as regras de negcio do cliente e a apresentao das informaes e reduz o esforo utilizado para resolver detalhes de baixo nvel como segurana, acesso a dados e comunicao com outros ambientes. O Demoiselle Framework cumpre esse papel, ao implementar a padronizao da implementao e criar um ambiente propcio para a prtica da reusabilidade. A padronizao garante maior facilidade de suporte e absoro de sistemas e facilidade de integrao e disponibilizao de servios para os novos sistemas. Essa padronizao resultado da anlise, integrao e utilizao de tecnologias mais reconhecidas utilizadas pelas comunidades de desenvolvedores. O modelo de desenvolvimento baseado em componentes facilita o reuso de mtodos, prticas e processos padronizados, e termina por permitir o reuso de componentes de negcio. A sua caracterstica de ser aberto, com desenvolvimento compartilhado, e de agregar implementaes de software baseadas em padres e especificaes lhe d condies de ser uma ferramenta totalmente voltada a integrao de diferentes instituies e diferentes tecnologias. O Demoiselle Framework abre caminho para a estruturao da anlise de sistemas em domnios, de modo a criar uma gesto orientada a polticas de contedos e promoes de contedos. Porque a infraestrutura de software no o mais o problema, o que abre espao para os desenvolvedores se preocuparem em os problemas relacionados a um determinado domnio de conhecimento. O Demoiselle atende prioritariamente a trs domnios especficos: a integrao de organizaes do Governo com a sociedade, a integrao dentro das organizaes e a integrao de grupos de sistemas. Isso o torna uma plataforma de desenvolvimento de uso geral, que pode ser mantida e usufruda por toda a sociedade, e evoluda de modo a beneficiar a todos.

378

APNDICE A Demoiselle Wizard


A criao de classes para a aplicao livrariademoiselle foi feita manualmente, mas existe um plugin para Eclipse que ajuda na gerao de cdigo no padro Demoiselle Framework. O plugin Demoiselle Wizard pode ser instalado via updatesite pela URL http://demoiselle.sourceforge.net/wizard/updatesite. Ele possui as seguintes funcionalidades: Configurar projeto: Permite a configurao de variveis e mensagens da aplicao, est distribuda em quatro grupos: Configurao do Hibernate, Configurao de JPA, configurao dos arquivos de recursos da aplicao e o cadastro das mensagens da aplicao.

Editar projeto: Destina-se a manuteno das diversas camadas de uma aplicao que utiliza o Demoiselle (criao, edio e remoo). Realiza a gerao de DAOs, Business Controllers, Managed Beans, Fachadas, regras de navegao da aplicao e testes unitrios

Criar pginas: Destina-se a criao de pginas JSP, as pginas podem ser de trs tipos: Listagem, Edio e Visualizao.

Criar CRUD: Destina-se a criao de fluxos do tipo CRUD (Create; Remove; Update e Delete) de entidades a partir de um Pojo selecionado.

Adicionar caractersticas do Demoiselle: Destina-se a transformao de projetos existentes na workspace em projetos do tipo Demoiselle que utilizam o framework Demoiselle.

Remover caractersticas do Demoiselle: Destina-se a transformao de projetos do tipo Demoiselle existentes na workspace em projetos Web, removendo assim as caractersticas do framework Demoiselle.

379

APNDICE B Script para criao do banco de dados


O modo mais fcil de instalar o PostgreSQL usando os pacotes binrios. A pgina http://www.postgresql.org/download contm uma seo chamada Binary packages, onde voc pode encontrar distribuies para os sistemas operacionais mais utilizados. Esses pacotes geralmente contm o pgAdmin III, uma interface grfica para administrao de bancos PostgreSQL.
CREATE DATABASE livraria WITH OWNER = postgres ENCODING = 'UTF8' LC_COLLATE = 'pt_BR.UTF-8' LC_CTYPE = 'pt_BR.UTF-8' CONNECTION LIMIT = -1;

CREATE TABLE autores ( id_autor serial NOT NULL, sobrenome character varying(20) NOT NULL, nome character varying(30), CONSTRAINT autores_pkey PRIMARY KEY (id_autor) ) WITH ( OIDS=FALSE ); ALTER TABLE autores OWNER TO postgres;

CREATE TABLE clientes (

380

id_cliente serial NOT NULL, cpf character(11) NOT NULL, nome character varying(80) NOT NULL, apelido character varying(10) NOT NULL, senha character(8) NOT NULL, email character varying(40) NOT NULL,

CONSTRAINT clientes_pkey PRIMARY KEY (id_cliente), CONSTRAINT clientes_apelido_key UNIQUE (apelido), CONSTRAINT clientes_cpf_key UNIQUE (cpf) ) WITH ( OIDS=FALSE ); ALTER TABLE clientes OWNER TO postgres;

CREATE TABLE editoras ( id_editora serial NOT NULL, nome character varying(30) NOT NULL, CONSTRAINT editoras_pkey PRIMARY KEY (id_editora) ) WITH ( OIDS=FALSE ); ALTER TABLE editoras OWNER TO postgres;

CREATE TABLE funcionarios ( id_usuario serial NOT NULL, matricula character(8) NOT NULL,

381

nome character varying(80) NOT NULL, apelido character varying(10) NOT NULL, senha character(8) NOT NULL, email character varying(40) NOT NULL, CONSTRAINT funcionarios_pkey PRIMARY KEY (id_usuario), CONSTRAINT funcionarios_apelido_key UNIQUE (apelido) ) WITH ( OIDS=FALSE ); ALTER TABLE funcionarios OWNER TO postgres;

CREATE TABLE locais ( id_local serial NOT NULL, nome character varying(30) NOT NULL, CONSTRAINT locais_pkey PRIMARY KEY (id_local) ) WITH ( OIDS=FALSE ); ALTER TABLE locais OWNER TO postgres;

CREATE TABLE pedidos ( numero_pedido bigint NOT NULL, data_pedido date NOT NULL, id_cliente integer NOT NULL, CONSTRAINT pedidos_pkey PRIMARY KEY (numero_pedido), CONSTRAINT pedidos_id_cliente_fkey FOREIGN KEY (id_cliente) REFERENCES clientes (id_cliente) MATCH SIMPLE

382

ON UPDATE NO ACTION ON DELETE NO ACTION ) WITH ( OIDS=FALSE ); ALTER TABLE pedidos OWNER TO postgres;

CREATE TABLE telefones ( id_telefone serial NOT NULL, numero character varying(16) NOT NULL, tipo character varying(20) NOT NULL, CONSTRAINT telefones_pkey PRIMARY KEY (id_telefone) ) WITH ( OIDS=FALSE ); ALTER TABLE telefones OWNER TO postgres;

CREATE TABLE telefones_cliente ( id_telefone integer NOT NULL, id_cliente integer NOT NULL, CONSTRAINT telefones_cliente_pkey PRIMARY KEY (id_telefone, id_cliente), CONSTRAINT telefones_cliente_id_cliente_fkey FOREIGN KEY (id_cliente) REFERENCES clientes (id_cliente) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT telefones_cliente_id_telefone_fkey FOREIGN KEY (id_telefone) REFERENCES telefones (id_telefone) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION )

383

WITH ( OIDS=FALSE ); ALTER TABLE telefones_cliente OWNER TO postgres;

CREATE TABLE telefones_funcionario ( id_telefone integer NOT NULL, id_funcionario integer NOT NULL, CONSTRAINT telefones_funcionario_pkey PRIMARY KEY (id_telefone, id_funcionario), CONSTRAINT telefones_funcionario_id_funcionario_fkey FOREIGN KEY (id_funcionario) REFERENCES funcionarios (id_usuario) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT telefones_funcionario_id_telefone_fkey FOREIGN KEY (id_telefone) REFERENCES telefones (id_telefone) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) WITH ( OIDS=FALSE ); ALTER TABLE telefones_funcionario OWNER TO postgres;

CREATE TABLE livros ( id_livro serial NOT NULL, isbn character varying(13) NOT NULL, titulo character varying(255) NOT NULL, id_local integer NOT NULL, id_editora integer NOT NULL, ano integer NOT NULL, preco money NOT NULL,

384

CONSTRAINT livros_pkey PRIMARY KEY (id_livro), CONSTRAINT livros_id_editora_fkey FOREIGN KEY (id_editora) REFERENCES editoras (id_editora) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT livros_id_local_fkey FOREIGN KEY (id_local) REFERENCES locais (id_local) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) WITH ( OIDS=FALSE ); ALTER TABLE livros OWNER TO postgres;

CREATE TABLE autores_livro ( id_autor integer NOT NULL, id_livro integer NOT NULL, ordem integer NOT NULL, CONSTRAINT autores_livro_pkey PRIMARY KEY (id_autor, id_livro), CONSTRAINT autores_livro_id_autor_fkey FOREIGN KEY (id_autor) REFERENCES autores (id_autor) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT autores_livro_id_livro_fkey FOREIGN KEY (id_livro) REFERENCES livros (id_livro) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) WITH ( OIDS=FALSE ); ALTER TABLE autores_livro OWNER TO postgres;

385

CREATE TABLE itens_pedido ( id_item serial NOT NULL, id_pedido integer NOT NULL, id_livro integer NOT NULL, preco money NOT NULL, quantidade integer NOT NULL, CONSTRAINT itens_pedido_pkey PRIMARY KEY (id_item), CONSTRAINT itens_pedido_id_livro_fkey FOREIGN KEY (id_livro) REFERENCES livros (id_livro) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT itens_pedido_id_pedido_fkey FOREIGN KEY (id_pedido) REFERENCES pedidos (numero_pedido) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) WITH ( OIDS=FALSE ); ALTER TABLE itens_pedido OWNER TO postgres;

386

APNDICE C Script para apagar as tabelas


drop table itens_pedido; drop table pedidos; drop table autores_livro; drop table livros; drop table autores; drop table editoras; drop table locais; drop table telefones_cliente; drop table clientes; drop table telefones_funcionario; drop table funcionarios; drop table telefones;

387

APNDICE D Driver JDBC para PostgreSQL


O driver JDBC para PostgreSQL est disponvel em http://jdbc.postgresql.org/download.html. Nas aplicaes deste livro foi utilizado a verso 8.4 para JDBC 3. O driver foi instalado no diretrio de bibliotecas da JDK (jre/lib/ext), para que no fosse necessria modificao do Build Path. Lembrando que o JDBC 3 para a JDK 5. Para usar na JDK 6, necessrio o JDBC 4.

388

Referncias Bibliogrficas
Allen, P. The Service Oriented Process. CBDI Journal. Fevereiro. 2007. Soa Best Practice Report. Disponvel em <http://www.cbdiforum.com/secure/interact/200702/service_oriented_process.php>. Acesso em 21/07/2009. APACHE SOFTWARE FOUNDATION. Open Letter to Sun Microsystems. Disponvel em <http://www.apache.org/jcp/sunopenletterfaq.html>. Acesso em 29/07/2009. Basham, B. Sierra, K. e Bates, B. Use a Cabea! Servlets & JSP. Rio de Janeiro. Alta Books, 2005. Booch, G. Rumbaugh J. Jacobson, I. The Unified Modeling Language User Guide, AddisonWesley, Reading, MA, 1998. BRASIL. Ministrio do Planejamento, Oramento e Gesto. Documento de Referncia da e-PING Verso 4.0. 16/12/2008. Disponvel em <http://www.governoeletronico.gov.br/anexos/e-ping-versao-4.0>. Acesso em 21/07/2009. Burnette, E. Houghton, A. Getting Started with Eclipse. Disponvel <http://refcardz.dzone.com/refcardz/getting-started-eclipse>. Acesso 23/04/2010. em em

Casett, O. Akamatu, D. M. Kirner, C. Paradigmas para construo de sistemas distribudos. Tema. n 114. Ano III. 1993. Disponvel em <http://www.serpro.gov.br/imprensa/publicacoes/tematec/1993/ttec13>. Acesso em 21/07/2009. Dai, N. WTP Tutorials Building and Running a Web Application. Disponvel em <http://www.eclipse.org/webtools/community/tutorials/BuildJ2EEWebApp/BuildJ2EEW ebApp.html>. Acesso em 26/04/2010. Deitel, H. M. E Deitel, P. J. Java: Como Programar. 6.ed. So Paulo, Pearson Prentice Hall, 2005. Fayad, M. Schmidt, D. Object-Oriented Application Frameworks. Communications of the ACM, New York, v. 40, n.10, p. 32-38, Oct. 1997. Fields, D. K. e Kolb, M.A. Desenvolvendo na Web com JavaServer Pages. Rio de Janeiro. Cincia Moderna, 2000. Fogel, K. Producing Open Source Software: How to Run a Successful Free Software Project. Disponvel em <http://producingoss.com/en/producingoss.pdf>. Acesso em 03/08/2009. Fowler, Martin. Inversion of Control Containers and the Dependency Injection pattern. Disponvel em <http://martinfowler.com/articles/injection.html>. Acesso em 14/08/2009.

389

Fowler, Martin. Padres de Arquitetura de Aplicaes Corporativas. Porto Alegre. Bookman, 2006. Fowler, M. POJO. Disponvel em <http://martinfowler.com/bliki/POJO.html>. Acesso em 04/05/2010. Fraga Filho, C. V. e Reis, J. M. Controla: Ferramenta de Apoio ao Processo de Desenvolvimento de Software em Pequenas Empresas. Anais do Conbratec, 2005. Gonalves, E. Desenvolvendo Aplicaes Web com JSP, Servlets, JavaServer Faces, Hibernate, EJB 3 Persistence e Ajax. Rio de Janeiro. Cincia Moderna, 2007. Grohs, E. M. et al. Framework JSerpro. Congresso Serpro de Tecnologia e Gesto Aplicadas a Servios Pblicos, 2007. Hall, M. e Brown, L. Core Servlets e JavaServer Pages. Volume 1: Tecnologias Core. Rio de Janeiro, Cincia Moderna, 2005. Hofmeister, C. Nord, R. Soni, D. Applied Software Architecture. Addison Wesley, 2000. Lakhani, K. R. e Wolf, R. G. Why Hackers Do What They Do: Understanding Motivation and Effort in Free/Open Source Software Projects. Disponvel em <http://freesoftware.mit.edu/papers/lakhaniwolf.pdf>. Acesso em 13/05/2009. Macias, A. M. Frameworks de Desenvolvimento Viso Geral. Tematec, Ano X, n XX, p. 1, 2008. Disponvel em <www.serpro.gov.br/clientes/serpro/serpro/imprensa/publicacoes/tematec/2008/ttec9 2_a>. Acesso em 28/07/2007. Mariaca, M. Gesto da Diversidade. Disponvel <http://imasters.uol.com.br/artigo/12603/tendencias/gestao_da_diversidade>. Acesso em 17/07/2009. em

McConnell, S. Code Complete: Um Guia Prtico para a Construo de Software. Porto Alegre. Bookman, 2005. McLaughkin, Brett. Pollice, Gary. e West, David. Anlise e Projeto Orientado ao Objeto. Rio de Janeiro. Alta Books, 2007. Miller, J. Padres na Prtica: Coeso e acoplamento. <http://msdn.microsoft.com/pt-br/magazine/cc947917.aspx>. 21/07/2009. Disponvel Acesso em em

Pacitti, Trcio. Paradigmas do Software Aberto. Rio de Janeiro. Livros Tcnicos e Cientficos, 2006. Paula Filho, Wilson P. Engenharia de Software: Fundamentos, Mtodos e Padres. 2.ed. Rio de Janeiro. Livros Tcnicos e Cientficos, 2003. Peltz, C. Web Services Orchestration and Choreography. Disponvel em <http://soa.syscon.com/node/39800>. Acesso em 21/07/2009.

390

Pinho, V. D. M. Processo de Desenvolvimento Demoiselle. <http://demoiselle-proc.sourceforge.net>. Acesso em 29/03/2010.

Disponvel

em

Pressman, R. S. Engenharia de Software. 6.ed. So Paulo. McGraw-Hill, 2006. Raymond. Eric. S. A Catedral e o Bazar. Disponvel <http://www.dominiopublico.gov.br/download/texto/tl000001.pdf>. Acesso 03/08/2009. em em

Reese, G. Programao para banco de dados: JDBC e Java. 2.ed. So Paulo. Berkeley, 2001. Silberschatz, A. Knorth, H. F. Sudarshan, S. Sistema de Banco de Dados. 3.ed. So Paulo. Makron Books, 1999. Silveira, G. et al. Java para desenvolvimento Web. So Paulo. Caelum, 2005. Shore, J. Warden, S. A Arte do Desenvolvimento gil. Rio de Janeiro. Alta Books, 2008. Sommerville, I. Engenharia de Software. 8.ed. So Paulo. Pearson Addison-Wesley, 2007. Srinivasan, Raghu. N. WTP Tutorials JavaServer Faces Tools Tutorial. Disponvel em <http://www.eclipse.org/webtools/jsf/docs/tutorial/JSFTools_1_0_tutorial.html>. Acesso em 14/06/2010. Taurion, C. Software Livre no Ambiente Corporativo: Situao atual e tendncias. I Workshop sobre Software no Ambiente Corporativo. 2004. So Paulo. Disponvel em <http://www.poli.usp.br/pro/sl/IWSLAC/Apresentacao_Cezar_Taurion.pdf>. Acesso em 04/08/2009. WIKIPEDIA. Brimstone. Disponvel <http://en.wikipedia.org/wiki/Brimstone_(TV_series)>. Acesso em 11/09/2008. em

Winck, D. V. e Goetten JUNIOR, V. AspectJ: Programao Orientada a Aspectos com Java. So Paulo. Novatec, 2006.

391