terça-feira, 14 de agosto de 2012

Desenvolvendo uma aplicação Java EE 6 com Eclipse (parte 4)


[linu.com.br] - [parte 1] - [parte 2] - [parte 3] - [parte 4] - lgapontes@gmail.com

Esse é o último capítulo de nossa história. Faremos aqui todos os testes diretamente nas telas do sistema. Faremos também um apanhado geral sobre como publicar a aplicação num servidor de aplicação (através de um arquivo EAR).
Vamos lá!
 
 
Testes gerais na aplicação
Antes de colocarmos a prova a implementação dos requisitos, faremos uma passagem geral pelo sistema. Conforme vimos, assim que a aplicação é publicada no GlassFish, teremos acesso a página inicial.
 
 
Note que, como não existem tópicos cadastrados, a mensagem Nenhum tópico foi encontrado foi disparada diretamente pela camada View. Certamente que o mecanismo de consulta ainda não poderá ser testado. Faremos agora o acesso à página de cadastro de tópicos - através do link Cadastrar Tópicos. Lembre-se que esse link foi definido na template.xhtml do Facelets e faz a navegação através do recurso de Navegação Implícita.
 
 
Lembre-se que esta página foi definida em @RequestScoped, logo, o Managed Bean responsável por sua construção já foi liberado. Veja que o título padrão Novo Tópico que definimos no comportamento @PostConstruct de TopicView foi exibido com sucesso. Preencha o formulário com os dados abaixo:
 
Título: Show do Guns N' Roses no Rio
Usuário: Guilherme
Tópico:
Fala galera!
Alguém foi ao show do guns no Rio?
Eu fui... e foi foda!
 
 
Em seguida, clique em Postar
 
 
 
De acordo com o outcome da página topics.xhtml, fomos redirecionados para a página index.xhtml, que agora passa a exibir o tópico cadastrado.
Antes de prosseguir, vamos nos atentar em como os dados foram registrados no banco de dados. Logicamente, os campos id, title, userName, creationDate e text de Topic foram salvos na tabela topic. Veja abaixo uma imagem retirada do utilitário PgAdmin3.
 
 
 
Essa inserção foi trivial. Entretanto, devemos nos atentar que toda a lógica de Business compreendida em TopicBusiness estava decorada com o serviço createMetadata() de MetadataService. Considerando também a lógica elaborada para o armazenamento das palavras dos tópicos (e comentários), podemos prever quais metadatas foram registradas. Como vimos (nas definições das camadas Business e Services), os valores do title e text dos tópicos serão utilizados para criar Metadatas. Veja abaixo que palavras foram utilizadas.
 
Show do Guns N' Roses no Rio
Fala galera!
Alguém foi ao show do guns no Rio?
Eu fui... e foi foda!
 
Lembre-se que existem algumas restrições: todos os pontos serão retirados; as palavras precisam conter no mínimo 3 e no máximo 255 caracteres; todas as palavras serão salvas em caixa-alta. Dessa forma, espera-se que a sequência abaixo tenha sido definida.
 
SHOW - 2 ocorrências
GUNS - 2 ocorrências
ROSES - 1 ocorrência
RIO - 2 ocorrências
FALA - 1 ocorrência
GALERA - 1 ocorrência
ALGUÉM - 1 ocorrência
FOI - 2 ocorrências
FUI - 1 ocorrência
FODA - 1 ocorrência
 
Vejamos então os registros:
 
 
Muito bem, tudo beleza! Clique novamente no link Cadastrar Tópicos e preencha o formulário de cadastro com os dados abaixo:
 
Título: Show do Dream Theater 2010
Usuário: Pontes
Tópico:
Esse foi o melhor show de rock que eu já fui!
 
 
Mais uma vez, novos Metadatas foram incluídos.
 
