Sei sulla pagina 1di 66

Módulo

Regras de Negócio
.
E

Este módulo traz uma exposição detalhada da “Visão Comportamental” da


arquitetura MVC suportada no jCompany FS Framework, além de tutoriais com
técnicas diversas de implementação de regras de negócio Orientadas a Objetos, em
Java EE.
Capítulo
Programando Java com
6
1
E

jCompany

Introdução

- Nota para ramo Facelets (jCompany 5.5) e versão 6.0 Preview (para Rally)
Este capítulo possui alguns conteúdos referindo-se às tecnologia JSP e Tiles, além do uso do framework
javascript DOJO, todas tecnologias utilizadas até a versao 5.2.
Mais recentemente, a partir da versão 5.5 e na versãso 6.0 Preview (utilizada apenas para o Rally Java
EE Open Source), estas foram aprimoradas em função do surgimento do Facelets como parte do padrão
Java EE 6 (JSF 2.0) e da popularização do mecanismo de "Java Não Obstrutivo" do jQuery.
Apesar disto, a grande maioria do conteúdo e mesmo as explicações e diagramas presentes no capítulo
se mantém úteis, até inclusive a versão 5.5. Há plano para revisão integral deste capítulo, por advento
do lançamento da versão oficial 6.0 do jCompany, prevista para 2011.

- Programação Declarativa x Programação Procedimental


Até este capítulo, estivemos principalmente envolvidos com técnicas de reúso de generalizações através
de “programação declarativa”, o que fizemos tanto em XML (Tiles, JSF, web.xml, etc.) quanto em
Anotações (JPA, jCompany, etc.).
A técnica de reúso a partir de declarações é muito interessante para a ativação de parcelas de código
repetitivo ao longo de diversos Casos de Uso e Aplicações, mas não será compensadora para
programações específicas de cada cenário. Por isso, a partir de agora iremos iniciar uma exploração mais
detalhada acerca das possibilidades de programação procedimental (algorítmica) em Java, sobre a
arquitetura do jCompany FS Framework.
Basicamente, precisaremos compreender como organizar nossa programação em camadas, utilizando
MVC tipo 2 e com segmentação da camada de Persistência por DP DAO (o que chamamos
resumidamente de MVC2-P). São alguns dos nossos objetivos de aprendizado, com relação ao
jCompany FS Framework:
Entender como ele implementa a arquitetura MVC2-P, de uma forma geral;
Entender as técnicas empregadas de Inversão de Controle (IoC) e como variam em cada camada;
Enteder as técnicas de Injeção de Dependência (DI), em cada camada;
Entender como são realizadas as transações orientadas a aspectos (via AOP);
Entender como são implementados os principais Design Patterns, em cada camada, tais como “Template
Method”, “Façade”, “Service Locator”, “Delegate” e “Singleton”.

- Arquitetura MVC2-P (Model-View Controller 2 with Persistence Layer)


Manter uma aplicação que se adapte facilmente à inovação, com menor risco de ser descartada ou entrar
em obsolescência, em função de adventos tecnológicos, é uma preocupação válida. Mas não deve vir
acompanhada de um ônus de produtividade que inviabilize os resultados imediatos que forem
necessários.
O jCompany procura promover um balanço ótimo entre “flexibilidade e produtividade”, recomendando
que implementações específicas sigam certas orientações de arquitetura e DPs (Design Patterns) “pauta
mínima”. Ainda assim, procura manter o processo produtivo, sem abrir mão da arquitetura MVC-2 que
introduzimos no Capítulo 4 do Módulo A.
No presente capítulo, iremos nos aprofundar em práticas de programação, para cada camada desta
arquitetura.
- Convenções de Nomenclatura
Neste capítulo, chamaremos os fluxos de processamentos de resposta da aplicação para eventos
disparados por usuários de “Seqüência de Transação”. Tipicamente, estes eventos são disparados a
partir de cliques em botões e/ou hiperlinks. Já o agrupamento de possíveis eventos em torno de um
único formulário/URL chamaremos de “Colaboração” (como já o temos feito).
Por exemplo, dizemos que a “Colaboração de Manutenção de Clientes” é identificada pela URL
“/clienteman” e tem estereótipo “plcCrud”, sendo composta dos eventos de usuário “F7-Novo”, “F12-
Gravar”, “Excluir”, “Clonar”, etc.. Cada um destes eventos, por sua vez, dispara a sua “Seqüência de
Transação”, basicamente processando o atendimento de forma segmentada por camadas, em respeito à
arquitetura MVC2-P.

Anatomia de requisições da arquitetura do jCompany FS Framework

- Visão geral das principais Classes e Interfaces, em cada camada MVC2-P


Vamos analisar, em um nível macro, a anatomia de requisições padrões na arquitetura MVC2-P do
jCompany, através da Figura E16.1.

*
Figura E16.1. Categorias de classes/camadas participantes de uma seqüência de atendimento .

#1. Em uma aplicação Web, o processamento principal ocorre no servidor. Por este motivo, o
código Javascript que eventualmente roda em Navegadores, na máquina do usuário (cliente),
não é normalmente considerado, em uma análise de arquitetura MVC. Isto tem mudado, nos
últimos anos, com a popularização das tecnologias Ajax e da Web 2.0 em geral. Por este
motivo, iremos representá-la em nossos diagramas.

Chamaremos a esta subcamada, segmentação da camada Visão que roda no Navegador, de


“camada Visão do Cliente”. As implementações do jCompany nesta área estão
principalmente contidas no arquivo de bibliotecas Javascript “/plc/javascript/PlcGeral.js”,
no projeto “jcompany_visao”, e podem ser complementadas por bibliotecas específicas
reunidas no arquivo sugerido “/plc/javascript/AppGeral.js”, presente em cada projeto, via
templates INI.

#2. A “camada Visão do Servidor” é representada por diversos frameworks de base integrados
pelo jCompany FS Framework, para “tirar o máximo” de uma Interface com o Usuário via
Web. Dentre eles, o JSF via componentes Apache Trinidad, o Tiles, o JSP e o JSTL, dentre
outros.

Não se pode destacar uma única classe ou artefato que represente um papel preponderante
nesta camada. Diversas especializações de componentes Apache Trinidad, JSPs de leiaute e
componentes de leiaute Tiles, Tag-Files e Tag-Libs (Struts e JSF), dentre outros, atuam com
interação, nesta camada.

*
As classes representadas no diagrama são implementações concretas ou interfaces que possuem algum papel de destaque em sua
camada. As implementações reais são bem mais sofisticadas, como veremos, muias vezes envolvendo interações entre dezenas classes
e tecnologias, em uma mesma camada.
#3. A “camada Controle” cuida da maior parte de processamento de internacionalização, cookies,
conversões e adaptações diversas, além de manter o “estado” (ou conversação) das transações
mais comuns. Trata-se de uma camada bastante complexa, especialmente quando se pretende
produzir GUIs sofisticadas via Web.

Ela é principalmente representada pela classe “PlcBaseJsfAction” (Ou em Struts, pelo


"PlcBaseAction"), que contém o código principal mais “visível”, nesta área. Mas dezenas de
outras classes também estão envolvidas neste segmento, desde Servlets (Front Controllers),
Filters e Listeners, até classes de ciclo de vida de componentes JSF (“PlcPhaseListener”),
JBoss Seam, serviços e utilitários de escopo da camada (Service e Helpers do jCompany).
Uma classe descendente “AppAction” costuma atuar de forma pré-configurada nas aplicações,
para permitir sobreposições e isolamento dos ancestrais do framework.

#4. A “camada Modelo” engloba tipicamente os números 4, 5, 7 e 8, representados na Figura


E16.1. Mas em nosso caso discutiremos a camada de Persistência à parte. Por este motivo, a
camada Modelo será representada somente pelas subcamadas 4 (Fachada) e 5
(Serviço de Negócio).

A “subcamada de Fachada” (DP Façade) tem na interface “IPlcFacade” a definição do


“contrato” da camada Controle com a camada Modelo, deste modo permitindo um claro
isolamento entre ambas, requisito fundamental para um baixo acoplamento “garantido”, que
torne mais seguro escalar aplicações em complexidade.

A implementação padrão “PlcFacadeImpl” realiza apenas um código de adaptação e também


de gerenciamento de transação, como veremos adiante. Tanto o contrato (interface) quanto a
implementação padrão não atuam diretamente, mas através de IoC com os descendentes
“IAppFacade” e “AppFacadeImpl”, específicos de cada projetos, deste modo possibilitando
extensões e sobreposições por parte das aplicações.

#5. A “subcamada de Serviço” contém a maior parte do código Java que realiza a orquestração
principal de retaguarda dos Casos de Uso Padrões do jCompany, para tratamento dos eventos
de manutenção do ciclo de vida para agregações complexas de objetos de domínio, como
vimos até aqui.

Mais especificamente, a classe “PlcBaseBO” traz 90% das implementações generalizadas para
este fim, nesta subcamada*. Uma descendente "AppBaseManager", gerada de forma
específica em cada aplicação, também atua via IoC, de forma similar a outras camadas, para
prover ponto de extensão e isolamento.

#6. A “camada de Domínio” foi muito utilizada ao longo dos tutoriais, trazendo programações de
decisão no escopo das agregações de classes que representam conceitos do negócio, sem
depender de outras camadas ou orquestrar transações.

O ancestral comum para entidades de domínio “PlcBaseVO” mantém código para


generalização de manipulação de Object-ID, equals, hashCode e algumas outras funções de
interesse comum a todos os objetos de domínio†.

Lembre-se que, apesar de se encontrar representada nesta posição do diagrama de seqüência,


estas classes de Domínio se localizam em um projeto “comuns”, sendo “ortogonal” às demais
camadas, ou seja, visível por todas elas. Revise o capítulo 4, para um melhor entendimento.

#7. A “camada de Persistência” em uma arquitetura MVC2-P é definida pelas subcamadas 7 e 8.


Na subcamada 7, o contrato “IPlcDAO” define a relação entre a camada de “Modelo” e a de
“Persistência”, funcionando também como uma “fachada” (DP Façade) entre estas duas

*
Além desta categoria de classes que lidam com manutenção de ciclo de vida de documentos (também chamadas de Managers no
jCompany), encontraremos também, nesta subcamada, classes de categorias conhecidas como Application Servers (AS),
orquestradoras de lógicas de programação “batch” ou outros serviços de negócio, não necessariamente vinculados a “ciclos de vida” de
agregações. Neste caso, não há comportamento generalizado, por isto esta categoria não foi representada.

O sufixo “VO” é mantido para compatibilidade com versões anteriores, mas isso não implica que estas classes devam seguir o DP
Value Object (VO). Seu funcionamento deve seguir orientações de Domain-Driven Design (DDD), como vimos, e inclusive com sufixos
personalizados nos descendentes.
camadas. Deste modo, permite que sejam definidas variações de implementação de
persistência para, por exemplo, persistir para arquivos convencionais XML, LDAP ou até mesmo
Web-Services, sem afetar nenhuma das demais camadas, discutidas até aqui!

A implementação da Interface “IPlcDAO” é realizada por um DP Abstract Factory, que por


sua vez envolve um ancestral abstrato “PlcBaseDAO” e diversos descendentes possíveis. O
jCompany já traz duas implementações concretas para o “PlcBaseDAO”: uma chamada
"PlcBaseHibernateDAO", para Hibernate, e outra chamada "PlcBaseJpaDAO", para o JPA*.

#8. A subcamada 8 é representada pelo framework que provê os serviços de persistência padrão
para SGBD-R relacionais. Ela é evidenciada no diagrama devido ao papel preponderante que
possui, eliminando códigos de INSERT, UPDATE e DELETE das classes de DAO, bem como
montando grafos de entidades de Domínio na memória a partir de “Result Sets JDBC” (deste
modo, viabilizando programações OO com produtividade).

#9. Seqüência do empilhamento de chamadas (requisição).

#10. Seqüência do desempilhamento (resposta).

Analisando as seqüências representadas pelos ítens 9 e 10, podemos nos surpreender com alguns
detalhes: a ordem de processamento pode não ser bem a inicialmente esperado, para quem está
iniciando na arquitetura MVC2.
Na prática, é bem mais fácil compreender uma arquitetura MVC1, na qual uma requisição é recebida por
um artefato específico de camada Visão (como uma “JSP”). Na variação MVC2, um único Servlet
“controlador” (DP Front Controller) é quem recepciona todas as requisições – a camada Controle é,
portanto, a responsável por iniciar o tratamento das requisições.
Vamos acompanhar, por exemplo, nesta numeração alternativa da Figura E16.1, a seqüência de uma
requisição GET, que é a que ocorre quando o usuário clica em algum item de menu, por exemplo. Neste
caso, vamos acompanhar uma Colaboração Padrão “plcTabular”, utilizada para realizar um Caso de Uso
“Manter Classe”.

- Seqüência MVC2-P em nível macro, para “Manter Classe”


A Seqüência de Transação para um evento de abertura (equivalente ao “F9-Pesquisar”) para uma
Colaboração “plcTabular” é a seguinte:
Seqüência de Requisição ou Empilhamento (Ida) para uma abertura de Colaboração Padrão
“plcTabular”
1. S1. A requisição inicia com um usuário clicando em algum hiperlink de aplicação (como nos menus)
ou digitando uma URL, tal como http://www.acme.com.br/rhtutorial/f/t/uf. Hiperlinks enviam
comandos HTTP GET, que possuem processamento trivial pelos Navegadores (camada Visão do
Cliente). Por isto, a requisição foi representada partindo direto do Ator.

2. S2. O comando HTTP GET com o endereço da transação digitado (URL) é recepcionado pelo Servlet
Controller “FacesServlet”, que por sua vez utiliza mecanismos declarativos padrões do JSF,
definidos nos arquivos “faces-config.xml”, para despachar a requisição para classes de controle mais
“especializadas”. Nos Casos de Uso padrões do jCompany, quando não há classe de controle
especificamente declarada no metadados da Colaboração, o tratamento é delegado para a classe
“PlcBaseJsfAction” ou “AppAction” (sua descendentes em escopo de aplicações). Isto é realizado
após um trâmite inicial que será detalhado mais a frente.

A classe de controle “PlcBaseJsfAction” reconhece que o padrão utilizado na Colaboração é o


“plcTabular” (TABULAR), pelos metadados associados à colaboração (URL “/f/t/uf”), encontrados no
arquivo padrão de anotações “package-info.java”, localizado no pacote
“com.powerlogic.jcompany.config.app.uf”. Deste modo, assume o padrão inicial para este tipo
de Colaboração, que é recuperar todos os objetos da classe. Na seqüência, envia uma requisição

*
É importante notar que a classe "PlcBaseDAO", apesar de abstrata, traz códigos comuns entre Hibernate e JPA. Portanto, o DP
Abstract Factory, no jCompany, deve ser utilizado somente para customizações relativas ao uso destas tecnologias de mapeamento
objeto-relacional, tais como adaptações para variações de versão. Para variações mais radicais, para mecanismos de persistência não
relacionais, por exemplo, deve-se reimplementar o contrato “IPlcDao”.
para a camada Modelo, via contrato “IPlcFacade”, passando informações de contexto da transação
(metadados relevantes, usuário, etc.) e o tipo (Entidade Raiz) da classe principal envolvida.

3. S3. A implementação padrão “AppFacadeImpl” atende à chamada, já que é declarada no arquivo


de metadados no escopo de aplicação, em “com.powerlogic.jcompany.config.app”, através da
propriedade “facadeImplementacaoPadrao” na anotação "PlcConfigControleIoC". Esta
implementação de fachada, neste caso, somente aciona um mecanismo de Inversão de Controle
(IoC), que é implementado dentro de um algoritmo de DP Service Locator.

Este algoritmo, somente na primeira requisição de cada “tipo”, tenta localizar o melhor “serviço”
(classe da hierarquia padrão) da camada Modelo para atender à requisição. Este algoritmo faz a
localização, por default, baseado em amarração automática a partir de padrão de nomenclatura
(Pattern Based Auto-Wiring IoC), que será explicado mais a frente. Se não encontrar nenhuma
classe específica para “atuar” na requisição em questão, utiliza a classe genérica “PlcBaseBO” (ou
alguma descendente, que pode ser declarada como padrão).

4. S4. A classe “PlcBaseBO”, neste caso, somente chama o serviço de recuperação simples de
objetos, chamado “recuperaTodos”, definido no contrato “IPlcDAO”.

A forma de localização do serviço de persistência também é um ponto chave aqui. A implementação


padrão para este contrato utilizada será ‘PlcBaseHibernateDAO”, caso a definição da “tecnologia”
em “PlcConfigModeloTecnologia”, definida em escopo da aplicação, seja “POJO”. Se for “EJB3”,
a implementação padrão utilizada será “PlcBaseJpaDAO”.

Mas aqui também é utilizado IoC com amarração automática, de modo que um DAO específico e
com nomenclatura padrão, se existir, será ativado, facilmente expandindo ou alterando
implementações.

5. S5. Quaisquer das implementações de DAO irá iniciar seu trabalho recuperando uma conexão de um
pool de conexões JDBC via endereço “JNDI” declarado no arquivo “web.xml” ou outro mecanismo
disponibilizado pelo Application Server.

Se a implementação for “PlcBaseHibernateDAO”, uma transação inicial com o SGBD-R (BEGIN


TRANSACTION) será gerada, no primeiro acesso ao SGBD. Se for “PlcBaseJpaDAO”, ela terá se
iniciado em conformidade com regras do container, possivelmente desde a chamada da fachada, que
contém anotações JPA para início de transações no padrão Java EE 5.

6. S6. Em seguida, a recuperação é feita via mecanismo de persistência (Hibernate ou outra


implementação O-R que suporte o JPA), e inicia-se o desempilhamento da requisição, ou ciclo de
resposta.

Seqüência de Resposta ou Desempilhamento (Volta) para uma abertura de Colaboração


Padrão “plcTabular”
7. S7. O próprio JPA cuidará de instanciar uma coleção de agregações de Entidades de Domínio após
recuperar seu “estado” do SGBD-R. Eventualmente, em métodos “setter” e “getter”, alguma
pequena programação neste nível poderá ser acionada.

8. S8. Programações de pouca relevância serão feitas no caminho de volta da camada Modelo, mas a
finalização do serviço de fachada merece menção, pois é aqui que a transação com o SGBD-R é
encerrada. Na prática, uma rotina AOP do jCompany implementada na classe
“PlcAOPModeloCallbackService” intercepta chamadas às implementações de interfaces de
fachada, e ao final delas faz uma chamada adicional ao método “dao.rollback” ou “dao.commit”,
métodos disponíveis no contrato da classe “PlcBaseDAO”.

No caso do exemplo de uma requisição de recuperação de lista de objetos, a transação é encerrada


com o “rollback”. Em gravações, com um “commit”. Perceba que, como a transação dura até a
finalização da execução na camada modelo, pode-se implementar acessos adicionais, tanto de
leitura quanto de gravação, durante todo o trajeto, de ida ou de volta, desde que atrás da
“fachada”*.

9. S9. A classe de controle costuma trabalhar um pouco mais que as demais no retorno, já que deve
montar uma estrutura de resposta para o usuário. Uma boa parte deste trabalho é feita nesta
camada, mas a maioria é delegada para a camada Visão.

Em linhas gerais: após decidir qual a “visão de retorno” será utilizada, analisando a declaração de
fluxo definida em arquivos como “faces-config.xml” (ou “struts-config.xml”, para tecnologia
Struts), a camada controle delega a responsabilidade de renderizar o documento de resposta para
classes da camada de Visão.

10. S10. As classes da camada Visão, formadas por uma combinado de frameworks e tecnologias
harmonizadas pelo jCompany, cumprem então o seu objetivo final de montar e renderizar um
documento HTML ou XHTML (se o cliente for um Navegador Web), acompanhado por rotinas
Javascript, CSS, mídia, etc., - e com dados relevantes devidamente “preenchidos”, incorporados em
textos ou em valores de campos de formulários HTML.

Perceba que, em uma seqüência típica MVC2, a camada Visão será a última a atuar. Em uma
atualização, componentes JSF de camada Visão entrariam com algum processamento na seqüência
de requisição (Empilhamento), mas 90% do processamento desta camada ainda se daria na
seqüência de resposta (Desempilhamento).

11. S11. Para um estudo convencional de MVC2-P, a seqüência de processamento estaria encerrada.
Porém, sabemos que ainda ocorrerão processamentos importantes relacionados à interface com o
usuário, através de rotinas Javascript que executam após a carga (onload) do HTML, por exemplo,
ajustando foco de campo, redefinindo Hot-Keys, alterando estilos dinamicamente, etc..etc.

Como dissemos, o processamento da camada Visão do Cliente não pode mais ser ignorado. Nos
últimos anos, tem crescido em popularidade e importância.

A Figura E16.2 mostra uma representação completa do Diagrama de Seqüência em discussão, com
alguns pontos adicionais em destaque.

*
Existem alguns “anti-patterns” de gerenciamento de sessões de persistência, que apregoam deixá-la aberta durante toda a requisição
HTTP (incluindo camada controle!), que chegam a dar arrepios de tantas possibilidades de problemas que podem causar. Infelizmente
mesmo Gavin King, o criado do Hibernate, chegou a aventar esta como uma possível “técnica”, em seu primeiro livro “Hibernate in
Action”. Mas hoje já se compreende os horrores que este alto acoplamento e falta de divisão de responsabilidade pelas camadas MVC
podem trazer, à exceção das mais simples aplicações, de um tipo que não é foco deste livro.
Figura E16.2. Diagrama de seqüência para “Manter Classe”. Eventos “F9-Pesquisar” e “F7-Novo”.