SHOW - 2 ocorrências
DREAM - 1 ocorrência
THEATER - 1 ocorrência
2010 - 1 ocorrência
ESSE - 1 ocorrência
FOI - 1 ocorrência
MELHOR - 1 ocorrência
ROCK - 1 ocorrência
QUE - 1 ocorrência
FUI - 1 ocorrência
 
Portanto...
 
 
Veja que, apesar de existirem duas linhas com a coluna word valorada como SHOW, elas pertencem a tópicos diferentes. Isso pode ser visualizado através da coluna topic_id. Lembre-se que todos os ids do sistema foram inseridos automaticamente pelo JPA.
Novamente nós fomos redirecionados para a página principal.
 
 
Vamos fazer agora um teste com o mecanismo de consulta! Preencha o campo de busca com a palavra GuNs
 
 
Veja que, propositalmente, estamos digitando uma palavra com caracteres maiúsculos e minúsculos. Clique em Pesquisar
 
 
Conforme o esperado, somente o tópico sobre o Guns N' Roses foi mostrado. Repare que as buscas sempre serão realizadas com caixa-alta. Por isso a palavra "GuNs" pode ser associada ao valor armazenado no banco "GUNS". Limpe a caixa "Digite uma palavra:" e clique em Pesquisar
 
 
Lembre-se que quando uma pesquisa é realizada com word vazia, todos os tópicos serão retornados. Assim que o resultado acima foi construído.
Clique sobre o link Show do Guns N' Roses no Rio, indicado na segunda linha da tabela, para acessarmos a página comments.xhtml com os comentários associados a esse tópico.
 
 
Muito bem! Como não existem comentários, somente a descrição do tópico foi mostrada. Preencha então o formulário Adicionar Comentário com os valores abaixo:
 
Usuário:
Comentário:
Eu também fui!
Pena que o Slash saiu do guns!
 
Por opção, deixaremos o campo Usuário em branco.
 
 
Clique em Postar
 
 
Lembre-se que, como uma das regras de cadastro de comentários, quando um usuário não informar seu nome, a palavra Visitante seria incluída automaticamente. Isso justifica o valor encontrado na exibição do comentário cadastrado.
Apenas para constar, quando esse registro foi incluído, algumas Metadatas relacionadas a esse tópico foram inseridas ou atualizadas. A palavra "também" não existia na descrição do tópico, logo, ela foi inserida com uma ocorrência. A palavra "guns", no entanto, já possuía duas ocorrências. Dessa forma espera-se que agora ela tenha 3. Continuando o raciocínio, podemos identificar que, para esse tópico, temos os seguintes registros:
 
SHOW - 2 ocorrências
GUNS - 3 ocorrências
ROSES - 1 ocorrência
RIO - 2 ocorrências
FALA - 1 ocorrência
GALERA - 1 ocorrência
ALGUÉM - 1 ocorrência
FOI - 2 ocorrências
FUI - 2 ocorrências
FODA - 1 ocorrência
TAMBÉM - 1 ocorrência
PENA - 1 ocorrência
QUE - 1 ocorrência
SLASH - 1 ocorrência
SAIU - 1 ocorrência
 
Vamos ver o resultado.
 
 
Veja que, como esperávamos, os novos Metadatas foram incluídos e os já existentes, atualizados. Clique agora sobre o link Buscar Tópicos
 
 
Veja que a coluna Comentários do tópico do Guns foi acrescida para 1. Lembre-se que esse dado foi obtido do getCountComments() do TopicViewable.
Esses foram os testes básicos do sistema. Vamos agora testas os requisitos.
 

Testando os requisitos funcionais tratados no sistema
Por conveniência, vamos replicar aqui os 8 requisitos definidos na parte 1 desse material.
 
  1. Cada tópico será composto por um título, por um texto (tópico em si), pelo nome do autor e data de criação;
  2. Depois de postado, o tópico poderá receber comentários de outros usuários;
  3. Os comentários serão formados por texto, data de criação e nome do usuário;
  4. Usuários terão a palavra "Visitante" associado ao tópico e/ou comentário caso não informe seu nome;
  5. A primeira página do sistema deverá mostrar uma relação dos tópicos cadastrados, ordenados em relação a data de postagem, do mais recente para o menos recente; Além disso a listagem de tópicos deve exibir a quantidade de comentários associados;
  6. O título de um Tópico deve ser único no sistema;
  7. Não poderão ser enviados comentários do usuário criador do tópico (ou seja, quem criou o tópico não pode comentá-lo).
  8. Deve existir uma ferramenta de busca que ordenará os tópicos pela quantidade de ocorrências de uma palavra. Neste caso, para facilitar, apenas uma palavra poderá ser pesquisada por vez.
 
Conforme vimos, todos esses requisitos foram plenamente atendidos. Veja que conseguimos abstrair a real importância do sistema nas camadas Model e Business/Services. Foram também separadas as responsabilidades da camada de persistência e camada de apresentação.
 
O requisito 1 não precisa de tela para comprovar. A própria estrutura da tabela já é capaz de identificar que esses campos foram concebidos.
 
 
Quando acessamos um tópico por seu link, temos mecanismos para inclusão de comentários, conforme já vimos. Portanto o requisito 2 foi atendido. O requisito 3 também pode ser conferido pela estrutura da tabela comment.
 
 
O 4º requisito pode ser visualizado se acessarmos a tela de comentários do tópico Show do Guns N' Roses no Rio
 

 Veja que, como o comentário foi inserido sem a declaração do userName, a palavra Visitante foi definida. Requisito 4 atendido. O 5º requisito pode ser verificado acessando a página inicial.
 
 
Como o tópico do Dream Theater foi inserido após o tópico do Guns, ele aparece primeiro - conforme a definição. Acesse agora a tela Cadastrar Tópicos e digite no formulário, os valores abaixo.
 
Título: Show do Guns N' Roses no Rio
Usuário: Guilherme
Tópico:
Apenas um teste do requisito 6.
 
 
Clique em Postar
 
 
Como podemos ver, a mensagem que definimos na camada de Business foi exibida na tela. Essa mensagem é disparada por uma BusinessException no método validate() de TopicBo, repassada pelo método create() de BasicBo e pelo createTopic() de TopicService. É então capturada pela nossa ExceptionHandlerForum, enviada para a página XHTML e exibida pela tag <h:messages>. Legal isso né? Enfim, tópico 6 validado.
 
Para testarmos o requisito 7, acesse a página de comentários do tópico Show do Dream Theater 2010 (através do link na página inicial). Preencha o formulário de cadastro de comentários com os valores.
 
Usuário: Pontes
Comentário:
Apenas um teste do requisito 7.
 
 
Clique em Postar
 
 
Veja que, como previsto, a mensagem disparada na CommentBo foi exibida na tela. Por fim, para testar o requisito 8, tente fazer uma consulta pela palavra "fui".
 
 
Como o tópico do Guns possui mais ocorrências da palavra "fui" (no caso, 2) do que o tópico do Dream Theater, ele foi exibido primeiro - está é a ordenação que já tinha sido definida diretamente na jpaQL da entidade Metadata. Se tentarmos pesquisar as palavras "teste requisito", teremos:
 
 
 