#1. Se o usuário clica em “F9-Pesquisar”, perceba que a seqüência disparada será a mesma da
chamada do menu. Isto é porque esta operação de pesquisa é default para este padrão
“plcTabular”. Mas no segundo caso, do clique no botão, o comando HTTP enviado será um
“POST” e será também enviado via “Ajax”*. Deste modo, evita-se das vezes subseqüentes a
renderização completa da página HTML†.

#2. Um novo fluxo exibido no diagrama de seqüência da Figura E16.2 é o do evento “F7-Novo”.
Perceba que ele também é enviado via Ajax. Uma outra vantagem desta arquitetura de
comunicação do jCompany é a de se não “sujar” a História do Usuário, mantida pelos
Navegadores. Como percebemos em tutoriais passados, nenhuma destas submissões de POST
subseqüentes, por serem utilizadas com Ajax, gera entradas nesta história, tornando-a útil‡.

#3. Tal como no caso da primeira chamada, a requisição é sempre atendida pela camada Controle.
Mais especificamente, como veremos em mais detalhes, por classes do tipo “Filter”
(“PlcMasterFilter”) e “Listener” (“PlcPhaseListener”), pelo Servlet de DP Front-Controller
“FacesServlet” e, para o processamento principal, para a classe central da camada Controle,
a “PlcBaseJsfAction”.

#4. Agora vemos uma segunda situação onde instâncias de objetos de Domínio são criadas. A
primeira ocorreu pelo Hibernate ou JPA, ao recuperar informações a partir a abertura ou
pesquisa explícita pelo usuário. Agora, o próprio jCompany produz instâncias da agregação
desejada, para “gerar entradas vazias correspondentes”, no formulário.

#5. Ao final, o HTML traz mais entradas (linhas ou itens) em branco para o usuário, que é o
propósito do evento “F7-Novo”, neste padrão.

Vejamos agora, complementando, como seria o fluxo de gravação (“F12-Gravar”), também para a
Colaboração “plcTabular”, na Figura E16.3.

*
O usuário pode desativar esta função, mas este é o esquema padrão proposto de interface.

O ganho se dará, principalmente, devido à não renderização do menu Pull-Down, que é normalmente o maior pesado.

Se desligar o uso de Ajax, os POSTs também passam a ser armazenados na história do usuário. O jCompany evita problemas
funcionais como quando o usuário clica no botão “Volta” (Back) dos Navegadores. No entanto, itens inúteis passam a poluir a história
de uso, na prática, tornando-a pouco útil.
Figura E16.3. Diagrama de seqüência para “Manter Classe”. F12-Gravar.

#1. A implementação de fachada agora realiza uma pequena tarefa de “adaptação”, interpretando,
em uma coleção, quais são as operações que deverão ser realizadas em cada objeto. Para
tanto, analisa a propriedade padrão “indExcPlc”, que armazena marcações possíveis na caixa
de exclusão do objeto, a presença ou não de Object-Id gerado, dentre outras técnicas para
interpretação do “estado atual de cada objeto”.

Ao final, decide por incluir (se forem novos objetos), alterar (se forem alterações em objetos
pré-recuperados) ou excluir (se forem objetos marcados para exclusão), delegando
individualmente esta tarefa, para a subcamada de serviços.

#2. O serviço de manutenção do ciclo de vida então é reutilizado, em laço, para cada objeto. Deste
modo as mesmas funções “inclui”, “altera” e “exclui” que atuam para manutenções de
apenas uma agregação de objetos são reutilizadas (Ex.: Manter Agregação Simples ou
Mestre/Detalhe)

#3. Serviços de persistência de nome correlato são também acionados e cada um utiliza o
framework base de persistência para gerar os comandos SQL necessários*.

#4. Neste evento, ao final da fachada, o encerramento de transação ocorrerá via chamada
“dao.commit()”, para confirmar as gravações, a menos que uma exceção seja disparada, o
que produziria um “dao.rollback()”†.

#5. O HTML final traz o conteúdo da lista atualizado (linhas excluídas removidas, alterações,
Object-id preenchido, etc.) e também a mensagem “Registro gravado com sucesso”.

- Seqüência MVC2-P em nível macro, para “Manter Agregação Simples” e “Mestre/Detalhe”


As seqüências principais de transação (requisição e resposta) para eventos em outros padrões de
Colaboração terão uma anatomia similar à exposta para o padrão “Manter Classe”, apenas com variação
dos serviços chamados da fachada e persistência.
Por exemplo, a anatomia do evento “F9-Pesquisar” para as Colaborações Padrões do tipo “plcSelecao”
ou “plcConsulta”, utilizadas em Casos de Uso Padrões “Manter Agregação Simples”, “Mestre/Detalhe” e
variações, são próximas da que vimos na Figura E16.1 e na Figura E16.2. O que irá variar serão somente
os serviços escolhidos, a partir da camada Controle.
No caso do “F9-Pesquisar” em “Manter Classe”, o método “pesquisa” da classe “PlcBaseJsfAction”
usou o serviço de fachada “recuperaListaSimples” (recupera todos os objetos de uma classe). Já no

*
o jCompany não produz SQLs, delegando esta atividade inteiramente para frameworks de implementações do padrão JPA tais como
o “Hibernate”.

Quando utilizando EJB3 e gerenciamento de transação pelo conteiner, ela também se encerrará neste mesmo ponto, conforme a
opção declarada de transação.
caso das Colaborações de Seleção e Consulta, o serviço usado será o “recuperaLista”, já que este
último permite a passagem de argumentos.
O trecho de Código E16.1 mostra um exemplo de como esta chamada é efetivamente implementada.

public String pesquisa() throws PlcException {



if (Logica.TABULAR.equals(logica)) {
...
listaVO = getServiceFacade().recuperaListaSimples(context,
this.configUrlColaboracaoPlc.getAcao().entidade(),
propriedadeOrdenacao);
} else {
if (numPorPagina == -1) {
...
listaVO = getServiceFacade().recuperaLista(context,
this.configUrlColaboracaoPlc.getAcao().entidade(),
controleConversacaoPlc.getOrdenacaoPlc(),listaArgumentos);
} else {
// Pesquisa com Navegador
listaVO = pesquisaComNavegador(context, request, listaArgumentos);
}
}

Código E16.1. Código de Controle, decidindo sobre qual serviço utilizar do contrato de fachada.

Note que, além de testar a delegação conforme o padrão corrente seja “plcTabular” (Logica.TABULAR)
ou não, este método de controle também verifica se uma seleção “paginada” está sendo utilizada,
situação em que uma terceira alternativa de serviço de fachada será utilizada. O Diagrama de Seqüência
correspondente para o evento “F9-Pesquisar” nas Colaborações “plcSelecao” ou “plcPesquisa” é
exibido na Figura E16.4.

Figura E16.4. Diagrama de seqüência para “plcSelecao” ou “plcConsulta”. Evento “F9-Pesquisar”.

#1. A chamada agora é “recuperaLista”.

#2. Por sua vez, a implementação da fachada para “recuperaLista” chave “recuperaListaQBE”, no
serviço de negócio.

#3. Este utiliza o serviço de persistência “recuperaComFiltroPadrao”, comum tanto ao Hibernate


quanto ao JPA (implementado no “PlcBaseDAO”).

#4. O método de persistência ainda delega a execução em si para o “hqlRecuperaQBE” (apesar do


nome inicial, submete tanto queries “JPA-QL” quanto “H-QL”). Esta delegação é para facilitar
interceptações em descendentes, pois diversos métodos de DAO concentram as submissões
neste mesmo ponto.

#5. Na camada visão, o HTML gerado que será exibido para o usuário irá variar, naturalmente, em
comparação ao que geramos na pesquisa de “Manter Classe” - até porque, neste último caso, a
lista será para manutenção, e a nossa atual será utilizada para consulta apenas. Porém, em
ambos os casos os dados retornaram na forma homogênea de uma coleção de Entidades
“List<PlcBaseVO>”.

Se analisarmos as seqüências para os eventos “F7-Novo” e “F12-Gravar”, veremos também uma


anatomia MVC2-P similar, porém com acionamentos diferentes.
Figura E16.5. Diagrama de seqüência para “plcCrud” ou “plcMestreDetalhe”. Eventos “F7-Novo” e “F12-Gravar”.

#1. A criação de novos objetos ocorre como no caso anterior, sem transações, mas agora não há
“laço” de criação para o objeto raiz, pois trabalhamos com apenas uma agregação por vez.

#2. A gravação é agora delegada para “gravaObjeto” (em vez de “gravaTabular”), e o serviço
de fachada utilizado é o “gravaObjeto” (em lugar de “gravaTabular”).

#3. Na fachada, há uma interpretação, baseada na comparação com a imagem anterior do objeto,
para decidir se ele será alterado ou criado (incluído). Em função disso, métodos distintos do
serviço de negócio serão acionados. Repare que, neste caso, a exclusão não é realizada
simultaneamente com a inclusão e alteração, mas por um evento próprio disparado pelo botão
“Excluir”.

#4. Ao final, o método “save” do dispositivo de persistência é acionado. Não há codificação de


SQLs, mesmo na arquitetura.

#5. A transação encerra na saída da “fachada”, via chamada do método “dao.commit()”


(Hibernate) ou pelo container EJB3 (JPA). A mesma visualização anterior, contendo o
formulário, é exibida, acrescida da mensagem padrão “Registro Gravado com Sucesso”.

Para o fluxo de exclusão, que neste caso é disparado por evento próprio, há uma seqüência inteiramente
nova.

Figura E16.6. Diagrama de seqüência para “plcCrud” ou “plcMestreDetalhe”. Evento “Excluir”.


#1. A requisição chega ao “PlcBaseJsfAction” no método “exclui”, que por sua vez chama serviço
“excluiObjeto” da fachada.

#2. O “PlcFacadeImpl” verifica se há uma declaração para uso de “exclusão lógica” nos
metadados. Se existir, muda o rumo da transação para uma “alteração” (sitHistoricoPlc=”I”),
em lugar da exclusão física em si.

#3. Os comandos utilizados para comunicação com a camada de persistência são “delete” para
exclusão física e o “save”, para atualização.

#4. A transação é também encerrada no final do método de fachada, via AOP, com comando
“dao.commit()”.

#5. Se tudo transcorre corretamente, uma mensagem “Registro Excluído com Sucesso” é montada
em escopo de requisição (usando a interface “HttpServletRequest”) e a seqüência do evento
“novo” é chamada. Deste modo, o usuário recebe um formulário em branco com a mensagem
de confirmação da exclusão.

Como deixamos claro na introdução deste tópico, estas são visões gerais das seqüências de transação
para alguns eventos, simplificadas para compreensão dos mecanismos primários da arquitetura MVC2-P
generalizada no jCompany FS Framework. Iremos, ainda neste capítulo, colocar uma “lupa” em cada
uma destas camadas, para enxergá-la com um nível adicional de detalhamento.

- Análise da arquitetura – simplicidade x escalabilidade e flexibilidade


Para quem não tem experiência em desenvolvimento Web ou em arquitetura MVC para Java EE (através
dos famosos “Blue Prints” recomendados pela Sun), a arquitetura acima pode parecer um tanto
monumental. Surgem logo reflexões naturais: Tudo isso é realmente útil? Mesmo para realizar
manutenções e pesquisas de documentos?
Por outro lado, para aqueles que advêm do J2EE com uso de EJB 2.x (Session e Entity), a arquitetura que
discutimos parecerá não somente familiar como até mesmo simplificada*.

As vantagens da arquitetura MVC2-P são reais, mas muitas vezes visíveis somente no médio prazo.
É uma arquitetura que nos permite modificar alguma de suas camadas radicalmente, com um
mínimo impacto nas demais – ao que chamamos de arquitetura “feita para durar” ou “à prova de
futuro” (future proof).

Vejamos a alguns exemplos reais de benefícios, postos à prova no próprio projeto do jCompany
Developer Suite, concebido somente com um framework, em 2002/2003.
Flexibilidade da camada Controle.

Graças à sua arquitetura MVC, a tecnologia JSF pôde ser incorporada para suportar o padrão Java EE
5 e novas tendências do mercado, apenas com a refatoração de uma parcela dos pacotes das
camadas Controle e Visão (“parcelas” porque, dentro das camadas Controle e Visão, já existiam
pacotes isolados com baixo ou nenhum acoplamento com a tecnologia Struts).
Flexibilidade da camada de Persistência.

Como outro exemplo similar, o isolamento da camada Persistência também possibilitou a


incorporação do padrão JPA, como alternativa ao Hibernate usado diretamente†, também com o
mínimo de impacto nas demais camadas.
Flexibilidade da camada de Visão.
Em suas primeiras versões, o jCompany não possuía outros kits de renderização ou variações da
camada Visão para outros formatos de saída, à exceção do HTML. Porém:

*
Devido à ausência de classes para lidarem com tecnologias de “remoting” como Business Delegate e Service Locators nas fachadas,
Data Transfer Objects, etc..

Lembrando que o próprio Hibernate também pode ser usado como uma implementação JPA, indiretamente.
Como sempre houve arquitetura de delegação das tarefas de “renderização” do HTML para um
segmento específico de classes, específicas da camada Visão (mesmo em Struts, via Tag-Files),
uma empresa produziu uma saída alternativa em WML em pouco tempo, para atendimento a
dispositivos móveis, sem implicar em revisões ou impacto em outras camadas.
A Powerlogic produziu, na versão 2.7 do jCompany, uma implementação de referência para
integração com Lazslo, gerando XML em lugar de HTML*.
Neste instante, a Powerlogic está em vias de liberar uma opção de “sindicalização universal” de
documentos, que permitirá que quaisquer formulários, consultas ou seleções, desenvolvidos por
clientes em jCompany, possam ser sindicalizados em agregadores de conteúdo diversos, em
tecnologia RSS/RDF/Atom. E isso vale para aplicações já existentes, em versões anteriores.
Tudo isso foi possível, com baixo ou nenhum impacto em programações de camada Controle, e
nenhum impacto “da fachada para trás”!

Flexibilidade da camada de Modelo.


Como várias empresas que logo reconheceram o “excesso de engenharia” (overenginnering)
produzido pelo uso extensivo da tecnologia EJB até a versão 1.x, a Powerlogic também não
incorporou esta tecnologia como quesito obrigatório do jCompany - mas incorporou todos os
Design Patterns de arquitetura MVC subjacentes a ela†. Deste modo:
Em 2003, um cliente exigiu o uso de Web-Services encapsulando todos os serviços da camada de
negócio - um ensaio incipiente de abordagem SOA. Nesta arquitetura distribuída, as
camadas “Visão/Controle/Domínio” deveriam sem embaladas e distribuídas em uma
máquina (consumidor) e as camadas de “Modelo/Persistência/Domínio”‡ ficariam
embaladas e disponibilizadas em outras (serviços). Esta arquitetura foi possível apenas com
revisões de rotinas Ant e reescrevendo-se a implementação da subcamada de Fachada, para
fazer chamadas remotas.
Com o advento do EJB3, a SUN finalmente tornou esta tecnologia produtiva e desejável, na maior
parte dos casos. Como o jCompany já possuía separação clara de “fachada” e arquitetura de
POJOs, foi possível suportar este padrão com pouquíssimo impacto na própria camada Modelo,
e nenhum nas demais. Nas versões atuais, com o simples ato de se configurar anotações para
uso da tecnologia EJB3, o jCompany passa a operar com chamadas “JNDI” na fachada (para
localizar EJB Session Beans).
Note que, em uma arquitetura com alto acoplamento entre as camadas, a maior parte das modificações
acima seria improvável de ser realizada. Mesmo em aplicações MVC sem implementações fatoradas em
uma arquitetura rica, tais refatorações costumam não acontecer - por envolverem um custo que não
oferecem ganhos de escala (para um único projeto).
Mas perceba que, nos exemplos acima, enfocamos vantagens do MVC para fins de flexibilidade. Este
quesito é importante porque provê longevidade para a aplicação (mais tempo de sobrevida, a menores
custos) e também a viabilidade da preservação de um patamar tecnológico que mantenha o potencial de
inovação tecnológica.
Mas a adoção da arquitetura MVC oferece outras vantagens, além da flexibilidade:
Especialização (Separação de papéis “por camada”).
Do ponto de vista da separação de papéis, a arquitetura MVC permite que perfis diferentes de
profissionais atuem em diversos segmentos, para projetos realmente grandes, que exijam este tipo
de especialização.
Na parcela de requisitos que recaem em Casos de Uso Padrões, esta separação de papéis não será
vantajosa§. Mas, para os demais casos pode ser uma boa idéia especializar Desenvolvedores em

*
O uso deste recurso foi depois desestimulado, com a popularização da tecnologia Ajax, pouco tempo depois. E novidades nesta área
estão previstas, para versões superiores à utilizada neste livro.

Méritos sejam dados a Rod Johnson, pioneiro nesta área com seu framework Spring e livros com dicas para substituição apropriada
dos excessos da tecnologias EJB 2.x.

Note que a camada ortogonal de Domínio está presente em ambos os empacotamentos, no lugar dos DTOs dos EJBs 2.x.
§
Devido ao alto nível de automação em todas as camadas, com qualidade final de produção.
tecnologias de camada Visão (JSF, Ajax), camada de Controle (JBoss Seam), serviços de negócio e
camada Persistência (JPA, Hibernate).
Escala em complexidade sem perda de controle, ou “produtividade sustentada”.
Mas o benefício mais fundamental (e muitas vezes “subvalorizado”), do uso da arquitetura MVC é a
sua capacidade de encapsular especialidades de forma refinada, preservando um bom
entendimento e controle de aplicações corporativas, mesmo quando estas evoluem em
tamanho e complexidade.

Infelizmente, para os benefícios de uma arquitetura MVC aparecerem, será necessário o bom
uso da Orientação a Objetos* e também o passar do tempo. Em um projeto que irá produzir
a primeira versão de uma aplicação, por exemplo, pode-se não perceber nenhum ganho nítido,
nesta área† - por este motivo, vemos muitas vezes fornecedores contratados “por projeto”
produzindo código “espaguete”, altamente acoplado, pressionados para entregarem a “bomba
relógio” no prazo.

Implementações simplificadas do MVC também facilitam a perda de controle advinda do aumento


da complexidade. Um exemplo neste sentido, dos dias de hoje, é o estímulo ao uso de EJBs como
“Backing Beans” JSF. O framework JBoss Seam homologado no jCompany, é um dos que
possibilita esta abordagem, que tem sido utilizada em algumas apresentações tipo RAD‡ da Sun
para Java EE 5§.
Neste tipo de apresentação, o mesmo método do EJB que recebe a requisição de controle também
recebe por Injeção de Dependência uma sessão de persistência (Entity Manager) e logo dispara
comandos e transações JPA, resolvendo tudo de uma só vez, em um só lugar. É algo bonito de
se vez, em um caso simples, mas tenebroso de se manter, em uma escala de complexidade
real**.
No próprio jCompany encontramos exemplos de complexidades típicas abstraídas em
apresentações de marketing - basta vistoriar o código de uma classe qualquer, em alguma das
camadas MVC-P, que pareça “mera burocracia”. Mesmo generalizações para programações
aparentemente básicas, voltadas para “manutenções de ciclo de vida”, por exemplo, no mundo real
envolvem diversas variações de situações que incrementam consideravelmente a complexidade,
tais como:
Exclusão física e lógica;
Auditorias “pauta mínima” e “rígida”;
Manipulação de arquivos anexados;
Fluxos de aprovação, reprovação, versionamento e publicação;
Paginação de conteúdos em seleções;
Assistentes de entradas de dados;
Geração automatizada de leiautes de impressão;
Etc., etc..
Nos próximos tópicos deste capítulo vamos, inclusive, usufruir da separação de conceitos das camadas
MVC2-P, analisando as principais práticas de programação em cada camada, separadamente, a começar
pela “subcamada Visão do Cliente”.

*
A arquitetura MVC não é a prova de programação “COBOL” embutida dentro das camadas!

E, infelizmente, muitas empresas buscam ansiosamente diminuir seu déficit de projetos, muitas vezes sacrificando arquitetura em
uma “primeira versão” rápida, que nas fases de manutenção cobram seu preço, com juros e correção monetária.

Rapid Application Developement. Sigla utilizada para representar desenvolvimentos rápidos focados na produção de Interfaces com o
Usuário via “arrasta-e-solta” e “WYSIWYG”, onde componentes visuais são normalmente vinculados (binding) à camadas de
persistência.
§
Como sabemos, visando simplificação extrema para concorrer com a Microsoft no mercado “varejo” do “.NET”.
**
Apesar de visivelmente perigosa, alguns argumentam que esta arquitetura ainda respeita o MVC original, conforme definido na
época do Smalltalk. O problema é que uma implementação MVC rasa como esta não reforça a separação de aspectos e confia
demasiadamente na disciplina do Desenvolvedor – no que chamamos de recaída para o desenvolvimento “artesanal”. Esta variação
pode ser uma simplificação interessante para um segmento do mercado, mas não a recomendamos para o corporativo.
Programações da Camada Visão - Cliente