Pronto! Todos os requisitos foram atendidos. Apenas como complemento, lembre-se que também existe uma validação quanto ao tamanho do texto de tópicos e comentários. Se tentarmos incluir um registro em branco (menor que 1) ou superior à 500 caracteres, teremos uma restrição.
 
 
Note que essa validação foi realizada diretamente através da anotação @Size definida no atributo text da entidade Topic do modelo.
Outro detalhe é que, quando clicamos nos links dos tópicos na página inicial, o código do tópico é passado pela URL. Isso significa que, se tentarmos acessar essa página informando o código, os dados serão acessados. Tente, por exemplo, acessar a URL: http://localhost:8080/SuperForumWeb/faces/comments.xhtml?topic=1
Obs. No meu caso, existe um tópico de código 1. Como o JPA insere os ids automaticamente, não é garantido que os códigos em seu banco sejam exatamente os mesmos do meu.
 
 
E se eu apontar para um ID que não existe? Lembre-se que nós fizemos todo o controle no método refresh() de CommentView. Tente por exemplo acessar a URL:
 
 
Bom meus caros, acho que já é suficiente! Requisitos funcionais atendidos.
 
 
Publicando a aplicação no GlassFish (arquivo EAR)
Agora que sabemos que nossa aplicação está funcionando, vamos ver os procedimentos necessários para publicá-la através de um servidor de aplicação. O primeiro passo é empacotar todos os projetos dentro de um EAR. Isso é possível pelo próprio Eclipse.
 
Clique com o botão direito sobre o projeto SuperForum, selecione a opção Export, EAR file

 
 
Mantenha o nome do EAR project como SuperForum e defina um path para Destination. Caso haja necessidade de exportar o projeto com os fontes, marque a opção Export sources files. Isso não é necessário em ambiente de produção. Clique em Finish.
 
Agora, vamos iniciar o servidor de aplicação.
Detalhe: caso você esteja fazendo esse procedimento no mesmo servidor de aplicação utilizado no ambiente de desenvolvimento (no caso, no seu micro), o próprio Eclipse já terá definido que o projeto SuperForum será executado a partir do GlassFish. Portanto, quando iniciarmos o servidor, talvez não seja possível adicionar o EAR gerado no passo anterior. Ou seja, esse EAR já está configurado, ok? Faça isso apenas em outro GlassFish ou retire os projetos que o Eclipse associou ao seu servidor de desenvolvimento.

Banco de dados: lembre-se que deve existir um banco de dados chamado SuperServer rodando no Postgres em localhost. Nossa aplicação foi construída dessa forma.

Entre no Shell do Linux ou Prompt de Comando do Windows do micro onde está configurado o servidor de aplicação de produção. Efetuei esse procedimento no Linux, mas esses comandos podem ser adaptados facilmente ao Windows.
Acesse o diretório do servidor GlassFish. Dentro dessa pasta existem os seguintes diretórios:

drwxr-xr-x  2 guilherme guilherme 4096 2009-12-03 05:44 bin
drwxr-xr-x 10 guilherme guilherme 4096 2009-12-03 04:24 glassfish
drwxr-xr-x  4 guilherme guilherme 4096 2009-12-03 05:43 javadb
drwxr-xr-x  5 guilherme guilherme 4096 2009-12-03 05:44 mq
drwxr-xr-x  9 guilherme guilherme 4096 2009-12-03 06:11 .org.opensolaris,pkg
drwxrwxr-x  4 guilherme guilherme 4096 2009-12-03 05:42 pkg

Libraries: Não se esqueça de copiar as bibliotecas necessárias para o GlassFish.
Copie as bibliotecas commons-lang-2.5.jar e postgresql-8.4-701.jdbc4.jar para o diretório glassfish/lib (tendo como base o diretório de instalação - mostrado acima). Isso deve ser feito antes de inicializar o servidor.

Para iniciar o servidor, entre em bin e execute o comando

./asadmin start-domain domain1



Esse comando inicializa o domínio de nome domain1. Adapte o comando para seu caso. Agora acesse a página de administração do GlassFish. Para isso, basta acessar pelo navegador o IP do servidor na porta 4848. No meu caso: http://10.2.6.228:4848

JDBC: Lembre-se de configurar o recurso de acesso ao banco de dados no GlassFish. Isso pode ser visualizado na parte 1 desse tutorial. Não vamos tratar dessa configuração aqui novamente, mas ela é necessária para que a aplicação funcione.

Vamos, por fim, publicar o SuperForum. Acesse a página inicial http://10.2.6.228:4848


Vamos então configurar a aplicação. Clique, à esquerda, na opção Applications


Clique no botão Deploy...


Selecione o arquivo SuperForum.ear publicado pelo Eclipse. Em type, mantenha a opção Enterprise Application. Clique em OK.


Dessa forma, já podemos acessar a aplicação através da URL: http://10.2.6.228:8080/SuperForumWeb/



Detalhes da publicação EAR
char-set
É importante considerar alguns detalhes sobre a publicação de uma aplicação EAR nos servidores de aplicação.
O primeiro deles gira em torno do chat-set. Quando desenvolvemos uma aplicação Web, precisamos definir um chat-set padrão de acordo com as plataformas onde a aplicação foi desenvolvida e será publicada. Geralmente, em sistemas Linux, é utilizado o UTF-8 e, em ambiente Microsoft, iso-8859-1. Como eu desenvolvi esse material em máquinas diferentes, onde a maioria delas só possuía o SO Windows XP, optei em criar os arquivos XHTML e CSS no padrão iso-8859-1. Talvez você precise alterar esse detalhe dependendo do seu ambiente de desenvolvimento.

context-root
A aplicação disponível num pacote EAR possui um contexto principal. Note que em nossa aplicação, foi mantido o contexto padrão (criado pelo Eclipse) SuperForumWeb. Isso pode ser alterado no arquivo SuperForumWeb/WebContent/WEB-INF/sun-web.xml e no arquivo SuperForum/META-INF/application.xml através da tag <context-root>. Geralmente um contexto formatado em caixa-baixa, com um número menor de caracteres, é mais viável. Em nosso caso, talvez o contexto forum fosse mais apropriado.


Java EE 6: O que não foi usado?
Utilizamos muitas novidades durante esse projeto, mas ainda existem novos recursos que não contemplamos. Veremos agora um apanhado rápido sobre esses recursos.

Profile
O Java EE 6 possui 26 especificações. Nem sempre precisamos utilizar todas. Na verdade, muitos projetos poderiam ser construídos apenas com os principais pacotes. Podemos então configurar a plataforma Java EE 6 para trabalhar com algumas especificações, deixando outras de lado. O nome de recurso é Profile. Esse tipo de recurso é interessante quando temos aplicações pequenas que não precisam de todas as especificações. Dessa forma, o servidor de aplicação suportará o que o Profile definir, fazendo com que menos recursos de hardware sejam necessários.

@Named
Além das anotações @Inject, @Qualifier e @Singleton, nós temos agregada à CDI o recurso @Named. Essa anotação faz com que o objeto, bean gerenciado pela CDI do servidor, possa ser acessado diretamente pela camada de apresentação (no caso, as páginas XHTML) através de EL - de forma semelhante aos @ManagedBean's. A diferença é que quando um objeto está em CDI, ele pode ser obtido por @Inject e fazer referência (via @Inject também) a outros beans da CDI. Um @ManagedBean não possui esse comportamento. Então, caso você precise disponibilizar um bean CDI na camada de apresentação, use o @Named.

Navegação Condicional
Além da navegação implícita, existe também a possibilidade de criar uma condição de navegação (um IF) na <nagegation-rule> e direcionar o usuário para páginas diferentes. Isso só pode ser feito via configuração do arquivo faces-config.xml.

Servlet 3.0
Os servlets seguiram o mesmo caminho dos JSF: agora eles também podem ser declarados diretamente nas classes, via @WebServlet. Na versão antiga do Java EE, os servlets precisavam, obrigatoriamente, ser declarados no web.xml. Isso não é mais necessário.

Timer Service
Através de uma nova anotação @Schedule, nós podemos agendar tarefas com o recurso Cron do Linux. Para quem não conhece, o Cron permite agendamento de tarefas no ambiente UNIX.