- Visão geral
Há inúmeras possibilidades de se implementar interações sofisticadas com o usuário hoje, através dos
Navegadores Web, com base nas tecnologias DHTML/Javascript e Ajax, para citar algumas. O jCompany
homologa frameworks como o DOJO, especializadas nesta área, bem como recursos do Apache Trinidad,
embutidos em seus componentes JSF, prontamente disponíveis para uso. Além disso, traz bibliotecas
Javascript/Ajax próprias, que realizam tarefas como:
Tab-Folder DHTML (comuta abas sem transmissão do Navegador);
Hot-Key dos botões;
Foco inteligente (posiciona no primeiro campo vazio do formulário, após a carga);
Envio de comandos POST via AJAX (F12-Gravar, F7-Novo, F9-Pesquisar);
Mensagens de advertências (“Tem certeza que deseja excluir...”);
Etc.
Para se realizar variações em Javascript, como vimos para o lançamento de “ProventoDesconto”, o
desafio passará não somente pelo conhecimento desta tecnologia mas, principalmente, por conhecimento
sobre como utilizá-la de uma maneira “cross-Browser”, que se comporte bem com a larga variedade de
modelos e versões destes Navegadores.
Vejamos a arquitetura básica sugerida para a confecção de rotinas Javascript específicas, sejam “puras”
ou através do framework DOJO.

- Arquitetura de Programação da Camada Visão (Cliente) - Javascript II


O jCompany agrupa 98% de suas rotinas Javascript em uma biblioteca de funções no arquivo
“/plc/javascript/PlcGeral.js” localizado no projeto “jcompany_visao”. Este arquivo, por sua vez, é
incluído no documento HTML pelo componente de leiaute
“/plc/layouts/htmlcomuns/PlcGeralLayoutIncludeHeader.jsp”.
Outras poucas funções Javascript estão embutidas em componentes de leiaute, por exigirem algum
tratamento dinâmico no servidor (o que não é tão simples em arquivos externos) ou para executarem no
momento da carga destas páginas.
Os arquivos de Javascript tais como o “PlcGeral.js” são baixados no primeiro acesso do usuário e
mantidos em caching pelo Navegador, a partir daí, segundo o mesmo mecanismo já explicado para
arquivos CSS. Por este motivo, é aconselhável que o desenvolvedor também mantenha seus arquivos
específicos Javascript no diretório padrão “/plc/javascript”. Para padronizar e promover esta prática, os
projetos de template INI do jCompany trazem um arquivo vazio com nome de “AppGeral.js”, localizado
no diretório recomendado “/plc/javascript” dos projetos específicos, para conter programações
Javascript específicas.
Importante: Este arquivo não é importado automaticamente pelos leiautes (ou seja, pela página
“/plc/layouts/htmlcomuns/PlcGeralLayoutIncludeHead.jsp”). Para evitar uma requisição HTTP
desnecessária, caso não se tenha nenhum código específico em Javascript codificado, os leiautes somente
irão tentar importar este arquivo se for declarada uma opção de metadados para este fim (de maneira
similar ao uso do ”/plc/css/AppGeral.css”, para estilos desvinculados de pele, específicos da
aplicação).
Vamos realizar um pequeno tutorial, para entender os passos necessários para a utilização de
programação Javascript específica, de uma maneira padronizada e otimizada:
1. Edite o arquivo de metadados para a aplicação do pacote
“com.powerlogic.jcompany.config.app” e inclua a anotação @PlcConfigOtimizacao, conforme
o trecho de Código E16.2.

...
@PlcConfigOtimizacao(javascriptEspecificoUsa=true)
...
Código E16.2. Metadados para declaração de uso de biblioteca Javascript “AppGeral.js”.
2. Edite agora o arquivo “AppGeral.js” (Control+Shift+R) e inclua nossa primeira função Javascript em
nível de biblioteca*, conforme o trecho de Código E16.3.

...
/**
* Javascript também merece documentação!
*/
function minhaPrimeiraFuncao() {
alert('Alerta de Teste');
}
...
Código E16.3. Código de Controle, Primeira função Javascript no AppGeral.js.

3. Para chamar esta função, após a carga da página principal da aplicação, por exemplo, edite a página
“/WEB-INF/jsps/principalIntroducao.jsp” e inclua o código em Código E16.4.

...
<%@ taglib uri="/WEB-INF/fmt.tld" prefix="fmt"%>
<fmt:setBundle basename="ApplicationResources"/>
<script>
// Registra a função Javascript para executar
setFuncaoOnLoad('minhaPrimeiraFuncao()');
</script>
<table width="500" border="0" cellspacing="0" cellpadding="0">
...
Código E16.4. Registro de função Javascript, para execução após a carga (renderização) da página.

Este código Javascript “embutido” chama uma função do jCompany “setFuncaoOnLoad”, que
por sua vez registra a nossa função Javascript para execução ao final da carga da página†.

Importante: Lembre-se de passar os parênteses junto ao nome da função, como argumento, e


também de usar as aspas simples – dois erros comumente praticados por “pobres mortais”
desacostumados com linguagens de script, como a maior parte dos programadores Java.
Como funciona? Esta função irá executar durante o carregamento desta página específica pelo
Navegador (todos os códigos dentro de tags “<script></script>” o são), registrando a nossa
função para que ocorra ao final de toda a renderização – este sim, um momento típico e seguro
para execução de rotinas Javascript que realizem ajustes dinâmicos importantes.
Outra forma de dispararmos uma função Javascript no evento “onload” de uma página seria
especializar o componente de leiaute
“/plc/layouts/htmlcomuns/PlcGeralLayoutIncludeBodyInicio.jsp” do projeto
“jcompany_visao”. Esta especialização, porém, somente seria recomendada se a modificação
fosse de interesse global, para todas as Colaborações da aplicação.
Veja no Código E16.5, o conteúdo total deste componente de leiaute, como se encontra do
framework, com a função Javascript “iniciarPagina()” configurada para execução.

<body onload="iniciarPagina();" onkeydown="return executarAcaoFuncoes(event);" id="corpo_geral">


Código E16.5. Código de Controle 5, Declaração de body fatorada para todos os leiautes, com função genérica.

A função “iniciarPagina()” não somente encapsula programações genéricas do jCompany como


também chama todas as funções específicas, registradas para execução pelo Desenvolvedor via
“setFuncaoOnLoad”.
Obs.: Para alterações genéricas no “onload”, basta chamar novas funções específicas após o
“iniciarPagina();”, sempre separadas por ponto e vírgula.
4. Faça agora uma “Liberação Rápida para Tomcat com Reinício” (porque modificamos metadados) e
entre novamente na aplicação, para ver se nossa função será ativada na página principal, conforme
a Figura E16.7.

*
Já fizemos uma função embutida em uma página, para o Caso de Uso “Manter Coleção”, em tutoriais passados. Aquela função, agora
que sabemos, deveria ser externada para o arquivo AppGeral.js, para dar ênfase a otimização.

A função “setFuncaoOnLoad” provê um tipo de registro de IoC em Javascript.
Figura E16.7. Alerta Javascript após a carga da página inicial.

- Programando Javascript Cross-Browser - Javascript III


Para um exemplo mais interessante de programação Javascript, em nossa página principal - e também
para compreendermos algumas técnicas para codificação Javascript “cross-Browser” no jCompany,
vamos realizar mais um tutorial, que irá fazer com que a nossa imagem principal de destaque apareça
com efeito de “surgimento” (Fading In).
Para este tipo de efeito, a sintaxe Javascript para cada Navegador terá que ser diferente e, portanto,
iremos realizar duas implementações distintas, acionando cada uma em função do navegador atual.
1. Edite a página “principalIntroducao.jsp” e dê uma denominação “id” para a a imagem
“acme_banner.gif”. Desta forma, ela passa a ser identificável em programações Javascript.
Também aplique os dois estilos iniciais exemplificados no trecho de Código E16.6, que fazem com
que a imagem apareça opaca em nível 0 (invisível, na verdade), no início de nossa animação.

...
<img id="bannerACME" style="-moz-opacity:0;filter:alpha(opacity=0)"
alt="ACME - RH Tutorial"
src="${pageContext.request.contextPath}/plc/midia/acme/acme_banner.gif" />
...
Código E16.6. Imagem “identificável” via Javascript e com estilos de opacidade.

Perceba que há dois códigos CSS diferentes, separados por ponto e vírgula, para fazer a mesma
coisa: um no padrão Mozilla e outro no padrão do Internet Explorer. Neste caso inicial, ambos
podem ser misturados, sem seqüelas.
2. Altere o conteúdo do arquivo “AppGeral.js”, no projeto “rhtutorial”, incluindo a nossa função
“minhaPrimeiraFuncao”, conforme o trecho de Código E16.7.

function minhaPrimeiraFuncao() {
if (NavYes) {
alert('Sou navegador!'); // 1
setInterval("MOZ()",50); // 2
}
if (ExpYes) {
alert('Sou explorador!');
setInterval("IE()",50);
}
if (Opr) {
alert('Não sou suportado - mas me comporto bem!'); // 3
}
}

valor=0; // 4

function IE(){
if (valor<=95) valor+=5; // 4
document.getElementById("bannerACME").filters[0].opacity=valor; // 5
}

function MOZ() {
if (valor<=95) valor+=5;
document.getElementById("bannerACME").style.MozOpacity=valor/100; // 6
}
...
Código E16.7. Código de Controle, de Nova função Javascript acionada no “onload” da página principal.

#1. As variáveis globais “NavYes” (Navigator / Mozilla), “ExpYes” (Explorer – IE) e “Opr" (Opera)
nos permitem identificar a família do Navegador corrente. Elas foram disponibilizadas pela
biblioteca Javascript jCompany. Um alerta foi incluído somente para depuração inicial*.

#2. A função Javascript “setInterval” irá chamar uma função com código específico de um dos
navegadores suportados, várias vezes, de acordo com o intervalo em milisegundos informado.

#3. O Navegador “Opera” não está exemplificado, pois não foi priorizado por nossa empresa
hipotética. Mas é importante notar que esta facilidade irá “degradar” bem para este caso - ou
seja, não haverá perda funcional, mas apenas estética, caso o usuário esteja utilizando este
Navegador.

#4. Uma variável global deve ser criada, para conter o nível da opacidade que será incrementado a
cada chamada. Note que basta declararmos a variável fora de qualquer função, para que seja
definida.

Importante: ela deve ser declarada antes de ser utilizada.

#5. A cada chamada de alguma das funções, ela incrementa 5% de aumento da opacidade
(diminuição da transparência), até que atinja 100, quando estará totalmente opaca (visível) e a
rotina não mais terá efeito.

#6. No caso do Mozilla, a mudança é feita através de estilos, e a escala é de 0 a 1, e não 0 a 100.
Por este motivo, uma divisão é realizada.

Confira em cada um dos tipos de Navegadores, se o alerta aparece de acordo e se a imagem de


entrada surge graciosamente, após a abertura da página.
3. Retire, após esta conferência, as mensagens de alerta, para prosseguirmos.

- Apache Trinidad e Programação da Camada Visão (Cliente) - Javascript IV


Fizemos uma codificação Javascript genérica, independente de tecnologia JSF ou Struts, mas a maior
parte deste tipo de codificação específica será, provavelmente, associada aos eventos que ocorrem em
formulários, de uma maneira semelhante à primeira codificação Javascript que fizemos no tutorial para
“Manter Coleção”, no capítulo 13.
Por este motivo, os componentes JSF do Apache Trinidad oferecem também algumas implementações
de Javascript prontas, que podem ser reutilizadas em cenários diversos. Muitas destas implementações
são gerenciadas pelo jCompany em suas especializações do Trinidad, tais como o uso de “Ajax” em
certas operações de formulário, como no caso do botão “F12-Gravar”. O código deste botão retirado da
página “geralAcoesJsfPlc.jsp” é exibido no Código E16.8.

...
<plcf:botaoAcao id="botaoAcaoGravar" acao="grava" partialSubmit="#{requestScope.ajaxUsa}"
label="jcompany.evt.gravar" botaoArrayID="GRAVAR" rendered="#{requestScope.exibeGravarPlc=='S' and empty
requestScope.estiloApresentacaoPlc and requestScope.exibe_jcompany_evt_gravar!='N'}"
hotKey="#{requestScope.gravarHotKey}" alertaExcluirDetalhe="jcompany.alerta.excluir.detalhe.tabular" />
...
Código E16.8. Declaração do componente de botão para “F12-Gravar”, com submissão parcial via Ajax.

Perceba, pelo trecho de código em destaque, que uma “submissão parcial” Ajax é ativada, se e somente
se o usuário está com a opção “ajaxUsa” ativa. Esta opção pode ser ativada pelo próprio usuário,
dinamicamente, em “Personalização de Formulário”, e é default nos templates INI†. O jCompany

*
É sempre bom certificar-se de que sua versão mais nova de Navegador está sendo capturada corretamente, pois esta é uma
categoria de software em franca evolução.

Também é possível ao Desenvolvedor desativá-la globalmente ou localmente em uma Colaboração, via metadados.
realiza esta e outras configurações de modo a tornar o uso de Ajax imediatamente funcional para os
casos mais comuns.
Para mais informações sobre todas as possibilidades de uso de Javascript via Apache Trinidad,
recomendamos uma visita ao Web-Site deste projeto, disponível nas referências bibliográficas deste livro.

- DOJO e Programação da Camada Visão - Javascript V


Com a exceção do rodapé padrão FishEye*, o jCompany não utiliza o framework DOJO em nenhum
outro momento. Para suas ações genéricas nesta área, trabalha tão somente suas próprias rotinas
Javascript/Ajax ou via Apache Trinidad. Apesar disto, o DOJO é homologado e empacotado juntamente
com as aplicações, de forma que está “pronto-para-uso” por parte dos Desenvolvedores.
Ao contrário do Apache Trinidad, que é um framework de componentes JSF que possui funções Javascript
e Ajax como acessórias, o DOJO é um framework eminentemente dedicado ao mundo da
“camada Visão do Cliente”, por assim dizer, e trará sofisticações bem interessantes em termos de
Interface com o Usuário, se bem entendido.
Do ponto de vista de arquitetura, o framework DOJO é estrategicamente inserido abaixo de
“/plc/javascript/dojo”, no projeto “jcompany_visao”, para participar da estratégia de padronização e
caching para Javascript. Além disso, como dissemos, suas rotinas Javascript não são importadas em
nenhum ponto do jCompany, o que não traz nenhum impacto de sobrecarga, em produção, quando ele
não é utilizado.
Importante: Por outro lado, se for utilizado, por ser o DOJO um framework Javascript extenso, o
recomendado é que cada uma de suas diversas bibliotecas Javascript sejam carregadas “por
demanda”. Vamos exemplificar como isso é possível em nosso próximo tutorial, onde iremos incluir
nosso primeiro componente DOJO (chamado de Widget) como decoração em nossa página principal.
1. Edite a página “/WEB-INF/jsps/principalIntroducao.jsp” e inclua uma nova coluna
“<td></td>”, ao lado da coluna que contém a imagem que manipulamos há pouco.

2. Codifique a rotina Javascript como no Código E16.9.

<td>
<script type="text/javascript">
// 1
if (typeof dojo=='undefined') {
document.write(
"<script type=\"text/javascript\" src=\"${pageContext.request.contextPath}/plc/javascript/dojo/dojo.js\"><\/script>");
}
</script>
// 2
<script type="text/javascript">
dojo.require("dojo.widget.Clock");
</script>
// 3
<div dojoType="Clock" label="Rh Tutorial" />
</td>
</tr>
...
Código E16.9. Código Javascript que introduz uma primeira declaração de importação do DOJO.

#1. No primeiro bloco de declaração Javascript, realizamos o teste padrão para importação
dinâmica do Javascript DOJO, que evita carregá-lo duas vezes (no caso de ele ter sido utilizado
em outros componentes de leiaute).

#2. Em outro bloco de Javascript (é importante que seja outro), indicamos as dependências
que iremos utilizar somente para o nosso caso, equivalentes ao “import” do Java.

#3. Finalmente, neste ponto, definimos uma nova divisão HTML “<div/>”, com o atributo
“dojoType” indicando o tipo “Clock”, um relógio disponível como Widget no DOJO. Um opção
de rótulo também foi definida em “label”.

*
Lembre-se que nós o retiramos de nosso exemplo “rhtutorial”, no momento em que aplicamos o Web-Design de rodapé “simplificado”
que fizemos, baseado em tabelas “<table>”. O FishEye naquele ponto iria requerer uso de divisões “<div>”.
3. Como estamos no mundo do Cliente, não há necessidade de liberação Maven quando editamos
somente JSPs e Javascript. Teste imediatamente o resultado de nosso código no Tomcat, que deve
aparecer agora como a Figura E16.8.

Figura E16.8. Widget DOJO na página principal.

Este é um exemplo simplório, mas dá as dicas fundamentais do potencial deste novo mundo. Veja na
Figura E16.9, a relação de pacotes e Widgets do DOJO, indo desde relógios, calendários e utilitários
de animação, até rotinas de gráficos e editores multimídia.

Figura E16.9. Visão geral dos pacotes de bibliotecas Javascript do DOJO, homologados no jCompany.

Obs.: Os Widgets do DOJO são baseados na renderização de divisões “<div/>” com atributos
proprietários dinamicamente interpretados - inexistentes nos esquemas estáticos esperados para um
documento XHTML, conforme definido pelo W3C (tais como as propriedades “dojoType” e “label”, em
nosso exemplo). Este não costuma ser um problema para a grande maioria dos casos, pois estes
atributos são desprezados pelos Navegadores. Mas para empresas que exigem documentos HTML com o
formato “Strict”, esta será uma área de conflito, pois verificadores de formato rejeitarão documentos
que usam este padrão do DOJO como Strict válidos*.

*
Note que, mesmo assim, os Navegadores interpretarão os Widgets corretamente, mesmo utilizando formato Strict! A ressalva diz
respeito somente a validadores de formatação que visam garantir “boas práticas” no formato Strict.
Programações da Camada Visão - Servidor

- Visão geral
Vamos agora nos mudar para o mundo do servidor. Como vimos, é aqui onde os objetos da “camada
Visão do Servidor” renderizam documentos HTML ou XHTML para navegadores Web e, possivelmente,
outros formatos tais como WML para dispositivos móveis ou mesmo XML para integrações diversas.
De um modo geral, um grande objetivo da camada Visão é conter o mínimo possível de lógicas
procedimentais. Para tanto, usamos a camada de Controle para absorver tanto processamento quanto
possível. Porém, algum tipo básico de condicionais e laços serão inevitáveis. Eles poderão aparecer em
componentes JSF do Apache Trinidad ou mesmo em JSTL, ambos sobre a tecnologia JSP*.
Do ponto de vista tecnológico, já vimos que o jCompany usa JSP 2.0, JSF 1.2 e JSTL 1.1, em sua
versão atual (5.1, no momento da escrita deste livro) de forma integrada. Todas estas tecnologias
possuem mecanismos de “programação” possíveis, para a camada Visão†.
Vejamos, nos tópicos seguintes, exemplos de programações típicas de camada Visão do Servidor, na
arquitetura do jCompany FS Framework.

- Condicionais com assertivas e laços, via componentes JSF Apache Trinidad


Testes condicionais e laços podem ser realizados na camada Visão, via componentes Apache Trinidad,
com os seguintes recursos básicos:
Atributo “rendered”: Este atributo permite que se informe assertivas na forma de expressões que,
quando resultam em “verdadeiro”, permitem o prosseguimento da renderização do componente, e
quando resultam em “falso”, não o renderizam.
Componente “plcf:iteracao": Este componente do jCompany especializa o componente “UIXIterator”
do Apache Trinidad, que por sua vez é especializado em renderizar uma tabela associada a uma
coleção de beans (Entidades, em nosso caso). Equivale a um laço (loop) em Java.

Figura E16.10. Programação de camada Visão com tags/componentes Apache Trinidad.

#1. Componente de iteração, utilizando coleção que o jCompany disponibiliza em escopo de


conversação do JBoss Seam, visível para o Apache Trinidad.

#2. Atributo “rendered”, implementando a regra: “CPF para funcionários que não são solteiros é
confidencial”*.

*
Deve-se evitar a linguagem Java nesta camada. Experimentalmente, esta prática já se comprovou como inadequada.
Desenvolvedores que a utilizam tendem a não respeitar claramente a separação das camadas Controle e Visão, com algoritmos
excessivamente complexos, miscigenados às lógicas de renderização de páginas.

A opção pelo uso do JSF integrado às JSPs preserva um grande leque cultural e ainda possibilita a gestão de leiautes OO com
IoC, via Tiles. O uso de alternativas de leiaute mais recentes como “facelets”, por exemplo, não está descartado pela Powerlogic
(podendo inclusive ser realizado imediatamente, através de customizações), mas estava com prioridade baixa no momento desta
escrita, uma vez que as JSPs no jCompany se encontram em estágio bastante avançado em termos de simplicidade.
#3. Como estamos eliminando condicionalmente uma coluna, precisamos de uma alternativa para
que nossa lista não apareça com deslocamentos indevidos. Assim, na condição inversa,
estamos exibindo condicionalmente e em vermelho, o termo “[Confidencial]”.

A Figura E16.11 exibe o resultado desta pequena trama de programação:

Figura E16.11. Iteração e condição via componentes Apache Trinidad.

Obs.: As Tag-files do jCompany, utilizadas nas JSPs para a tecnologia Struts, implementam um
mecanismo similar ao “rendered” do Trinidad, através da propriedade “exibeSe”.

- Condicionais e laços, via JSTL


O uso de JSTL (especialmente das tags “if”, “choose” e “forEach”, da Tag-lib Core) é uma alternativa
análoga à anterior, em situações onde não se esteja necessariamente utilizando componentes JSF. O
mais comum de se encontrar no jCompany são iterações via “c:forEach” e condições via “c:if”.

...
<c:if test="${empty requestScope.passoAssistentePlc or requestScope.passoAssistentePlc==3}">
<plcf:linha>
<plcf:celula>
<plcf:titulo tituloChave="label.temCursoSuperior"/>
<plcf:caixaMarcacao id="temCursoSuperior"
value="#{plcEntidade.temCursoSuperior}" />
</plcf:celula>
</plcf:linha>
</c:if>
...
Código E16.10. Programação de camada Visão com JSTL Core “if”

Não iremos descrever todas as possibilidades de “controle de fluxo” das Tag-Libs Core JSTL e nem dos
componentes JSF. De qualquer modo, é uma boa prática manter o uso de tais recursos em seus
níveis básicos. Suspeite da necessidade de programações mais intrincadas neste ponto: elas
não podem ser “movidas” para a camada Controle?

Programações da Camada Controle

- Visão geral
De uma maneira simplificada, a camada Controle deve conter programações relacionadas à interface com
o usuário, segurança, navegação e validações de entrada, não incluindo regras do negócio e nem de
acesso a bases de dados, por exemplo.
Muito embora não tenham acesso direto a sessões de Persistência, as classes de Controle devem ser as
únicas com acesso aos objetos Web, tais como HttpSession, HttpServletRequest, etc.) e a certos
frameworks especialistas nesta camada, tais como JSF/Apache Trinidad (ou Struts), JBoss Seam ou Tiles
(parte de Controller).

*
Não me perguntem por que, raios, existiria uma regra como essa!
Para facilitar o estudo das seqüências de atendimento, podemos dividir o trabalho da camada de Controle
em duas metades distintas:
Fase de Empilhamento (equivale às fases JSF de Requisição e de início da Resposta): Nesta
fase “de ida”, as classes de controle recepcionam requisições advindas dos Navegadores, validam os
dados recebidos e os transformam em estruturas de objetos, com semântica mais rica e apropriada
para o prosseguimento da requisição. Iniciando o processamento da resposta, os métodos de
controle chamam serviços de fachada, que encapsulam regras de negócio e acesso à persistência.
Fase de Desempilhamento (equivale à fase JSF de finalização da Resposta): Nesta fase “de
volta”, informações devolvidas da camada Modelo são recebidas e recebem manipulações eventuais,
incluindo tratamento de cenários de exceção e análise de fluxos de desvio declarados. Regras de
programação associadas ao mundo da Interface com o Usuário podem ser realizadas, quando estão
acima do escopo de componentes JSF individuais. Deste modo, ao delegar o processamento de
renderização dos documentos de resposta para a camada Visão, resta a esta última camada
somente um trabalho de programação essencial, realizável através de primitivas simples como
assertivas e laços.

- Anatomia da Fase de Empilhamento (da requisição inicial até a Fachada).


Vamos analisar a anatomia de uma Seqüência de Transação típica da fase de Empilhamento (Requisição
e início de Resposta) agora detalhando um pouco mais a camada Controle, através da Figura E16.12.

Figura E16.12. Seqüência mais detalhada de requisição GET para colaboração “plcTabular”.

#1. Chamada via menu: Como vimos anteriormente, este tipo de evento envia um comando
HTTP GET para a camada Controle tratar. Nestes diagramas mais detalhado, abstrairemos da
representação Javascript utilizada na introdução.

#2. Os filtros que atuam são agora explicitados. Classes do tipo “Filter” foram introduzidas na
especificação “Servlet 2.3”, para atuarem “em torno de um Servlet”; por isso, são as que
primeiro executam processamento, após a chegada de uma requisição*.

Muito embora estas classes, na maioria dos casos, não requeiram atenção e especialização,
haverá situações onde compreender a sua atuação será importante. Os seguintes filtros são
registrados e atuam nesta fase:

“PlcMasterFilter”:

- Garante o registra do encoding (Padrão de codificação das páginas HTML) para

*
No jCompany, classes de filtro são nomeadas com a convenção “Plc[Nome]Filter”.
“utf-8”, em cada requisição HTTP. Deste modo fica-se independente de configurações de cada
Application Server, que podem utilizar “latin-1” ou outro padrão que não corresponderá ao
utilizado pelo jCompany.

- Trata integração com o jCompany Security. Quando há uma configuração de metadados


“PlcConfigJSecurity(usa=true)”, em escopo de aplicação ou empresa, este filtro realiza
implementações de segurança.

- Realiza iniciações do “one-click profiling”, que é um recurso de logging que


conheceremos ainda neste capítulo.

“PlcTrinidadFilter”: É um mero “invólucro” (Wrapper) implementado via herança da classe


“TrinidadFilter” do Apache Trinidad. Esta classe introduz apenas logging, mas preserva um
espaço na arquitetura pré-configurado para especializações futuras que possam se fazer
necessárias no jCompany. O ancestral “TrinidadFilter” realiza tratamentos para upload de
arquivos e outros, de menor relevância para nosso estudo atual.

#3. Ao término das interceptações dos filtros, a classe de Servlet padrão


“javax.faces.webapp.FacesServlet” inicia a implementação JSF. Esta classe, em seu método
“service”, dispara o início do tratamento de “ciclo de vida” dos componentes JSF, que pode
sofrer interferências de programação específica através de implementações de “ouvintes”
(Listeners JSF).

Há uma seqüência omitida de um bom tamanho, entre o servlet “FacesServlet” e a classe


"AppPhaseListener". Em grande parte, é a seqüência padrão de tratamento do JSF, que pode
ser encontrada em livros especializados nesta tecnologia. Para nosso propósito atual, iremos
nos abstrair desta seqüência e partir direto para esta implementação genérica da Interface
“PhaseListener”.

#4. Perceba que, a partir deste ponto, classes descendentes e especificas de cada projeto, em
esquema de Inversão de Controle, passam a atuar, tais como "AppPhaseListener" e
"AppAction". A classe “AppPhaseListener”, descendente de “PlcPhaseListener”, é incluída
mesmo que sem implementações específicas, pelos templates INI, para facilitar e promover
especializações neste ponto, de forma padronizada.

O métodos “beforePhase” e “afterPhase” são disparados pelo Apache Trinidad, que realiza
os trabalhos de recepção e reconstrução do “estado” dos componentes JSF (basicamente, a
reconstrução da árvore de componentes no servidor, conforme estabelece o padrão JSF). O
jCompany atuará, através da classe “PlcPhaseListener”, com implementações genéricas nos
métodos “beforePhase” e “afterPhase” para o evento “RESTORE_VIEW 1”*.

Na prática, como nossa requisição específica é um mero “GET” e não envia mudanças de
estado significativas em componentes JSF, esta fase de “RESTORE VIEW” é bastante trivial.
Para os interessados em maior aprofundamento nesta área, sugerimos o estudo deste ciclo de
vida em literatura específica sobre JSF.

#5. É neste ponto, após a recriação no servidor do estado de componentes JSF, onde se inicia a
fase de renderização da resposta para o usuário. Ou seja, a partir deste ponto já sabemos o
que o usuário quer e validamos sua solicitação – vamos então prosseguir para conseguir
montar um documento com a resposta apropriada. Mas note que, de um ponto de vista de
mais baixo nível, ainda estamos “empilhando” chamadas de métodos de objetos, na
pilha da memória (Heap).

É a partir da interceptação do “beforePhase” para o evento “RENDER_RESPONSE 6”, da


classe “PlcPhaseListener”, que o fluxo genérico mais importante de processamento do
jCompany ocorre.

*
Segundo o contrato de interceptação padrão do JSF, os diversos eventos de ciclo de vida de componentes são passados como
argumento, para os mesmos métodos “beforePhase” e “afterPhase”.
#6. De forma simplificada*, a classe “PlcPhaseListener” termina por delegar para o método
“inicializaManagedBeans” a tarefa de obter instâncias do objeto que encapsula metadados
do jCompany, do objeto que mantém em memória os dados transmitidos (em nosso caso, não
transmitimos nenhum) e também do objeto que irá realizar o processamento de Controle,
específico para a requisição (nossa classe no padrão Action).

#7. Neste método, no momento em que o processamento tenta interpretar uma expressão para
obter referência ao objeto que encapsula os metadados do jCompany, o JBoss Seam entra
em ação. A partir deste ponto, precisamos de conhecimentos básicos sobre este framework†.

Tudo começa porque o objeto de metadados em questão, cuja referência tentamos obter
dinamicamente via o interpretador de expressão EL
“PlcElHelper.getInstance().evaluateExpressionGet” é “gerenciado pelo jBoss Seam”.
Este objeto é declarado como variável de instância da classe "PlcBaseJsfAction", e as
anotações reproduzidas no Código E16.11 declaram este “gerenciamento”.

...
@In(value = PlcJsfConstantes.PLC_CONFIG_URL_COLABORACAO, required = false, scope = ScopeType.EVENT)
@Out(value = PlcJsfConstantes.PLC_CONFIG_URL_COLABORACAO, required = false, scope = ScopeType.EVENT)
protected PlcConfigUrlColaboracao configUrlColaboracaoPlc;
...
Código E16.11. Declaração de objeto de metadados “gerenciado” pelo JBoss Seam, no “PlcBaseJsfAction”.

#8. Além do objeto que encapsula os metadados, o método chamado


“criaConfigUrlColaboracao”, também da classe “PlcBaseJsfAction”, é definido para o JBoss
Seam como “factory” (DP Factory) para os objetos de configuração, conforme o Código E16.12.