@Typed
Lembra-se da nossa camada Business. Nós criamos qualificadores (@Qualifier) para indicar ao servidor qual bean seria obtido da CDI. Na declaração dos bean, entretanto, nós podemos também identificar para qual classe esse bean poderia ser resgatado. Ou seja, se declararmos @Typed(ClasseM.class) na declaração da ClasseM, quando ela fosse obtida via @Inject, sua instância só poderia ser guardada no tipo ClasseM.class. Isso significa que se tentássemos obter uma ClasseM e guardá-la em um Object, por exemplo, teríamos um erro em tempo de deployment.

@Alternative
Esse recurso oferece a possibilidade de criar beans alternativos, substituindo a implementação original quando necessário. O desenvolvedor escolheria qual bean seria utilizado no momento do deploy.

Interceptors
Como sabemos, esse recurso já estava disponível na versão Java EE 5. Os Interceptors são elementos que interceptam (ohhh...) a chamada dos métodos de uma classe. Geralmente é utilizado para fins de LOG ou auditoria. Aqui, porém, tivemos algumas melhoras. Eles deixaram de ser construídos de forma intrusiva. Minha nossa Senhora... isso morde? Seguinte, isso é apenas uma forma "bonita" de dizer que o Interceptor antigo era muito acoplado ao interceptado. Da forma como foi construída no Java EE 6 (os chamados Interceptor Bindings) isso não acontece.

Eventos
Existem agora mecanismos para que eventos sejam disparados (através da classe javax.enterprise.event.Event) e capturados por @Observes. Esse recurso é muito interessante quando temos vários procedimentos atrelados a um comportamento de determinado serviço. Imagine por exemplo que quando um comentário fosse postado, o criador do tópico devesse receber um aviso por e-mail. Isso poderia ser implementado com eventos.


Download do SuperForum
Estou disponibilizando o pacote EAR pronto para ser publicado num servidor de aplicação compatível com EE 6 (hoje, por enquanto, só existe o GlassFish v3, mas isso é questão de tempo). Lembre-se apenas de fazer os passos identificados no item Publicando a aplicação no GlassFish (arquivo EAR) nesse material.


Conclusão
Amigo leitor, eu espero ter contribuído para sua carreira de desenvolvedor ou para sua sempre bem-vida curiosidade acadêmica no que diz respeito ao desenvolvimento de sistemas Java EE. Como disse, uma aplicação desse porte (SuperForum) não utilizaria nem 30% do que as especificações do Java EE 6 nos oferecem. Contudo tentei explorar muitas novidades para que pudéssemos estar preparados para os desafios diários na confecção de um sistema. De qualquer forma, acho que alcançamos um resultado satisfatório.
Resta-me então agradecê-lo pela companhia e desculpar-me pelos possíveis erros na passagem do conteúdo (e mais possíveis ainda erros de gramática - uffff!).
Ahhh... Estarei sempre disponível para tirar quaisquer dúvidas relacionadas ao Java, Linux e Banco de Dados - se eu souber, é claro! Se não souber, pesquisaremos juntos, hehe! Fique à vontade para enviá-las via e-mail (lgapontes@gmail.com).