...
@Factory(PlcJsfConstantes.PLC_CONFIG_URL_COLABORACAO)
public void criaConfigUrlColaboracao() throws PlcException {
...
Código E16.12. Declaração de método “factory” para objeto de metadados no “PlcBaseJsfAction”, para o
jBoss Seam.

#9. Assim, da primeira vez que a aplicação tenta acessar uma Colaboração padrão em uma
conversação‡ e seus “metadados” ainda não existem disponíveis para acesso, o JBoss Seam
aciona este método de factory. Este método, somente uma primeira vez na vida de uma
aplicação§, obtém as anotações de metadados tanto da camada Controle quanto Comuns
(Domínio) para esta Colaboração e as mantém encapsuladas, para facilitar o acesso do
framework.

Note que a instância deste objeto é representada no diagrama como


“plcConfigUrlColaboracao”, que é o valor da constante PLC_CONFIG_URL_COLABORACAO.

#10. O método “inicializaManagedBeans” tenta capturar, em seguida, os dados principais da


colaboração (valores de coleção para “Uf”, em nosso caso) e o mesmo mecanismo é ativado,
agora para um objeto padrão com nome “plcLogicaItens”. Este objeto, de forma similar ao
objeto de metadados, também é gerenciado pelo jBoss Seam, mas encapsula uma lista de
dados no formato “List<PlcBaseVO>”, que irá variar a cada nova conversação. Portanto, não
pode ser mantida em caching no escopo de aplicação.

É importante saber que, dependendo do padrão da Colaboração, dois objetos genéricos


distintos são utilizados para encapsular dados de uma conversação, pelo jCompany:

*
Já que existem várias chamadas do “beforePhase”, até este ponto que nos interessa.

A representação da chamada de “AppPhaseListener” para o JBoss Seam no Diagrama de Seqüência está em alto nível de abstração,
apenas para fins didáticos. O mecanismo real é mais intrincado e também poderoso.

Uma escopo de “conversação” do JBoss Seam é formado por um conjunto de requisições HTTP que compartilham de um mesmo
“estado”. Este estado é gerenciado pelo jBoss Seam, de forma equivalente a uma sessão HTTP, porém normalmente de menor duração.
§
Isto somente é realizado uma única vez, já que as informações de metadados não variam a cada requisição e nem mesmo durante a
vida da aplicação. Portanto, elas ficam armazenadas em caching na primeira requisição do usuário e são reutilizadas da memória, daí
por diante.
- O objeto “plcLogicaItens”, de classe “List<PlcBaseVO>” será utilizado para Colaborações
no padrão “plcTabular”, “plcCrudTabular”, “plcSelecao” e “plcConsulta”, ou seja, para aquelas
que manipulam coleções de entidades,

- O objeto “plcEntidade”, de classe “PlcBaseVO”, será utilizado para as demais, que


manipulam uma agregação de objetos por vez.

...
@In(value = PlcJsfConstantes.PLC_LOGICA_ITENS, required = false, scope = ScopeType.CONVERSATION)
@Out(value = PlcJsfConstantes.PLC_LOGICA_ITENS, required = false, scope = ScopeType.CONVERSATION)
protected PlcBaseLogicaItens logicaItensPlc;
...
Código E16.13. Declaração de objeto que encapsula listas para as Colaborações “plcTabular”,
“plcCrudTabular”, “plcSelecao”, “plcConsulta”, gerenciado pelo jBoss Seam, em “PlcBaseJsfAction”.

#11. Como a colaboração de nosso exemplo é “plcTabular”, o jCompany tenta capturar dados no
objeto “plcLogicaItens”. Se eles não existirem (como no caso da primeira requisição), o
método “criaLogicaItens”, definido como “factory JBoss Seam” para este objeto, é
acionado, iniciando uma conversação.

...
@Factory(PlcJsfConstantes.PLC_LOGICA_ITENS)
@Begin(join = true)
public void criaLogicaItens() throws PlcException {
...
Código E16.14. Método de factory JBoss Seam para “plcLogicaItens”, em “PlcBaseJsfAction”.

#12. A implementação deste método irá variar, dependendo do padrão da Colaboração corrente.
Para o caso do “plcTabular”, como a operação default é a recuperação de todos os objetos, o
processamento de criação será delegado para o método “pesquisa” (o mesmo acionado
quando o usuários clica em “F9-Pesquisar”).

O método “pesquisa” obtém, por fim, uma referência do contrato de fachada padrão
(“IAppFacade” – “AppFacadeImpl”) e chama um serviço da Camada Modelo/Persistência, para
recuperação da lista de Entidades.

- Anatomia da Fase de Desempilhamento (do retorno da fachada até resposta).


Vamos analisar agora a anatomia da Seqüência de Transação típica da fase de Desempilhamento
(Resposta) da camada Controle, que inicia após a devolução de algum resultado de serviços da camada
Modelo. Chamamos a esta segunda metade do processamento de “desempilhamento”, porque irá
promover a finalização das chamadas e desempilhar os objetos inicialmente “empilhados para execução”
na memória.
Figura E16.13. Seqüência de desempilhamento da requisição GET para colaboração “plcTabular”.

#1. Após o recebimento da coleção recuperada via serviços da camada Modelo, o método
“pesquisa” simplesmente disponibiliza a lista de objetos retornada no objeto “plcLogicaItens”*,
disponível como variável de instância da própria classe†.

#2. O processamento do evento “RENDER_RESPONSE 6” continua, com a chamada de métodos


diversos necessários para a complementação da resposta, tais como o “registraAjax”, que
delineia parâmetros para o uso genérico da tecnologia Ajax do Apache Trinidad pelo
jCompany.

#3. O método “conversacaoEncerra” averigua situações de encerramento de conversações JBoss


Seam, para gerenciar este encerramento também de forma genérica‡. Este método do
“PlcPhaseListener” é acionado ainda na fase de “empilhamento” e fica “empilhado” por toda
a execução de serviços de fachada, encerrando-se neste ponto.

#4. Uma nova fase JSF é iniciada e o método “afterPhase” é executado para o evento
“RENDER_RESPONSE”, ainda na classe “PlcPhaseListener”.

#5. A partir deste ponto o processamento é delegado para o Tiles, que através de uma JSP de
Front-Controller “tilesDispatchPlc.jsp”§ começa a etapa de “despacho” de conteúdo HTML. O
uso da JSP é necessário como técnica de integração do Tiles com o JSF e seu código é de
extrema simplicidade, realizando uma de duas coisas:

- Se a Colaboração corrente estiver utilizando o leiaute Universal do jCompany, esta página irá
inserir uma definição Tiles “def.universal.automatico” (utilizando a Tag “tiles:insert”).

- Se a Colaboração corrente estiver utilizando um leiaute específico, ela irá tentar inserir uma
definição Tiles com mesmo nome que a URL (Ex.: “uf”).

#6. Definições de leiaute Tiles são recursivas, como já vimos. A definição principal
“def.universal.automatico”, por sua vez, inclui referências a outras subdefinições de
forma dinâmica, com base em convenções de nomenclatura.

*
Dependendo do padrão, poderia ser uma Agregação de Objetos, disponibilizada no objeto “plcEntidade”.

Note que, em JSF, as classes de Action do jCompany são statefull em escopo de “conversação JBoss Seam”, aceitando objetos que
contém dados como variáveis de instância - ao contrário do Struts, onde são stateless e tais objetos devem ser obtidos da sessão
(HttpSession).

Novamente, existem diversos outros métodos executados nesta fase, não representados. Note que a fase “beforePhase” para o
evento “RENDER_RESPONSE 6” é a de maior duração.
§
Esta JSP atua como um Servlet, sendo inclusive declarada como tal no “web.xml”, em uma das técnicas mais utilizadas para
integração os frameworks JSF e Tiles. Como internamente, toda JSP se torna um Servlet, neste caso ela é efetivamente utilizada como
um Servlet de Front Controller para poder ser valer de Tag-Libs Tiles para inserção de leiautes.
#7. Cada definição, em seu nível, pode declarar o uso de uma classe Java considerada de camada
Controle, chamada “Tiles Controller”*. Este tipo de classe implementa a interface “Controller”
do Tiles, que exige o método “execute”. Este método tem código que roda antes do despacho
de cada trecho de leiaute, permitindo programação dinâmica, em seu contexto.

#8. Cada definição, em seu nível, após a execução da classe Tiles Controller, despacha a execução
de uma JSP de leiaute (path) e outras adicionais representando componentes do segmento de
leiaute. As páginas JSP, por sua vez, podem conter diversos componentes Trinidad,
representados por Tag-Libs JSP.

Nas JSPs, o fluxo já é considerado da camada Visão, dedicado a renderizar um documento em


formato HTML ou outro qualquer, dependendo do Render Kit e das implementações de leiaute
utilizadas.

- Modelo de classes principais da camada Controle.


Nos diagramas de seqüência da camada Controle que apresentamos, as classes de filtro utilizadas foram
classes do jCompany, diretamente, enquanto outras como a interceptora de fases JSF e a de controle
foram da aplicação.
Estas classes da aplicação “AppPhaseListener” e “AppAction” herdam de “PlcPhaseListener” e
“PlcBaseJsfAction”, respectivamente, e são disponibilizadas e pré-configuradas pelos templates INI
para atuarem em um esquema de Inversão de Controle – deste modo facilitando lógicas de programação
específicas em pontos chave do processamento de uma requisição.
Seria possível pré-configurar um esquema similar para as classes de filtro. No entanto, como ocorrem
muito cedo na seqüência de transação, este tipo de especialização não costuma ser tão útil.
De todas as classes representadas no diagrama da Figura E16.13, somente o “FacesServlet” não
aceita especializações diretas. Porém, a sua implementação delega a maior parte do processamento
para uma arquitetura de POJOs onde se inserem as classes “AppPhaseListener” e “AppAction”.

- Modelo de classes do tipo “PhaseListener”


No caso da interceptação no padrão JSF “PhaseListener”, a classe que estará atuando (se o esquema
padrão sugerido pelo jCompany não for modificado) será a “AppPhaseListener”, específica da aplicação e
descendente de “PlcPhaseListener”.
Esta classe já vem pré-configurada no arquivo “faces-config.xml” da aplicação, como “phase-listener”
padrão, mas reusa todo o seu código do ancestral, a princípio. Com o tempo, o Desenvolvedor poderá
usá-la para imediatamente sobrepor ou especializar programações neste segmento.
O modelo de classes para este segmento é bem simples, como mostra a Figura E16.14.

*
Esta é uma classificação que pode ser polêmica. Por ocorrerem já na fase de renderização do documento de resposta, poder-se-ia
classificar as classes de controle do Tiles como de “camada Visão”. Porém, estas classes de controle Tiles são certamente
“controladoras” do ponto de vista do Tiles e podem ser entendidas como complementares as classes de Action, sendo inclusive
independentes do formato do documento – por este motivo, são organizadas como camada Controle, do ponto de vista do jCompany.
Figura E16.14. “AppPhaseListener” e “PlcPhaseListener”.

#1. As classes de implementação de “PhaseListener” são stateless, significando que não possuem
propriedades com estado variante (variáveis de instância).

#2. Os métodos requeridos pela interface “PhaseListener” estão disponíveis, para sobreposições
que se possam fazer necessárias.

#3. No entanto, o jCompany implementa os métodos exigidos pela Interface e utiliza o DP


Template Method para prover métodos de extensão mais refinados, para nossa arquitetura
específica. Para maior reúso e menor redundância, sempre que possível, deve-se especializar
esta classe através estes métodos.

#4. Diversos “Template Methods” estão disponíveis. Os métodos que terminam com “Antes”,
“Apos” e “Api”, como já vimos, são convenções que indicam que não possuem código no
ancestral – dedicados a especializações.

#5. O mecanismo de IoC que faz com que “AppPhaseListener” atue é provido pela implementação
JSF. Os templates INI trazem este descedente declarado no “faces-config.xml” para que atue e
facilite implementações específicas.

#6. No exemplo hipotético, o desenvolvedor especializou o início e o fim da fase “RenderResponse”


em dois métodos “Antes” e “Apos".

- Modelos da Agregação “PlcBaseJsfAction”


Recomenda-se especializações na parte de “PhaseListener” somente para aqueles procedimentos que
façam sentido para todas as Colaborações de um aplicação. Especializações mais refinadas, cujo escopo
seja de apenas uma Colaboração ou conversação (possível fluxo de Colaborações), devem ser realizadas
na parte mais “central” da camada Controle, em descendentes da classe “PlcBaseJsfAction”.
Esta classe é Raiz de uma agregação que engloba serviços de controle mais especializados (Service) e
estados (Entities, POJOs) importantes para cada Colaboração. Além disso, faz uso de utilitários diversos
(Helper), em vários pontos de processamento.
Sua arquitetura é, portanto, um pouco mais intrincada, como mostra a Figura E16.15.
Figura E16.15. Agregação “PlcBaseJsfAction”, do ponto de vista de serviços (Service).

#1. As classes utilizadas como “Action” no JSF são “Statefull”, ao contrário do Struts, onde são
“Stateless”.

#2. Como forma de encapsular processamentos especializados em classes mais coesas, o


jCompany utiliza DP “Delegação”* para classes de serviço, que são sufixadas com “Service”.

#3. A maior parte do código das classes “Service” da camada Controle são independentes da
tecnologia Struts ou JSF†. Quando há alguma diferenciação específica que necessite de
acoplamento a alguma destas tecnologias, uma classe de serviço descendente é definida
(geralmente para JSF), como as demarcadas, mantendo a independência do ancestral
genérico.

*
Uma das diferenciações do conceito de Delegação comparado a uma chamada simples é a flexibilidade para se especializar as classes
de serviço utilizada em ancestrais. No jCompany, é possível se declarar especializações destas classes em metadados, alterando
qualquer comportamento envolvido na agregação, não somente da classe principal.

Este é um bom exemplo de ganhos advindos da Delegação. Muito embora a classe Raiz seja dependente de tecnologia JSF ou Struts,
os códigos comuns a ambas estão fatorados nos serviços.
Figura E16.16. Agregação “PlcBaseJsfAction”, do ponto de vista de utilitários (Helper).

#1. Classes de utilitários utilizadas com freqüência por toda a classe, são definidas em variáveis de
instância, para maior clareza.

#2. Classes de utilitários são definidas com DP Singleton. Note que este DP exige construtores
“privados” para impedir instanciamentos desnecessários – que como efeito colateral também
impedem a herança. Deste modo, classes utilizada com DP Singleton do jCompany não
são projetadas para serem especializadas. Geralmente contêm métodos simples, que
podem ser substituídos inteiramente por outros, sem produzirem redundância significativa.

#3. Apesar de possuírem nomes similares, as classes "PlcContextHelper" e


"PlcContextMontaHelper" tem propósito bem distinto. Enquanto a primeira provê acesso da
classe de Action para objetos da tecnologia Servlet (request, response, etc.), a segunda é
incumbida de montar um objeto que encapsula dados da conversação mantidos na camada
Controle, para envio à camada modelo, em cada requisição*.

*
Exemplos são o “perfil do usuário corrente” e alguns metadados que podem ser modificados dinamicamente.
Figura E16.17. Agregação “PlcBaseJsfAction”, do ponto de vista de metadados.

#1. Os objetos que contêm representações de metadados para uma Colaboração corrente são
injetados como variáveis de instância no “PlcBaseJsfAction” pelo JBoss Seam.

#2. A classe "PlcConfiguUrlColaboracao" encapsula dois grupos de anotações de camadas


distintas, "@PlcConfigGrupoControle" (camada Controle) e "@PlcConfigGrupoAgregacao"
(camada Domínio/Comuns), desta forma simplificando o acesso a estas informações durante o
processamento genérico da requisição.

#3. A classe de Controle genérica utiliza um POJO "PlcControleConversacao" para encapsular


informações de controle (estado) de uma conversação, tais como “aba correntemente
selecionada de um Tab-Folder de leiaute”, “situação de um Detalhe ‘por demanda’ (recuperado,
pendente)”, etc.. Note que estas não são informações de metadados mas de controle do
estado de determinados componentes de leiaute Tiles, não gerenciados pelo JSF. Os
valores que estarão presentes neste objeto dependem dos componentes de leiaute utilizados,
declarados nos metadados de Controle.
Figura E16.18. Grafo “PlcBaseJsfAction” do ponto de vista de objetos ‘de Domínio’.

#1. Os objetos que representam agregações de Domínio e também o POJO que encapsula
informações de contexto* também ficam disponíveis para a classe “PlcBaseJSFAction” como
variáveis de instância, e são gerenciados pelo JBoss Seam.

É importante notar que estes objetos têm importância própria e fazem sentido mesmo que
desvinculados do “PlcBaseJsfAction”. Portanto, não são considerados “agregações” da classe
“PlcBaseJsfAction”.

#2. Se o padrão da Colaboração for “plcTabular”, “plcCrudTabular”, “plcSelecao” ou


“plcConsulta”, pelo mecanismo que já apresentamos, uma instância da classe
“PlcBaseLogicaItens” será injetada na classe Action, com nome de objeto “plcLogicaItens”.
Por sua vez, esta classe encapsula uma coleção de entidades de nome “itensPlc” e tipo
“List<PlcBaseVO>”, que é onde as informações recuperadas e/ou informadas ficam
armazenadas, durante uma conversação.

Se conferirmos a JSP “ufTabular.jsp”, veremos a referência JSF a esta classe da seguinte


forma:

...
<plcf:iteracao id="plcLogicaItens" value="#{plcLogicaItens.itensPlc}">
(...)
<plcf:celula>
<plcf:texto id="nome" value="#{item.nome}" ajudaChave="ajuda.nome" />
</plcf:celula>
...
Código E16.15. Referência a “itensPlc”, dentro de “plcLogicaItens” (o “Action” corrente é assumido
implicitamente pelos componentes JSF do jCompany).

O componente “iteracao" cria um laço e disponibiliza cada objeto da coleção na variável local
“item”, de modo que todo o “grafo de Domínio” pode ser acessado via notação de pontos tipo
“#{item.objeto.[objeto]}”.

*
Na prática, dados mantidos na sessão HTTP ou em uma conversação JBoss Seam – de interesse dos serviços da camada Modelo.
#3. Note que a coleção anterior pode não ser mantida durante uma conversação*, o que é inclusive
o default do jCompany para evitar aumento de consumo de memória sem necessidade. O uso
do metadado de controle “detalheLembra=true”, para a Colaboração, faz com que coleções
previamente recuperadas (portanto, antes de eventuais modificações) também sejam mantidos
em memória durante uma conversação.

...
comportamento = @PlcConfigComportamento(detalheLembra = true),
...
Código E16.16. Indica para o framework manter a coleção ‘anteriormente recuperada’ em
“plcLogicaItensAnterior”.

Esta configuração somente deve ser usada quando for necessário implementar lógicas de
programação do tipo “se alterou uma propriedade do valor ‘A’ para o valor ‘B’, então
...”.
#4. Se o padrão da Colaboração for “plcCrud”, “plcMestreDetalhe”, “plcMantemDetalhe”,
“plcManSubDetalhe”, “plcPrefAplicacao” ou “plcPrefUsuario”, ou seja, em padrões onde
se manipula “uma agregação por vez”, então a agregação de domínio é incluída diretamente
em “plcEntidade”, através de referência ao seu objeto Raiz. Neste caso, a versão anterior é
sempre mantida pelo jCompany por default, mas somente do objeto Raiz da agregação.

#5. Além do modelo de Domínio, em seus estados atuais e anteriores a modificações, um POJO
adicional é sempre enviado pelo jCompany, da camada Controle para a camada Modelo,
conforme pode ser investigado pela assinatura do Façade "IPlcFacade". Este objeto
implementa o DP J2EE Context Object, que define padrões para encapsulamento de dados
úteis aos serviços de Modelo, porém mantido somente no contexto da camada Controle†.

Após a exposição da arquitetura das generalizações de camada Controle, podemos compreender um


pouco melhor as suas formas de especialização. Elas se dão basicamente via “herança simples com
Template Method”, para a classe “PlcBaseJsfAction” em si e via Injeção de Dependência do JBoss
Seam, para as classes de serviço auxiliares (sufixadas com “Service”) ou para incluir novos dados no
POJO “PlcBaseContextVO”.

*
Indicado pela multiplicidade zero no diagrama UML.

Muito embora este objeto seja relativamente extenso, a maior parte das informações não é composta em uma requisição típica - o
envio do perfil do usuário corrente é seu propósito mais fundamental, na maior parte dos casos.
Figura E16.19. Esquema previsto para especialização dos serviços centrais de controle.

#1. A classe “PlcBaseJsfAction” contém as implementações específicas para cada evento padrão
(disparados, em sua maioria, pelos botões de ação), utilizando DP Template Method. Desta
vez, representamos apenas a parte de operações desta classe, para enfatizar esta
implementação (nos outros diagramas, analisávamos as variáveis de instância).

#2. Uma classe “AppAction” é configurada como default, em cada projeto, através dos templates
INI, pronta para conter especializações genéricas para toda a aplicação. No exemplo acima,
esta classe sobrepõe um método exclui para toda a aplicação (algo mais “radical”, porém
possível) e também acrescenta procedimentos após a edição, para todos os objetos.

#3. Se houver necessidade de processamento de controle específico, basta criar um novo


descendente e configurá-lo nos metadados, como já fizemos em tutoriais passados. No
exemplo, uma sobreposição à especialização realizada pelo “AppAction” é implementada; e
também uma especialização para “antes de se abrir um diálogo de seleção”, para esta
Colaboração.

#4. Neste caso, o mecanismo de IoC é gerenciado pelo jCompany, principalmente.

#5. Para especializar serviços que recebem delegações da classe “PlcBaseJsfAction”, tais como
"PlcValidacaoJsfService", basta criar um descendente, declará-lo como uma classe
gerenciada pelo Seam e implementar um novo método de “factory”, em “AppServiceFactory”,
classe disponível nos templates INI. Exemplos:

@Name("AppMeuValidationJsfService ")
@Scope(ScopeType.APPLICATION)
public class AppMeuValidationJsfService extends PlcValidacaoJsfService{

// Especializações ao service, que serão ativada em todo o framework.

Código E16.17. Classe que especializa PlcValidacaoJsfService.

@Name("AppServiceFactory")
@Scope(ScopeType.APPLICATION)
@AutoCreate
public class AppServiceFactory {

@Factory(value="serviceValidacaoJsfPlc")
public PlcEntidadeService geraValidacaoJsfService() {
return (PlcValidacaoJsfService)Component.getInstance("AppMeuValidationJsfService",true);

}
}

Código E16.18. Método de "factory" que altera a implementação default, em AppServiceFactory.

#6. Finalmente, para repassar novas informações de contexto para a camada Modelo, deve-se
especializar o POJO “PlcBaseContextVO”, criar a nova informação de contexto (por exemplo,
empresa ou filial corrente, em uma aplicação multi-empresa) e, em seguida, especializar a
classe Action para montar este valor.

Neste tópico, desvendamos apenas as especializações de camada Controle mais comuns e


recomendadas, mantendo um nível de abstração prático, viável de se demonstrar em Diagramas de
Sequencia UML. Porém, algumas demandas mais raras (mas reais) exigirão ajustes em granularidade
mais fina, ou até mesmo em nível dos frameworks de base! Para estes casos, o nível de informação que
passamos não é suficiente.
Para aprofundar-se ainda mais no entendimento das seqüências de transações – e deste modo atender a
qualquer nível de demanda - será inevitável que o Desenvolvedor conheça e utilize certas facilidades
chave da IDE e do jCompany.

- Compreendendo a seqüência em maior detalhe – Depuração e Logging II (Tutorial)


Um recurso muito interessante que o jCompany provê, com base em especialização do framework
Log4j, é o de inspeção da anatomia de seqüências de transação via logs.
O jCompany provê esta facilidade utilizando classes de logging separadas por camada e especializadas
para exibir fluxos importantes em cada uma delas. Além disso, o jCompany traz um Servlet que permite
a alteração dinâmica de níveis de logging, sem necessidade de nova liberação da aplicação, recurso
essencial para tornar prático o uso deste recurso, no dia a dia.
Vamos realizar um tutorial para ativar a exibição da seqüência da camada Controle para “/f/t/uf”, que
estudamos nos tópicos anteriores:
1. Com a aplicação rodando, acione o menu “Área de TI -> Logs – Gerenciamento”.
Uma janela deverá abrir em outra instância do Navegador, semelhante à exibida na Figura E16.20.
Somente cerca de sete classes de logging são exibidas, consideradas “de uso mais freqüente”.
Cinco destas classes nos permitem ativar mensagens de log de nível DEBUG, que expõem as
seqüências de execução principais em cada camada da arquitetura MVC2-P. Além delas, uma
classe de logging do Hibernate também está disponível – quando ligada para DEBUG, esta classe
exibe logs com valores para parâmetros de comandos SQL enviados com uso de Prepared
Statement (e que, por este motivo, aparecem escondidos em símbolos “?”, na console).

Figura E16.20. Diálogo que permite a manipulação de níveis de logging dinamicamente.

2. Antes de editar estas classes, experimente alterar a URL, incluindo três diferentes níveis de detalhe
via parâmetro “logSpyPlc=”, informando valores de 1 a 3. Em cada nível, um maior número de
classes é exibido. O resultado do nível 1 é exibido na Figura E16.21.
Figura E16.21. Todas as classes de log que possuem pacotes padrões do jCompany.

Obs.: O nível 3 filtra somente classes de logging de JSPs pré-compiladas, que aparecem após uma
“liberação com pré-compilação”, voltada para produção. Por este motivo, em desenvolvimento
pode-se não perceber diferenças significativas entre os níveis 2 e 3.
3. Agora retorne ao Eclipse e procure a janela de console do Tomcat. Clique no botão “Clear Console”
exibido na Figura E16.22.

Figura E16.22. Console do Tomcat no Eclipse. Somente SQLs são exibidos, na configuração padrão.

Dois problemas podem acontecer aqui: se a janela “Console” não estiver visível, você poderá ter
que ativá-la através da opção de menu “Windows -> Show View”; ou se a janela console estiver
exibindo informações do Apache Derby ou Maven, você terá que comutá-la para Tomcat, no botão
“Display Selected Console”.
4. Volte o jCompany Log4j Console para o modo resumido, simplesmente informando “logSpyPlc=0”
na URL. Em seguida, troque o nível da classe de log “jcompany.controle.log” de “INFO” para
“DEBUG” e clique em “Set”.

Figura E16.23. Alteração dinâmica de nível de logging para classe especial do jCompany.

5. Agora retorne para a aplicação e acesse a URL “/f/t/uf”. Após sua execução, comute para o Eclipse e
consulte o resultado na janela de Console. Ele deve estar semelhante ao resultado exibido na Figura
E16.24.
Figura E16.24. Perfil de execução via logging, destacando classes/métodos fundamentais da camada Controle.

#1. Fase em empilhamento de chamadas da camada Controle.

#2. Fase de desempilhamento de chamadas da camada Controle.

Veja como agora fica fácil identificar a seqüência de empilhamento e desempilhamento das
execuções, através da endentação automatizada que o jCompany provê para estas classes
especiais de logging, nomeadas como “com.powerlogic.jcompany.[camada].log”.
Este recurso, aliado com o bom uso do logging convencional, pode auxiliar na identificação de
gargalos de performance e também na localização de problemas, de forma complementar ao
depurador.
6. Experimente agora ligar também o nível de DEBUG para a classe
“com.powerlogic.jcompany.visao.log”, para ver o fluxo de camada Visão, juntamente com o da
camada Controle. Estude o resultado juntamente com os diagramas de seqüência que estudamos
anteriormente.

A despeito do esforço que se faça para diagramar seqüências de execução de software, há um


limite prático de escalabilidade destes diagramas em UML. Por isso, o uso deste “perfil de execução
via Log4j” disponibilizado pelo jCompany é uma ferramenta bastante útil para uma compreensão
dinâmica e “ao vivo” destes cenários, em maiores detalhes.

- Compreendendo a seqüência real – Depuração e Logging III (Tutorial)


A técnica de logging acima nos dá uma visão mais aprofundada do que a demonstrada pelas abstrações
dos Diagramas de Seqüência, mas ainda não representam a seqüência real, completa, de todo o fluxo de
atendimento realizado!
Isto porque as mensagens de log são incluídas em classes do jCompany apenas. Mesmo ao ligar-se o
nível DEBUG para classes de log dos frameworks de base, corre-se o risco de que elas não tenham sido
utilizadas pelo desenvolvedor, não havendo garantia de exibirem uma visão completa do fluxo.
Uma solução para ver a seqüência completa, real, seria utilizar ferramentas de profiling, que utilizam
técnicas em nível da JVM para capturar todos os métodos executados em uma Thread*, mas na
realidade não precisaremos chegar a tanto. Afinal, utilizamos OO para reutilizar e nos abstrair das muitas
camadas de software mais profundas.

*
Em Struts, o jCompany implementa uma solução chamada de “one-click profiling”, que exibe uma pilha de execução também via
Log4j, mas utilizando técnicas de AOP via CGLib, para exibir métodos do Tiles e Struts, dentre outros. Esta é ainda uma visão
intermediária entre o log que vimos para JSF e um profiling completo.
Nos cenários eventuais quando necessitarmos de conhecimento ainda mais profundo, a recomendação é
para usarmos as ferramentas de depuração (Debug) do Eclipse, o que pode ser feito com os seguintes
passos:
1. Após descobrir um trecho de execução “suspeito”, seja na aplicação, seja no jCompany ou
frameworks de base, navegue via hiperlinks pelos códigos fontes destas classes (“control+Clique”
sobre o nome das referências) e aperte “duplo-Clique” na barra lateral esquerda da linha desejada,
para marcar um ponto de parada.

Figura E16.25. Linha de código de classe do jCompany, com “breakpoint” para depuração.

2. Ao executar a aplicação novamente, o “Debug” do Eclipse irá propiciar os diversos recursos que se
espera dos melhores utilitários para este fim, tais como execução “passo a passo”, investigação e
alteração dos valores de variáveis na memória, inclusão de condicionais (Ex.: “somente parar aqui
se variável a for igual b”) e inclusive alteração de código com efeito imediato – seguida de um “Hot
Deploy”.

Figura E16.26. Diálogo do “Debug”, após encontrar um ponto de parada.

#1. Relação de “Threads” em execução no Tomcat. Como trabalhamos com ambientes de execução
multi-thread, existirá um conjunto delas (pool) criadas na memória, mas apenas uma conterá a
nossa execução principal, e esta já se apresentará aberta, com a pilha de execução real
exibida, até o ponto de parada definido.

#2. Uma barra de botões permite opções tais como execução “linha a linha” (botão verde), salto
para o próximo ponto de parada, retrocesso e indicativo para se entrar em uma função (em
lugar de considerá-la apenas uma linha de execução).

#3. Na janela “Variables”, pode-se consultar e alterar valores de variáveis em memória, na medida
em que se avança de forma paulatinamente, na execução.

#4. Em “Breakpoints”, podem-se excluir pontos de paradas existentes ou incluir novos, na medida
em que se executa a depuração, inclusive informando-se condicionais.

#5. Finalmente, com o código fonte disponível, pode-se alterá-lo, para avaliar seu efeito imediato.
Lembre-se de que este “Hot-Deploy” realizado não é perene, e será perdido após um reinício
do Application Server. Após algumas alterações em modo de depuração, deve-se realizar uma
liberação “rápida com reinicio”.
Para aprender mais sobre a opção de “Debug” do Eclipse, consulte no Ajuda On-Line do Eclipse o tópico
“Java Development User Guide -> Concepts -> Debugger”. Se você não conhece ainda esta ferramenta,
esta é uma leitura obrigatória!
Programações da Camada Modelo - Fachada

- Visão geral
O estudo da programação da camada Modelo pode ser segmentado em duas subcamadas, já
desconsiderando a de Persistência:
Subcamada de Fachada (DP Façade): Realiza a adaptação de requisições da camada Controle para a
subcamada de Serviços ou do Negócio, incluindo o delineamento das transações. Não implementa os
serviços em si, mas delega para a subcamada de Serviços. Esporadicamente, para casos mais
simples, pode chamar a camada de Persistência diretamente*.
Subcamada de Serviços do Negócio (DP Java EE AS-Application Service ou BO-Business
Object): Realiza os serviços principais do negócio, via delegação das implementações da fachada. É
importante esta separação, para manter os métodos de serviços com assinaturas “de negócio”. Além
disso, por não delinearem transações, os métodos desta camada se tornam mais reutilizáveis.

- Programações da Subcamada de Fachada (DP Façade)


Os serviços da camada Modelo são isolados da camada Controle através de um contrato bem definido e
de uma implementação de adaptação que segue o DP Façade. Para seu propósito, o jCompany traz
como contrato a Interface “IPlcFacade” e como implementação a Classe “PlcFacadeImpl”. O contrato
define com mais rigor e clareza a “fronteira” entre as camadas, facilitando novas implementações; a
implementação default realiza adaptações nos parâmetros recebidos e gerenciamento de transações,
delegando a parte mais “nobre” do processamento para a subcamada de serviços, representada por
classes de Application Service (sufixadas com AS) ou de Business Object (sufixadas com BO ou
Manager).
Ao isolar os serviços de negócio completamente, tanto de implementações de Controle quanto do
tratamento de argumentos de contexto e de transações, como veremos, a subcamada de fachada presta
um grande serviço: permite à subcamada seguinte se dedicar a uma implementação mais “limpa” e
“estável”, a “implementação do Caso de Uso” em si, de maior interesse para o cliente.
Este isolamento rigoroso permite, ainda, uma fácil distribuição da aplicação, seja para estratégias
abrangentes de SOA, seja para necessidades pontuais de distribuição†.

- Modelos da Subcamada de Fachada


A arquitetura do DP Façade no jCompany provê um contrato que define todas as operações mais
comuns para atender a Manutenções do Ciclo de Vida de Agregações de Entidades, com robustez
corporativa, e também operações de consulta mais comuns.
Isso engloba não somente a possibilidade de incluir, alterar, recuperar (editar) e excluir uma Entidade
Raiz e suas Entidades agregadas (detalhes, subdetalhes, componentes, arquivos anexados, etc.), em
uma mesma transação, mas também de gravar auditorias mínima (usuário e data da última
modificação), rígida (imagens de alterações), realizar exclusão lógica, aprovações e outras variações
generalizadas pelo jCompany (Inclusões de Extensões Padrões).
No que concerne às consultas, o contrato provê alternativas diversas para se realizar operações tipo
“QBE” (Query By Example) genericamente (recebendo coleções de argumentos e operadores, por
exemplo), dentre outras variações.
A recomendação é para que, caso o desenvolvedor queira definir novas “cláusulas” contratuais (métodos
de fachada), relacionadas aos assuntos acima (Manutenção do Ciclo de Vida e Consultas de Coleções de
Objetos), ele especialize tanto a interface IPlcFacade quanto a implementação “PlcFacadeImpl”
disponibilizados pelo jCompany, ao invés de criar contratos e implementações independentes. Para isso,

*
A chamada de serviços da persistência diretamente de implementações de fachada é aceita pelos DPs J2EE, para casos triviais, mas
pouco utilizada pelo jCompany, exceto em recuperações de listas simples para colaborações “plcTabular”. A rigor, esta chamada direta
indicaria que a subcamada de fachada e a subcamada de serviços são laterais mas, na prática, é melhor compreendê-las como
camadas superpostas.

Nesta arquitetura, um arquivo EAR contendo arquivos JAR gerados dos projetos “rhtutorial_modelo” e “rhtutorial_comuns” deverá ser
embalado e instalado para funcionamento remoto, em um container EJB3, com seus serviços acessíveis via RMI/IIOP, JMS ou Web-
Services. Já os projetos “rhtutorial (principal)” e “rhtutorial_comuns” (este último residirá nas duas pontas, possivelmente, ao menos
para os Casos de Uso Padrões), devem sem embalados um arquivo WAR, funcionando como “cliente”. Esta arquitetura será analisada
no livro “Volume II – Tópicos Avançados”, desta sérieo.
o jCompany já disponibiliza inclusive a interface "IAppFacade" e "AppFacadeImpl", nas aplicações,
atuando prioritariamente através de um mecanismo de IoC próprio. Veja na Figura E16.27.

Figura E16.27. Arquitetura de classes e IoC da subcamada de Fachada.

#1. Contrato de Fachada Padrão para Manutenção de Ciclo de Vida e Consulta Parametrizada, do
jCompany.

#2. Implementação de Fachada Padrão para o contrato IPlcFacade.

#3. A implementação possui ancestrais com métodos de apoio restritos a esta subcamada.

#4. Descendente do Contrato de Fachada Padrão, utilizado automaticamente quando a aplicação é


liberada de forma distribuída.

#5. Descendente do Contrato de Fachada Padrão, na aplicação, para permitir novas “cláusulas
contratuais”, que tenham afinidade com o assunto do contrato.

#6. Versão da interface remota na aplicação. Veja que aqui utilizamos “herança múltipla”, possível
para Interfaces (esta Interface especializa tanto o "IAppFacade" quanto o "IPlcFacadeRemote")

#7. Descendente da Implementação de Fachada Padrão, para implementações padrões das novas
“cláusulas contratuais”.

É importante notar que o uso do esquema padrão de especialização do contrato de fachada deve estar
estritamente relacionado ao seu objetivo (“objeto principal” do contrato), que é a Manutenção e
Consulta Parametrizada em Agregações de Entidades. Para quaisquer outros casos de serviços
necessários, mas não relacionados ao objeto, deve-se definir um contrato e implementações de
fachada “à parte”.
Praticaremos com estas duas situações, em tutoriais dos próximos capítulos.

- Anatomia da IoC para obtenção da Interface de Fachada.


Uma vez entendida a parte estrutural da arquitetura de fachada, é interessante conhecer o mecanismo
pelo qual a camada Controle, através das classes “*Action”, obtêm referências de “*FacadeImpl” via
seus contratos “I[*]Facade” ou “I[*]FacadeRemote”.
O esquema de obtenção da referência da fachada é especialmente importante, porque:
Utiliza uma estrutura de IoC similar à que será utilizada tanto para obtenção de referências de
BO/Managers da camada Modelo quanto para obtenção de referências de persistência “IPlcDAO”.
Esta estrutura utiliza um par de classes que seguem o padrão de nomenclatura
“Plc[Camada]Locator” e “Plc[Camada]IocFactoryService” (Ex.: “PlcFacadeLocator” e
“PlcFacadeIocFactoryService”), utilizadas para localizar e em seguida armazenar em caching a
referência de implementação de fachada encontrada.
Utiliza, de forma transparente para a classe de controle, um algoritmo para localização de serviços
potencialmente remotos com tecnologia EJB3, utilizando lookups JNDI e DP Business Delegate.
No caso de não utilizar EJB3, e após localizar a classe adequada a ser utilizada para a implementação de
fachada, o algoritmo de instanciação do jCompany utiliza técnicas de AOP via Proxy CGLib, de
modo a permitir interceptações AOP nos métodos desta classe.
Vejamos, pela Figura E16.28, a seqüência de IoC para obtenção da referência da fachada.

Figura E16.28. Seqüência em maior profundidade, da arquitetura de IoC utilizada para localizar a fachada.

#1. Métodos de controle tais como o “pesquisa” obtém referências à Interface de fachada
“IAppFacade”, através do método “getServiceFacade()”, que encapsula toda a
complexidade envolvida em sua obtenção.

#2. A classe "PlcControleLocator", utilizando DP “Service Locator”, orquestra o processo de


obtenção de uma referência da fachada, em conformidade com a anotação
“@PlcConfigModeloTecnologia”. Se ela for “@PlcConfigModeloTecnologia (tecnologia=
PlcConfigModeloTecnologia.Tecnologia.EJB3)”, prossegue tentando localizar a
implementação de fachada como um EJB3 Session Bean. Se for
““@PlcConfigModeloTecnologia (tecnologia=
PlcConfigModeloTecnologia.Tecnologia.POJO)”, prossegue tentando localizar a
implementação como um POJO embalado localmente, no mesmo arquivo.

#3. Em qualquer das duas hipóteses, o serviço de IoC "PlcControleFactoryIoCService" é


utilizado. Perceba que, como indica a convenção de sufixo “Service”, ele é um POJO extensível
– portanto, pode-se especializar os algoritmos padrões de IoC do jCompany, aqui
expostos.

#4. Quando utilizando tecnologia EJB3, esta classe irá delegar a localização da referência para a
classe "PlcEjbHelper", que encapsula o algoritmo de DP Business Delegate, para obter uma
referência possivelmente remota da fachada*.

*
Perceba que, muito embora neste cenário o “AppFacadeImpl” seja um EJB3 Session Bean, ele necessariamente poderá não estar
remoto, sendo também possível acessá-lo localmente, segundo o padrão EJB.
#5. Quando utilizando POJO será utilizado um algoritmo de IoC via DP “Service Locator” e reflexão,
para pegar uma referência de implementação localmente disponível (camada Modelo no
mesmo WAR).

#6. O retorno de cada um dos métodos irá variar, sendo a Interface potencialmente remota
devolvida no primeiro caso, e a local no segundo. Mas em qualquer dos casos, o uso funcional
permanecerá idêntico.

#7. No primeiro caso a classe de controle, agora de posse de uma referência de Interface remota,
indiretamente pode disparar chamadas remotas, no padrão EJB3.

#8. No segundo caso a classe de controle realiza sempre uma chamada local, indiretamente via
Interface. Note que, indiferentemente da forma e tecnologia de implementação, a
camada Controle opera da mesma forma, nos dois cenários!

- Anatomia de comunicação da Fachada com camadas inferiores.


A classe de implementação de fachada também localiza serviços abaixo de seu nível, ou seja, da
subcamada de Serviço/Negócio ou mesmo da camada de Persistência, através padrões de localização
similares ao que já vimos:
“PlcModeloLocator” + “PlcModeloIocFactoryService”, para localizar e manter em cache,
referências a serviços adequados, por requisição
“PlcPersistenciaLocator” + “PlcPersistenciaFactoryIocService”, para localizar e manter em cache,
referências a serviços de persistência.
Vejamos este mecanismo mais em detalhes, pela Figura E16.29.

Figura E16.29. Seqüência em maior profundidade, da arquitetura de IoC utilizada pela fachada.

#1. A maior parte dos métodos de acionamento são como os iniciados por esta primeira seqüência,
típica da pesquisa quando feita em colaborações “plcTabular” ou “plcConsulta”.

#2. A implementação de Fachada irá realizar procedimentos mínimos e pegar uma referência da
classe de utilitário para localização serviços, através do método “getBO(PlcBaseVO)“ que, a
exemplo do “getServiceFacade”, irá encapsular a lógica de obtenção do serviço de Business
Object apropriado para tratar a requisição.

#3. A classe “PlcModeloLocator”, também análoga à "PlcFacadeLocator", implementa um “DP


Service Locator”, mantendo a classe localizada como resultado em cache, para chamadas
subseqüentes.

#4. O algoritmo de localização do melhor serviço, por si, é delegado para a classe
“PlcModeloIoCFactoryService”, que é extensível. Este algoritmo recebe uma classe de
Entidade e procura localizar uma classe de gerenciamento com base em convenção de
nomenclatura (Ex.: "FuncionarioManager" para entidade "FuncionarioEntity") ou com
base em anotações explicitas, na Entidade (Ex.:
@PlcIoC(nomeClasseBC=”com.empresa.rhtutorial.modelo.MeuServico”)). Se não
encontrar, reutiliza uma instância da classe padrão “PlcBaseBO”.

#5. A partir da segunda chamada, a referência que está em cache para a requisição é reutilizada.

#6. No caso específico da chamada da colaboração “plcTabular” através do serviço


“recuperaListaSimples”, uma referência da Interface de persistência é obtida diretamente,
iniciando pelo uso do método “getDAO(PlcBaseVO)”

#7. A classe “PlcPersistenciaLocator” executa algoritmo similar ao das classes anteriores para
Modelo e Facade, incluindo a delegação do algoritmo de IoC para a classe
"PlcPersistenciaIoCFactoryService", extensível.

#8. A obtenção de referência à implementação para a Interface de persistência “IPlcDAO” será


detalhada mais adiante.

#9. A referência de persistência é então obtida para uso direto do método de fachada
(recomendado somente para casos mais simples, como este).

- Anatomia do gerenciamento do objeto de contexto “PlcBaseContextVO”


Uma outra seqüência importante de se compreender, que se inicia na camada Controle e passa por um
tratamento especial na entrada dos métodos de fachada, é a seqüência de gerenciamento do objeto de
contexto “PlcBaseContextVO”, que segue o DP “J2EE Context Object”.
Neste padrão, informações de contexto da camada controle são encapsuladas em um objeto e enviadas
para a camada Modelo. O jCompany encapsula perfil do usuário corrente, “metadados” e outros estados
importantes neste mesmo objeto, de modo a manter a camada Modelo totalmente “Stateless” e,
portanto, mais escalável e fácil de se gerenciar.
Uma questão importante sobre objetos de contexto é que eles não devem ser passados como parâmetros
de métodos de serviço de negócio (subcamada de serviços), pois deste modo estariam presentes em
(quase) todos eles, “poluindo” os contratos. Uma exceção se faz necessária apenas nos contratos da
fachada porque, possivelmente, estes podem ser chamados de forma remota – o que elimina o uso
possível de outras técnicas (como pegar a referência de alguma área de escopo global da requisição).
Independente de como este objeto é mantido internamente, o jCompany o mantém acessível tanto na
camada de Controle quanto na de Modelo, para quaisquer classes da arquitetura (Action, Manager/BO,
DAO) via método dos ancestrais “getContext()”. Muito embora haja esta uniformidade, a técnica
empregada difere bastante:
Na camada Controle, este objeto é montado e mantido em escopo de requisição utilizando internamente
o objeto HttpServletRequest (“request.setAttribute()”).
Já no caso da camada Modelo, ele é recebido e armazenado em uma “Thread Local”, que é uma área
de caching global também disponível no escopo de uma requisição específica. Esta técnica é
necessária já que esta camada é Stateless na arquitetura, para manter-se mais escalável, não tendo
também acesso (e acoplamento, por conseqüência) a objetos da tecnologia de Servlet, como o
“HttpServletRequest”.
Veja no diagrama da Figura E16.30, a seqüência de gerenciamento completa, para este tipo de objeto.
Figura E16.30. Seqüência do gerenciamento do ciclo de vida de objetos de contexto.

#1. Como o “Context Object” é mais utilizado em manutenções, desta vez vamos analisar a
seqüência de transação do ponto de vista de um método de atualização como o “grava”.

#2. Métodos genéricos de controle chamam o utilitário “PlcContextMontaHelper”, para criar um


novo objeto do tipo “AppBaseContextVO”*, contendo informações de contexto, tais como o
login do usuário corrente e alguns metadados de relevância para a camada Modelo, tais como
“padrão utilizado”, informações de arquivo anexado, recuperações de “detalhe por demanda”,
“navegação entre combos” e outras.

Por default, somente informações que o jCompany necessita são montadas, mas novas
informações de contexto podem ser adicionadas via especializações. Importante: este objeto,
quando especializado, deve conter somente metadados e informações de contexto! Parâmetros
“do negócio” devem ser explicitamente enviados como tais, explícitos em novas cláusulas do
contrato de fachada (“IAppFacade” ou outro).

Após sua criação, que ocorre uma vez a cada requisição, o objeto de contexto é armazenado
com escopo de requisição (HttpServletRequest), evitando de ser passado também na
assinatura dos métodos de controle, para não “poluir” todas as assinaturas.

#3. Antes de enviar chamadas à fachada, o métodos de controle obtêm uma instância atual do
objeto de contexto através de “getContext”. Este método recupera do escopo de requisição o
objeto de contexto gerado.

#4. Nas chamadas de fachada, como reza o DP Context Object, este objeto é enviado
explicitamente (Lembre-se de que esta pode ser uma chamada remota). Além disso, como há
restrição ao uso da tecnologia de Servlet na camada de modelo, mesmo com as camadas
embaladas localmente (no mesmo WAR), não haveria como a camada Modelo obter este
objeto.

#5. O primeiro comando que todos os métodos de implementação de fachada realizam é um


“setContext”, que objetiva armazenar o objeto de contexto de uma forma acessível
globalmente, em nível desta requisição, a partir deste ponto - e, assim, evitar passá-lo como
parâmetro em todas as assinaturas de métodos de serviço!

*
Lembrando que aqui também atua um esquema de IoC. Ou seja, é possível declarar um outro descendente específico de
“PlcBaseContextVO”, para conter valores de “contexto” específicos do negócio, para sempre ser enviado para serviços da camada
Modelo.
#6. Este trabalho é então delegado para uma classe de gerenciamento de Context Objects
chamada “PlcContextManager”, que armazena o objeto em uma “Thread Local”*.

#7. A “Thread Local” funciona como área globalmente visível durante a seqüência de
processamento da camada modelo, no escopo da requisição, como desejamos. A classe
“PlcContextManager” encapsula uma declaração estática com esta “Thread”.

#8. Métodos da camada de serviço (ou do negócio) não mais necessitam enviar este objeto como
parâmetro, ficando com a assinatura mais sucinta e objetiva, definindo estritamente a sua
necessidade de negócio.

#9. Em classes descendentes de "PlcBaseVO", tipicamente sufixadas com “BO” ou “Managers”, o


acesso ao Context Object é feito com o método “getContext”, que está disponível no
ancestral, basicamente acessando o “PlcContextManager” para obter a instância corrente do
“AppBaseContextVO” (ou outro descendente específico registrado na camada controle).

Nesta camada, o objeto de contexto é usado principalmente para pegar informações de


metadados diversas, como indicadores para manipulação de arquivos anexados, modo de
exclusão (variantes por colaboração), dentre outros.

#10. Na camada de implementação da persistência, este objeto de contexto é utilizado


principalmente para pegar a “fábrica” definida para esta requisição e que deverá utilizada pela
persistência, o que é relevante apenas quando se trabalha com mais de um SGBD ou com
Bancos de Dados diferentes, dentro de um mesmo SGBD.

#11. Finalmente, quando se trabalha com Hibernate, seja diretamente, seja como uma
implementação JPA, o jCompany possui interceptadores (Hibernate Listeners) em eventos de
persistência que visam realizar otimizações (evitar queries desnecessárias em diversos
momentos) e também registrar usuário e data da última alteração, para auditoria “pauta
mínima”.

Nesta classe, o objeto de contexto é utilizado para se capturar o padrão corrente (para
otimizações), nomes de classes de Raiz/Mestre e Detalhe – além do perfil do usuário corrente.

- Anatomia de gerenciamento de transação


Como última, mas uma das mais importantes incumbências da subcamada de fachada, devemos analisar
a seqüência de “gerenciamento de transação de persistência”.
Como já citamos, o jCompany pode trabalhar na camada Modelo/Persistência, tanto com
tecnologia EJB3 quanto POJO. Pode-se inclusive comutar entre elas, através de poucas alterações nos
metadados e nenhuma alteração de programação! Isso, graças ao novo modelo do EJB3 e a um esforço
adicional por parte da Powerlogic. Com a arquitetura do jCompany nesta área, o maior trabalho para se
comutar entre estas tecnologias será apenas na parte de “embalagem e liberação” das aplicações, não na
parte funcional.
Neste livro, vamos analisar como ocorre o gerenciamento de transação em uma arquitetura POJO, que
funcionará de forma apropriada e escalável, somente com as seguintes limitações:
Como a transação com POJO é local via JDBC, ela tem que iniciar e finalizar em uma mesma
aplicação (ou seja, não é voltada para transações distribuídas, por exemplo, com gravações
dispersas por vários componentes remotos da rede).
É possível se utilizar inclusive vários bancos de dados, de vários SGBD-Rs, simultaneamente, mesmo
para gravações, mas não será possível realizar um “Two-Phase Commit” que garanta
integridade entre gravações simultâneas nestes bancos de dados heterogêneos.
Para as duas necessidades acima, existe o JTA (Java Transaction Architecture), que é a
implementação padrão Java EE para transações distribuídas - e a tecnologia internamente utilizada pelos
EJBs. Portanto, a existência de alguma das duas necessidades acima pode ser justificativa para o uso do
EJB3 em lugar do POJO.

*
Para compreender melhor o que são as Thread Locals e a técnica de algoritmo empregada nesta área, sugerimos a busca por este
termo em documentações da Sun e listas em geral. O algoritmo utilizado pelo jCompany é bastante comum sendo inclusive, o mesmo
utilizado internamente pela Hibernate, para manter referência às sessões de persistência.
Porém, um grande leque de requisitos não exigirá estas sofisticações, e nestes casos o uso do
JTA não trará vantagens consideráveis. Pelo contrário, irá gerar complexidade para uma taxa de
retorno próxima de zero!
Note que benefícios tais como “transação declarativa via anotações/AOP”, providos adicionalmente ao JTA
pela tecnologia EJB3, estão também disponíveis no jCompany com POJOs, bem como IoC e DI. Como
uma eventual evolução de POJO para EJB3 será possível, quando, e se, for necessária – o recomendável
para a ser a utilização da alternativa “mais simples que atenda aos requisitos em jogo”, em geral a
transação local via JDBC.
Vamos analisar os diagramas das Figura E16.31 e Figura E16.32, que explicam a arquitetura de
gerenciamento de transações locais declarativas via AOP, do jCompany.

Figura E16.31. Estrutura das classes envolvidas no AOP para fachadas, utilizando CGLib.

#1. O framework “CGlib” provê AOP (Aspect Oriented Programming), permitindo que instanciemos
classes descendentes (de quaisquer outras) que somente existem em tempo de execução,
conhecidas como “proxies”. O jCompany traz uma classe "PlcAopManager", na camada
“comuns”, que encapsula este processo de instanciação de proxies CGlib via a chamada:

PlcAopManager.createProxy(classe,aopBaseCallback);
onde
- classe: é a classe AppFacadeImpl (ou qualquer outra de fachada, em nosso caso)
- aopBaseCallback: É a classe que implementará métodos de interceptação dos métodos de
‘classe’.

#2. A classe “Proxy”, após ser criada em tempo de execução, funciona como um descendente e
tem sufixo padrão assumido dinamicamente pelo CGLib como “$$EnhancerByCGLib$$”.

A classe de interceptação registrada para “PlcFacadeImpl” é a


"PlcAopModeloCallbackService", POJO que fica alocado na camada Modelo e que herda de
um ancestral abstrato disponível na camada Comuns. Este ancestral é um “mini-framework
para AOP” com base no CGLib, que pode ser utilizado em arquitetura similar à utilizada no
jCompany, para novas utilizações AOP que o Desenvolvedor deseje implementar.

Basicamente, classes de interceptação podem codificar lógicas de programação “antes” e


“depois” da execução de quaisquer métodos interceptados pela classe original (O método e
seus argumentos são disponibilizados como parâmetro!) – ou mesmo reimplementá-los.

A classe de interceptação de fachadas, de nosso exemplo, implementa somente o


“interceptaApos”, onde fecha as transações, conforme anotações obtidas do método
interceptado.

#3. Os métodos “interceptaAntes” e “interceptaApos” são abstrações do jCompany. Segundo


o CGLib, o método chamado será o “intercept”, que no jCompany fica implementado no
ancestral comum. Este método cria um Template Methodo que chama, na ordem:

- O método abstrato “interceptaAntes”;


- O método originalmente interceptado, do ancestral do Proxy (“gravaObjeto”, no
exemplo);
- O método abstrato “interceptaApos”.
Com isso, o desenvolvedor pode simplesmente criar fachadas, bastando instanciá-las com o serviço
"PlcFacadeLocator". Este serviço cuidará de, neste caso, devolver um “Proxy” CGLib com a arquitetura
acima, pronto para receber anotações de transação, a saber:
“@PlcTransacaoGravacao”: Encerra com um “commit” (default);
“@PlcTransacaoLeitura”: Encerra a transação com um “rollback”;
“@PlcTransacaoNaoAplica”: Não trata transações por anotação (deve então ser
programada, se necessária).
Além disso, qualquer disparo de exceção na camada Modelo implicará em “rollback” de
transações, independente da anotação. Vejamos, na Figura E16.32, a seqüência de gerenciamento
de transações completa:

Figura E16.32. Seqüência do gerenciamento de transações via AOP para POJOs.

#1. Ao capturar uma interface de fachada, em tempo de execução, vimos que a implementação
retornada é instanciada via CGLib, sendo na verdade um “Proxy” (descendente dinâmico) da
classe “conhecida” pelo desenvolvedor.

#2. A classe de “Proxy” tem nome igual ao da classe base, sufixada com “$$EnhancedCGlib$$”.
A qualquer tentativa de executar métodos de fachada, em “AppFacadeImpl”, ela irá capturar
a tentativa e passar para a classe de interceptação, “PlcAopModeloCallbackService”.

#3. A classe de interceptação (na verdade, como vimos, seu ancestral), chama o método
“interceptaAntes”, mas não há implementação corrente do jCompany neste ponto.

#4. Em seguida, ela chama o método original, acionando diretamente o “ancestral” do “Proxy”, via
comando: “retValFromSuper = proxy.invokeSuper(obj, args);”.

#5. A seqüência então toma seu rumo original, com chamadas possíveis à camada Modelo e
Persistência.

#6. À primeira tentativa de se pegar uma sessão de persistência, seja via Hibernate (Session) ou
JPA (EntityManager), uma nova transação será iniciada, com o SGBD (BEGIN TRANSACTION).

#7. Repare que, se o desenvolvedor programa em pontos de extensão “[metodo]Antes” dos


Template Methods da camada Modelo, que ocorrem antes da operação genérica do jCompany,
eles estarão “fora de transação”, oferecendo pouca sobrecarga. Somente após o primeiro
“getSession()” ou “getEntityManager” é que a transação se iniciará, utilizando
configurações de isolamento e outras definidas no driver JDBC e/ou pool de conexões do
Application Server.

#8. O comando JPA difere ligeiramente do comando Hibernate, para abertura de transação, mas o
jCompany os torna transparentes do ponto de vista do desenvolvedor.
#9. Após a execução do método interceptado, o interceptador chama o método “interceptaApos”.
Este sim, é encarregado de realizar o fechamento das transações, em conformidade com as
anotações e o transcorrer da requisição sem exceções, conforme já foi explicado.

#10. Note que, quando programa em pontos de extensão “[metodo]Apos” dos Template Methods da
camada Modelo, o desenvolvedor está codificando “dentro da transação”, significando que
qualquer objeto que venha a ser persistido manualmente, neste ponto, será gravado
na mesma “Unidade Lógica de Transação – ULT” da agregação principal gravada,
genericamente.

Para encerrar a transação efetivamente, o interceptador naturalmente delega para a


implementação de DAO corrente. Para isso, obtém uma referência à interface de DAO. A
implementação de DAO deve, por sua vez, implementar o “commit” ou “rollback” na forma
exigida pelo mecanismo de persistência. As implementações do jCompany o fazem em
conformidade com o padrão Hibernate ou JPA.

- Pool de Conexões e Sessão de Persistência.


Além da transação em si, o jCompany realiza um trabalho de gerenciamento da sessão de
persistência e da manipulação do “pool de conexões”*. E isso independe de se estar utilizando
POJO ou EJB3. As únicas implementações que ficam inativas no jCompany, quando trabalhando em um
ambiente gerenciado por um conteiner EJB são a gerência de transações em si e a Injeção de
Dependência.
Para se alterar o mecanismo de “gerência de transação” e de “Inversão de Controle” do jCompany para
um conteiner EJB3, basta que se declare no arquivo de metadados em nível da aplicação
“com.powerlogic.jcompany.config.app”:
// Para gerenciamento de transação feito pelo Container (default é false)
@PlcConfigComportamento(containerGerenciaTransacao=true)
// Para mecanismos de IoC e DI
@PlcConfigModeloTecnologia ( tecnologia=
PlcConfigModeloTecnologia.Tecnologia.EJB3)
// Complemento para ambos os casos
@PlcConfigEjbFacadeRef(nomePrefixoJNDIApp="ejb", nomeFacadeApp=
"AppFacadeImpl")
Independente de ser o jCompany ou um container EJB3 a gerenciar transações, o importante é que
estas sejam delineadas de forma declarativa, e não programadas. Salvo em raras exceções,
codificar “commits”, “rollbacks” e outros controles críticos abre um flanco para problemas típicos, de
difícil antecipação e graves conseqüências em produção:
Transação: Problemas de transações mal elaboradas (Ex.: um “commit” para gravar Nota Fiscal e Itens
e outro “commit” para atualizar o saldo do estoque) são difíceis de se pegar em tempo de teste,
inclusive por áreas de Controle de Qualidade, quando existem. Frequentemente, estes problemas se
manifestam apenas em produção, na forma de inconsistências diversas (saldos que não “batem”,
etc.).
Pool de Conexões: O mesmo ocorre quando um código da aplicação pega uma conexão de um “pool de
conexões” e não a devolve apropriadamente, em situações eventuais. Outro caso de erro difícil de
capturar, mesmo em tempo de testes. Em produção, ele se manifesta com aplicações que se tornam
mais lentas com o tempo, terminando por “congelar” e exigir reinícios do Application Server (para
reconstrução do pool).
Sessão de Persistência: A gerência mal elaborada da sessão de persistência pode, também, produzir
problemas sérios de performance e escalabilidade, na forma de “leaks de memória” (perda de área
útil de memória ao longo do tempo, devido a algum “lixo” deixado indevidamente).
Por todos estes motivos, o jCompany assume a responsabilidade por gerenciar estes recursos em nível
da arquitetura, mitigando riscos para o caso das transações OLTP (On-Line Trasaction Process). Ainda

*
Envolve a captura de uma conexão JDBC de um conjunto (pool) mantido pelo App Server para uso pela implementação de
persistência e sua devida liberação, após o uso, de forma transparente para o Desenvolvedor.
assim, permite intervenção e gerenciamento manuais assistidos (semi-automatizados), tipicamente para
atendimento a transações BATCH, que exigem gerenciamento diferenciado*.

- Especialização de contrato de fachada existente.


Quando um novo evento de camada visão se torna necessário (um novo botão, por exemplo), é provável
que um novo método de fachada tenha que ser construído. Neste caso, deve-se tomar a seguinte decisão
arquitetural:
Se desejarmos que este serviço seja visível somente para a aplicação corrente, podemos mantê-lo no
mesmo contrato “IAppFacade”, disponibilizado pelo jCompany em cada aplicação†. Os trechos de Código
E16.19 e Código E16.20 exemplificam esta opção.

...
public interface IAppFacade extends IPlcFacade {

public Integer calculaTotalFuncionarioPorSexo(String sexo) throws PlcException;


}
...
Código E16.19. “Aditivo contratual” à Interface de fachada existente, em escopo da aplicação.

...
public class AppFacadeImpl extends PlcFacadeImpl implements IAppFacade {

@PlcTransacaoLeitura
public Integer calculaTotalCandidatosPorSexo(String sexo) throws PlcException {

FuncionarioManager funcionarioManager = (FuncionarioManager)


getBO(FuncionarioManager.class);
return (Integer) funcionarioManager.verificaTotal(sexo);
}
...
Código E16.20. Implementação específica da nova cláusula, com transação anotada para “rollback”.

Se desejarmos que este serviço seja visível para reúso em outras aplicações, devemos criar um novo
contrato, digamos “IFuncionarioService” (leia-se: serviços associados a funcionários – explicitando a
intenção de reúso corporativo), e disponibilizá-lo em um “módulo”, que no jCompany segue padrões
bem definidos: projeto Eclipse distinto, empacotado em JAR separado, etc.. Os trechos de Código E16.21
e Código E16.22 exemplificam esta opção.

...
public interface IFuncionarioService {

public Integer calculaTotalFuncionarioPorSexo(String sexo) throws PlcException;


}
...
Código E16.21. Novo contrato, para reúso corporativo (como estratégias SOA, por exemplo).

...
public class FuncionarioServiceImpl {

@PlcTransacaoLeitura
public Integer calculaTotalFuncionariosPorSexo(Sexo sexo) throws PlcException {

FuncionarioManager funcionarioManager = (FuncionarioManager)


getBO(FuncionarioManager.class);
return (Integer) funcionarioManager.verificaTotal(sexo);
}
...
Código E16.22. Implementação específica da nova cláusula.

Neste segundo caso, para instanciação simplificada, é recomendável que se crie a Interface e a Classe de
implementação com padrões de nomenclatura: “I[Nome]” e “[Nome]Impl”, respectivamente. Se

*
O gerenciamento de transações “semi-automatizado”, para casos de programação BATCH será exemplificado em tutorial nos
próximos capítulos.

Este contrato de fachada deve ser entendido como um “contrato de fachada para a aplicação corrente”, para operações que não
sejam projetadas para reúso corporativo.
ambas estiverem no mesmo pacote* e seguindo o padrão de nomenclatura acima, podem-se obter
referências corretamente instanciadas (ou seja, como Proxies com transação gerenciada) a partir das
classes de Action, conforme o trecho de Código E16.23.

...
public class MeuAction {

public String calculaTotalFuncionariosPorSexo() throws PlcException {

IFuncionarioService funcionarioService = (IFuncionarioService)


PlcControleLocator.getInstance().getFacadeNegocio(IFuncionarioService.class);
...
}
...
Código E16.23. Obtenção de referência à implementação de um contrato específico de fachada, em classes de
Action.

*
Note que, por “mesmo pacote”, não queremos dizer que estarão no “mesmo projeto” ou nem na “mesma camada MVC”. Ex.: A
Interface “IPlcFacade” do jCompany, está no pacote “com.powerlogic.jcompany.facade”, assim como a implementação “PlcFacadeImpl”.
Mas a Interface fica no projeto Eclipse “comuns” (camada ortogonal, visível por todas as demais do MVC2-P), enquando a Classe fica no
projeto Eclipse “modelo” (em escopo de camada Modelo).
Programações da Camada Modelo – Serviços de Negócio

- Programações da Subcamada de Serviços


Como vimos, deixamos por conta das camadas de Visão, Controle e da subcamada de Fachada, as lógicas
de programação relacionadas a Interfaces com o Usuário, navegação, validações de entrada (restrições
variáveis), manipulações de contextos, metadados e outras do gênero.
Além disso, já antecipamos que a camada de Persistência ficará encarrega de todos os serviços que
recuperam ou armazenam dados em dispositivos tais como SGBD-R ou outros, utilizando DP DAO.
Resta à camada Modelo, portanto, implementar lógicas de programação que reflitam os serviços
principais do negócio, propriamente ditos, tais como são comumente referenciados por Casos de Uso, por
exemplo. É na camada de serviço, através de classes sufixadas como “BO/Manager” ou AS”, onde se
inicia a “orquestração” central destes algoritmos “de negócio”, mesmo que muitos de seus trechos sejam
delegados para Entidades de Domínio.
Portanto, existem duas categorias de classes centrais nesta camada que deveremos conhecer: Business
Object e Application Servers.

- Programações em Business Objects (BO ou Manager)


Classes de Business Objects podem ser sufixadas com “BO”, “Service” ou, preferencialmente, com
“Manager”, e são destinadas a orquestrar serviços de escopo restrito a uma Agregação de Entidades de
Domínio. Assim, serviços de manutenção do ciclo de vida para “FuncionarioEntity”, por exemplo, devem
ser implementados pela classe “FuncionarioManager” (ou “FuncionarioBO”).
Obviamente, como nós já vimos, estas classes não precisam nem existir, se tudo o que precisarem
realizar neste sentido estiver generalizado pelo seu ancestral em nível da arquitetura, na classe
“PlcBaseBO”. Deste modo, deve-se criar este tipo de classe “por demanda”, na medida em que se faça
necessário especializar algum Template Method ou criar um novo serviço qualquer, dentro do escopo da
mesma agregação.

Ainda com relação à nomenclatura, é recomendável que se utilizem convenções de sufixo diferentes, para
ênfases arquiteturais diferentes:
BO + VO: O uso de BO como sufixo para classes de serviço da camada Modelo remete aos padrões de
nomenclatura clássicos do J2EE, normalmente utilizados em conjunto com o sufixo VO (Value
Object) para o que seriam nossas Entidades (para as quais temos utilizado Entity). Neste contexto
“J2EE Clássico”, os BOs absorvem todo e qualquer processamento, deixando para as “Entidades do
tipo VO” somente a responsabilidade de transportar dados (similar aos DTOs).

Apesar de ainda ser possível se trabalhar deste modo no jCompany*, recomendamos a abordagem
Domain-Driven Design (DDD), mais interessante e Orientada a Objeto.
Manager + Entity: Para uma ênfase maior em OO via práticas de Domain-Driven Design (DDD), nossas
próprias Entidades encapsularão métodos que representam regras de negócio de sua alçada. Os
antigos BOs, agora sufixados como “Managers”, irão apenas recepcionar eventos e, eventualmente,
tratar pré-condições e acionar serviços de dados. Em se havendo regras de Domínio, estas serão
delegadas para as Entidades responsáveis.
Importante: Feita a recomendação, é importante frisar que o jCompany não impedirá que se trabalhe
com este ou aquele sufixo. Qualquer outro poderá ser definido em metadados, no escopo de aplicação -
recomenda-se apenas que seja usado um mesmo padrão, para uma mesma organização.

Um exemplo de implementação deste tipo de classe pode ser visto no trecho de Código E16.24.

...
public class FuncionarioManager extends PlcBaseBO {

// 1
FuncionarioDAO funcDAO;
public FuncionarioManager(FuncionarioDAO funcDAO) {
this.funcDAO = funcDAO;

*
Inclusive, em seus ancestrais, o jCompany FS Framework ainda usa estes sufixos, em “PlcBaseVO” e “PlcBaseBO” para Entities e
Managers, respectivamente, por questão de compatibilidade.
}

// 2
protected void incluiAntes (PlcBaseVO entidade) throws PlcException {

// 3
Funcionario funcionario = (Funcionario) entidade;

// 4
FichaFuncional ff = funcDAO.recuperaFicha(funcionario.getCpf());

// 5
funcionario.validaMaximoSalario(ff);
}

}
Código E16.24. Classe Manager acessando serviço de dados em DAO e delegando regras para Entidades de
Domínio.

#1. Injeção de Dependência (DI) gerenciada pelo jCompany (Constructor Based


Dependency Injection). Neste caso, basta declarar objetos como variáveis de instância e
recebê-los em um construtor, para que o jCompany “injete” uma instância para uso,
garantindo otimização e legibilidade.

#2. O “incluiAntes” é um exemplo de método padrão para extensão (Method Based


Dependency Injection). Estes métodos terminam com “Antes”, “Apos" e “Api” e são
participantes de um DP Template Method para a operação de inclusão (método “inclui” do
ancestral). O parâmetro “entidade”, recebido, é outro exemplo de DI.

#3. A primeira providência ao especializar Template Methods, é fazer ajuste de tipo (casting) das
Entidades recebidas – se possível, tentando trabalhar com o ancestral abstrato, que encapsula
as informações de negócio (“Funcionario”, e não “FuncionarioEntity”).

#4. Acesso ao serviço de dados. Somente classes de Facade, AS ou BO/Managers podem acessar
DAOs.

#5. Delegação para que a Entidade Funcionário implemente a regra de negócio em si. Ela não foi
representada, por não ser relevante, mas perceba que é de responsabilidade da camada de
Domínio. Os métodos de serviços do tipo “Manager” irão realizar interceptação de eventos,
acionamento de serviços de dados, tratamentos eventuais de pré-condições e outras atividades
de “burocráticas” do serviço, mas delegarão para Entidades de Domínio regras de sua alçada.

- Anatomia de seqüência típica de processamento de classes Manager


A arquitetura típica de dependências de uma classe Manager é ilustrada na Figura E16.33.

Figura E16.33. Arquitetura de dependências típica para classes Manager.


#1. O ancestral “PlcBaseBO” encapsula serviços de manutenção de ciclo de vida de agregações e
suas variações padrões, expondo diversos Template Methods com métodos projetados para
extensão, encerrados com “Antes”, “Apos" ou “Api”.

#2. Um ancestral "AppManager" é gerado via template INI por default, como sugestão para
conter extensões para toda a aplicação (e, neste caso, já faz uma “adaptação de nome” para o
sufixo “Manager”). No exemplo, um código foi incluído para executar após a inclusão de
qualquer agregação, mantida dentro desta aplicação.

#3. As classes específicas de Manager, associadas a Entidades, devem preferencialmente seguir o


padrão “[NomeEntidadeAbstrata]Manager”. Deste modo, não é preciso configurar nenhum
metadados de IoC, para que o jCompany localize um serviço para gerenciar a manutenção do
ciclo de vida de Funcionários, na camada Modelo.

Note o grande número de dependências desta classe. Ela irá depender de classe de DAO para
serviços de persistência e do modelo de Domínio, para regras de negócio, no mínimo.

#4. Para enfatizar o desacoplamento com a camada DAO, o recomendado é utilizá-la via Interfaces,
mantendo uma fachada (DP Façade) também entre a camada Modelo e a de Persistência.
Deste modo, facilitam-se futuras portabilidades.

#5. Mas é possível utilizar a implementação de DAO diretamente, sem grandes prejuízos na maioria
dos casos. Neste caso, mantém-se o isolamento entre as camadas Modelo e Persistência, mas
sem o rigor de outra “fachada”. Muito embora o jCompany utilize Interfaces, a extensão de
seu uso pelo desenvolvedor é opcional, em função das perspectivas do cliente de manutenções
nesta área. Em ambos os casos, será possível a utilização de DI nas classes Manager.

Importante: Ao escolher uma das duas abordagens, deve-se manter fiel a ela,
preferencialmente em nível da empresa.

A anatomia da seqüência de uma execução típica da subcamada de serviços é analisada na Figura


E16.34.

Figura E16.34. Seqüência típica de processamento de classe Manager.

#1. A maior parte das implementações de classes Manager serão interceptações de Template
Methods, que mantém o ciclo de vida de agregações, na camada Modelo.
#2. As implementações principais dos métodos chamam métodos vazios para especialização,
injetando uma instância da agregação a ser mantida, como parâmetro*.

#3. Métodos de extensão serão possivelmente especializados para executar acessos a dados e
tratar pré-condições.

#4. Após recuperar os dados necessários, de forma a prover valores para as “variáveis” a serem
utilizadas em regras de negócio, a classe Manager delega esta incumbência para Entidades de
Domínio. Regras que não sejam claramente encasuláveis, podem ser agrupadas em classes
próprias, transientes, também na camada de Domínio.

#5. A classe de Manager somente aciona regras a partir da classe Raiz da Agregação. Esta, por sua
vez, pode trocar mensagens dentro de seu grafo de alcance, de modo a complementar as
informações necessárias para o resultado esperado.

- Programações em Application Services (AS)


Classes de Application Services devem ser utilizadas como “orquestradoras” de lógicas de
programação que não possam ser facilmente encapsuladas em nenhuma agregação específica, ou que
acessem informações de várias agregações de Entidades diferentes. Alguns exemplos são rotinas tais
como “Cálculo da Folha de Pagamento”, e processamentos Batch complexos, dentre outras.

Existem três regras práticas que devem orientar um bom projeto de classe de AS:
A classe de Application Service, em si, não deve implementar cálculos do negócio, mas
somente fluxos de delegações, incluindo condições e laços. É o conceito de orquestração,
propriamente dito, em nível do Caso de Uso†.
Na dúvida sobre implementar em Fachada ou em AS, prefira AS. Haverá uma natural tentação de
ser fazer, na própria implementação de fachada, toda a orquestração de chamadas necessária, mas
haverá algumas desvantagens: para casos complexos, isso impede o reúso de blocos de
processamento de AS, já que estes ficam acoplados a uma transação; não é possível usar
“Constructor Based Dependency Injection” no Façade; algumas tarefas de adaptação da fachada
podem “poluir” as orquestrações de negócio.
Na dúvida sobre implementar em Manager ou AS, pense nos “imports”: Por ser uma
orquestradora, a classe de AS tenderá, naturalmente, a possuir dependências com um grande
número de classes (em conformidade com o tamanho e extensão de seu algoritmo). Pense: Se estas
importações fossem realizadas no Manager, elas trariam acoplamento com classes que não têm
relação com a agregação gerenciada por esta última classe? Por exemplo, mover importações de
“TabelaIR” para “FuncionarioManager”, sendo a primeira uma classe que não pertence ao grafo de
“Funcionario”, é um sintoma de que métodos apropriados para AS podem estar sendo movidos para
Managers, indevidamente.
Implementações de AS devem herdar de “PlcBaseAS” para obterem recursos de caching, IoC e DI. Um
exemplo de implementação pode ser visto no trecho de Código E16.25.

...
public class CalculoFolhaAS extends PlcBaseAS {
...
// Injeção de Dependência no construtor
....
public Integer calculaFolha(Periodo periodo) throws PlcException {

// Loop por funcionarios


(...)
FichaFuncional ff = funcDAO.recuperaFicha(matricula);

BigDecimal adicDep = depBO.calculaAdicional(ff.getDependentes());

(...)

*
O método de alteração traz ainda a imagem anterior da agregação também (antes de sofrer modificações), porém somente com a
imagem anterior do seu objeto “raiz” (ex.: Funcionario). Para que “agregados” anteriores sejam também “lembrados”, deve-se
informar o metadado “detalheLembra=true”.

Em uma analogia com ferramentas de workflow ou ferramentas de BPM/SOA, esta classe representa de forma programada, o “fluxo
de trabalho” propriamente dito, mas não necessariamente as regras disparadas durante o fluxo.
}

}

Código E16.25. Classe de Application Service. Nada de regras de negócio – somente chamadas, laços e
condicionais.

- Anatomia de seqüência típica de processamento de classes AS

Figura E16.35. Seqüência típica de processamento de classe de Application Service.

#1. Application Services são provavelmente acionados por novos eventos, e não a partir dos
eventos padrões do jCompany.

#2. A implementação de fachada não orquestra a execução. Ela apenas realiza ajustes em
argumentos e delineia a transação*.

#3. O Application Server executa uma varredura por todos os funcionários para os quais deverá ser
executado o cálculo, para o período passado por parâmetro.

#4. Operações de ciclo de vida são utilizadas via “FuncionarioManager”, tais como a recuperação de
um funcionário. Os métodos genéricos são utilizados, desde que complementações ao ciclo de
vida sejam relevantes. Pode-se também utilizar o "FuncionarioDAO" diretamente, exceto se a
empresa quiser estabelecer o rigor de sempre haver “Managers” intermediando (como uma
camada, entre os “Application Servers” e os “Data Access Objects”).

#5. Rotinas de orquestração podem ficam extensas. Deve-se buscar uma segmentação que facilite
a compreensão, preservando a simplicidade do fluxo de execução tanto quanto possível, em
cada método do AS.

#6. Chamada direta de classe DAO, para requerimentos “centrados em dados”, basicamente.

#7. Chamada direta a Entidade. A camada de Domínio é ortogonal, e visível por todas as demais.

*
Neste exemplo, pouco provável no mundo real, estaríamos encerrando um cálculo de folha com apenas um “commit()” ao final! O
mais provável seria termos de gerenciar transações manualmente, chamando os métodos “commit” ou “rollback” da interface DAO,
para gravar ULT menores, em blocos de 100 em 100 funcionários, por exemplo. Faremos um exemplo deste gerenciamento nos
próximos capítulos.
Importante: Classes de AS podem acionar quaisquer das classes de Entidade, Manager ou
DAO. Deste modo, elas ficam altamente dependentes de um grande número de classes, mas
têm esta complexidade balanceada com a simplicidade de não processarem regras de negócio,
internamente.

#8. Para a atualização, o acesso também é feito via Manager, caso os métodos de especialização ao
ciclo de vida sejam relevantes.
Programações da Camada Persistência

- Estrutura de classes de configuração – Hibernate.


Antes de analisarmos a implementação das classes de DAO em si, é bom compreendermos a arquitetura
de configuração do mecanismo de persistência em si, representado na Figura E16.36.

Figura E16.36. Esquema de configuração utilizado para uso do Hibernate.

#1. A primeira classe a ser acionada, para devolver uma sessão de persistência, será a
"PlcHibernateManagerLocator", que é um singleton que armazena em caching as
referências aos objetos gerenciadores de sessões de persistência.

Cada objeto gerenciador, descendente de "PlcBaseHibernateManager", é armazenado em


um Map, cuja chave é um String e o valor é a referência ao objeto.

#2. O ancestral para objetos de gerenciamento de sessões de persistência


"PlcBaseHibernateManager" traz métodos comuns para criação da fábrica de sessões de
persistência e também para mantê-la em caching. Algumas facilidades específicas do
jCompany como o “autoDetectDialect” são também genericamente implementadas aqui,
independente do número de gerenciadores utilizados.

#3. A classe "PlcBaseHibernateManager" é abstrata, mas o jCompany já disponibiliza um


descendente concreto que é utilizado por default, quando somente se possui acesso a um único
SGBD-R/Banco de Dados, na aplicação. Esta classe é chamada "PlcHibernateManager" e,
basicamente, herda todo seu comportamento do ancestral, incluindo apenas uma anotação
nomeando a fábrica como “default” e indicando para utilização do “autoDetectDialect”:
@PlcFabrica(nome="default",autoDetectDialect=true).

#4. Cada classe descendente de "PlcBaseHibernateManager", ao definir o nome da fábrica,


define também o nome do arquivo de configuração associado, que será lido para coleta de
configurações a serem utilizadas na criação da fábrica de sessões de persistência. O nome do
arquivo deve seguir a convenção “[nome da fábrica].cfg.xml”. A única exceção se faz com o
nome “default”, reservado, que espera um arquivo com nome “hibernate.cfg.xml”.

O arquivo de configuração define parâmetros globais para uma fábrica, tais como endereço
JNDI para pool de conexões e muitos outros, sendo alguns de maior relevância específica para
o jCompany, discutidos nos itens 5 e 6.

#5. O parâmetro “connection.provider_class” do “hibernate.cfg.xml” define a classe


"PlcConnectionProvider", do jCompany, como responsável por pegar e devolver conexões
JDBC. O jCompany irá utilizar um pool de conexões definido no Application Server, pegando-o
conexões via JNDI e mantendo sua referência em caching. A classe "PlcConnectionProvider"
ainda implementa uma distinção importante para o WebSphere, nesta área.

<property name="connection.provider_class">
com.powerlogic.jcompany.persistencia.hibernate.PlcConnectionProvider
</property>

Código E16.26. Classe provedora de conexões JDBC do jCompany, configurada no Hibernate.

#6. Os parâmetros de otimização indicam para que a classe “PlcBaseHibernateListener” do


jCompany utilize técnicas de otimização interferindo na geração de SQLs, evitando alguns
problemas conhecidos nesta área. Além disso, esta classe de Listener é a responsável pelo
algoritmo de Auditoria Rígida, que grava imagens de alteração em objetos.


<property name="plc.manyToOneLazyOtimiza">S</property>
<property name="plc.updateOtimiza">S</property>
<property name="plc.autoDetectDialect">S</property>
<property name="plc.auditoriaRigida">S</property>

Código E16.27. Parâmetros de configuração especiais do jCompany no “hibernate.cfg.xml”.

É interessante notar que a classe “PlcBaseHibernateListener” não está configurada no


arquivo “hibernate.cfg.xml”, como seria possível. Ela é, alternativamente, registrada via
programação no "PlcBaseHibernateManager" porque implementa vários eventos ao mesmo
tempo (Ex.: “PreLoadEventListener”, “PreInsertEventListener”, etc.).
#7. Para acesso a dois ou mais SGBD-R/Bancos de Dados simultaneamente, portanto, é preciso
apenas definir uma nova classe descendente de “PlcBaseHibernateManager”, por exemplo,
“AppPedidoManager” ou “AppCorporativoManager”, e incluir as anotações, respectivamente:
@PlcFabrica(nome="pedido",autoDetectDialect=true) ou
@PlcFabrica(nome="corporativo",autoDetectDialect=false), para cada classe.

Não é necessário nenhuma código Java específico nestas classes, a menos que se queira
modificar alguma programação genérica do jCompany, presente em
“PlcBaseHibernateManager”.

#8. Para cada caso exemplificado acima, deve-se definir um arquivo de configurações a exemplo do
“hibernate.cfg.xml”, com nomes respectivos “pedido.cfg.xml” e “corporativo.cfg.xml”. É
dentro destes que se pode modificar informações específicas, tais como dialeto (SGBD-R),
endereço JNDI do pool de conexões (que o jCompany irá utilizar), etc..

- Auto-Detect Dialect.
O jCompany possui a facilidade de detectar automaticamente o dialeto ideal para o SGBD-R corrente,
sem que o Desenvolvedor precise se preocupar em informá-lo nos arquivos de configuração. Este recurso
é útil para quem deseja fazer produtos portáveis para vários SGBDs e que, desta forma, não
precisam modificar em nada os arquivo WAR ou EAR finais!

A detecção automática investiga e decide qual dialeto utilizar, se baseando na URL declarada para a
conexão pelo driver JDBC, capturada via pool de conexões. Este processamento é delegado da
classe “PlcBaseHibernateManager” para a classe “PlcHibernateHelper”, que executa um código
similar ao Código E16.28.


if (url != null && url.toLowerCase().indexOf("derby")>-1) { // CloudScape/Derby
p.put("dialect", DerbyDialect.class.getName());
p.put("hibernate.dialect", DerbyDialect.class.getName());
} else if (driver.toLowerCase().trim().indexOf("ibm db2") > -1) { // DB2
p.put("dialect", DB2Dialect.class.getName());
p.put("hibernate.dialect", DB2Dialect.class.getName());
} else if (driver.toLowerCase().trim().indexOf("oracle") > -1) { // Oracle
p.put("dialect", Oracle9Dialect.class.getName());
p.put("hibernate.dialect", Oracle9Dialect.class.getName());
} else if (driver.toLowerCase().trim().indexOf("sqlserver") > -1){ //SqlServer
p.put("dialect", SQLServerDialect.class.getName());
p.put("hibernate.dialect", SQLServerDialect.class.getName());
} else if (driver.toLowerCase().trim().indexOf("mysql") > -1) { // Mysql
p.put("dialect", MySQLDialect.class.getName());
p.put("hibernate.dialect", MySQLDialect.class.getName());
} else if (driver.toLowerCase().trim().indexOf("postgresql") > -1) { // PostgreSql
p.put("dialect", PostgreSQLDialect.class.getName());
p.put("hibernate.dialect", org.hibernate.dialect.PostgreSQLDialect.class.getName());
} else if (driver.toLowerCase().trim().indexOf("sybase") > -1){ //Sybase
p.put("dialect", SybaseDialect.class.getName());
p.put("hibernate.dialect", SybaseDialect.class.getName());
}
Código E16.28. Algoritmo de definição de dialeto dinamicamente com base na URL do driver JDBC.
Note que, muito embora interessante, este recurso tem margem de erro e alcance limitado aos SGBDs
acima contemplados. Para situações de exceção, deve-se informar “false” na detecção automática (na
anotação ou no arquivo de configuração), informando-se o dialeto diretamente no arquivo
“hibernate.cfg.xml”.

- Estrutura de classes de configuração – JPA.


As classes de configuração do JPA são distintas, mas análogas. Esta configuração somente será analisada
em detalhes no livro “Volume II – Tópicos Avançados” desta série, nos tutoriais de EJB3 com JPA e JTA.

- Estrutura de classes de persistência – DP DAO


A organização das classes de persistência, que provêem as implementações de serviços de dados em si,
pode ser analisada pelo diagrama da Figura E16.37.

Figura E16.37. Seqüência típica de processamento de classes de DAO.

#1. Contrato principal com a camada de persistência. Uma Interface é exigida por muitas
implementações de JPA, que não aceitam o uso de uma classe abstrata como “PlcBaseDAO”
diretamente. Portanto, a Interface “IPlcDAO” foi introduzida ao DP Abstract Factory
implementado por “PlcBaseDAO”.

#2. A classe “PlcBaseDAO” é abstrata e implementa a Interface “IPlcDAO”. Esta classe


também passou a receber implementações concretas comuns, fatoradas das duas
descendentes, para serviços de implementação idêntica, em ambas.

#3. O descendente "PlcBaseJpaDAO" traz implementações de persistência JPA que


diferem do Hibernate. Mantém ainda o EntityManager em uma ThreadLocal acessível via
“getEntityManager”, para homogeneizar o acesso com a alternativa Hibernate.

#4. O descendente "PlcBaseHibernateDAO" traz implementações Hibernate que diferem


do JPA.

#5. Classes DAO específicas podem herdar de alguma das implementações concretas de Hibernate
ou JPA, mas não obrigatoriamente. A herança facilita o acesso a sessões de persistência via
“getSession(“minhaFabrica”)” ou “getEntityManager(“minhaUnidadePersistencia”)”,
mas elas podem ser pegas alternativamente via classes de utilitários.

Em Hibernate, por exemplo, pode-se pegar a sessão corrente, de qualquer POJO, via:

Session sess = PlcHibernateManagerLocator.getInstance().


getHibernateManagerClasse(“[nomeFabrica]”).getSession();

Em JPA, pode-se pegar o EntityManager via:


EntityManager em = PlcJpaManagerLocator.getInstance().
getJpaManagerClasse(“[nomeUnidadePersistencia]”).
getEntityManager();

#6. O contrato entre a camada de negócio e os serviços de persistência pode ser definido de forma
trivial, através de uma Interface.

#7. Para capturar uma implementação de persistência via Interfaces e DI, deve-se declarar a
Interface na classe Manager de alguma das formas abaixo:

// Classe de Manager, com Injeção de Interface via Factory


public class CandidatoManager extends AppManager {
// 1
IQuestionario questionario;
// 2
public CandidatoBO(@PlcImplementacao(fabricaClasse=com.empresa.que.modelo.QueFactory.class) IQuestionario
questionario)
{
this.questionario = questionario;
}
(…)
}

// 3
public class QueFactory extends QueAbstractFactory {

private static QueFactory INSTANCE = new QueFactory();

private QueFactory() { }
public static QueFactory getInstance(){
return INSTANCE;
}
@Override
public IQuestionario createQuestionario() throws PlcException {
return (IQuestionario) PlcModeloLocator.getInstance().get(QuestionarioMestreManager.class);
}
}
Código E16.29. Injeção de Dependência com uso de Interfaces - estratégia de Factory.

1. Interface declarada, como variável de instância em BO/Manager, AS ou DAO.


2. Classe de fábrica declarada via anotação no parâmetro recebido no construtor, em
“@PlcImplementacao”
3. Implementação da fábrica, com o método padrão “create[Nome]”.

// Classe de Manager, com Injeçao de Interface via Factory


public class CandidatoManager extends AppManager {
IQuestionario questionario;
public CandidatoBO(@PlcImplementacao(classe=”com.empresa.que.modelo.QuestionarioMestreManager”)
IQuestionario questionario)
{
this.questionario = questionario;
}
...
}
Código E16.30. Injeção de Dependência com uso de Interfaces - implementação anotada diretamente.

Note que na segunda variação, a classe de implementação é anotada diretamente. Ela dificulta a
modificação de implementações externamente, mas preserva o baixo acoplamento (já que a
anotação é apenas metadado).

- Exemplo de código de Data Access Object (DAO).


Um exemplo de implementação de um serviço de dados que utiliza Hibernate pode ser visto no Código
E16.31.

...
public class FuncionarioDAO extends PlcBaseHibernateDAO {

public Integer recuperaTotalPorSexo(Sexo sexo) throws PlcException {

try {
// 1
Session sess = getSession();
// 2
return (Integer) sess.createQuery("select count(*) from FuncionarioEntity f " +
"where f.sexo=:sexo”).setParameter(“sexo”,sexo).uniqueResult();

} catch (Exception e) {
// 3
throw new PlcException("jcompany.erro.generico", new Object[] {
"recuperaTotalPorSexo", e }, e,log);
}
}

Código E16.31. Exemplo de implementação de método de DAO com Hibernate.

#1. Captura a sessão corrente de persistência. Todas as sessões devolvida por este método,
durante uma requisição na camada Modelo, retornam a mesma referência (mesma sessão de
persistência).

#2. A execução da cláusula em si deve obedecer à sintaxe HQL para Hibernate ou JPA-QL
para JPA. Pode-se ainda indicar para que mesmo o Hibernate somente aceite sintaxe JPA, em
seu arquivo de configuração “hibernate.cfg.xml”.

#3. O tratamento contra exceções na camada de Persistência atuará provavelmente para


problemas externos; raramente para problemas provocados no próprio método.

Para este caso, basta utilizar o template padrão de tratamento do jCompany, digitando-se
“try” + Control+Space. Uma cláusula de “try – catch” similar à do Código E16.31 será gerada.
Este código padrão realizará um tratamento genérico para exceções externas considerado
“pauta mínima”, incluindo:

- Envio de detalhes do erro via log (Log4j);


- Envio de detalhes do erro via e-mail;
- Exibição de mensagem de exceção inesperada para o usuário.

A versão JPA é muitíssimo parecida:

...
public class FuncionarioDAO extends PlcBaseJpaDAO {

public Integer recuperaTotalPorSexo(Sexo sexo) throws PlcException {

try {

EntityManager em = getEntityManager();

return (Integer) em.createQuery("select count(*) from FuncionarioEntity f " +


"where f.sexo=:sexo”).setParameter(“sexo”,sexo).uniqueResult();

} catch (Exception e) {
throw new PlcException("jcompany.erro.generico", new Object[] {
"recuperaTotalPorSexo", e }, e,log);
}
}

Código E16.32. Exemplo de implementação de método de DAO com JPA.

Neste caso específico, somente a Interface de persistência mudou. Devido à influência que teve Gavin
King, o criador do Hibernate, como líder da especificação que resultou no padrão JPA, o percentual de
similaridade entre as duas implementações chega a 90%.
Do ponto de vista de comunicação entre as camadas, já vimos a Injeção de Dependência em Manager/BO
e AS, via declaração de DAOs ou outros Managers, no construtor das classes:


public class CandidatoManager extends PlcBaseBO {

CandidatoDAO candidatoDAO;
AreaProfissionalDAO areaProfissionalDAO;

public CandidatoManager (CandidatoDAO candidatoDAO,


AreaProfissionalDAO areaProfissionalDAO) {
this.candidatoDAO = candidatoDAO;
this.areaProfissionalBO = areaProfissionalBO;
}
}
...
Código E16.33. Constructor Based Dependency Injection, em classes Manager/BO e Application Service.

Importante: Classes DAO não possuem “Template Methods” do jCompany. Não se espera
programações de negócio ou quaisquer outras que requeiram generalizações mesmo parciais, nesta
categoria de classes. Basicamente, elas devem oferecer métodos reutilizáveis de acessos a dados, sem
inclusive envolver muitas trocas de mensagens entre si (orquestrações na camada de Persistência) - pelo
menos, no que tange a persistências para SGBDs relacionais.
Sumário
Neste capítulo, discutimos em maior profundidade diversos aspectos da arquitetura Orientada a Objetos
do jCompany, nas várias camadas do MVC2-P, provendo alta flexibilidade e separação de conceitos que
visam preservar a simplicidade em implementações específicas, da aplicação.
Muitas das complexidades arquiteturais que discutimos têm um propósito bem claro: eliminar código
desnecessário em aplicações de negócio, em todas as camadas, generalizando cenários de Casos de Uso
por completo.
Desenvolvedores acostumados com a programação J2EE deverão ter compreendido o suficiente para
inclusive efetuarem ajustes arquiteturais no jCompany, se necessário for (com uma ajuda complementar
das ferramentas de logging e do depurador do Eclipse, apresentados).
Caso você não tenha compreendido por completo todos os Design Patterns e técnicas OO aqui discutidas,
não se preocupe: a maior parte do conhecimento que foi descrito pode ser abstraído, mesmo em estágios
intermediários de uso do jCompany FS Framework. Ao surgirem demandas que exijam maiores
customizações, retorne a este capítulo.

Potrebbero piacerti anche