Referências
Revista Mundo Java (edição 40)
http://java.sun.com/developer/technicalArticles/JavaEE/JavaEE6Overview.html
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd
http://martinfowler.com/articles/injection.html
http://www.cssdrive.com/index.php/examples/exampleitem/tableless_forms/
http://www.guj.com.br/posts/list/53250.java
http://andyschwartz.wordpress.com/2009/07/31/whats-new-in-jsf-2/
http://docs.jboss.org/hibernate/stable/validator/reference/en/html/validator-usingvalidator.html
http://java.sun.com/javaee/technologies/index.jsp
http://www.theserverside.com/news/2240016831/Part-3-of-dependency-injection-in-Java-EE-6
http://www.coreservlets.com/JSF-Tutorial/jsf2/
http://www.laliluna.de/articles/jsf-2-evaluation-test.html
http://blog.gilliard.eti.br/2008/10/view-scope-no-jsf-2/
http://72.5.124.55/javaee/6/docs/tutorial/doc/gfirp.html
http://java.sun.com/javaee/5/docs/tutorial/doc/bnaxw.html
http://blog.caelum.com.br/2007/10/02/internacionalizacao-no-codigo-java/
http://www.laliluna.de/articles/jsf-2-evaluation-test.html
http://stackoverflow.com/questions/1791610/java-find-the-first-cause-of-an-exception
http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/objectstate.html
http://blogs.sun.com/rlubke/entry/jsf_2_0_bookmarability_view
http://www.exadel.com/tutorial/jsf/jsftags-guide.html
http://www.ibm.com/developerworks/library/j-jsf2/
http://www.edsongoncalves.com.br/2010/01/18/javaserver-faces-2-0-na-pratica-parte-1/
http://www.laliluna.de/articles/jsf-2-evaluation-test.html
http://java.sun.com/javaee/downloads/index.jsp
http://www.eclipse.org/downloads/
http://jude.change-vision.com/jude-web/download/index.html
http://www.postgresql.org/
http://linubr.blogspot.com.br/2012/08/configurando-eclipse-para-java-ee-6.html
http://linubr.blogspot.com.br/2012/08/entendendo-persistencia-de-dados-e.html
http://linubr.blogspot.com.br/2012/08/desenvolvendo-um-crud-para-web-com-java.html
http://jdbc.postgresql.org/download.html
http://linubr.blogspot.com.br/2012/08/criar-dao-com-singleton-ou-nao-eis.html
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd
http://martinfowler.com/articles/injection.html
http://linubr.blogspot.com.br/2012/08/utilizando-variavel-final-no-looping.html
http://en.wikipedia.org/wiki/Decorator_pattern
http://javawora.blogspot.com/2007/08/tutorial-faceltes.html
http://pt.wikipedia.org/wiki/XHTML
http://www.edsongoncalves.com.br/2010/01/18/javaserver-faces-2-0-na-pratica-parte-1/
http://maujor.com/
http://www.cssdrive.com/index.php/examples/exampleitem/tableless_forms/
http://maujor.com/tutorial/xhtml.php
http://pt.wikipedia.org/wiki/XHTML
http://www.coreservlets.com/JSF-Tutorial/jsf2/
http://en.wikipedia.org/wiki/Primitive_wrapper_class
http://www.laliluna.de/articles/jsf-2-evaluation-test.html
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/NullPointerException.html
http://java.sun.com/developer/technicalArticles/JavaEE/JavaEE6Overview.html
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd
http://martinfowler.com/articles/injection.html
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd
http://markmail.org/message/rnmtyphhjbj3dxww
http://technicalbrainwave.wordpress.com/2009/09/21/exception-handling-in-jsf/
http://www.furutani.com.br/2008/08/jsf-javaserver-faces-exception-handler/
http://www.guj.com.br/posts/list/132529.java
http://commons.apache.org/lang/download_lang.cgi
https://glassfishplugins.dev.java.net/download/index.html

Poxa!! Dessa vez tive muitas referências heim!?
Só para constar: esse tutorial (as quatro partes) possui 178 páginas (aproximadas). Dá próxima vez vou escrever um livro... hehe.

"Se você é bom em alguma coisa, nunca a faça de graça." - Coringa em "O Cavaleiro das Trevas"

"O capitão começou a investir num negócio de frutas." - Forrest Gump
Detalhe: ele disse isso quando seu amigo Dan Taylor começou a investir na Apple. Hehehehe. Cara, esse filme é foda!!!!

"Você pode ser famoso e se hospedar nos hotéis mais caros, mas quando for ao banheiro usará o mesmo papel higiênico que as outras pessoas" - Slash

Valeu galera!
Att, Guilherme Pontes

[linu.com.br] - [parte 1] - [parte 2] - [parte 3] - [parte 4] - lgapontes@gmail.com

Nenhum comentário:

Postar um comentário