Вы находитесь на странице: 1из 195

Guia de Referência do Framework Java Arquitetura Brasil

Version 1.13.6

Copyright © 2004-2010 Isban , Arquitetura de sistemas - Superintendência de Arquitetura

Este documento é de propriedade da Isban.


Índice
I.Introdução........................................................................................................................................
1.Pré-requisitos .........................................................................................................................
1.1. Conhecimentos necessários do desenvolvedor .................................................................2
2.Arquitetura ............................................................................................................................
2.1.Introdução ....................................................................................................................3
2.2. A arquitetura do Framework ..........................................................................................4
2.3. A arquitetura das aplicações ...........................................................................................5
2.4. Modos de execução - running modes .............................................................................. 9
3. O ambiente de desenvolvimento .............................................................................................
3.1.InstalaçãodoFramework ...............................................................................................11
3.2. Estrutura de diretórios padrão ........................................................................................13
3.3.Procedimentodebuild ...................................................................................................13
3.4.ConfiguraçãodoEclipse ................................................................................................14
3.4.1.Criaçãodoprojeto ..............................................................................................14
3.4.2. Configuração dos diretórios de fontes .................................................................. 15
3.4.3. Configuração dos padrões de formatação e estilo .................................................. 16
3.4.4. Configuração web e JSF .....................................................................................17
3.4.5.Configurandoasbibliotecas ................................................................................18
II.OFramework ..................................................................................................................................
4.Serviçosdenegócio .................................................................................................................
4.1.Introdução ....................................................................................................................22
4.2.Criandoserviços ...........................................................................................................22
4.3.Usandoserviços ............................................................................................................24
4.4.Transaçõeseserviços ....................................................................................................24
4.4.1.Tiposdepropagação ...........................................................................................25
4.5.Interceptadores..............................................................................................................26
4.6.EJB3.0.........................................................................................................................27
4.6.1.TiposdeEJB's ....................................................................................................27
5.Logging ..................................................................................................................................
5.1.Introdução ....................................................................................................................30
5.2.SLF4J...........................................................................................................................30
5.2.1.ObtendooLogger...............................................................................................31
5.2.2.UsandooLogger ................................................................................................31
5.3.Logback .......................................................................................................................32
5.4.Boaspráticas.................................................................................................................33
5.4.1. Não use System.out ou System.err ....................................................................... 33
5.4.2. O logger de uma classe deve ser um atributo privado, estático e final ..................... 34
5.4.3. Use o nome da classe executada como nome do logger ......................................... 34
5.4.4. Use o nível de log adequado ................................................................................ 34
5.4.5. Escreva as mensagens de log pensando no público alvo ........................................ 35
5.4.6. Não faça várias chamadas de log para informações relacionadas ............................ 35
5.4.7. Não dependa de logs em diferentes níveis para obter uma informação .................... 36
5.4.8. Considere o custo de geração do log .................................................................... 36
5.4.9. Faça suas classes "logáveis" ................................................................................36
5.4.10. Use Arrays.asList(Object[]) para logar arrays de objetos ..................................... 37
5.5.Logdeserviços .............................................................................................................38
5.5.1. Log da chamada de serviços ................................................................................ 38
5.5.2. Log de estatísticas de serviços ............................................................................. 38

Framework Java Arquitetura Brasil ii


Guia de Referência do Framework Java Arquitetura Brasil

6.Usodeexceções ......................................................................................................................
6.1.Introdução ....................................................................................................................39
6.2.Usodeexceções ............................................................................................................39
6.2.1. O uso de BusinessException ................................................................................40
6.2.2. O uso de SystemException ..................................................................................41
6.3. Tratamento de exceções em serviços .............................................................................. 41
6.3.1. Controle transacional e exceções .........................................................................42
6.4. Boas práticas no uso de exceções ................................................................................... 42
6.4.1.Tratandoexceções. .............................................................................................43
6.4.2.Lançandoexceções. ............................................................................................43
6.4.3. Definindo classes de exceção ..............................................................................43
7.Persistência ............................................................................................................................
7.1.Introdução ....................................................................................................................45
7.2. DAO - Data Access Object ............................................................................................ 45
7.2.1.JPA ...................................................................................................................46
7.2.2.JDBC ................................................................................................................50
7.2.3.CriandoumDAO ...............................................................................................52
7.3.Transações....................................................................................................................53
7.4. Configuração de banco de dados .................................................................................... 53
7.4.1.Configuraçõesdodatasource ...............................................................................53
7.4.2.ConfiguraçãodoJPA ..........................................................................................54
7.4.3. Como adicionar um perisistence unit no arquivo data_access.xml .......................... 55
7.4.4. Como adicionar um segundo ou mais persistence units no arquivo data_access.xml.
....................................................................................................................................
56
7.4.5.UtilizandováriosDataSources/PersistenceUnits ...................................................57
8.Mensageria.............................................................................................................................
8.1.Introdução ....................................................................................................................59
8.2.JMS .............................................................................................................................59
8.2.1.ConfiguraçãodoJMS .........................................................................................59
8.2.2. Configuração do JMS (Fora do Websphere) ......................................................... 60
8.2.3.AbstractMessagingGateway ................................................................................61
8.2.4.Modosíncrono ...................................................................................................64
8.2.5.Modoassíncrono ................................................................................................66
8.3.MDB............................................................................................................................69
8.4.ArquiteturaEstendidaAltair ..........................................................................................70
8.4.1. Mapeamento para o formato de Request (Envio) ................................................... 71
8.4.2. Mapeamento para o formato de Response (Retorno) ............................................. 73
8.4.3. Mapeamento de tipos de retorno .......................................................................... 73
8.4.4. Enviando mensagens para a Arquitetura Estendida Altair ...................................... 73
9.WebServices ..........................................................................................................................
9.1.Introdução ....................................................................................................................75
9.2. Exportando um serviço de negócio como web service ...................................................... 75
9.3. Gerando um cliente web service a partir do WSDL .......................................................... 80
9.4.Consumindowebservices ..............................................................................................81
9.5. Expondo serviços para serem consumidos pelo WebCon ................................................. 83
10.Segurança.............................................................................................................................
10.1.Introdução ..................................................................................................................84
10.2.Autenticação ...............................................................................................................84
10.2.1. Configuração da autenticação para diferentes runningModes. .............................. 84
10.2.2.AuthFilter ........................................................................................................85
10.2.3.SmartAuthFilter................................................................................................86
10.3.Autorização ................................................................................................................87

Framework Java Arquitetura Brasil iii


Guia de Referência do Framework Java Arquitetura Brasil

10.3.1. Criação do menu personalizado .........................................................................87


10.3.2.Autorizaçãodeserviços ....................................................................................88
10.3.3. Configuração para acesso ao MBS ..................................................................... 88
10.4.Criptografia ................................................................................................................89
10.4.1.Digesting .........................................................................................................90
10.4.2. Encriptação de senhas (usando digesting) ........................................................... 90
10.4.3.Encriptaçãodetexto .........................................................................................91
10.4.4.Encriptaçãodenúmeros ....................................................................................91
10.4.5.Encriptaçãodebinários .....................................................................................92
10.4.6.Algoritmoscriptográficos..................................................................................93
10.5.Auditoria ....................................................................................................................94
10.5.1.Auditoriamanual ..............................................................................................96
10.5.2.Auditoriaautomática.........................................................................................96
11.InterfaceWeb.......................................................................................................................
11.1.Introdução ..................................................................................................................97
11.2.SobreoJSF .................................................................................................................97
11.3.Configurandoaaplicação .............................................................................................102
11.4.ConfigurandoJSF........................................................................................................108
11.4.1.ConfigurandoFacelets ......................................................................................109
11.4.2. Criando uma nova UI ........................................................................................110
11.5.BasicBBean ................................................................................................................112
11.6.CRUD ........................................................................................................................113
11.7.RelatórioscomJasperReports.......................................................................................114
11.8. Menu de acesso configurado pelo MBS ........................................................................ 116
11.9.ServletdeImagem .......................................................................................................117
12.Batch ....................................................................................................................................
12.1.Introdução ..................................................................................................................119
12.2.Processamento ............................................................................................................120
12.2.1.Criandoumbatch .............................................................................................120
12.2.2.Configuração....................................................................................................123
12.2.3.Executandoobatch ...........................................................................................124
12.2.4.ParâmetrosdoBatchRunner ..............................................................................125
12.3.Manipulandoarquivos .................................................................................................125
12.3.1.DefaultDataInput ..............................................................................................125
12.3.2.DefaultFileDataOutput......................................................................................126
12.3.3.FlatfileContextDataOutput ................................................................................126
12.4.Processamentoderegistros ..........................................................................................128
12.4.1.CSV ................................................................................................................128
12.4.2. Registros de tamanho fixo .................................................................................129
12.5. Configurando o banco de dados com autenticação no MBS ............................................ 131
12.6. Configurando um pool de conexões com o banco de dados ............................................ 132
13.LDAP ...................................................................................................................................
13.1. Acesso a servidores LDAP ...........................................................................................133
13.1.1. Configurando o servidor Ldap ...........................................................................134
13.1.2. Métodos da classe GenericLdapDao ...................................................................134
13.1.3. Utilizando um SimpleLdapTemplate específico ..................................................135
14.Classesutilitárias .................................................................................................................
14.1.Introdução ..................................................................................................................136
14.2. Manipulação de data e hora .......................................................................................... 136
14.2.1.DataeHorário ..................................................................................................136
14.2.2. Intervalos e períodos de tempo .......................................................................... 137
14.2.3.InputandOutput...............................................................................................138

Framework Java Arquitetura Brasil iv


Guia de Referência do Framework Java Arquitetura Brasil

14.2.4.InteroperabilidadecomJDK ..............................................................................140
14.3.Miscelânea..................................................................................................................140
14.3.1. A biblioteca Commons Lang .............................................................................140
14.3.2. A biblioteca Commons Collections ....................................................................143
14.4.Validadores.................................................................................................................145
14.4.1.Criandoumvalidador .......................................................................................147
14.5.Conversores ................................................................................................................147
14.5.1.Criandoumconversor .......................................................................................149
14.6.Manipulaçãodearquivos .............................................................................................149
14.6.1.CommonsIO ....................................................................................................150
14.6.2.Commonscodec ...............................................................................................151
14.6.3. Manipulação de arquivos formatados .................................................................153
14.7.ManipulaçãodeXML ..................................................................................................153
14.7.1.DOM ...............................................................................................................153
14.7.2.SAX ................................................................................................................154
14.8.Enviodee-mail ...........................................................................................................155
15.Gerenciamentoemonitoração ..............................................................................................
15.1.Introdução ..................................................................................................................157
15.1.1.JMX ................................................................................................................157
15.2.Gerenciamentopadrão .................................................................................................157
15.2.1.Monitoraçãodeserviços....................................................................................157
15.3.Monitoraçãodeversão .................................................................................................159
15.4. Exportando informações para gerenciamento ................................................................160
15.5. Uso do wsadmin com MBeans ..................................................................................... 161
16.TestesUnitários ....................................................................................................................
16.1.Introdução ..................................................................................................................162
16.2.Objetivo......................................................................................................................162
16.3.Benefícios...................................................................................................................162
16.4. Como criar testes unitários ...........................................................................................162
III.AplicaçãodeReferência .................................................................................................................
17. A aplicação de referência .....................................................................................................
17.1.Introdução ..................................................................................................................168
17.2.ABC-CDOnline..........................................................................................................168
17.2.1.ABC-Online.....................................................................................................168
17.2.2.ABC-Admin.....................................................................................................170
18.Arquiteturaeimplementação ...............................................................................................
18.1.Introdução ..................................................................................................................172
18.2.ABCCDOnline ..........................................................................................................172
18.2.1.CamadadePersistência .....................................................................................172
18.2.2.CamadadeServiço ...........................................................................................173
18.2.3.CamadaWeb ....................................................................................................175
18.3.ABC-Admin ...............................................................................................................177
18.3.1.CamadadePersistência .....................................................................................177
18.3.2.CamadadeServiço ...........................................................................................178
18.3.3.CamadaWeb ....................................................................................................180
18.4. Aplicações Batch ABC CD Online ............................................................................... 181
18.4.1.TratamentodePedido .......................................................................................181
18.4.2. Processamento Batch para Cds ..........................................................................183
A.Referências.....................................................................................................................................
A.1.Referências ..........................................................................................................................189

(1.13.6)
Parte I. Introdução
O Framework Java Arquitetura Brasil tem como objetivo padronizar o desenvolvimento de aplicações Java em
plataforma distribuída, garantindo um nível de performance, segurança, conectividade, produtividade e
reusabilidade de componentes das aplicações desenvolvidas pela Isban. Definindo uma arquitetura padrão,
podemos obter maior qualidade do software.

Esta seção apresenta os conceitos usados pelo Framework e introduz a arquitetura adotada para a construção de
aplicações.

• Capítulo 1. Pré-requisitos

• Capítulo 2. Arquitetura

• Capítulo 3. O ambiente de desenvolvimento

Framework Java Arquitetura Brasil 1


Capítulo 1. Pré-requisitos

1.1. Conhecimentos necessários do desenvolvedor


O Framework Java Arquitetura Brasil, incorpora uma série de tecnologias já disponíveis no mercado. Portanto,
para uma total compreensão do Framework, essas tecnologias devem ser estudadas a priori.

Este manual considera como pré-requisitos mínimos os itens abaixo:

• Linguagem Java - http://java.sun.com/

• JDBC - http://java.sun.com/j2se/1.5.0/docs/guide/jdbc/

• JPA/Hibernate - http://java.sun.com/javaee/technologies/persistence.jsp

• JAX-WS e JAXB - https://jax-ws.dev.java.net/ e https://jaxb.dev.java.net/

• JSF e ICEfaces - http://java.sun.com/javaee/javaserverfaces/ e http://www.icefaces.org/

• JasperReports - http://jasperforge.org/plugins/project/project_home.php?group_id=102

Framework Java Arquitetura Brasil 2


Capítulo 2. Arquitetura

2.1. Introdução
O Framework foi construído sobre os padrões Java Standard Edition 5 e Java 2 Enterprise Edition 1.4,
além de uma série de produtos de mercado que implementam funcionalidades adicionais.

Ele inclui um conjunto de bibliotecas e de diretrizes para a construção de aplicações baseadas nele.

O cenário planejado de uso do framework é dentro de um servidor de aplicações. Neste cenário o sistema que
faz uso do framework é um EAR instalado em um servidor de aplicações, e pode utilizar todas as APIs da
especificação J2EE, e as facilidades oferecidas pelo servidor de aplicações.

O ambiente padrão, que serve de base para o Framework é o WebSphere 6.1 rodando em servidor Intel com
sistema operacional Windows.

No entanto, o Framework não tem dependências internas com o WebSphere, podendo ser usado em servidores
de aplicação de outros fabricantes. Mas como o WebSphere 6.1 é o padrão atual, muitas funcionalidades já
estão pré-configuradas para esse ambiente. A figura abaixo mostra esse cenário:

Figura 2.1. Cenário de uso do Framewok

Também é possível usar o Framework em outos cenários, de acordo com as necessidades da aplicação. Sendo o
Framework modular, o princípio básico de construção da aplicação será o mesmo, sendo seus módulos
substituídos ou desativados de acordo com a situação. Apenas o conjunto de funcionalidades e integrações
disponíveis em cada cenário será diferente.

Atenção
Vale lembrar que qualquer solução diferente do cenário com o WebSphere, não é homologada e

Framework Java Arquitetura Brasil 3


Arquitetura

não existe infra-estrutura para sua execução, precisando ser analisada sob as óticas de arquitetura,
segurança e produção.

2.2. A arquitetura do Framework


A arquitetura de aplicações corporativas deve seguir o padrão multi-camadas. Este modelo define uma camada
específica para visualização, outra para regras de negócios e outra para integração, estando elas minimamente
acopladas por uma interface bem definida. Uma camada pode depender de camadas inferiores, mas nunca
das superiores.

O Framework Java Arquitetura Brasil define três camadas fundamentais:

• Camada de Apresentação

• Camada de Negócio

• Camada de Integração (persistência, mensagens, web services)

Framework Java Arquitetura Brasil 4


Arquitetura

Figura 2.2. Camadas do Framework

A camada de negócios, é o centro da arquitetura, e nela devem ser concentrados os esforços no


desenvolvimento de uma aplicação.

Abaixo da camada de negócios, podem existir várias camadas, nomeadas genericamente de “camadas de
integração“. As camadas de persistência, mensagens e web services, são exemplos concretos de integração, que
serão providas pelo Framework.

A camada de aplicações web pode ser opcional, quando o sistema tiver apenas serviços de negócio, sem
nenhuma interface visual integrada. Neste caso, os clientes acessarão diretamente a camada de negócios.

O Framework foi implementado usando o Spring para integrar todos esses componentes em torno da camada de
serviços, simplificando o modelo de desenvolvimento.

2.3. A arquitetura das aplicações


Uma aplicação típica possui uma camada web para interface com o usuário, uma camada de negócios e uma
camada de persistência implementada com JPA e JDBC. Os pacotes dessa aplicação devem ser estruturados da
seguinte maneira:

Tabela 2.1. Packages da aplicação

Package Descrição

com.altec.bsbr.app.[sistema].audit Implementação de AuditHandler, para a persistência


dos eventos de auditoria.

com.altec.bsbr.app.[sistema].converter Conversores de dados (classes que implementem


Converter.)

com.altec.bsbr.app.[sistema].dao Interface dos DAOs da aplicação. Deve ter como


sufixo DAO

com.altec.bsbr.app.[sistema].dao.impl Implementação dos DAOs da aplicação. Deve ter o


mesmo nome da interface seguido por 'Impl'.

com.altec.bsbr.app.[sistema].ejb Implementação de EJBs.

com.altec.bsbr.app.[sistema].entity Entidades JPA.

com.altec.bsbr.app.[sistema].exception Exceptions da aplicação.

com.altec.bsbr.app.[sistema].jms Interface dos componentes de acesso JMS. Caso


estenda alguma classe MessagingGateway deve ter
como sufixo MessagingGateway.

com.altec.bsbr.app.[sistema].jms.impl Implementações de dos componetnes de acesso JMS


(Inclusive Listeners). Deve ter o mesmo nome da
interface seguido por 'Impl'.

com.altec.bsbr.app.[sistema].mbean Implementação de ManagedBeans do JMX.

com.altec.bsbr.app.[sistema].message Arquivos de mensagens (.properties) usados pela


aplicação web.

Framework Java Arquitetura Brasil 5


Arquitetura

Package Descrição

com.altec.bsbr.app.[sistema].report Relatórios JasperReports (arquivos .jasper e .jrxml).

com.altec.bsbr.app.[sistema].service Interfaces dos serviços (*Service). Deve ter o sufixo


'Service'.

com.altec.bsbr.app.[sistema].service.impl Implementação dos serviços (*ServiceImpl). Deve ter


o mesmo nome da interface seguido por 'Impl'.

com.altec.bsbr.app.[sistema].dto DTOs usados pelos serviços

com.altec.bsbr.app.[sistema].validator Validadores de dados (classes que implementem


Validator.)

com.altec.bsbr.app.[sistema].web.filter Servlet filters.

com.altec.bsbr.app.[sistema].web.jsf Backing beans do JSF.

com.altec.bsbr.app.[sistema].web.jsf.component Componentes JSF.

com.altec.bsbr.app.[sistema].web.jsf.converter Conversores de tipo JSF.

com.altec.bsbr.app.[sistema].web.jsf.validator Validadores de tipo JSF.

com.altec.bsbr.app.[sistema].webclient Clientes de web services.

com.altec.bsbr.app.[sistema].webservice Interface dos Endpoints de web services.

com.altec.bsbr.app.[sistema].webservice.impl Implemetação dos Endpoints de web services. Deve


ter o mesmo nome da interface seguido por Impl.

Nota
Note que nem sempre todos esses pacotes serão necessários, podendo ser omitidos se for o caso. As
classes referentes a serviços e DAOs estarão presentes em praticamente todas aplicações.

A figura abaixo mostra um diagrama conceitual dos principais componentes presentes numa aplicação.

(1.13.6)
Arquitetura

Figura 2.3. Arquitetura de aplicação

A camada de apresentação usa o modelo MVC, sendo a página JSF o "view", o backing bean o "controller" e as
entidades ou DTOs o "model".

(1.13.6)
Arquitetura

Figura 2.4. Padrão MVC

Os arquivos de configuração padrão que devem estar presentes no diretório src:

Tabela 2.2. Arquivos de configuração

Arquivo Descrição

META-INF/config/application.properties Informações sobre a aplicação.

META-INF/config/persistence.properties Indica qual o arquivo de persistência do JPA.

META-INF/config/aea.xml Configura usuário de acesso da AEA.

META-INF/config/audit.xml Configura auditoria.

META-INF/config/authentication.xml Configura autenticação.

META-INF/config/authorization.xml Configura autorização.

META-INF/config/data_access.xml Configura a camada de persistência.

META-INF/config/jms.xml Configura filas e connection factory.

META-INF/config/mail.xml Configura mail session.

META-INF/config/ejb-clients.xml Configura clientes ejb.

META-INF/config/ws-clients Configure clientes web services.

META-INF/persistence-<runningMode>.xml Configura persistência JPA.

Framework Java Arquitetura Brasil 8


Arquitetura

Arquivo Descrição

ehcache.xml Configura cache do Hibernate.

Nota
Note que nem sempre todos esses arquivos de configuração serão necessários, podendo ser
omitidos se for o caso. O arquivo application.properties é essencial, pois ele é usado pelo
processo de build.

2.4. Modos de execução - running modes


Quando construímos uma aplicação, alguns dos problemas a serem resolvidos são:

• Onde guardar a configuração dos meus beans?

• Como fazer sua parametrização de forma dinâminca?

• Onde guardar essas informações?

• Como tratar diferentes ambientes, como produção, testes e desenvolvimento?

• Como distribuir o código com suas configurações correspondentes?

Para resolver tais problemas, foi usado o conceito de running mode, que permite determinar qual ambiente a
aplicação está sendo executada, e usar configurações distintas para cada um desses modos. Um running mode é
definido como uma chave de texto única, usada para identificar uma configuração possível.

Podemos definir tantos running modes quanto necessários, por exemplo: dev, pi, hml, prod, meu_ambiente, etc.

No entanto, somente dois estarão ativos simultaneamente:

• um indicando qual o tipo de servidor em uso (WebSphere, Geronimo) que é definido automaticamente pelo
Framework.

• um indicando qual ambiente em uso (prod, dev, etc), definido externamente pelo administrador.

Dica
Esses running modes são usados para guardar configurações específicas de cada ambiente. As
aplicações são encorajadas a usar a mesma estratégia para separar qualquer tipo de configuração
que dependa de ambiente. Exemplos: o data source é obtido de uma maneira rodando no
WebSphere e de outra no Geronimo; a URL de um web service pode ser distinta nos ambientes de
desenvolvimento, homologação e produção.

O running mode corrente é determinado em tempo de execução através da seguinte lógica:

1. Determina automaticamente o tipo de servidor em uso. Ativa um running mode com o valor websphere,
geronimo, batch ou unknown.

2. Se houver uma system property chamada runningMode, esse running mode é ativado.

Framework Java Arquitetura Brasil 9


Arquitetura

Por exemplo, o servidor WebSphere do ambiente de produção deve ser configurado com o parâmetro da JVM:

-DrunningMode=prod

então os running modes ativos serão websphere,prod.

Definidos os running modes, o Framework carregara os arquivos de configuração correspondentes. No diretório


base META-INF/config ficam os arquivos de configuração Spring comums a qualquer running mode, e no
diretório META-INF/config/<runningMode> ficam os arquivos específicos do running mode chamado
<runningMode>.

Primeiro é carregada a configuração do logback, depois as propriedades e então os beans do Spring:

Tabela 2.3. Ordem de carregamento dos arquivos de configuração

Ordem Arquivos Descrição

1 META-INF/log/logback-<runningMode>.xml Carrega configuração do logback para


<runningMode>.

2 META-INF/config/*.properties Carrega propriedades comuns.

3 META-INF/config/<runningMode>/*.propertiesCarrega propriedades de <runningMode>.

4 META-INF/config/*.xml Carrega beans comuns.

5 META-INF/config/<runningMode>/*.xml Carrega beans de <runningMode>.

(1.13.6)
Capítulo 3. O ambiente de desenvolvimento

3.1. Instalação do Framework


O Framework é disponibilizado na forma de um arquivo ZIP contendo um conjunto de bibliotecas no formato
jar. Para seu correto funcionamento, o Framework depende de uma série de bibliotecas de terceiros, também
distribuídas no mesmo pacote, e que devem ser incluídas durante o processo de compilação e build.

O conteúdo do arquivo fw-1.13.6-dist.zip é listado a seguir:

fw-1.13.6-dist\lib:
bundle:
fw-1.13.6.jar
compile:
apache-commons\commons-beanutils-1.8.2.jar
apache-commons\commons-codec-1.3.jar
apache-commons\commons-collections-3.2.1.jar
apache-commons\commons-digester-1.8.jar
apache-commons\commons-httpclient-3.1.jar
apache-commons\commons-io-1.4.jar
apache-commons\commons-lang-2.4.jar
apache-commons\commons-pool-1.3.jar
ehcache\backport-util-concurrent.jar
ehcache\ehcache-1.5.0.jar
ehcache\jsr107cache-1.0.jar
hibernate\antlr-2.7.6.jar
hibernate\dom4j-1.6.1.jar
hibernate\hibernate-annotations-3.4.0.GA.jar
hibernate\hibernate-commons-annotations-3.1.0.GA.jar
hibernate\hibernate-entitymanager-3.4.0.GA.jar
hibernate\hibernate-validator-3.1.0.CR2.jar
hibernate\hibernate3-3.3.1.GA.jar
hibernate\javassist-3.4.GA.jar
hsqldb\hsqldb.jar
jamon\fdsapi-1.2.jar
jamon\jamon-2.7.jar
jasper\iText-2.1.3.jar
jasper\jasperreports-3.0.1.jar
jasper\jcommon-1.0.13.jar
jasper\jfreechart-1.0.10.jar
jasper\poi-3.0.1-FINAL-20070705.jar
jasypt\icu4j-3.8.jar
jasypt\jasypt-1.5.jar
joda-time\joda-time-1.6.jar
jsf\commons-fileupload-1.3.jar
jsf\el-api.jar
jsf\el-ri.jar
jsf\icefaces-1.7.2-SP2.jar
jsf\icefaces-comps-1.7.2-SP2.jar
jsf\icefaces-facelets-1.7.2-SP2.jar
jsf\krysalis-jCharts-1.0.0-alpha-1.jar
logging\jcl-over-slf4j-1.5.5.jar
logging\logback-classic-0.9.15.jar
logging\logback-core-0.9.15.jar
logging\slf4j-api-1.5.6.jar
mbs\MBS_Client.jar
mbs\axis.jar
mbs\commons-discovery-0.2.jar
mbs\jaxrpc.jar
mbs\saaj.jar
spring\asm-2.2.3.jar
spring\asm-commons-2.2.3.jar
spring\asm-util-2.2.3.jar
spring\aspectjrt.jar
spring\aspectjweaver.jar
spring\cglib-nodep-2.1_3.jar
spring\jakarta-oro-2.0.8.jar
spring\spring-2.5.6.SEC01.jar
spring\spring-ldap-1.2.1.jar
spring\spring-ldap-tiger-1.2.1.jar
spring\spring-modules-cache-0.9.jar

Framework Java Arquitetura Brasil 11


O ambiente de desenvolvimento

spring\spring-webmvc-2.5.6.SEC01.jar
sun-ldap\ldapbp-1.0.jar
tibco\ssoRMI.jar
provided:
apache-commons\commons-dbcp-1.2.2.jar
j2ee\activation.jar
j2ee\ejb-api-3.0.jar
j2ee\jms.jar
j2ee\jta.jar
j2ee\mail.jar
j2ee\servlet-api.jar
jaxws\FastInfoset.jar
jaxws\http.jar
jaxws\jaxb-api.jar
jaxws\jaxb-impl.jar
jaxws\jaxb-xjc.jar
jaxws\jaxws-api.jar
jaxws\jaxws-rt.jar
jaxws\jaxws-tools.jar
jaxws\jsr173_api.jar
jaxws\jsr181-api.jar
jaxws\jsr250-api.jar
jaxws\mimepull.jar
jaxws\resolver.jar
jaxws\saaj-api.jar
jaxws\saaj-impl.jar
jaxws\sjsxp.jar
jaxws\stax-ex.jar
jaxws\streambuffer.jar
jpa\ejb3-persistence.jar
jsf\jsf-api-1.1_02.jar
jsf\jsf-impl-1.1_02.jar
jsf\jstl.jar
jsf\standard-1.1.2.jar
junit\junit-4.4.jar
mbs\wsdl4j-1.5.1.jar
mq\com.ibm.mq.jar
mq\com.ibm.mqjms.jar
mq\connector.jar
mq\dhbcore.jar
oracle\ojdbc14.jar
tests:
dbunit\dbunit-2.3.0.jar
mockrunner-j2ee1.4\dependencies.txt
mockrunner-j2ee1.4\mockrunner-ejb.jar
mockrunner-j2ee1.4\mockrunner-jca.jar
mockrunner-j2ee1.4\mockrunner-jdbc.jar
mockrunner-j2ee1.4\mockrunner-jms.jar
mockrunner-j2ee1.4\mockrunner-servlet.jar
mockrunner-j2ee1.4\mockrunner-tag.jar
mockrunner-j2ee1.4\mockrunner.jar
mockrunner-jee5\dependencies.txt
mockrunner-jee5\mockrunner-ejb.jar
mockrunner-jee5\mockrunner.jar
spring-test\spring-test.jar
checkstyle:
Altec_CheckStyle.xml
Altec_CheckStyle_ImportControl.xml
Altec_CheckStyle_critical.xml
Isban_CheckStyle_ImportControl.xml
Isban_Checkstyle_Critical.xml
Isban_Checkstyle_ImportControl_Critical.xml
altec-checkstyle.xml
checkstyle-all-5.0.jar
checkstyle-altec.xsl
eclipse\AltecStyle.importorder
eclipse\AltecStyle_CleanUp.xml
eclipse\AltecStyle_Formatter.xml

O arquivo no diretório lib/bundle contém a biblioteca com as classes e configurações do Framework.

As bibliotecas contidas no diretório lib/compile devem ser usadas para a compilação do projeto, e serão
incluidas no pacote final da aplicação como dependências. As que estão no diretório lib/provided, devem ser
usadas apenas para a compilação, mas não farão parte do pacote por já estarem presentes no servidor de

Framework Java Arquitetura Brasil 12


O ambiente de desenvolvimento

aplicações.

3.2. Estrutura de diretórios padrão


O Framework define uma estrutura de diretórios padrão, onde devem ser colocados todos os artefatos usados na
construção de uma aplicação. Usando essa hierarquia, o arquivo de build Ant provido pelo Framework pode ser
usado sem nenhuma alteração.

dist - onde são colocados os pacotes jar, war e ear gerados pelo build
ear - onde ficam os arquivos application.xml, usados para gerar o ear
lib/bundle - bibliotecas que devem ser integradas a aplicação
lib/compile - bibliotecas que vão ser incluídas como dependência da aplicação
lib/provided - bibliotecas que não vão ser incluídas como dependência da aplicação
src - fontes da aplicação
src-published - fontes da aplicação, que serão colocadas num jar separado, para ser reutilizado
web/resources - classes e recursos a serem incluidos no arquivo war

O diretório src-published deve ser usado quando existirem algumas classes da aplicação que devem ficar
disponíveis para a reutilização. Assim, as classes presentes neste diretório serão empacotadas num arquivo jar
independente (com o sufixo-api) que poderá ser distribuído para ser usado em outras aplicações. Isso pode ser
preciso, por exemplo, quando uma interface de negócios for exportada, seus objetos de transferência (DTO) ou
ainda entidades JPA. Caso esta necessidade não esteja presente, o diretório pode ficar vazio.

No diretório lib da aplicação só devem ser incluídas dependências exclusivas da aplicação, e que ainda não são
atendidas pelo Framework. Na maioria dos casos esses diretórios podem ficar vazios. Caso a aplicação
necessite de alguma biblioteca adicional (como de leitura de código de barras ou uma API de serviços de outra
aplicação, por exemplo) ela pode ser colocada dentro do diretório lib/bundle, lib/compile.

3.3. Procedimento de build

Os pré requisitos mínimos para o desenvolvimento com o Framework são:

• Sun J2SE 5.0 - SDK para desenvolvimento em Java.

• Apache Ant 1.7 - ferramenta de build.

Para obter e instalar esses produtos, consulte as informações apresentadas nos respectivos web sites.

Uma aplicação construída seguindo as normas do Framework pode ser gerada simplesmente com a linha de
comando, através da ferramenta Ant.

Um arquivo build.xml é provido, e ele pode ser usado sem nenhuma alteração. A única configuração
necessária é no arquivo build.properties presente na raíz do projeto. Ele precisa conter apenas a definição da
propriedade shared-lib.dir que aponta para o diretório onde estão todas as libs de dependências do
Framework.

O script de build possui os seguintes targets

• clean - limpa todos os artefatos gerados pelo build, retornando ao estado inicial.

• compile - compila os fontes Java.

Framework Java Arquitetura Brasil 13


O ambiente de desenvolvimento

• package - gera os arquivos de empacotamento: jar, war e ear.

• javadoc - gera os javadocs da aplicação.

• test - executa os testes unitários da aplicação.

• dist - faz um clean e package.

Portanto, para gerar uma aplicação recem obtida do repositório, basta executar

ant dist

no diretorio raíz do projeto, que todos os artefatos necessários para o deploy serão gerados.

3.4. Configuração do Eclipse


O Framework foi construído de maneira a não depender de nenhum IDE específico, sendo apenas o JDK e Ant
suficientes. No entanto, o uso de um IDE moderno é essencial para a produtividade do programador, e o
Eclipse é o produto adotado como padrão pela Isban para esse fim.

O procedimento de configuração do Eclipse 3.4 para o desenvolvimento de uma aplicação com o Framework é
descrito a seguir.

3.4.1. Criação do projeto

Ao iniciar um novo projeto é recomendado cria-lo a partir de uma aplicação vazia já existente. São fornecidos
os projetos WEB_blank, EJB_blank e Batch_blank, que podem ser usados como ponto de partida. O nome da
aplicação deve então ser alterado de blank para o nome correto do sistema a ser desenvolvido, e os arquivos que
não forem usados podem ser apagados.

Para criar o projeto clique em File -> New -> Java Project. Na tela New Java Project preencha da seguinte
forma:

1. Digite o nome do Projeto em Project Name.

2. Em Contents selecione Create project from existing source.

3. Selecione o diretório raiz do projeto.

4. Em JRE selecione o JDK 5.0.

5. Clique em Next.

(1.13.6)
O ambiente de desenvolvimento

Figura 3.1.

3.4.2. Configuração dos diretórios de fontes

1. Adicione src e src-published como fontes do projeto, selecionando os dois diretórios e clicando no ícone

2. Clique em Next.

(1.13.6)
O ambiente de desenvolvimento

Figura 3.2.

3.4.3. Configuração dos padrões de formatação e estilo

1. Acesse o menu Window -> Preferences.

2. Expanda a árvore Java -> Code Style -> Clean Up.

3. Importe o arquivo AltecStyle_CleanUp.xml.

4. Expanda a árvore Java -> Code Style -> Formater.

5. Importe o arquivo AltecStyle_Formatter.xml.

6. Expanda a árvore Java -> Code Style -> Organize Imports.

7. Importe o arquivo AltecStyle.importorder.

Framework Java Arquitetura Brasil 16


O ambiente de desenvolvimento

3.4.4. Configuração web e JSF

Crie o arquivo web.xml no diretório abaixo:

Figura 3.3.

Abaixo há uma visualização do projeto:

Framework Java Arquitetura Brasil 17


O ambiente de desenvolvimento

Figura 3.4.

3.4.5. Configurando as bibliotecas

Existem 2 bibliotecas principais que devem ser configuradas. Uma é a biblioteca do Framework que vem
dentro do arquivo zip do Framework. E as bibliotecas da aplicação que devem ser adicionadas de acordo com
as necessidades de cada aplicação.

Estas 2 bibliotecas devem ser configuradas seguindo os passos abaixo:

1. Acesse o menu Window -> Preferences.

2. Expanda a árvore Java -> Build Path -> User Libraries.

(1.13.6)
O ambiente de desenvolvimento

Figura 3.5. User Libraries

3. Crie uma nova Biblioteca, com o nome desejado, clicando em New....

Figura 3.6. New User Library

4. Adicione os Jars da nova biblioteca clicando em Add Jars....

5. Após adicionar os Jars de dependências clique em OK na janela Preferences.

(1.13.6)
O ambiente de desenvolvimento

6. Adicione a biblioteca ao Projeto. Acesse o menu Project -> Properties.

7. Clique na opção Java Build Path.

8. Clique na aba Libraries.

9. Clique no botão Add Library....

10. Selecione User Library e clique em Next.

Figura 3.7. Add Library

11. Selecione a Biblioteca que foi criada e clique em Finish.

Para cada novo projeto que utilizará a biblioteca do Framework apenas repita os passos a partir do passo 6 em
diante.

Framework Java Arquitetura Brasil 20


Parte II. O Framework
Esta seção documenta a forma de utilização do Framework e boas práticas de programação.

• Capítulo 4. Serviços de negócio

• Capítulo 5. Logging

• Capítulo 6. Uso de exceções

• Capítulo 7. Persistência

• Capítulo 8. Mensageria

• Capítulo 9. Web Services

• Capítulo 10. Segurança

• Capítulo 11. Interface Web

• Capítulo 12. Batch

• Capítulo 15. Gerenciamento e monitoração

Framework Java Arquitetura Brasil 21


Capítulo 4. Serviços de negócio

4.1. Introdução

O que é um serviço?

Nós definimos um serviço como sendo a unidade básica da camada de negócio, que executa regras de negócio,
e agrega uma série de métodos relacionados. Os serviços presentes num sistema definem a interface externa da
camada de negócio, que poderá ser usada pelas camadas superiores.

Este capítulo explica o conceito de serviços no Framework e sua forma de uso.

A camada de negócios é composta por vários serviços, que vão prover funcionalidades de negócio em alto
nível. A camada de negócio pode acessar as camadas inferiores, mas nunca as superiores.

Ao desenhar uma solução, a separação do negócio em serviços e métodos é a parte essencial. Deve ser tomada
atenção especial em quais objetos de domínio serão expostos pelos serviços e a granularidade dos métodos, ou
seja, o grau de detalhamamento e profundidade das informações que vão constituir a interface de negócios do
serviço.

Para a construção de um serviço são necessárias duas partes:

1. Interface - uma interface Java com os métodos de negócio do serviço. É ela que define o "contrato"
oferecido pelo serviço. A interface deve fazer referência apenas a outras classes de negócio ou tipos
básicos de Java, nunca a classes de frameworks, protocolos, infra-estrutura, etc.

2. Implementação - uma classe Java que implementa a interface do serviço. Ela deve conter apenas lógica de
negócio. Lógica de persistência ou de integração deve ser delegada a outras camadas.

A definição do serviço não deve depender da classe que a implementa. E um usuário do serviço vai acessá-lo
através da interface apenas. Assim, ao chamador do serviço basta a interface de negócio.

O Framework provê uma série de funcionalidades adicionais aos serviços da camada de negócios durante
runtime. Assim, podemos facilmente controlar e monitorar os serviços, sem ter um esforço adicional. Essa
características serão detalhadas na seção de interceptadores de serviços.

4.2. Criando serviços


Para a criação de um serviço no Framework devem ser seguidas as seguintes regras:

Tabela 4.1. Regras para criação de serviços

Um serviço deve:

1 Ter uma interface com o sufixo *Service no nome. Essa interface define o "contrato" do serviço
e será usada pelos clientes.

2 A interface deve estar num pacote chamado service.

3 Ter uma implementação com o sufixo *ServiceImpl no nome, que implemente a interface. Essa

Framework Java Arquitetura Brasil 22


Serviços de negócio

Um serviço deve:

classe define a implementação do serviço e não deve ser instanciada ou acessada diretamente
pelo cliente.

4 A implementação deve estar num pacote chamado service.impl.

5 Ter a anotação org.springframework.stereotype.Service na implementação (@Service).

6 Ter como pacote base com.altec.bsbr.app.*. Pode estar em qualquer outro subpacote, dadas as
restrições de nome declaradas acima.

Além dessas regras, é importante que a interface de um serviço só deve conter referências a objetos de tipos
básicos e de negócio. Não podem constar classes como ResultSet, Connection, HttpSession, HttpRequest,
ActionEvent, etc. A implementação só deve conter a lógica de negócios, sendo as lógicas de persistência ou de
integração delegadas a outras camadas.

Como exemplo, vamos definir um serviço para Pedidos, numa aplicação que tenha abc como nome ou sigla.

A interface do serviço:

package ❶com.altec.bsbr.app.abc.service;❷

import java.util.List;
import com.altec.bsbr.app.abc.entity.*;

interface PedidoService❸ {

Pedido criarPedido(Cliente cliente, FormaPagamento formaPagamento, List<EstoqueQuantidade> estoques)


throws PedidoException;

❶ A interface tem o package base com.altec.bsbr.app de aplicações do Framework, e seu package


específico abc.
❷ A interface está no package service.
❸ O nome da interface termina com Service.

A implementação do serviço:

package com.altec.bsbr.app.abc.service.impl;❶

import org.springframework.stereotype.Service;

@Service❷
public class PedidoServiceImpl❸ implements PedidoService❹ {
...
public Pedido criarPedido(Cliente cliente, FormaPagamento formaPagamento,
List<EstoqueQuantidade> estoques)throws PedidoException {
...
}
...
}

❶ A implementação está no sub package impl, tendo como base o mesmo package da interface.
❷ Possui a anotação @Service.
❸ O nome da implementação termina com ServiceImpl.
❹ Implementa a interface PedidoService.

Depois de criada a interface e a implementação do serviço de acordo com essas regras, não é necessário
nehuma configuração especial. O Framework fará automaticamente uma busca pelos serviços e os colocará a

Framework Java Arquitetura Brasil 23


Serviços de negócio

disposição no contexto do Spring, para serem utilizados por outros componentes.

4.3. Usando serviços


Todo serviço do Framework também é um componente gerenciado pelo container do Spring. Portanto o serviço
pode receber a injeção de suas dependências de forma automática, e também ficar disponível para uso em
outros componentes.

Quando um serviço precisar acessar algum componente gerenciado pelo Spring, basta usar a anotação
org.springframework.beans.factory.annotation.Autowired no campo (@Autowired), que ele será injetado
durante a construção do serviço. No exemplo a seguir, o serviço FooServiceImpl vai acessar um outro serviço
BarService

@Service
public class FooServiceImpl implements FooService {

@Autowired
private BarService barService;
...
public void exemplo() {
barService.fazAlgo();
}
}

A injeção de dependência pela anotação @Autowired é feita "por tipo", ou seja, será injetado um bean que seja
do tipo BarService. Caso ocorra a situação de existir mais de um bean do mesmo tipo, ocorrerá um erro
durante a inicialização, pois o Spring não pode determinar qual deles é a dependência desejada. Neste caso
deve ser usada a anotação org.springframework.beans.factory.annotation.Qualifier (@Qualifier), que
vai dizer qual o nome do bean a ser injetado. Exemplo:

@Autowired
@Qualifier("barServiceImpl")
private BarService barService;

Para obter maiores informações sobre os mecanismos de injeção de dependências, consulte a documentação
oficial do Spring

4.4. Transações e serviços


Um aspecto essencial dos serviços da camada de negócios, é o controle transacional. O Framework define essa
camada como delimitadora de transações, e faz o gerenciamento de forma automática.

Quando métodos precisarem fazer parte de uma transação ela sempre será delimitada nesta camada. Portanto,
uma transação sempre começará na entrada de um método de serviço e terminará quando a execução sair fora
desta camada.

Em uma operação que irá rodar dentro de um contexto transacional é importante que se defina quando a
transação será comitada e quando deverá ser feito o rollback. Normalmente, caso não ocorram erros a transação
corrente deve ser comitada ao sair da camada de serviço, e quando ele terminar com uma exceção deve ser feito
o rollback. Além disso, é importante checar o tipo de propagação, ou seja, se é necessário que outros
componentes estejam ou não dentro de uma transação. Portanto, após definir estes pontos vamos para a
implementação.

O Framework define o escopo de uma transação por métodos executados na camada de serviços. São usadas

Framework Java Arquitetura Brasil 24


Serviços de negócio

anotacões para demarcar contextos transacionais.

A anotação org.springframework.transaction.annotation.Transactional (@Transactional) é usada para


anotar métodos de serviço que deve fazer parte de uma transação.

Exemplo:

@Service
public class AnimalServiceImpl implements AnimalService {

@Transactional(❶
readOnly = false,❷
propagation = Propagation.Required,❸
rollbackFor = RuntimException.class)❹
public Animal salvar(Animal animal) {
...
}

❶ Anotação para demarcar o contexto transacional.


❷ Indica se a transação será apenas de leitura ou se haverá alteração de dados. Por padrão é false.
❸ Usando a classe org.springframework.transaction.annotation.Propagation informar o tipo de
propagação da transação. Por padrão é Propagation.REQUIRED.
❹ Indica quais exceções resultarão em rollback. No exemplo acima definimos que deverá ser feito o rollback
para todas as RuntimeException. Por padrão é para qualquer tipo de exceção.

Dica
Na maioria dos casos os parâmetros padrão de @Transactional são suficientes.

4.4.1. Tipos de propagação

Os tipos de propagação suportados estão resumidos na tabela abaixo. Para maiores informações, consulte
manual do Spring.

Tabela 4.2.

Tipo Descrição

Mandatory É obrigatório que exista uma transação ativa, lança uma exceção caso não exista
nenhuma.

Nested Executa em uma transação separada caso exista uma.

Never Não executa dentro de uma transação, lança uma exceção caso exista uma.

Not Supported Não executa dentro de uma transação, ele suspende a transação caso uma já
exista.

Required Executa dentro de uma transação, caso não exista ele cria uma nova.

Requires New Executa dentro de uma transação, caso já exista uma cria-se uma nova.

Supports Executa dentro de uma transação, caso já exista uma, caso contrário executa fora
de uma transação.

(1.13.6)
Serviços de negócio

4.5. Interceptadores
Todos os serviços do Framework ganharão uma série de funcionalidades adicionais de forma transparente.
Através de recursos de AOP do Spring, são acrescentados interceptadores aos serviços, que serão invocados
durante sua chamada.

Figura 4.1. Interceptadores dos serviços

• Auditoria - faz a auditoria da chamada do serviço. Para tanto, o método precisa ter a anotação @Audit. Veja
o seção de auditoria.

• Autorização - verifica autorização do usuário para executar o serviço. Para tanto, o método precisa ter a
anotação @Authorize. Veja o seção de autorização.

(1.13.6)
Serviços de negócio

• Tratamento de exceções - faz um tratamento padrão das exceções que ocorrerem no método. Veja a seção
de tratamento de exceções.

• Log - registra a chamada do método, parâmetros de entrada e saída. Veja a seção de logging.

• Monitoração - monitora a execução do método e mede o tempo gasto. Veja a seção de gerenciamento.

• Controle transacional - gerencia a abertura, fechamento e rollback de transações. Veja a seção de


transações.

4.6. EJB 3.0


A especificação da API EJB 3.0 provê uma maneira padrão de implementar a camada de negócios de
aplicações corporativas. Ela possibilita exportar serviços para serem acessados por outras aplicações.

O Framework utiliza EJB's apenas para situações onde é necessário expor serviços remotamente para outras
aplicações utilizando o protocolo RMI/IIOP.

4.6.1. Tipos de EJB's

Existem atualmente 3 tipos de EJB's, veja quais são:

4.6.1.1. Stateless Session Beans (SLSB)

Stateless Session Beans são EJB's que não possuem estado. Cada chamada requisita uma instância do Pool de
SLSB's. Desta forma, ele é a forma de Session Beans mais escalável que existe.

Para criarmos um SLSB precisamos seguir os passos descritos abaixo:

1. Crie o serviço o qual irá ser exportado. Nos exemplos abaixo exportaremos o serviço ProdutoService.

2. Registre a classe de implementação do Serviço com.altec...ProdutoServiceImpl no arquivo


src/META-INF/app-beans.xml. Como exemplificado abaixo:

...
<bean class="com.altec.bsbr.app.projeto.service.impl.ProdutoServiceImpl"/>
...

3. Crie a interface de negócio contendo os métodos de negócio do EJB anotando com a annotation @Remote.
Neste caso é permitido que se estenda a interface de Servico, se houver a necessidade de exportar todos os
métodos do serviço.

...
import javax.ejb.Remote;
...
@Remote
public interface ProdutoRemote {
public void criarProduto(Produto produto);
}

4. Crie a classe do EJB a qual irá expor os métodos do serviço anotando-a com a annotation @Stateless e
adicionando o Interceptor com.altec.bsbr.fw.ejb.EjbAutowiringInterceptor.

...

Framework Java Arquitetura Brasil 27


Serviços de negócio

import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
...
import com.altec.bsbr.fw.ejb.EjbAutowiringInterceptor;
...
@Stateless
@Interceptors(EjbAutowiringInterceptor.class)
public class ProdutoBean implements ProdutoRemote {
@Autowired
private ProdutoService produtoService;

public void criarProduto(Produto produto) {


produtoService.criarProduto(produto);
}
}

5. Faça o deploy do EAR.

4.6.1.2. Stateful Session Bean (SFSB)

Nota
Por questões de escalabilidade, recomendamos não usar Stateful Session Beans.

Stateful Session Bean são EJB's que possuem estado. Cada chamada requisita a mesma instância que foi
utilizada anteriormente, até que o Bean receba um status de removido ou ocorra um timeout.

Para criarmos um SFSB precisamos seguir os passos abaixo:

1. Crie o serviço o qual irá ser exportado. Nos exemplos abaixo exportaremos o serviço ProdutoService.

2. Registre a classe de implementação do Serviço com.altec...ProdutoServiceImpl no arquivo


src/META-INF/app-beans.xml. Como exemplificado abaixo:

...
<bean class="com.altec.bsbr.app.projeto.service.impl.ProdutoServiceImpl"/>
...

3. Crie a interface de negócio contendo os métodos de negócio do EJB anotado com a annotation @Remote.
Neste caso é permitido que se estenda a interface de Servico, se houver a necessidade de exportar todos os
métodos do serviço.

...
import javax.ejb.Remote;
...
@Remote
public interface ProdutoRemote {
public void criarProduto(Produto produto);
}

4. Crie a classe do EJB a qual irá expor os métodos do serviço anotando-a com a annotation @Stateful e
adicionando o Interceptor com.altec.bsbr.fw.ejb.EjbAutowiringInterceptor.

...
import javax.ejb.Stateful;
import javax.interceptor.Interceptors;
...
import com.altec.bsbr.fw.ejb.EjbAutowiringInterceptor;
...
@Stateful
@Interceptors(EjbAutowiringInterceptor.class)

Framework Java Arquitetura Brasil 28


Serviços de negócio

public class ProdutoBean implements ProdutoRemote {


@Autowired
private ProdutoService produtoService;

public void criarProduto(Produto produto) {


produtoService.criarProduto(produto);
}
}

5. Faça o deploy do EAR.

4.6.1.3. Message Driven Bean (MDB)

Este componente representa a integração do Java Enterprise Edition com a API JMS, ou seja, adiciona o
suporte a mensagens a especificação de EJB's.

Este componente está descrito em mais detalhes na seção MDB.

(1.13.6)
Capítulo 5. Logging

5.1. Introdução
O fluxo de uma aplicação deve gerar diversos eventos de Log que permitem acompanhar sua execução. O
mecanismo de Log do Framework captura estes eventos e os reporta em um destino configurado.

Para a implementação desta funcionalidade foram usadas as bibliotecas open source slf4j e Logback.

5.2. SLF4J
O Framework usa a API open source slf4j como interface de log. O slf4j provê uma simples fachada para vários
sistemas de logging. Todos os eventos de log são consumidos pelo slf4j e direcionados para o Logback que por
sua vez, fará o tratamento dos eventos baseado nos seus níveis e loggers.

O slf4j também intercepta chamadas ao Apache commons-logging usado por bibliotecas de terceiros (como o
Spring ou Hibernate) e permite que eles também recebam o mesmo tratamento dos eventos de log da aplicação.

Figura 5.1. SLF4J

O framework tem uma configuração do Logback para gravar os logs de cada aplicação em arquivos
independentes além de repassá-los ao log padrão java.util.logging (JUL) do JDK para ser tratado pelo
WebSphere de uma maneira global, consolidando os logs de todas aplicações hospedadas no servidor.

Neste guia é feita apenas uma breve introdução ao slf4j. Para maiores informações consulte o site oficial do
slf4j.

Os níveis de log suportados pelo slf4j são listados abaixo. Uma orientação de quando usar cada um desses
níveis está na seção de boas práticas

Framework Java Arquitetura Brasil 30


Logging

1. ERROR - erro

2. WARN - aviso

3. INFO - informação

4. DEBUG - debug

5. TRACE - trace

5.2.1. Obtendo o Logger

Para gerar algum evento de log é necessário ter um logger. O primeiro passo é obter a instancia do logger
desejado. A recomendação do Framework é usar o nome completamente qualificado da classe que está sendo
executada como o nome do logger. Dentro de uma classe Teste, podemos obter o logger da seguinte maneira:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
class Teste {
private static final Logger logger = LoggerFactory.getLogger(Teste.class);
}

5.2.2. Usando o Logger

Com o logger disponível, podemos chamar os métodos com os níveis desejados: trace(), debug(), info(),
warn(), error(). Os principais métodos da classe Logger são

• void trace(String msg) - loga uma mensagem no nível TRACE.

• void trace(String format, Object arg) - loga uma mensagem no nível TRACE, usando o formato
especificado com um argumento.

• void trace(String format, Object arg1, Object arg2) - loga uma mensagem no nível TRACE,
usando o formato especificado com dois argumentos.

• void trace(String format, Object[] argArray) - loga uma mensagem no nível TRACE, usando o
formato especificado com um array de argumentos. O formato da mensagem é bem simples, usando {}
como marcadores que serão substituídos pelos parâmetros, na mesma ordem em que eles aparecem.

• void trace(String msg, Throwable t) - loga uma exceção no nível TRACE, com uma mensagem.

• boolean isTraceEnabled() - verifica se o logger esta habilitado para o nível de TRACE.

• Também existe um conjunto de métodos análogos para debug, info, warn e error.

Veja um exemplo de uso abaixo:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Teste {

private static final Logger logger = LoggerFactory.getLogger(Teste.class);

Integer t;

Framework Java Arquitetura Brasil 31


Logging

Integer oldT;

public void setTemperature(Integer temperature) {


oldT = t;
t = temperature;

logger.debug("A temperatura mudou de {} para {}.", oldT, t);

if(temperature.intValue() > 50) {


logger.info("A temperatura ultrapassou 50 graus.");
}
}
}

5.3. Logback
O Framework usa a biblioteca open source Logback para fazer a geração de logs.

O Framework tem uma configuração interna do Logback que gera automaticamente as seguintes saídas de log:

• Arquivo de log da aplicação. O Logback gera um arquivo exclusivo para cada aplicação, com o nome
${application.name}.log onde application.name é valor da propriedada definida no arquivo
META-INF/config/application.properties. O arquivo é gerado no diretório definido pela propriedade
Java BASE_LOG_PATH, ou caso ela não esteja definida, no diretório corrente do processo Java. A propriedade
no formato abaixo pode ser colocada na definição do processo Java do servidor de aplicações ou
equivalente:

-DBASE_LOG_PATH=c:/temp

• Log do WebSphere. O Logback direciona todas mensagens de erro para o java.util.logging do JDK, que
vai ser tratado pelo WebSphere. Por default, todos logs de nível INFO e superior são enviados para o
arquivo SystemOut.log

A aplicação pode adicionar configurações do Logback caso seja preciso. O Framework vai carregar
automaticamente o arquivo META-INF/log/logback-runningMode.xml, caso ele exista.

No exemplo a seguir, definimos um arquivo META-INF/log/logback-dev.xml, para ser executado quando no


running mode "dev":

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

<!-- ===================================================================================== -->


<!-- Appenders -->
<!-- ===================================================================================== -->

<appender name="DEBUG_APPLICATION_LOG_FILE" class="ch.qos.logback.core.FileAppender"><co id="co-log-1" />


<File>${BASE_LOG_PATH}/${application.name}-debug.log</File><co id="co-log-2" />
<Append>false</Append>

<rollingPolicy class=ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<FileNamePattern;${BASE_LOG_PATH}/${application.name}_%.log.zip</FileNamePattern>
<MinIndex>1;/MinIndex>
<MaxIndex>10;/MaxIndex>
</rollingPolicy>

<triggeringPolicy class=”ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy”>
<MaxFileSize>5MB;/MaxFileSize>
</triggeringPolicy>

Framework Java Arquitetura Brasil 32


Logging

<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} {%X{user}} %msg%n</Pattern><co
id="co-log-3" />
</layout>
</appender>

<!-- ===================================================================================== -->


<!-- Loggers -->
<!-- ===================================================================================== -->

<root>
<level value="DEBUG"/>
<appender-ref ref="DEBUG_APPLICATION_LOG_FILE"/><co id="co-log-4" />
</root>

<!-- Hibernate =========================================================================== -->

<logger name="org.hibernate">
<level value="INFO"/><co id="co-log-5" />
</logger>
<logger name="org.hibernate.type"><co id="co-log-6" />
<level value="DEBUG"/>
</logger>

<!-- Framework JAB ======================================================================= -->

<logger name="com.altec.bsbr.fw">
<level value="DEBUG"/><co id="co-log-7" />
</logger>

<!-- Aplicacao =========================================================================== -->

<logger name="com.altec.bsbr.app.abc">
<level value="TRACE"/><co id="co-log-8" />
</logger>

</configuration>

co-log-1:
Declaramos
??? um appender chamado DEBUG_APPLICATION_LOG_FILE, que vai gerar a saída em arquivo.
co-log-2:
O arquivo
??? vai ser gerado no diretório ${BASE_LOG_PATH} com o nome ${application.name}-debug.log.
co-log-3:
Foi usado
??? um formato de mensagem de log customizado.
co-log-4:
O appender
??? deve ser atribuído ao logger raíz.
co-log-5:
Definimos
??? o nível INFO para org.hibernate.
co-log-6:
Definimos
??? o nível DEBUG para org.hibernate.type.
co-log-7:
Definimos
??? o nível DEBUG para com.altec.bsbr.fw, as classes do Framework.
co-log-8:
Definimos
??? o nível TRACE para com.altec.bsbr.app.abc, as classes da aplicação abc.

No framework, o tamanho suportado para log é de até de 10M, ao atingir este tamanho o arquivo é zipado e um
novo arquivo de log será ativado.

Fica a critério do usuário configurar a quantidade de logs zipados. Por exemplo, o usuário pode decidir por
excluir um zip (mais antigo) a cada 30 zips.

Para maiores informações sobre configuração consulte o manual do Logback.

5.4. Boas práticas


Nesta seção são feitas algumas recomendações de boas práticas de uso de logs, que se seguidas, podem
aumentar a facilidade de manutenção do sistema, e a detecção de problemas tanto em tempo de
desenvolvimento como produção.

5.4.1. Não use System.out ou System.err

(1.13.6)
Logging

Use a API do slf4j ao invés de escrever direto na saída padrão ou de erros.

O uso direto de System.out para a geração de logs tem uma série de desvantagens:

• Não permite que os logs obedeçam a níveis.

• Não pode ser desligado sem alterar o programa.

• Não permite a separação em arquivos.

• Não permite configuração em loggers.

Portanto, use sempre o slf4j!

5.4.2. O logger de uma classe deve ser um atributo privado, estático e final

Veja o exemplo:

class Exemplo {
...
private static final Logger logger = ...;
...
}

5.4.3. Use o nome da classe executada como nome do logger

Usando o nome completamente qualificado da classe que está sendo executada como o nome do logger,
podemos agrupar os logger usando a mesma hierarquia de pacotes da aplicação. Essa estratégia tem a vantagem
de podermos configurar o nível de log desejado para cada pacote.

No trecho de código abaixo, usamos o método getLogger(Class) do slf4j para obter um logger com o nome da
classe passada como parâmetro:

class Exemplo {
...
private static final Logger logger = LoggerFactory.getLogger(Exemplo.class);
...
}

Importante
Cuidado ao fazer um copy and paste desse trecho de código! Lembre sempre de colocar o nome da
classe para onde você estiver copiando.

5.4.4. Use o nível de log adequado

Cada nível de log, deve ser usado para fins específicos. Os níveis existentes no log4j são:

Nível Descrição

ERROR Indica uma situação de erro ou exceção, um desvio do processamento normal.


Erros geralmente não podem ser recuperados de forma satisfatória, portanto
devem ser logados. Observação: Nem toda Exception que ocorrer num programa
é necessariamente um erro.

(1.13.6)
Logging

Nível Descrição

WARNING Indica a ocorrência de alguma situação anormal, mas que não impede a
continuidade do processamento, e pode gerar algum resultado inesperado.
Também pode indicar a recuperação de uma situação de erro.

INFO Indica alguma informação de interesse. É uma situação normal e continua com o
processamento normalmente. Geralmente mostra eventos de interesse durante a
operação em produção.

DEBUG Contém informações de debug e é usado durante o desenvolvimento ou na


detecção de problemas. Mostra informações internas do sistema e descreve o
comportamento dos componentes internos do sistema

TRACE Similar a DEBUG, mas num nível de detalhe e profundidade maior. Pode
potencialmente mostrar um grande volume de informações.

É essencial o entendimento dessas definições por todos integrantes do time de desenvolvimento, para que os
níveis de log sejam usados de maneira consistente em todo o sistema.

Nunca esqueça que...


...se aplicação funciona do modo esperado, a geração de logs de nível INFO e superior deve ser
sucinta. Se algo fora do planejado ocorrer, o log deve comunicar o fato da maneira mais clara
possível.

5.4.5. Escreva as mensagens de log pensando no público alvo

Cada nível de log tem um público alvo, portanto escreva as mensagens de log de cada nível tendo em mente
quem vai ve-las. A informação deve ser mais ou menos descritiva dependendo do nível.

Por exemplo, os níveis INFO para cima serão vistos pelo operador no ambiente de produção, enquanto os
níveis de DEBUG e TRACE pelo desenvolvedor.

5.4.6. Não faça várias chamadas de log para informações relacionadas

E bastante comum fazer o log de vários valores como abaixo:

public void aMethod(String id, int value, boolean activated) {


if (logger.isDebugEnabled()) {
logger.debug("id=" + id);
logger.debug("value=" + value);
logger.debug("activated=" + activate);
}
...
}

No entanto, num ambiente com muitos threads em execução simultaneamente, as mensagens de log podem
ficar intercaladas com outras, dificultando achar um correlacionamento entre elas. Neste caso, seria mais
apropriado o seguinte:

public void aMethod(String id, int value, boolean activated) {


if (logger.isDebugEnabled()) {
logger.debug("id=" + id + " value=" + value + " activated=" + activate);
}
...
}

Framework Java Arquitetura Brasil 35


Logging

5.4.7. Não dependa de logs em diferentes níveis para obter uma


informação

Considere o trecho de código abaixo:

private void doStuff(String name) {


logger.debug("name=" + name);
String value = giveMeTheValueFor(name);
if (value == null) {
logger.warn("value not found, using default.");
value = ...
}
...
}

Se a configuração do log mostra até o nível DEBUG, não há problema. Mas se o log estiver configurado para
mostrar apenas os níveis de WARNING e ERROR, o warning vai ser inútil, pois não vai mostrar todos dados
relevantes. Portanto, toda informação necessária para entender a situação deve estar contida num mesmo nível
de log.

5.4.8. Considere o custo de geração do log

Ocasionalmente, o custo de geração da mensagem de log pode ser muito alto. Por exemplo, no trecho abaixo,
existe o custo de converter o inteiro i e entry[i] em String e concatenar as strings intermediárias. Isso vai
ocorrer sendo a mensagem logada ou não.

logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));

Uma maneira de evitar esse custo quando a mensagem não for logada, é fazendo um teste antes:

if (logger.isDebugEnabled()) {
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
}

Uma boa alternativa é usar mensagens parametrizadas no log, pois os parâmetros só vão ser convertidos para
String, caso a mensagem de log seja mesmo gerada.

Object entry = new SomeObject();


logger.debug("The entry is {}.", entry);
logger.debug("The entry is " + entry + ".");

Atenção
O uso de mensagens parametrizadas apenas elimina o custo de conversão para String. Caso exista a
chamada de algum método que tenha um considerável custo de execução, a única solução é fazer o
teste antes de chamar o log:

if (logger.isDebugEnabled()) {
logger.debug("Taxa: {}", calculaTaxaComplicada());
}

5.4.9. Faça suas classes "logáveis"

Implemente o método toString(), para expor o estado de seus objetos de uma maneira legível. O método

Framework Java Arquitetura Brasil 36


Logging

toString() deve obedecer as seguintes regras:

• Ele não deve falhar nunca. (Cuidado para não ocorrer NullPointerException!)

• Ele deve mostrar o nome da classe.

Exemplo de método toString() que mostra as propriedades de um objeto:

public String toString(){


StringBuffer sb = new StringBuffer();
sb.append(getClass().getName())
sb.append(" myProperty=[").append(this.myProperty).append("]");
sb.append(" anotherProperty=[").append(this.anotherProperty).append("]");
return sb.toString();
}

Outra possibilidade para criar o método toString() é usar a biblioteca commons-lang que fornece a classe
ToStringBuilder que usa reflexão para criar um toString() com todos os atributos do objeto de uma forma
dinâmica (note que isso pode não ser desejável, por conter dados que podem ser irrelevantes e só dificultam a
leitura dos valores). Exemplo de uso:

public String toString() {


return ToStringBuilder.reflectionToString(this);
}

A classe ToStringBuilder também pode ser usada diretamente no log para mostrar dados de classes de
terceiros, e que não tenham um toString() amigável:

logger.debug("Um objeto: " + ToStringBuilder.reflectionToString(umObjeto));

5.4.10. Use Arrays.asList(Object[]) para logar arrays de objetos

Quando usamos o método toString() de um array em Java, obtemos uma representação que pode não ser
muito útil:

Object[] foo = {"bar", "baz"};


System.out.println(foo);

[Ljava.lang.Object;@e0b6f5

Para obter uma saída mais informativa podemos usar os métodos Arrays.asList(Object[]) ou
Arrays.deepToString(Object[]) presentes no pacote java.util do Java 5:

import java.util.Arrays;

Object[] foo = {"bar", "baz"};


System.out.println(Arrays.asList(foo));
System.out.println(Arrays.deepToString(foo));

[bar, baz]
[bar, baz]

Portanto, quando for preciso logar algum objeto array, é recomendado usar um dos métodos acima, para
facilitar a leitura dos resultados.

(1.13.6)
Logging

5.5. Log de serviços


O Framework faz automaticamente o log de informações referentes as chamadas a métodos da camada de
serviços, sem que seja necessária nenhuma intervenção do programador.

5.5.1. Log da chamada de serviços

O Framework faz automaticamente um log da entrada e saída de todas as chamada a métodos da camada de
serviços.

Mensagens com nível de DEBUG são geradas contendo informações dos parâmetros de entrada do método e os
valores retornados. A entrada do método é marcada com >> e a saída com <<, como mostrado no exemplo de
saída abaixo:

...
>> findAll(class com.altec.bsbr.app.abc.entity.Categoria,10)
<< findAll -> ArrayList[size=5]
...
>> get(class com.altec.bsbr.app.abc.entity.Estoque,2872,false)
<< get -> com.altec.bsbr.app.abc.entity.Estoque@2b942b94[codigo=2872,quantidade=16,preco=10,
produto=com.altec.bsbr.app.abc.entity.Produto@29aa29aa[codigo=2862,nomeTitulo=Ritchie Blackmore's
Rainbow,nomeArtista=Rainbow,anoLancamento=1975,
categoria=com.altec.bsbr.app.abc.entity.Categoria@2ac62ac6[codigo=2635,nome=Rock]]]
...
>> findByCategoria(<null>)
<< findByCategoria -> ArrayList[size=0]
...

Nota
Para a impressão dos parâmetros é usado o método toString() do objeto, ou se não houver, o
ToStringBuilder do commons-lang.

5.5.2. Log de estatísticas de serviços

Ao término da execução de cada método de serviço, é gerada uma mensagem com nível de DEBUG, contendo
algumas estatísticas das chamadas àquele método:

-- findAll: Hits=9.0, LastValue=12.0, Min=10.0, Max=228.0, Avg=65.66666666666667, Total=591.0,


StdDev=77.23, FirstAccess=Tue Sep 02 15:25:12 BRT 2008, LastAccess=Tue Sep 02 15:31:03 BRT 2008

Uma descrição dos parâmetros mostrados está na seção sobre gerenciamento de serviços

(1.13.6)
Capítulo 6. Uso de exceções

6.1. Introdução

Tipos de exceções

Em Java, os erros em tempo de execução (também conhecidos como exceções) são classificados como checked
e unchecked.

Exceções checked: são aquelas que obrigatoriamente devem ser tratadas pelo chamador, o que é verificado em
tempo de compilação. Assim, quando um método de negócio é construído, na sua assinatura são definidas as
exceções checked que podem ocorrer mediante circunstâncias diversas quando da sua chamada. Todos
elementos do sistemas que utilizarem esse método devem tratar a possível ocorrência dessas exceções. Uma das
vantagens de exceções checked é impedir que um programador desavisado esqueça de fazer o tratamento de
uma exceção gerada na camada de negócio e isso venha ocasionar um fluxo não esperado ou não tratado no
sistema, culminando muitas vezes na parada da aplicação ou em mensagens de erros sistêmicas para o
operador.

Exceções unchecked: são aquelas onde sua ocorrência é não determinística. Exemplos desse tipo de exceção
são a falta de memória, manipulação indevida variáveis, ponteiros nulos, etc. Esses erros podem ser tratados
mas necessitam que o programador se atente na possibilidade e circunstâncias pelas quais eles podem
acontecer. No entanto, sempre alguns casos escapam da análise e acabam ocasionando o mal funcionamento da
aplicação ou em mensagens de erros não tratadas para o operador do sistema.

A forma como um sistema lança e trata exceções pode ter um forte impacto na sua robustez e como ele vai se
comportar em operações do dia a dia.

Quando devemos lançar uma exceção? Quando o método encontrar uma situação anormal que ele não pode
tratar, uma exceção deve ser lançada.

E quando devemos tratar uma exceção? Quando o chamador do método souber e quiser tomar alguma medida
corretiva do erro ocorrido.

Pra resolver esses problemas, o Framework fornece algumas exceções base, e possui uma estratégia padrão já
implementada de tratamento de exeções na camada de serviços.

6.2. Uso de exceções


O Framework estabelece dois tipos de exceções a serem usadas pelo desenvolvedor:

• BusinessException: exceção checked para ser usada em erros de negócio, e que vão ser tratados pela
aplicação. A ocorrência de uma BusinessException deve ser considerada como parte do fluxo normal da
aplicação, não como um bug nem como uma condição de erro que venha a precisar de alguma intervenção
em produção.

Um exemplo seria SaldoNegativoException, que a aplicação trataria mostrando uma mensagem


"Operação não pode ser realizada pois o saldo está negativo".

Framework Java Arquitetura Brasil 39


Uso de exceções

• SystemException: exceção unchecked usada para sinalizar situações fora do curso esperado da aplicação, e
que não são tratadas explicitamente. A ocorrência de uma SystemException deve ser considerada anormal,
e para sua correção normalmente e necessário uma intervenção externa. Situações onde onde é
recomendado o uso da SystemException:

• Falhas do sistema ou de sistemas dependentes.

• Falhas de comunicação ou acesso a recursos.

• Uso indevido de classes ou métodos pelo programador.

• Bugs do sistema.

• FaultException: exceção unchecked de uso interno do Framework, usada para encapsular informações de
outras exceções capturadas na camada de serviços. É a classe base de SystemException.

Desta forma, a camada cliente irá tratar sempre esses tipos básicos de exceções. Nesses moldes, o framework
irá facilitar o rastreio de erros a partir do registro formatado da exceção em log, identificador para o elemento
causador da exceção e informações sobre a fonte causadora do erro.

O desenvolvedor, pode estender as classes BusinessException e SystemException, para criar as suas próprias
exceções, de acordo com as necessidades específicas da aplicação.

6.2.1. O uso de BusinessException

O uso típico de BusinessException é como uma classe base para a criação de exceções de negócio específicas
da aplicação.

public class SaldoNegativoException extends BusinessException {

private BigDecimal saldoAtual;

public SaldoNegativoException(BigDecimal saldo) {


super("Saldo negativo: " + saldo);
saldoAtual = saldo;
}

public BigDecimal getSaldoAtual() {


return saldoAtual;
}

Então, algum serviço da camada de negócios poderá usar essa BusinessException da declaração de um método:

@Service
public ContaCorrenteServiceImpl {

public void efetuaSaque(Integer numeroConta, BigDecimal valor) throws SaldoNegativoException {


...
BigDecimal saldo = conta.getSaldo();
if (saldo.signum() == -1)
throw new SaldoNegativoException(saldo);
...
}

E a camada de apresentação deve tratar essa exceção, quando chamar o serviço:

try {

Framework Java Arquitetura Brasil 40


Uso de exceções

contaCorrenteService.efetuaSaque(numeroConta, valor);
}
catch (SaldoNegativoException e) {
String mensagem = "Operação não pode ser realizada pois o saldo está negativo: " + e.getSaldoAtual();
// Mostra a mensagem de erro para o usuário explicando o motivo da não transferência
}

6.2.2. O uso de SystemException

Para instanciar uma SystemException é necessário passar um objeto do tipo ErrorMessage. Assim, todas as
possíveis exceções devem ter uma mensagem mapeada numa subclasse de com.altec.bsbr.fw.ErrorMessage
específica para cada aplicação.

A classe de mensagens de erro deve ter todos as instâncias de erros como atributos estáticos como no exemplo
abaixo:

public class MyErrorMessage extends ErrorMessage❶ {

public static final❷ MyErrorMessage MEU_ERRO = new MyErrorMessage(101, "Erro...");❸


public static final MyErrorMessage OUTRO_ERRO = new MyErrorMessage(102, "Valor {0} inválido");

protected MyErrorMessage(int code, String message) {


super(code, message);❹
}

❶ Deve estender ErrorMessage.


❷ Cada instância deve ser public static final.
❸ Cada instância deve ser criada com o construtor protected.
❹ Deve ser chamado o construtor da superclasse, passando o código da mensagem, e o seu formato. O
formato é o definido pela classe java.text.MessageFormat, e pode receber um número variável de
parâmetros.

Essa classe de erros pode então ser usada com SystemException:

throw new SystemException(MyErrorMessage.OUTRO_ERRO, param);

6.3. Tratamento de exceções em serviços


Existe um tratamento padrão de exceções para toda classe de serviço do Framework. Este tratamento irá
garantir que toda exceção ocorrida na camada de negócio – mesmo inesperada – seja filtrada, tratada e
encapsulada em exceções bem definidas pelo Framework podendo ser capturadas e direcionadas da forma mais
adequada pelo chamador.

Quando uma exceção resulta da chamada de um serviço, o Framework procede com o seguinte tratamento:

• Faz um log indicando término do método por causa de uma exceção.

• Se a exceção for BusinessException, ela é lançada novamente e o processamento continua.

• Caso contrário, encapsula a exceção numa FaultException, faz um log de erro, e lança a FaultException
no lugar da original. O log contem os dados abaixo:

Framework Java Arquitetura Brasil 41


Uso de exceções

• Identificador de ocorrência. Esse identificador de ocorrência é um número seqüencial gerado


automaticamente pelo Framework que pode ser usado para rastrear um erro visualizado no cliente (que
contenha esse id) com uma exceção específica no arquivo de log do servidor.

• Timestamp.

• Serviço.

• Método.

• Argumentos da chamada ao método.

• A exceção.

• A exceção raiz (a primeira a acontecer e que acarretou no erro).

• Stack trace da exceção raiz.

Exemplo de mensagem gerada no arquivo de log, quando da ocorrência de um SystemException dentro do


método de serviço criaPedido():

<< criaPedido -> EXCEPTION [15] [1: Null argument]


# Error code: 1
# Ocurrence: 15
# Timestamp: Mon Oct 06 20:25:51 BRT 2008
# Service: com.altec.bsbr.app.abc.service.impl.TestServiceImpl@79dc79dc
# Method: criaPedido
# Arguments: Jorge da Silva,230.2,0412X,Tue Aug 05 16:48:56 BRT 2008,<null>
# Exception: [1: Null argument]
# Stack:
com.altec.bsbr.fw.SystemException: [1: Null argument]
at com.altec.bsbr.app.abc.service.impl.TestServiceImpl.criaPedido(TestServiceImpl.java:26)
...

O encapsulamento automático de exceções na camada de negócios, facilita o trabalho de tratamento de erros na


interface de visualização do sistema. Além disso, o Framework coleta e registra em log as informações
necessárias para que o erro possa ser isolado, reproduzido e corrigido.

6.3.1. Controle transacional e exceções

Conforme descrito na seção sobre transações e serviços, os métodos da camada de negócios tem o controle
transacional feito automaticamente pelo Framework.

Quando um método do serviço tem a anotação @Transactional esse código será executado dentro de uma
transacão. Caso o método termine por causa de alguma exceção, o comportamente padrão é finalizar a
transação com um rollback. Se ele terminar normalmente, será feito um commit da transação.

Portanto, uma maneira simples de causar um rollback da transação é simplesmente lançar uma exceção
(BusinessException ou SystemException) dentro de um serviço, quando for desejado que não seja feito commit
da transação em uso.

6.4. Boas práticas no uso de exceções


O uso dessas boas práticas no uso de exceções, pode tornar o código mais robusto e fácil de manter.

(1.13.6)
Uso de exceções

6.4.1. Tratando exceções.

6.4.1.1. Não ignore exeções

Se algum erro ocorreu, alguma medida deve ser tomada.

Nota
Um erro muito comum é colocar apenas um log da exceção dentro do catch e continuar ou retornar
como se nada tivesse acontecido... Obviamente isso pode acarretar erros ainda mais graves
posteriormente.

No entanto, se voce não souber como tratar a exceção que aparecer, deixe-a passar, que em algum
momento ela será tratada por alguem. (O Framework possui um tratamento padrão na camada de
serviços, deixe que ele cuide disso)

6.4.1.2. Trate a exceção mais específica que for possível

Apenas faça o catch de uma superclasse quando tiver certeza que todas as subclasse tem o mesmo significado e
podem ser tratadas da mesma maneira.

6.4.1.3. Log de exceções

Não é necessário fazer o log de uma exceção se ela está sendo apenas relançada ou sendo traduzida para uma
outra exceção, senão, essa exceção será logada repetidas vezes, atrapalhando a leitura do arquivo de logs.

6.4.2. Lançando exceções.

6.4.2.1. Não lançe Exception ou Throwable

Nunca lançe uma exceção genérica como Exception ou Throwable.

Use uma exceção apropriada para a situação ocorrida, ou crie uma nova classe de exceção.

6.4.2.2. Exceções indicam quebra de contrato

Se o método descobrir que o cliente não obedeceu ao contrato (passando dados inválidos, por exemplo) uma
exceção deve ser lançada.

Se o método não puder cumprir seu contrato, ele pode lançar uma exceção, de preferência unchecked, pois não
é razoável esperar que o cliente trate sempre essa situação fora do normal.

6.4.2.3. Não coloque muitas exceções na cláusula throws de um método

Isso pode significar que:

• A implementação está sendo exposta como parte da interface do método, dificultando modificações futuras.

• O método está fazendo coisas demais e deveria ser dividido.

6.4.3. Definindo classes de exceção

(1.13.6)
Uso de exceções

Se você não quiser propagar uma exceção, pode traduzi-la para uma outra exceção dentro do domínio de
negócio que faça sentido para o cliente do método.

Voce pode criar uma classe de exceção para indicar erros que fazem parte do domínio de negócio. Lembre que
exceções só devem ser usadas para situações anormais, e que não fazem parte do fluxo natural de operação.

Dica
Lembre-se de acrescentar informações importantes sobre o erro na exceção. Assim o cliente terá
condições de tomar as medidas adequadas.

Use a classe com.altec.bsbr.fw.BusinessException como base para exceções de negócio.

Numa situação onde podem ocorrer muitos tipos de exceções diferentes, elas podem ser agrupadas em apenas
uma exceção específica para a situação. Isso facilita o cliente do método, que precisa tratar apenas uma
exceção. Além disso a interface do método se torna mais estável, não sendo afetada por mudanças internas do
método que poderiam acarretar em colocar ou retirar as exceções da assinatura do método.

Use a classe com.altec.bsbr.fw.SystemException como base para exceções de implementação, que não são
de negócio.

Importante
É importante que numa situação de tradução de uma exceção por outra, a exceção original seja
encapsulada, para preservar o problema original, o que pode ser vital para resolver o problema. A
exceção original pode ser obtida com o método getCause() da classe Exception.

Framework Java Arquitetura Brasil 44


Capítulo 7. Persistência

7.1. Introdução
A camada de persistência é responsável por fazer o acesso a bancos de dados. O mecanismo de persistência do
Framework é baseado em:

• JPA (Java Persistence API) usando o provider Hibernate 3.3. Com essa tecnologia é possível criar um
modelo de persistência independente de banco de dDados, pois os comandos SQL são gerados
automaticamente pelo Provider JPA.

• JDBC, acessando diretamente o banco de dados através de SQL.

A escolha adequada para cada situação depende da característica de acesso ao banco e a requisitos não
funcionais do projeto em questão.

O encapsulamento do mecanismo de persistência é feito usando o padrão DAO (Data Acess Object), por ser
bem conhecido e eficiente.

A principal vantagem desse padrão é expor uma API independente da tecnologia de persistência que será
utilizada pela camada de negócio. Caso seja necessário uma alteração no mecanismo de persistência em
decorrência de uma customização, evolução ou busca por melhor performance, a camada de negócio não é
impactada pois o padrão DAO proporciona desacoplamento entre a infra-estrutura de persistência e lógica de
negócio.

Sobre JPA
JPA ou Java Persistence API: Simplifica o modelo de persistência de entidades em Java
acrescentando um novo modo de mapeamento de entidades, usando Annotations. Além disso,
centraliza o acesso as entidades em um componente único chamado
javax.persistence.EntityManager.

JPA baseou-se nos principais frameworks de persistência existentes no mercado, como: Hibernate,
Oracle TopLink e Java Data Objects (JDO), para criar uma API que possua as melhores
características de cada um deles. Desta forma, é possível que existam várias implementações de
diferentes fornecedores.

No Framework foi usada a implementação do Hibernate.

Para mais informações veja o JEE 5 Tutorial - Part V Persistence e o site do Hibernate.

7.2. DAO - Data Access Object


No Framework existem 4 tipos básicos de DAOs implementados:

• GenericJpaDao

• GenericHibernateJpaDao

• CrudJpaDao

Framework Java Arquitetura Brasil 45


Persistência

• GenericJdbcDao

7.2.1. JPA

Para auxiliar na construção de DAOs que usam JPA, o Framework oferece algumas classes base.

7.2.1.1. GenericJpaDao

com.altec.bsbr.fw.dao.jpa.GenericJpaDao<T, ID>: Esta é uma classe abstrata a qual oferece métodos


básicos de persistência utilizando-se JPA.

A classe com.altec.bsbr.fw.dao.jpa.GenericJpaDao<T, ID> possui 2 parâmetros genéricos T e ID, onde em


geral, T é o tipo de uma entidade mapeada e o parâmetro ID o tipo do identificador (chave) da entidade.
Exemplo:

@Repository
pubic class FooDaoImpl extends GenericJpaDao <FooEntity❶, Long❷> implements FooDao {
...
}

❶ Tipo da entidade.
❷ Tipo do ID da classe de entidade, a classe que representa a chave primária.

Abaixo detalhamos alguns métodos da classe

• persist(T entity): Persiste uma entidade T, caso a entidade já exista no Banco ela atualiza seu estado, ou
seja, executa um UPDATE, caso a entidade não exista ela é criada, ou seja, executa um INSERT.

• remove(T entity): Remove uma entidade T do banco de dados, ou seja, executa um DELETE. O objeto em
memória continua a existir mas não é mais persistente.

• findById(ID id, boolean lock): Retorna uma instância do objeto com o ID e faz o lock da entidade caso
seja passado true.

• findAll(int maxResults): Retorna uma List <T> do tipo genérico definido, com um limite máximo de
resultados.

• findByQuery(String queryString, Object... params): Retorna uma List <T> utilizando uma JPA-QL.

Exemplo:

@Repository
public class AnimalDaoImpl extends GenericJpaDao implements AnimalDao {
public List<Animal> findAnimais(String nome) {
String jpaQuery = "select a from Animal a where a.nome=?1";
return findByQuery(jpaQuery, nome);
}
}

• findOneByQuery(String queryString, Object... params): Retorna uma única instância utilizando uma
JPA-QL.

Exemplo:

@Repository
public class AnimalDaoImpl extends GenericJpaDao implements AnimalDao {
public Animal findAnimalById(Long id) {

Framework Java Arquitetura Brasil 46


Persistência

String jpaQuery = "select a from Animal a where a.id=?1";


return findOneByQuery(jpaQuery, id);
}
}

• findByQueryWraper(QueryWrapper queryWrapper, Object... params): Retorna uma List <T>


utilizando um com.altec.bsbr.fw.dao.jpa.GenericJpaDao.QueryWrapper. Esta interface permite que o
próprio desenvolvedor faça o set dos parâmetros de acordo com sua necessidade. Abaixo mostramos a a sua
definição:

interface QueryWrapper {
public String getQueryString();❶
public void setParam(int index, Query query, Object value);❷
}

❶ Este método retorna a query JPA.


❷ Este método é utilizado para setar o parametro de acordo com a necessidade. Onde index é o índice
dos parâmetros da query, e query é a instância da query a qual será usada para setar os valores, e
value é o valor do parâmetro referente a esse índice que deve ser setado na query.

Exemplo:

@Repository
public class AnimalDaoImpl extends GenericJpaDao<Animal, Long> implements AnimalDao {
public List<Animal> findAnimais(String nome, boolean val) {
QueryWrapper queryWrapper = new QueryWrapper() {
public String getQueryString() {
return "select a from Animal a where a.nome=?1 and a.ativo=?2";
}
public void setParam(int index, Query query, Object value) {
switch (index) {
case 1: {
query.setString(index, (String)value);
break;
}
case 2: {
Boolean booleanVal = value;
String simNaoVal = (booleanVal ? "T" : "F");
query.setString(index, simNaoVal);
break;
}
}
}
};
return findByQuery(jpaQuery, nome);
}
}

• getEntityBeanType(): Retorna o tipo Generico da classe.

• getEntityManager(): Retorna uma instância do EntityManager.

Abaixo segue uma lista de referências sobre JPA:

JEE 5 Tutorial - Part V Persistence

Java Persistence API

Hibernate Entity Manager

Nota

Framework Java Arquitetura Brasil 47


Persistência

Para usar com vários PersistenceUnits consulte a seção 4.4.

7.2.1.2. GenericHibernateJpaDao

com.altec.bsbr.fw.dao.jpa.GenericHibernateJpaDao<T, ID>: é uma classe abstrata que estende de


GenericJpaDao oferecendo métodos que utilizam recursos específicos do Hibernate, como Criteria e
Example.

Esta classe possui 2 parâmetros genéricos T e ID, onde em geral, T é o tipo de uma entidade mapeada, e o
parâmetro ID é o tipo do identificador (chave) da entidade. Exemplo:

@Repository
public class FooDaoImpl extends GenericHibernateJpaDao <FooEntity❶, Long❷> implements FooDao {
...
}

❶ Tipo da entidade.
❷ Tipo do id da classe de entidade.

Abaixo detalhamos alguns métodos da classe

• findByExample(T exampleInstance, String... excludeProperty): Retorna uma List <T> utilizando


as propriedades da classe como parâmetros da Query caso não estejam no String[] excludeProperty.

Exemplo:

@Repository
public class AnimalDaoImpl extends GenericHibernateJpaDao<Animal, Long> implements AnimalDao {
public List<Animal> findByNome(String nome) {
Animal example = new Animal();
example.setNome(nome);
return findByExample(example, "id", "ativo");
}
public List<Animal> findByMesmaEspecie(Animal example) {
return findByExample(example, "id", "ativo");
}
}

• findOneByExample(T exampleInstance, String... excludeProperty):


Retorna uma instância T
utilizando as propriedades da classe como parâmetros da Query caso não estejam no String[]
excludeProperty.

Exemplo:

@Repository
public class AnimalDaoImpl extends GenericHibernateJpaDao<Animal, Long> implements AnimalDao {
public Animal findById(Long id) {
Animal example = new Animal();
example.setId(id);
return findOneByExample(example, "nome", "ativo");
}
}

• findByCriteria(org.hibernate.criterion.Criterion... criterion): Retorna uma List <T>


utilizando a criteria.

Exemplo:

@Repository
public class AnimalDaoImpl extends GenericHibernateJpaDao<Animal, Long> implements AnimalDao {

(1.13.6)
Persistência

public List<Animal> findByNome(String nome) {


return findByCriteria(org.hibernate.criterion.Restrictions.add(
org.hibernate.criterion.Restrictions.eq("nome", nome));
}
}

• findOneByCriteria(Criterion... criterion): Retorna uma instância T utilizando a criteria.

Exemplo:

@Repository
public class AnimalDaoImpl extends GenericHibernateJpaDao<Animal, Long> implements AnimalDao {
public Animal findById(Long id) {
return findOneByCriteria(org.hibernate.criterion.Restrictions.add(
org.hibernate.criterion.Restrictions.eq("id", id));
}
}

• findUsingCallback(HibernateCallback callback): Retorna uma List<T> utilizando uma instância da


classe org.springframework.orm.hibernate3.HibernateCallback. Esta classe permite que se tenha
acesso a org.hibernate.Session, permitindo assim uma maior flexibilidade na configuração do acesso a
dados.

Exemplo:

@Repository
public class AnimalDaoImpl extends GenericHibernateJpaDao<Animal, Long> implements AnimalDao {
public Animal findByNome(String nome) {
HibernateCallback callback = new HibernateCallback() {
public Object doInHibernate(Session session) {
return session.createCriteria(Animal.class).add(
Restrictions.add(Restrictions.eq("nome", nome)))
.setCacheable(true).setCacheMode(CacheMode.NORMAL)
.setCacheRegion("default").list();
}
};
return findUsingCallback(callback);
}
}

Para mais informações veja SpringFramework API - HibernateCallback.

• findOneUsingCallback(HibernateCallback callback): Retorna uma T utilizando uma instância da classe


org.springframework.orm.hibernate3.HibernateCallback. Esta classe permite que se tenha acesso a
org.hibernate.Session, permitindo assim uma maior flexibilidade na configuração do acesso a dados.

Exemplo:

@Repository
public class AnimalDaoImpl extends GenericHibernateJpaDao<Animal, Long> implements AnimalDao {
public Animal findById(Long id) {
HibernateCallback callback = new HibernateCallback() {
public Object doInHibernate(Session session) {
return session.createCriteria(Animal.class).add(
Restrictions.add(Restrictions.eq("id", id)))
.setCacheable(true).setCacheMode(CacheMode.NORMAL)
.setCacheRegion("default").list();
}
};
return findUsingCallback(callback);
}
...
}

(1.13.6)
Persistência

Para mais informações veja SpringFramework API - HibernateCallback.

• Nesta classe você encontrará


ainda os métodos que são herdados da classe
com.altec.bsbr.fw.dao.jpa.GenericJpaDao.

Nota
Para usar com vários PersistenceUnits consulte a seção 4.4.

7.2.1.3. CrudJpaDaoImpl

com.altec.bsbr.fw.dao.jpa.CrudJpaDaoImpl: é uma classe que possui suporte a generics e que possibilita


instanciar um DAO Genérico. Este DAO possui a infra-estrutura básica para acesso ao banco de dados
utilizando JPA através de operações simples.

Em muitas situações é necessário apenas um acesso comum de criar, listar, atualizar e apagar. Para essas
situações existe a classe com.altec.bsbr.fw.dao.jpa.CrudJpaDaoImpl.

Importante
Esta classe não pode ser estendida. Ela deve apenas ser usada nos casos específicos exemplificados
acima.

Abaixo detalhamos alguns métodos:

• persist(T entity): Persiste uma entidade T, caso a entidade já exista no Banco ela atualiza seu estado, ou
seja, executa um UPDATE, caso a entidade não exista ela é criada, ou seja, executa um INSERT.

• remove(Class<?> entityType, Serializable id):


Remove uma entidade de tipo T com o id
especificado do banco de dados, ou seja, executa um DELETE.

• findById(Class<?> entityType, Serializable id, boolean lock): Retorna uma instância da entidade
entityType utilizando o id e efetuando o lock caso seja true.

• findAll(Class<?> entityType, int maxResults): Retorna uma List <T> que tenha até no máximo a
quantidade maxResults. Este método executa um SELECT sem clausula WHERE, portanto é importante
definir um número máximo de resultados.

7.2.2. JDBC

O Framework também suporta o uso direto de comandos SQL através da API JDBC usada da forma descrita a
seguir.

7.2.2.1. GenericJdbcDao

Esta classe possibilita que se faça o acesso direto ao Banco de Dados usando a API JDBC. Este modelo de
acesso deve ser usado com cautela, pois aumenta o acoplamento da aplicação com o banco de dados,
dificultando a manutenção da aplicação e tornando difícil adicionar recursos como cache.

Esta é uma classe abstrata a qual estende de SimpleJdbcDaoSupport oferencendo suporte a acesso ao banco
utilizando JDBC. Através desse DAO é possível obter uma instância da classe SimpleJdbcTemplate
utilizando-se o método getSimpleJdbcTemplate(). Essa classe disponibiliza uma série de alternativas para se

Framework Java Arquitetura Brasil 50


Persistência

executar comandos SQL de tal forma que não é necessário utilizar a API JDBC de baixo nível, como
PreparedStatement, ResultSet, etc. Esta abstração trás vantagens em produtividade.

Nota
Para usar com vários DataSources consulte a seção 4.4.

7.2.2.2. Executando comandos SQL

Para executar comandos SQL utiliza-se a classe SimpleJdbcTemplate por uma série de métodos de acesso ao
banco de dados. Ela facilita o desenvolvimento, não sendo necessário preocupar-se com fechamento de
conexões e tratar ResultSets, além disso ela possui métodos que quando usados com Java 5 facilitam ainda
mais.

O uso para situações simples se torna trivial:

int rowCount = getSimpleJdbcTemplate().queryForInt("select count(*) from t_accrual");

List<Map<String,Object>> produtos = getSimpleJdbcTemplate().queryForList(


"select * from PRODUTOS where TIPO=? and PRECO > ?", tipo, valor);

Exemplo de um GenericJdbcDao:

@Repository
public class EstoqueJdbcDaoImpl extends GenericJdbcDao implements EstoqueDao {

public List<Estoque> findByNome(String desc) {


String query = " select e.CD_ESTQ, e.QT_PROD, e.VL_PREC_PROD, "
+ " p.CD_PROD, p.NM_TITU_PROD, p.NM_ARTI, p.AN_LANC, "
+ " p.IM_PROD, c.CD_CATG, c.NM_GENR_MUSI "
+ " from JAB.TB_ESTQ e, JAB.TB_PROD p, JAB.TB_CATG c "
+ " where e.CD_PROD = p.CD_PROD and p.CD_CATG = c.CD_CATG and "
+ " p.NM_TITU_PROD like %?% and p.NM_ARTI like %?% ";

ParameterizedRowMapper<Estoque> paramRowMapper = new ParameterizedRowMapper<Estoque>() {


public Estoque mapRow(ResultSet rs, int rowNum) throws SQLException {

Categoria cat = new Categoria(


rs.getLong(8),
rs.getString(9));

Produto prod = new Produto(


rs.getLong(4),
rs.getString(5),
rs.getString(6),
rs.getDate(7),
rs.getBytes(8),
cat);

return new Estoque(


rs.getLong(1),
rs.getInt(2),
rs.getBigDecimal(3),
prod);
}
};

return getSimpleJdbcTemplate().query(query, paramRowMapper, text, text);


}

Para uma referência completa consulte a documentação de JdbcTemplate e SimpleJdbcTemplate.

7.2.2.3. Chamando Stored Procedures

Framework Java Arquitetura Brasil 51


Persistência

A chamada de stored procedures é feita utilizando-se a classe SimpleJdbcCall que facilita a chamada a stored
procedures conforme mostra o exemplo abaixo:

@Repository
public class ActorJdbcDaoImpl extends GenericJdbcDao implements ActorDao {
private SimpleJdbcCall procReadActor;

@Autowired
public void initDataSource(DataSource dataSource) {
super.setDataSource(dataSource);
this.procReadActor = new SimpleJdbcCall(dataSource).withProcedureName("read_actor");
}

public Actor readActor(Long id) {


SqlParameterSource in = new MapSqlParameterSource().addValue("in_id", id);

Map out = procReadActor.execute(in);

Actor actor = new Actor();


actor.setId(id);
actor.setFirstName((String)out.get("out_first_name"));
actor.setLastName((String)out.get("out_last_name"));
actor.setBirthDate((Date)out.get("out_birth_date"));
return actor;
}

...
}

Para uma referência completa consulte documentação de SimpleJdbcCall.

7.2.2.4. Configurando um Datasource

É possível que um DAO JDBC utilize um Datasource específico, caso a aplicação possua vários Datasources.

7.2.3. Criando um DAO

Para criar um DAO existem 3 passos bem simples definidos abaixo:

• Criar a interface com os métodos que devem ser expostos.

public interface AnimalDao {

Animal findById(Long id, boolean lock);

void persist(Animal animal);

void remove(Animal animal);

void List<Animal> findAll(int maxResults);

// Se necessario adicionar outros metodos


}

• Criar uma nova classes que estenda com.altec.bsbr.fw.dao.jdbc.GenericJdbcDao,


com.altec.bsbr.fw.dao.jpa.GenericJpaDao ou com.altec.bsbr.fw.dao.jpa.GenericHibernateJpaDao
e implemente a interface que acabamos de criar.

public class AnimalDaoImpl extends GenericJpaDao<Animal, Long> implements AnimalDao {


// Se necessario implementar ou reescrever os metodos da interface
}

(1.13.6)
Persistência

• Anotar a classe DAO com a anotação org.springframework.stereotype.Repository.

@Repository
public class AnimalDaoImpl extends GenericJpaDao<Animal, Long> implements AnimalDao {
...
}

E desta forma concluimos a criação do DAO. Para acessá-lo dentro de um serviço, basta criar um atributo com
modificador de acesso private, com o tipo da interface do DAO e anotada com
org.springframework.beans.factory.annotation.Autowired.

@Service
public class AnimalServiceImpl implements AnimalService {

@Autowired
private AnimalDao animalDao;

...
}

7.3. Transações
O controle transacional é feito pelo Framework na camada de serviços, não sendo necessário colocar lógica de
transações nos DAOs.

Veja a seção sobre transações em serviços.

7.4. Configuração de banco de dados


Para o uso dos DAOs é necessário configurar um data source que aponte para o banco de dados usado, e o
arquivo de persistenência do JPA.

Vamos considerar a seguinte configuração de diretórios:

[Raiz_Projeto]/
src/

7.4.1. Configurações do datasource

Para configurar o data source deve seguir os seguintes passos.

• Criar o arquivo data_access.xml. Neste arquivo é possível que sejam configurados vários datasources.

Abaixo estão 2 exemplos de arquivos de configuração para dois running modes diferentes:

• Utilizando JNDI - META-INF/config/<runningMode>/data_access.xml obtemos o data source através de


um lookup JNDI no Websphere.

<?xml version="1.0" encoding="UTF-8"?>


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:jee="http://www.springframework.org/schema/jee"

(1.13.6)
Persistência

xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<jee:jndi-lookup id="dataSource1"❶
jndi-name="jdbc/jab"❷
/>

</beans>

❶ Nome do Datasource que será usado na aplicação.


❷ Nome JNDI configurado no servidor WebSphere.

• Utilizando Driver Manager - META-INF/config/<runningMode>/data_access.xml obtemos o data source


diretamente por JDBC.

<?xml version="1.0" encoding="UTF-8"?>


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<!-- ========================================================= -->


<!-- Data Source -->
<!-- ========================================================= -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="autoCommit" value="false"/>
</bean>

</beans>

Para a configuração acima precisamos acrescentar ao mesmo diretório um arquivo chamado


jdbc.properties:

jdbc.driverClassName=oracle.jdbc.OracleDriver
jdbc.url=jdbc:oracle:thin:@servidor:1521:DESENV
jdbc.username=usuario
jdbc.password=senha

7.4.2. Configuração do JPA

JPA exige a criação do arquivo de configuração de persistência. No Framework esse arquivo é apontado
indiretamente pela propriedade jpa.persistence.config.file.

Essa propriedade é definida dentro do arquivo persistence.properties. Para usar configurações diferentes
para servidores de aplicação diferentes, podemos usar os running modes definidos automaticamente pelo
Framework: websphere. Para maiores informações veja a seção de running modes.

Abaixo descrevemos cada arquivo:

• META-INF/config/<runningMode>/persistence.properties: Este arquivo possui informações do local

Framework Java Arquitetura Brasil 54


Persistência

onde encontra-se o arquivo de persistence-<runningMode>.xml. Em geral, deve conter a seguinte linha:

jpa.persistence.config.file=classpath*:META-INF/persistence-<runningMode>.xml

• META-INF/persistence-<runningMode>.xml

Exemplo:

WebSphere - META-INF/persistence-websphere.xml específico do WebSphere, que usa transações JTA.

<?xml version="1.0" encoding="UTF-8"?>


<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">

<persistence-unit name="manager1" transaction-type="JTA">


<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>datasource1</jta-data-source>❶
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle9iDialect"/>
<property name="hibernate.show_sql" value="false"/>
<property name="hibernate.format_sql" value="false"/>
<property name="hibernate.use_sql_comments" value="false"/>
<property name="hibernate.jdbc.wrap_result_sets" value="false"/>
<property name="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.WebSphereExtendedJTATransactionLookup"/>
<property name="jta.UserTransaction" value="java:comp/UserTransaction"/>
</properties>
</persistence-unit>

</persistence>

❶ Este datasource deve ser o mesmo que deve estar mapeado no arquivo
META-INF/config/<runningMode>/data_access.xml. Veja a seção 4.3.

Como exemplo, na aplicação de referência temos a seguinte árvore de diretórios:

[Raiz_Projeto]/
src/
META-INF/
config/
dev/
persistence.properties
data_access.xml
jdbc.properties
prod/
persistence.properties
data_access.xml
persistence-websphere.xml

7.4.3. Como adicionar um perisistence unit no arquivo data_access.xml

Para adicionar um novo persistence unit ao arquivo data_access.xml, é necessário seguir os passos abaixo:

1. Configure o persistence unit padrão a ser usado pela aplicação. Isso significa que quando for feita a
configuração do @PersistenceContext sem definir o parâmetro unitName,o framework irá assumir que
deseja-se usar o persistence unit padrão. Adicione a configuração a seguir ao arquivo data_access.xml.

<bean id="defaultPersistentUnitName" class="java.lang.String">


<constructor-arg value="manager1"/>❶
</bean>

Framework Java Arquitetura Brasil 55


Persistência

❶ Nome do persistence unit padrão. Este nome deve ser o mesmo nome, que é encontrado nos arquivos
persistence-<runningMode>.xml.

2. Adicionar o local onde encontra-se os arquivos persistence-<runningMode>.xml. Adicione a


configuração a seguir ao arquivo data_access.xml.

Adicione o namespace:

xmlns:util="http://www.springframework.org/schema/util"

Adicione a lista de possíveis locais:

<util:list id="persistentXmlPaths">
<value>${jpa.persistence.config.file}</value>❶
</util:list>

❶ Local o qual deve-se procurar o xml. <util:list/> elemento pode conter vários <value/>.

3. Criar um EntityManagerFactory para o persistent unit. Adicione a configuração a seguir ao arquivo


data_access.xml.

<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
autowire-candidate="default">
<property name="persistenceUnitManager" ref="persistenceUnitManager"/>❶
<property name="persistenceUnitName" value="manager1"/>❷
</bean>

❶ Referencia ao PersistenceUnitManager. Este é um valor fixo, pois o próprio framework irá fornecer,
basta configurá-lo de acordo com o valor mostrado no exemplo acima.
❷ Nome do persistence unit que está definido nos arquivos persistence-<runningMode>.xml.

4. Criar o DataSource conforme mostrado na seção 4.1.

5. Mapear o DataSource ao persistence unit. Adicione a configuração a seguir ao arquivo data_access.xml.

<util:map id="dataSources">
<entry key="datasource1">❶
<ref local="dataSource1"/>❷
</entry>
</util:map>

❶ Este é o nome do DataSource o qual está configurado no persistence unit que está definido nos
arquivos persistence-<runningMode>.xml.
❷ Este é o nome do DataSource que foi definido no passo anterior.

Nota
Caso seja necessário adicionar um novo persistence unit repita os passos a partir do passo 2.

7.4.4. Como adicionar um segundo ou mais persistence units no arquivo


data_access.xml.

Para configurar um segundo ou mais persistence units siga os passos abaixo:

(1.13.6)
Persistência

1. Verifique o local onde encontra-se o persistence unit da aplicação. Caso esteja no mesmo arquivo
persistence-<runningMode>.xml vá para o próximo passo. Caso não esteja adicione uma nova tag
<value/>. Como no exemplo abaixo:

<util:list id="persistentXmlPaths">
<value>${jpa.persistence.config.file}</value>
<value>classpath*:META-INF/persistence-2.xml</value>❶
</util:list>

❶ Local onde encontra-se o persistence.xml que deseja-se acessar.

2. Criar um EntityManagerFactory para o novo persistence unit. Adicione a configuração a seguir ao arquivo
data_access.xml.

<bean id="entityManagerFactory2"❶
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
autowire-candidate="default">
<property name="persistenceUnitManager" ref="persistenceUnitManager"/>
<property name="persistenceUnitName" value="manager2"/>❷
</bean>

❶ Nome do Entity Manager Factory. Para configurar um novo, acrescente um número ao lado do nome.
❷ Nome do persistence unit que será usado por este Bean. Este nome pode ser encontrado no arquivo
XML definido no passo anterior.

3. Criar o DataSource conforme mostrado na seção 4.1.

4. Mapear o DataSource ao persistence unit. Adicione a configuração a seguir ao arquivo data_access.xml.

<util:map id="dataSources">
<entry key="datasource2">❶
<ref local="dataSource2"/>❷
</entry>
</util:map>

❶ Este é o nome do DataSource o qual está configurado no persistence unit que está definido nos
arquivos XML definido no primeiro passo.
❷ Este é o nome do DataSource que foi definido no passo anterior.

7.4.5. Utilizando vários DataSources/PersistenceUnits

É possível definir o DataSource ou PersistenceUnit que será usado em um Dao específico. Para isso siga as
instruções definidas a seguir:

• Configurar o GenericJpaDao ou GenericHibernateDao para acessar um persistenceUnit específico:

@Repository
public class FooDaoImpl extends GenericJpaDao<Foo, Long> implements FooDao {

@PersistenceContext(unitName="manager1")❶
public void setEntityManager(EntityManager em) {
this.em = em;
}

...
}

❶ Nome do persistence unit definido no arquivo persistence-<runningMode>.xml.

(1.13.6)
Persistência

• Configurar o GenericJdbcDao para acessar um DataSource específico:

@Repository
public class FooDaoImpl extends GenericJdbcDao implements FooDao {

@Autowired
public void initDataSource(@Qualifier("datasource1")❶
DataSource dataSource) {
setDataSource(dataSource);
}

...
}

❶ DataSource definido no arquivo data_access.xml.

Framework Java Arquitetura Brasil 58


Capítulo 8. Mensageria

8.1. Introdução
Esta camada é responsável por fazer o acesso ao servidor de mensagens MQ, encapsulando toda a
implementação de baixo nível para postar e consumir mensagens. O Framework pode fazer a interação com o
MQ de duas formas: síncrona e assíncrona.

O formato das mensagens pode ser binário ou texto (com qualquer codificação) ficando o tratamento do
formato de entrada ou saída de responsabilidade da própria aplicação. O Framework provê classes utilitárias,
para tratar alguns dos formatos mais comuns, como descrito no capítulo de classes utilitárias.

8.2. JMS
Java Message Service (JMS) é um padrão de mensagens que permite componentes de aplicações baseados em
Java Enterprise Edition a criar, enviar, receber e ler mensagens. Ela permite comunicações distribuídas que são
pouco acopladas, confiáveis e asíncronas.

8.2.1. Configuração do JMS

Para usar JMS ou AEA é preciso configurar as filas a serem usadas. É necessário adicionar a referência aos
recursos no web.xml ou ejb-jar.xml conforme definido abaixo:

<resource-ref>
<description>Default ConnectionFactory</description>
<res-ref-name>jms/AEAConnectionFactory</res-ref-name>❶
<res-type>javax.jms.ConnectionFactory</res-type>
<res-auth>Container</res-auth>
</resource-ref>

<resource-ref>
<description>Default AEA Request Queue</description>
<res-ref-name>jms/RequestAEA</res-ref-name>❷
<res-type>javax.jms.Queue</res-type>
<res-auth>Container</res-auth>
</resource-ref>

<resource-ref>
<description>Default AEA Response Queue</description>
<res-ref-name>jms/ResponseAEA</res-ref-name>❸
<res-type>javax.jms.Queue</res-type>
<res-auth>Container</res-auth>
</resource-ref>

❶ Esta ConnectionFactory será mapeada para java:comp/env/jms/AEAConnectionFactory .


❷ Esta Queue estará disponível em java:comp/env/jms/RequestAEA .
❸ Esta Queue estará disponível em java:comp/env/jms/ResponseAEA .

E no arquivo META-INF/config/<runningMode>/jms.xml você disponibiliza as filas para que possamos


acessá-las.

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="http://www.springframework.org/schema/beans

Framework Java Arquitetura Brasil 59


Mensageria

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-2.5.xsd">

<jee:jndi-lookup id="jmsConnectionFactory"
jndi-name="java:comp/env/jms/AEAConnectionFactory"❶
expected-type="javax.jms.ConnectionFactory"
proxy-interface="javax.jms.ConnectionFactory"
lookup-on-startup="true"/>

<jee:jndi-lookup id="requestQueueAEA"
jndi-name="java:comp/env/jms/RequestAEA"❷
expected-type="javax.jms.Queue"
proxy-interface="javax.jms.Queue"
lookup-on-startup="true"/>

<jee:jndi-lookup id="responseQueueAEA"
jndi-name="java:comp/env/jms/ResponseAEA"❸
expected-type="javax.jms.Queue"
proxy-interface="javax.jms.Queue"
lookup-on-startup="true"/>

</beans>

❶ Local onde a ConnectionFactory que será mapeada.


❷ Local onde a Fila de Request deverá ser mapeada.
❸ Local onde a Fila de Response deverá ser mapeada.

8.2.2. Configuração do JMS (Fora do Websphere)

Para configurar aplicações que irão executar fora do ambiente do Websphere é necessário adicionar as
bibliotecas do MQ disponíveis no Framework e configurar o arquivo
META-INF/config/<runningMode>/jms.xml de acordo com o exemplo abaixo:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<util:constant id="queueTargetClient"
static-field="com.ibm.mq.jms.JMSC.MQJMS_CLIENT_NONJMS_MQ"/>

<util:constant id="transpType"
static-field="com.ibm.mq.jms.JMSC.MQJMS_TP_CLIENT_MQ_TCPIP"/>

<bean id="requestQueue" class="com.ibm.mq.jms.MQQueue">❶


<constructor-arg value="TESTE.REQUEST"/>❷
<property name="targetClient" ref="queueTargetClient"/>
</bean>

<bean id="connectionFactoryTarget"
class="com.ibm.mq.jms.MQConnectionFactory">❸
<property name="hostName" value="10.9.8.250"></property>❹
<property name="port" value="1414"></property>❺
<property name="transportType" ref="transpType"></property>
<property name="queueManager" value="QM1"></property>❻
<property name="channel" value="SYSTEM.DEF.SVRCONN"/>❼
</bean>

<bean id="connectionFactory"
class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="connectionFactoryTarget"/>
<property name="username" value=" "/>❽

Framework Java Arquitetura Brasil 60


Mensageria

<property name="password" value=" "/>❾


</bean>

</beans>

❶ Configuração de uma fila.


❷ Nome da fila.
❸ Configuração da conexão com o servidor MQ.
❹ Host do MQ.
❺ Porta do MQ.
❻ Queue Manager do MQ.
❼ Canal usado para conectar ao MQ.
❽ Usuário da conexão, caso não haja usuário é necessário por um espaço (" ") neste campo.
❾ Senha da conexão, caso não haja senha é necessário por um espaço (" ") neste campo.

8.2.3. AbstractMessagingGateway

A api JMS possui uma grande variedade de classes e operações que podem ser usadas para enviar mensagens.
Com o objetivo de formalizar e padronizar algumas operações, o Framework provê a classe
com.altec.bsbr.fw.jms.AbstractMessagingGateway que deve ser estendida quando houver a necessidade de
comunicar-se com filas de maneira estendida e confiável. Com ela é possível:

• Enviar mensagens sincronamente e assincronamente;

• Receber mensagens sincronamente;

• Definir um timeout para recebimento de mensagens sincronas.

A classe que estender AbstractMessagingGatewayImpl deverá definir as filas e a connection factory a serem
usadas, implementando os métodos abstratos getConnectionFactory(), getRequestQueue() e
getResponseQueue().

Para obter os recursos definidos no arquivo de configuração, basta usar autowiring nos atributos e passa-los
para os métodos que serão implementados. A classe precisa da anotação
org.springframework.stereotype.Component para ser carregada pelo Spring e ter suas dependências
injetadas. Exemplo abaixo:

@Component
public class FooMessaginGatewayImpl extends AbstractMessagingGateway implements FooMessagingGateway {

@Autowired
@Qualifier("requestQueue")❶
private Queue requestQueue;

@Autowired
@Qualifier("responseQueue")❷
private Queue responseQueue;

@Autowired
@Qualifier("jmsConnectionFactory")❸
private ConnectionFactory connectionFactory;

@Override
public Queue getRequestQueue() {❹
return requestQueue;
}

@Override
public Queue getResponseQueue() {❺
return responseQueue;
}

Framework Java Arquitetura Brasil 61


Mensageria

@Override
public ConnectionFactory getConnectionFactory() {❻
return connectionFactory;
}
}

❶ Nome do Bean da fila de request definido no arquivo jms.xml.


❷ Nome do Bean da fila de response definido no arquivo jms.xml.
❸ Nome do Bean da connection factory definido no arquivo jms.xml.
❹ Fila de request que será usada por padrão pela classe.
❺ Fila de response que será usada por padrão pela classe.
❻ ConnectionFactory que será usada por padrão pela classe.

Nota
É permitido que se retorne null para uma fila, caso caso ela não seja usada.

Nota
É permitido que se utilize a mesma fila tanto para request quanto para response

A seguir descrevemos em detalhes cada método da classe AbstractMessagingGateway e suas respectivas


utilizações:

• setTimeOut(long timeOut): define o timeout (em milisegundos) das operações que farão receive de uma
mensagem da fila.

• sendMessage(ExtendedMessageCreator<?> creator): javax.jms.Message: Envia uma mensagem para a


fila de Request. E retorna apenas a mensagem que foi enviada.

Este método não aguarda o retorno do processamento da mensagem no destino. Ele apenas posta a
mensagem na fila de request.

• sendTextMessage(String msg): javax.jms.Message: Envia uma mensagem para a fila de Request. E


retorna apenas a mensagem que foi enviada.

• receiveMessage(String selector): javax.jms.Message: Recebe uma mensagem qualquer utilizando o


selector.

• receiveMultipleMessages(String selector, int maxMsgCount, long totalTimeOut):


java.util.List<javax.jms.Message>: Recebe N mensagens texto utilizando um selector, utilizando o
parâmetro maxMsgCount como número máximo de mensagens a serem retornadas e utilizando o parâmetro
totalTimeOut como tempo (em milisegundos) máximo de espera até que cheguem mais mensagens.

• receiveTextMessage(String selector):String: Recebe uma mensagem utilizando o selector, e retorna


o conteúdo texto.

Nota
Para o uso deste método é necessário certificar-se que a mensagem sendo recebida é do tipo
javax.jms.TextMessage.

• receiveMultipleTextMessages(String selector, int maxMsgCount, long timeOut): List<String>:


Recebe N mensagens texto utilizando um selector, utilizando o parâmetro maxMsgCount como número
máximo de mensagens a serem retornadas e utilizando o parâmetro totalTimeOut como tempo (em

(1.13.6)
Mensageria

milisegundos) máximo de espera até que cheguem mais mensagens.

Nota
Para o uso deste método é necessário certificar-se que as mensagens sendo recebidas são do
tipo javax.jms.TextMessage.

• sendAndReceiveMessage(ExtendedMessageCreator<?> messageCreator, SelectorCreator


selectorCreator): javax.jms.Message: Envia uma mensagem para a fila de Request e recebe a
mensagem de resposta da fila de Response utilizando o selectorCreator para filtrar as mensagens.

• sendAndReceiveMessages(ExtendedMessageCreator<?> messageCreator, SelectorCreator


selectorCreator, int maxMsgCount, long timeOut): java.util.List<javax.jms.Message>: Envia
uma mensagem para a fila de Request e recebe várias mensagens de resposta utilizando o selectorCreator
para filtrar as mensagens, utilizando o parâmetro maxMsgCount como número máximo de mensagens a
serem retornadas e utilizando o parâmetro timeOut como tempo (em milisegundos) máximo de espera até
que cheguem mais mensagens.

• String sendAndReceiveTextMessage(String msg): Envia uma mensagem de texto para a fila de Request
e recebe a mensagem de resposta da fila de Response utilizando o JMSCorrelationID.

Para mais informações:

Message Selectors - JMS API Programming model

Mapping WebSphere MQ message fields and properties to JMS - IBM InfoCenter

Abaixo estão descritas algumas formas de uso desta classe nos diferentes contextos: síncrono e assíncrono.

8.2.3.1. ExtendedMessageCreator

A classe com.altec.bsbr.fw.jms.aea.ExtendedMessageCreator estende o uso da interface


org.springframework.jms.core.MessageCreator permitindo que se acesse a Mensagem que foi enviada para
o servidor de filas, além disso é possível setar os parâmetros da mensagem antes que ela seja efetivamente
enviada ao servidor.

Exemplo:

@Component
public class FooMessagingGatewayImpl extends AbstractMessagingGateway implements FooMessagingGateway {

public void enviar(String msg) {


ExtendedMessageCreator<TextMessage> creator = new ExtendedMessageCreator<TextMessage>() {
public void setParams(TextMessage message) {
message.setJMSCorrelationID("123");
message.setText(msg);
}
};
sendMessage(creator);
}
}

8.2.3.2. SelectorCreator

A classe com.altec.bsbr.fw.jms.aea.SelectorCreator é usada para fornecer o selector que será usado para
filtrar as mensagens de retorno.

Exemplo:

(1.13.6)
Mensageria

@Component
public class FooMessagingGatewayImpl extends AbstractMessagingGateway implements FooMessagingGateway {

public String enviar(String msg) {


ExtendedMessageCreator<TextMessage> creator = new ExtendedMessageCreator<TextMessage>() {
public void setParams(TextMessage message) {
message.setJMSCorrelationID("123");
message.setText(msg);
}
};
SelectorCreator selectorCreator = new SelectorCreator() {
public String createSelector(Message requestMessage) {
return "JMSCorrelationID = '" + requestMessage.getJMSMessageID() + "'";
}
};
TextMessage responseMessage = sendSyncMessage(creator, selectorCreator);
return responseMessage.getText();
}
}

8.2.4. Modo síncrono

O modelo síncrono de troca de mensagens é do tipo request/response, onde o cliente envia a mensagem numa
fila e fica esperando a resposta em outra fila. O Framework possui um componente que provê essa
funcionalidade para ser reutilizada em qualquer aplicação.

Para o usuário do componente, a chamada será apenas um método síncrono, simples de ser usado. O
Framework se encarregará de postar a mensagem e registrar um listener para esperar a resposta, fazendo a
sincronização. O diagrama de seqüencia a seguir mostra esse mecanismo.

Figura 8.1. Modo síncrono

O cliente pode especificar um tempo máximo de espera para a resposta chegar. Caso esse tempo seja
ultrapassado, não retornará nenhuma mensagem.

Abaixo decrevemos os passos necessários para acessar sincronamente Filas:

1. Criar uma interface de acesso ao serviço de envio de mensagem.

Exemplo:

Framework Java Arquitetura Brasil 64


Mensageria

public class EnviarReceberMessageGateway {


public String enviar(String message) throws JMSException;
}

2. Criar uma classe que estenda de com.altec.bsbr.fw.jms.AbstractMessagingGateway e implemente a


interface criada no passo anterior. É necessário que sejam fornecidas as filas de Request e Response.

@Component
public class EnviarReceberMessageGatewayImpl extends AbstractMessagingGateway
implements EnviarReceberMessageGateway {

@Autowired
@Qualifier("requestQueue")❶
private Queue requestQueue;

@Autowired
@Qualifier("responseQueue")❷
private Queue responseQueue;

@Autowired
@Qualifier("jmsConnectionFactory")❸
private ConnectionFactory connectionFactory;

@Override
public Queue getRequestQueue() {❹
return requestQueue;
}

@Override
public Queue getResponseQueue() {❺
return responseQueue;
}

@Override
public ConnectionFactory getConnectionFactory() {❻
return connectionFactory;
}

public String enviar(final String message) throws JMSException {

ExtendedMessageCreator<TextMessage> messageCreator = ❼
new ExtendedMessageCreator<TextMessage>() {
public void setParams(TextMessage textMessage) {
textMessage.setText(message);
}
};

SelectorCreator selector = ❽
new SelectorCreator() {
public String createSelector(Message reqMessage) {
return "JMSCorrelationID = '+reqMessage.getJMSMessageID()+'";
}
}

return sendAndReceiveTextMessage(messageCreator, selector);❾


}
}

❶ Nome do Bean da Queue de envio (request).


❷ Nome do Bean da Queue de resposta (response).
❸ Nome do Bean da Connection Factory.
❹ Request queue que será usada pela classe.
❺ Response queue que será usada pela classe.
❻ Connection Factory que será usada pela classe.
❼ ExtendedMessageCreator usado para criar mensagens.
❽ SelectorCreator usado para criar o selector para filtrar as mensagens da fila de resposta
(responseQueue).

Framework Java Arquitetura Brasil 65


Mensageria

❾ sendAndReceiveTextMessage método usado para enviar mensagens síncronas e receber apenas uma
mensagem de resposta, há também o método sendAndReceiveMessage. Caso seja necessário receber
várias mensagens particionadas usar o método:
sendAndReceiveMessages(ExtendedMessageCreator<?> messageCreator, SelectorCreator
selectorCreator, int maxMsgCount, long timeOut): java.util.List<javax.jms.Message>.

8.2.5. Modo assíncrono

No modelo assíncrono, o cliente posta uma mensagem na fila e não precisa esperar por uma resposta. O
framework possui uma API para postar mensagens em uma fila e abstrair os detalhes de baixo nível do JMS.

Para o recebimento de mensagens assíncronas, o framework disponibiliza um mecanismo para registrar um


objeto Java normal como listener de uma fila. Assim, quando uma mensagem chegar, o objeto será invocado
para tratá-la.

A recepção de mensagens no listener, poderá fazer parte de um contexto transacional compartilhado com outros
recursos (como banco de dados) se todos os drivers envolvidos forem XA compliant.

Para acessar uma fila é necessário estender a class com.altec.bsbr.fw.jms.AbstractMessagingGateway que


já possui as seguintes funcionalidades:

• Enviar mensagens assincronamente;

• Receber mensagens sincronamente.

Enviar e receber mensagems sincronamente: Criar uma classe que estenda de


com.altec.bsbr.fw.jms.AbstractMessagingGateway. Será necessário implementar 2 métodos principais:
getRequestQueue() apenas necessário para o envio de mensagens getResponseQueue() apenas necessário para
o recebimento de mensagens. Caso não haja a necessidade de enviar ou receber uma mensagem basta retornar
null para a fila respectiva.

8.2.5.1. Enviar mensagens assincronamente

No envio assíncrono não há resposta, desta maneira a mensagem pode ser processada em um processo
separado. De acordo com o diagrama de sequência a seguir:

Figura 8.2. Modo assíncrono

Abaixo estão descritos os passos para criar um gateway e enviar uma mensagem assincrona:

(1.13.6)
Mensageria

1. Criar a Interface para expor os métodos de negócio.

public interface EnviarMessagingGateway {


public void sendData(String msg);
}

2. Criar o Gateway para envio de mensagens:

@Component
public class EnviarMessagingGatewayImpl extends AbstractMessagingGateway implements EnviarMessagingGateway {

@Autowire
@Qualifier("filaRequest")
private Queue requestQueue;

public Queue getRequestQueue() {


return requestQueue;
}

public Queue getResponseQueue() {


return null;
}

public void sendData(String msg) {


//processa a msg antes de efetivamente envia-la.
sendTextMessage(msg);
}
}

3. Enviando mensagens usando serviços:

@Service
public class FooServiceImpl implements FooService {

@Autowired
private EnviarMessagingGateway enviarMessagingGateway;

public void enviar(String msg) {


enviarMessagingGateway.sendData(msg);
}
}

8.2.5.2. Receber mensagens assincronamente

Para receber mensagens assincronamente basta registrar um objeto que implemente a interface
javax.jms.MessageListener, que ele será invocado para tratar a mensagem assim que ela chegar (de modo
semelhante a MDB's).

A implementação deve-se seguir os seguintes passos:

1. Criar uma classe que implemente javax.jms.Listener, e usar a anotação


org.springframework.stereotype.Component.

@Component
public class ReceberMensagemAssincListener implements javax.jms.Listener {
public void onMessage(Message message) {
//processar mensagem
}
}

2. No arquivo de configuração META-INF/config/prod/jms.xml deve-se registrar o listener que irá acionar a


classe que acabamos de criar. Além disso, devemos registrar as filas usadas e a ConnectionFactory assim

(1.13.6)
Mensageria

como exemplificamos abaixo:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-2.5.xsd">

<bean id="requestQueueAEA.queueName"
class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/>❶

<bean id="jmsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">


<property name="expectedType" value="javax.jms.ConnectionFactory"/>
<property name="proxyInterfaces" value="javax.jms.ConnectionFactory"/>
<property name="jndiName" value="java:comp/env/jms/AEAConnectionFactory"/>
<property name="lookupOnStartup" value="true"/>
</bean>

<bean id="jmsContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="jmsConnectionFactory"/>
<property name="destinationName" ref="requestQueueAEA.queueName"></property>❷
<property name="messageListener" ref="receberMensagemAssincListener"/>❸
</bean>

</beans>

❶ Local onde definimos o nome que será mapeado para a fila. Através deste recurso obtemos o nome
da Fila a qual utilizaremos para configurar a fila de acesso.
❷ Local onde é mapeada a fila a ser usada.
❸ Nome do listener criado anteriormente que irá processar as mensagens assíncronamente.

Para mais informações sobre como registrar novos listeners: Asynchronous Message - Spring JMS.

Para utilizar listeners que utilizem JTA para controle de transação é necessário configurar o arquivo
META-INF/config/prod/jms.xml da seguinte maneira:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-2.5.xsd">

<bean id="requestQueue"
class="org.springframework.jndi.JndiObjectFactoryBean">❶
<property name="expectedType" value="javax.jms.Queue"/>
<property name="proxyInterfaces" value="javax.jms.Queue"/>
<property name="jndiName" value="java:comp/env/jms/RequestQueue"/>❷
<property name="lookupOnStartup" value="true"/>
</bean>

<bean id="responseQueue"
class="org.springframework.jndi.JndiObjectFactoryBean">❸
<property name="expectedType" value="javax.jms.Queue"/>
<property name="proxyInterfaces" value="javax.jms.Queue"/>
<property name="jndiName" value="java:comp/env/jms/ResponseQueue"/>❹
<property name="lookupOnStartup" value="true"/>
</bean>

<bean id="requestQueue.queueName"
class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/>❺

<bean id="jmsConnectionFactory"

Framework Java Arquitetura Brasil 68


Mensageria

class="org.springframework.jndi.JndiObjectFactoryBean">❻
<property name="expectedType" value="javax.jms.ConnectionFactory"/>
<property name="proxyInterfaces" value="javax.jms.ConnectionFactory"/>
<property name="jndiName" value="java:comp/env/jms/ConnectionFactory"/>❼
<property name="lookupOnStartup" value="true"/>
</bean>

<bean id="taskExecutor"
class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">❽
<property name="workManagerName" value="wm/default"/>
</bean>

<bean id="jmsContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">❾
<property name="connectionFactory" ref="jmsConnectionFactory"/>
<property name="destinationName" ref="requestQueue.queueName"></property>
<property name="messageListener" ref="sampleListener"/>
<property name="taskExecutor" ref="taskExecutor"></property> ❿
<property name="transactionManager" ref="transactionManager"></property> 11
<property name="recoveryInterval" value="5000"/> 12
<property name="concurrentConsumers" value="1"/> 13
<property name="maxConcurrentConsumers" value="1"/> 14
</bean>

</beans>

❶ Registro da Fila de Request.



❷ Registro da Fila de Response.
❹ Nome JNDI declarado no web.xml da fila de response.
❺ Nome da fila de request para ser usado no container.
❻ Registro da Connection Factory.
❼ Nome JNDI da Connection Factory.
❽ Registro do Task executor para Work Manager.
❾ JMS Container que irá escutar a fila de request.

11 Transaction Manager. Utilize uma referência a transactionManager já existente que o Framework
disponibiliza.
12 Tempo em milisegundos necessário que o listener fique parado sempre que ocorrer um erro no
processamento de uma mensagem antes de tentar processar a mensagem novamente. Valor padrão 5000
ms = 5 segundos.
13 Número inicial de consumidores concorrentes a ser criado. Valor padrão é 1.
14 Número máximo de consumidores concorrentes a serem criados enquanto houverem mensagens
disponíveis. Valor padrão é 1.

Nota
Para utilizar vários listeners é necessário
cadastrar um
org.springframework.jms.listener.DefaultMessageListenerContainer para cada fila de
request.

Para maiores detalhes de parâmetros que podem ser passados ao message listener acesse: Spring Doc -
DefaultMessageListenerContainer

8.3. MDB
Importante
A utilização Framework Jab com EJB's é um pouco diferente de utilizar o Framework como um
projeto WEB. Dentro de um projeto EJB o Framework perde algumas funcionalidades que dão
produtividade aos desenvolvedores, como: Registro automático de serviços, componentes e

Framework Java Arquitetura Brasil 69


Mensageria

recursos de Banco de dados e injeção automática de dependências via Annotations. Isso se deve
pelo fato do ClassLoader de uma aplicação EJB ser diferente de uma aplicação WEB comum.

Esta limitação obriga o desenvolvedor registrar manualmente todas as classes de serviço,


componentes, recursos de banco de dados, os quais são representados pelas repectivas annotations
@Service, @Component e @Resource. Além disso, existe a necessidade de injetar manualmente as
dependências as quais seriam representadas pela annotation @Autowired.

"Manualmente", se entende por declarar cada classe concreta, ou seja, apenas classes, não
interfaces Java, em um arquivo xml que somente está presente em aplicações EJB. Este arquivo
está localizado em [Raiz-projeto]/src/META-INF/config/app-beans.xml.

Abaixo mostramos um exemplo de como deverá ser feita a declaração manual de um serviço:

<?xml version="1.0" encoding="UTF-8"?>


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="testService" class="com.altec.bsbr.app.test.service.impl.TestServiceImpl">
<property name="dao" ref="testDao"/>
</bean>
<bean id="testDao" class="com.altec.bsbr.app.test.service.impl.TestDaoImpl">
<property name="dataSource" ref="dataSource1"/>
</bean>
</beans>

Para receber mensagens assincronamente você também pode criar um MDB de acordo com o exemplo abaixo:

Nota
Para MDB's é necessário criar as classes do MDB dentro do diretório [Raiz-Projeto]/src-ejb.

public class SampleMessageBean extends MDBSupport ❶


implements MessageListener {

private MessageListener delegate;

@Override
protected void onEjbCreate() {
delegate = (MessageListener) getBeanFactory().getBean("delegate");
}

public void onMessage(Message message) {


delegate.onMessage(message);
}
}

❶ Classe com.altec.bsbr.fw.ejb.MDBSupport utilizada para inicialização do Framework.

Nota
Note que é necessário utilizar o método getBeanFactory() da classe para obter as dependências.

Para mais informações sobre a criação de MDB's no WebSphere consulte o IBM Info Center.

8.4. Arquitetura Estendida Altair


A integração com mainframe pela Arquitetura Estendida, se baseia num modelo request/response, onde o

(1.13.6)
Mensageria

cliente envia a mensagem numa fila e fica esperando a resposta em outra fila.

Para enviar mensagens utilizando a Arquitetura Estendida Altair (AEA) deve-se primeiramente criar a classe de
request (que será mapeada para o formato de envio ao Altair) e as classes de response (que serão mapeadas para
os formatos de resposta do Altair).

8.4.1. Mapeamento para o formato de Request (Envio)

Para criar a classe mapeada de envio basta seguir os passos abaixo, suponhamos uma determinada transação
PE47:

<?xml version="1.0"?>
<requestMsg>
<dse_operationName>PE47</dse_operationName>
<dse_formattedData>
<kColl id="entryData">
<field id="Usuario" value="NXCARDP"/>
<field id="PENOMPE" value="FABRICIO"/>
<field id="PETIPPE" value="F"/>
<field id="PECODEN" value="0033"/>
</kColl>
</dse_formattedData>
<dse_processParameters>LIST</dse_processParameters>
</requestMsg>

Para o formato acima criaremos uma classe que mapeie todos os fields (campos) para um POJO, como
demonstramos abaixo:

@AeaRequestMessage(operationName = "PE47")
public class Pe47AeaRequest {

@AeaField
private String PENOMPE;

@AeaField
private String PETIPPE;

@AeaField(validator = PECODENValidator.class)
private String PECODEN;

// getters e setters
...
}

Nota
É possível customizar o nome do atributos para um nome diferente do que foi definido no
FORMATO da AEA, basta utilizar o atributo id da annotation
com.altec.bsbr.fw.record.adapters.aea.annotation.AeaField.

Nota
Observe que para alguns campos onde é necessário que haja uma conversão, e validação do tipo
que vem do Altair para as classes Java, basta indicar na seguinte anotação
com.altec.bsbr.fw.record.adapters.aea.annotation.AeaField, os atributos converter e
validator, assim como definido abaixo.

Todas as classes deconversão deverão estender a classe


com.altec.bsbr.fw.converter.BaseConverter. Para consultar os converters existentes no
Framework veja a tabela abaixo:

(1.13.6)
Mensageria

Tabela 8.1. Converters já existentes no Framework

Class Converter Tipo Java

com.altec.bsbr.fw.converter.BigDecimalConverter java.math.BigDecimal

com.altec.bsbr.fw.converter.BooleanConverter De valor qualquer para true e de um valor


qualquer para false.

com.altec.bsbr.fw.converter.DateConverter Converte do formato


yyyy-MM-dd-hh.mm.ss.ms para
java.util.Date.

com.altec.bsbr.fw.converter.DoubleConverter Converte um valor qualquer em um


double, se não for informado nenhum
pattern o padrão usado é 0.00.

com.altec.bsbr.fw.converter.OneZeroBooleanConverter Converte '1' para true e '0' para false.

com.altec.bsbr.fw.converter.SNBooleanConverter Converte 'S' para true e 'N' para false.

com.altec.bsbr.fw.converter.TFBooleanConverter Converte 'T' para true e 'F' para false.

com.altec.bsbr.fw.converter.TimestampDateConverter Converte do formato


yyyy-MM-dd-hh.mm.ss.ms para um
java.util.Date.

com.altec.bsbr.fw.converter.VFBooleanConverter Converte 'V' para true e 'F' para false.

com.altec.bsbr.fw.converter.YNBooleanConverter Converte 'Y' para true e 'N' para false.

com.altec.bsbr.fw.converter.YYYYMMDDDateConverter
Converter do formato yyyy-MM-dd para
um java.util.Date.

Todas as classes de
validação deverão estender a classe
com.altec.bsbr.fw.validator.BaseValidator.

Importante
Para os tipos não existentes deve-se criar um novo converter estendendo de
com.altec.bsbr.fw.converter.BaseConverter

Nota
O campo dse_operationName (<dse_operationName>PE47</dse_operationName>) pode ser
informado implementando o método getOperation() definido na interface AeaMessagingGateway

Nota
O campo Usuario (<field id="Usuario" value="NXCARDP"/>) deve ser informado por um bean
chamado aeaUserName, definido no arquivo META-INF/config/aea.xml como o exemplo que
segue:

<bean id="aeaUserName" class="com.altec.bsbr.fw.jms.aea.AeaUser">


<property name="userName" value="NXCARDP"/>
</bean>

Framework Java Arquitetura Brasil 72


Mensageria

8.4.2. Mapeamento para o formato de Response (Retorno)

E para cada formato de retorno criaremos uma classe, conforme a demonstração a seguir:

@AeaReplyMessage
public class PEM2650 {

@AeaField
private String PENUMPE; // NRO.PERSONANRO.PERSONA - A8

@AeaField
private String PECALPA; // CAL.PARCAL.PAR - A2

@AeaField(converter = com.altec.bsbr.fw.converter.TimestampDateConverter.class)
private Date PEHSTAM; // TIMESTAMPTIMESTAMP - A26

//getters e setters
...
}

8.4.3. Mapeamento de tipos de retorno

A interface AeaMessagingGateway define o método Map<String, Class<?>> getReplyFormats()


responsável pelo mapeamento do formatos retornados por uma mensagem de resposta da AEA. A
seguir um exemplo de implementação:

...
private Map<String, Class<?>> aeaReplyFormats;

{
HashMap<String, Class<?>> map = new HashMap<String, Class<?>>();
map.put("PEM2650"❶, PEM2650.class❷);
map.put("PEM2690", PEM2690.class);
aeaReplyFormats = Collections.unmodifiableMap(map);
}

public Map<String, Class<?>> getReplyFormats() {❸


return aeaReplyFormats;
}

...

❶ Formato do registro, exatamente igual ao definido na resposta. Exemplo:

<kColl>
<field id="DC_FORMATO" value="PEM2650"/>

❷ Classe que representa o formato do registro.


❸ Método que define o mapa de formatos de mensagem.

8.4.4. Enviando mensagens para a Arquitetura Estendida Altair

E para finalizar o processo enviamos mensagens utilizando o seguinte processo:

@Service
public class ExemploServiceImpl implements ExemploService {

@Autowired
private Pe47MessagingGateway<Pe47AeaRequest> pe47Messaging;

private Pe47AeaRequest request = new Pe47AeaRequest();

public void send(Pe47AeaRequest request) {


try {
pe47Messaging.send(request);

Framework Java Arquitetura Brasil 73


Mensageria

List<PEM2690> resultPEM2690Records = pe47Messaging.getList(PEM2690.class);


List<PEM2650> resultPEM2650Records = pe47Messaging.getList(PEM2650.class);

if (pe47Messaging.getWarnings() != null) {
for (AEAWarning warning : pe47Messaging.getWarnings())
// Processando warnings
}
// processa resultados
}
catch (AeaException ex) {
// tratamento de exceções
}
}
...
}

Note que para obtermos os resultados do envio existem dois principais métodos:

• getList(Class): Este método retorna os formatos encontrados que equivalem ao tipo fornecido.

• getOrderedRecords(): Este método retorna os registros na ordem de ocorrência no xml de resposta.

• getWarnings(): Este método retorna os


warnings que a AEA enviou do tipo
com.altec.bsbr.fw.record.adapters.aea.AEAWarning.

Caso ocorra qualquer problema será lançada uma com.altec.bsbr.fw.jms.aea.AeaException indicando o


erro. Existem 3 possíveis causas:

Tabela 8.2. Exceções que podem ser lançadas durante o processamento das respostas

Exceção Descrição Tratamento

ParseException
AEA respondeu com um Não há como continuar a leitura da resposta, o
XML inválido. Problema processamento é interrompido.
com o formato da resposta.

MessageErrorException
AEA respondeu com a existe um método getErrors() que retorna uma
indicação de um erro (status lista de AeaError, com o identificador do erro e
NOK). sua descrição.

ValidateException
Problema com o valor de Um validador foi definido para o campo, e o
um determinado campo valor indicado não é válido, portanto o
processamento é interrompido, pois a mensagem
não atende o esperado.

Caso aconteça algum erro (tratável) durante o parsing, a descrição desses erros pode ser recuperada chamando
o método getParsingErrors().

(1.13.6)
Capítulo 9. Web Services

9.1. Introdução
Para o uso de web services, o Framework adotou o "WebSphere Application Server Version 6.1 Feature Pack
for Web Services" que adiciona suporte ao padrão de nova geração JAX-WS 2.0 (Java API for XML-Based
Web Services) ao servidor de aplicações. Usando o modelo de programação do JAX-WS, o desenvolvimento
de serviços e clientes web é simplificado através do uso de anotações padronizadas.

Nota
O padrão JAX-WS veio para substituir o antigo JAX-RPC. Os dois modelos podem ser usados,
mas é recomendado o JAX-WS, pela sua facilidade de desenvolvimento através de anotações.

O JAX-WS usa o padrão JAXB (Java Architecture for XML Binding), uma especificação Java que provê uma
maneira fácil e conveniente de mapear classes Java e XML para facilitar o desenvolvimento de web services.
Para uma descrição detalhada consulte o documento Using JAXB for XML data binding.

9.2. Exportando um serviço de negócio como web service

O termo service endpoint interface (SEI) é usado no âmbito do Java Enterprise Edition quando um JavaBean é
exposto como um web service. Através dele pode ser gerado o WSDL que define os métodos de um web
service em particular.

Para desenvolver web services baseados no modelo de programação JAX-WS, pode ser usada uma técnica
"bottom-up", onde o desenvolvimento é iniciado a partir de um JavaBean, que pode ser abilitado a ser um
serviço web, adicionando a anotação @WebService a classe. Não é necessário criar o WSDL do web service
pois isso será feito automaticamente pelo servidor no momento de deploy da aplicação.

Vejamos a situação onde será exportado um serviço da camada de negócios do Framework, chamado
HelloService. Precisamos criar um endpoint que servirá como uma fachada para esse serviço, delegando a
execução dos métodos para a implementação do serviço.

Tabela 9.1. Construção de um Service Endpoint Interface de um serviço

Descrição

1 O endpoint deve estar no pacote com.altec.bsbr.app.[sistema].webservice.

2 O endpoint deve ter o mesmo nome do serviço com o sufixo Endpoint. Para um servico
HelloService, o endpoint será HelloEndpoint.

3 O endpoint deve implementar a interface do serviço.

4 O endpoint deve estender a classe

Framework Java Arquitetura Brasil 75


Web Services

Descrição

org.springframework.web.context.support.SpringBeanAutowiringSupport.

5 O endpoint deve ter a anotação javax.jws.WebService.

6 Todos os métodos exportados devem ter a anotação javax.jws.WebMethod.

7 Todos parâmetros dos métodos exportados devem ter a anotação javax.jws.WebParam.

8 A implementação do serviço deve ser obtida no atributo da classe com a anotação @Autowired. Se
houver mais de um bean implementando a mesma interface, usar também a anotação @Qualifier.

9 Os métodos do endpoint devem apenas delegar a execução da lógica para a implementação do


serviço.

Nota
Uma classe com a anotação @WebService é instanciada pelo servidor de aplicações e não pelo
Spring. Por isso é necessário o endpoint estender SpringBeanAutowiringSupport, para que ele
possa ter acesso ao serviços e outros beans disponíveis no contexto do Spring através da anotação
@Autowired.

Exemplo de um web service para o serviço Hello:

package com.altec.bsbr.app.demo.webservice;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;

import com.altec.bsbr.app.demo.service.HelloService;

@WebService
public class HelloEndpoint extends SpringBeanAutowiringSupport implements HelloService {

@Autowired
private HelloService service;

@WebMethod
public String sayHello(@WebParam(name = "name")String name) {
return service.sayHello(name);
}

Quando a interface desejada do web service não for exatamente a do serviço, deve ser criada uma interface
adicional, para uso exclusivo do web service.

Importante
A criação de uma interface diferenciada para o web service, distinta da interface do serviço de
negócio, pode ser necessária. Neste caso, o web service funciona como uma fachada para o serviço
propriamente dito, fazendo a adaptação de uma interface para a outra.

Framework Java Arquitetura Brasil 76


Web Services

Dessa maneira, desacoplamos o serviço de negócio do cliente, através da fachada de web service.
As vantagens do descoplamento são:

1. Evitamos expor tipos ou estruturas de dados internos do serviço aos clientes. Assim
conseguimos maior abstração do serviço.

2. O serviço de negócio e o web service podem ser modificados de maneira independente, os


clientes não precisam afetar o serviço e vice-versa.

3. Podem existir diferentes versões do mesmo web service, usando o mesmo serviço de negócio.
Isso permite uma evolução segura do contrato do serviço com os clientes.

4. Pode ser necessário adaptar a interface do web service para clientes específicos. Podemos
modificar apenas a fachada, através de ajustes do WSDL e XSD, deixando o serviço de
negócio intacto.

A construção do endpoint é similar ao descrito anteriormente. Os itens abaixo marcados com (*) são as
diferenças:

Tabela 9.2. Construção de um Service Endpoint Interface para um web service exclusivo

Descrição

0 (*) A interface deve ter o mesmo nome do serviço com o sufixo WebService. Para um serviço
HelloService, a interface será HelloWebService. O pacote deve ser o mesmo da interface original.

1 O endpoint deve estar no pacote com.altec.bsbr.app.[sistema].webservice.

2 O endpoint deve ter o mesmo nome do serviço com o sufixo Endpoint. Para um serviço
HelloService, o endpoint será HelloEndpoint.

3 (*) O endpoint deve implementar a nova interface, não a do serviço.

4 O endpoint deve estender a classe


org.springframework.web.context.support.SpringBeanAutowiringSupport.

5 O endpoint deve ter a anotação javax.jws.WebService.

6 Todos os métodos exportados devem ter a anotação javax.jws.WebMethod.

7 Todos parâmetros dos métodos exportados devem ter a anotação javax.jws.WebParam.

8 A implementação do serviço deve ser obtida no atributo da classe com a anotação @Autowired. Se
houver mais de um bean implementando a mesma interface, usar também a anotação @Qualifier.

9 (*) Os métodos do endpoint devem transformar os dados de entrada e saída do formato da interface
web para o formato usado na implementação do serviço da camada de negócios.

Framework Java Arquitetura Brasil 77


Web Services

Quando for necessário passar uma exceção de negócio do servidor para o cliente, de modo que essa informação
esteja presente no WSDL, basta criar uma exceção que contenha a anotação @WebFault. O Framework já possui
uma exeção desse tipo, chamada com.altec.bsbr.fw.webservice.WebServiceException, e que pode ser
usada por qualquer aplicação na implementação de um endpoint:

public void exemplo(int param) throws WebServiceException {


...
throw new WebServiceException("Mensagem do erro", codigoDoErro);
...
}

WebServiceException contém um objeto FaultInfo que possui as informações da mensagem de erro e do


código de erro. O WSDL gerado para um método que tenha WebServiceException na sua assinatura será
similar a estrutura abaixo:

WSDL:

<definitions name="TestEndpointService"
targetNamespace="http://webservice.abc.app.bsbr.altec.com/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://webservice.abc.app.bsbr.altec.com/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
...
<message name="WebServiceException">
<part name="fault" element="tns:WebServiceException"/>
</message>
...
<portType name="TestEndpoint">
...
<operation name="getCd">
<input message="tns:getCd"/>
<output message="tns:getCdResponse"/>
<fault name="WebServiceException" message="tns:WebServiceException"/>
</operation>
</portType>
<binding name="TestEndpointPortBinding" type="tns:TestEndpoint">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getCd">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
<fault name="WebServiceException">
<soap:fault name="WebServiceException" use="literal"/>
</fault>
</operation>
</binding>
...
</definitions>

XSD:

<xs:schema version="1.0">
...
<xs:complexType name="faultInfo">
<xs:sequence>
<xs:element name="code" type="xs:int" minOccurs="0"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
...
</xs:schema>

No exemplo a seguir vamos criar uma nova interface web para o servico ProductService.

(1.13.6)
Web Services

A interface do serviço de negócios:

package com.altec.bsbr.app.demo.service;

public interface ProductService {

void create(Product p);

A interface do web service a ser exportada:

package com.altec.bsbr.app.demo.service;

public interface ProductWebService {

void createProduct(Long id, String name, BigDecimal price, String description)


throws WebServiceException ;

A implementacao da fachada JAX-WS do serviço:

package com.altec.bsbr.app.demo.webservice;❶

import javax.jws.WebMethod;
import javax.jws.WebService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;

@WebService
public class ProductEndpoint❷ extends SpringBeanAutowiringSupport implements ProductWebService❸ {

@Autowired
ProductService service;❹

@WebMethod❺
void createProduct(Long code, String name, BigDecimal price, String description)
throws WebServiceException {

Validator v = new NumberRangeValidator((long) 1, (long) 999);


if (!v.isValid(code))❻
throw new WebServiceException("Codigo invalido", 10);❼

Product p = new Product(code, name, price, description);❽


service.create(p);❾
}

❶ Uso do pacote padrão para web services.


❷ Declaração do endpoint.
❸ Uso da interface exclusiva para o serviço web.
❹ Referência ao serviço de negócios puro.
❺ Declaração do método usando a interface do serviço web.
❻ Validação de parâmetros de entrada.
❼ Geração da WebServiceException, contendo o erro e código.
❽ Conversão da interface web para a interface de negócio.
❾ Chamada do serviço de negócio.

Para obter maiores informações de como criar um web service consulte a documentação do WebSphere para
JAX-WS, onde é possível encontrar todas as opções para a definição do WSDL desejado.

(1.13.6)
Web Services

9.3. Gerando um cliente web service a partir do WSDL


Pode ser necessário acessar um webservice desenvolvido por alguma tecnologia diferente de Java (como .Net
por exemplo) do qual temos acesso apenas ao WSDL.

Para essa situação, o padrão JAX-WS oferece uma ferramenta chamada wsimport que pode apenas a partir do
WSDL gerar todas as classes necessárias para consumir o web service.

JAX-WS Reference Implementation

O padrão JAX-WS possui uma implementação de referência que pode ser instalada separadamente de um
servidor de aplicações. Assim podemos usar mais facilmente ferramentas como o wsimport. O pacote de
instalação do JAX-WS Reference Implementation pode ser baixado do site da Sun, e instalado na máquina de
desenvolvimento.

Outra opção é usar o wsimport que vem no Web Services Feature Pack para o WebSphere 6.1.

O wsimport é uma ferramenta de linha de comando muito simples. Basta apontar para o WSDL (que pode ser
um arquivo ou uma URL) que será gerado um cliente Java que que poderá ser usado para acessar o web
service. Normalmente, serão gerados as seguintes classes:

• Uma classe principal que é o ponto de acesso ao web service, que estende javax.xml.ws.Service.

• Uma interface com os métodos do serviço web. Um objeto que implemente esta interface é fornecido pelo
objeto do tipo Service, citado acima.

• Um objeto do tipo request, que representa os dados de entrada de um dos métodos do serviço web.

• Um objeto do tipo response, que representa os dados de saída de um dos métodos do serviço web.

• Quaisquer outros objetos que representem a estrutrua interna dos objetos de request e response.

• Uma classe ObjectFactory, de uso interno, para criar os objetos do tipo request e response citados acima.

Todas essas classes devem ser geradas num package Java específico para cada web service, de modo a
mante-los separados e não haver conflitos. O package padrão do Framework é:

com.altec.bsbr.app.[sistema].webclient.[nome_servico]

A sintaxe do comando wsimport é wsimport [opções] [wsdl], e os parâmetros mínimos que devem ser
passados são:

Tabela 9.3. Opções do wsimport

Opção Descrição

-target 2.0 Especifica que o código gerado deve ser compatível com o JAX-WS
versão 2.0, que é a usada pelo WebSphere.

-s <diretório> Especifica o diretório onde serão gerados os fontes.

-p <package> Especifica o pacote onde serão gerados os fontes.

Framework Java Arquitetura Brasil 80


Web Services

Existem mais opções, que podem ser consultadas na documentação oficial do JAX-WS.

Como exemplo, vamos criar o cliente de um web service disponível na Internet, que faz uma validação de
endereço de e-mail, desenvolvido com tecnologia .Net, chamado XWebEmailValidation.

wsimport.bat -target 2.0


-s C:\proj\altec\abcAdmin\src
-p com.altec.bsbr.app.abcAdmin.webclient.test
http://ws.xwebservices.com/XWebEmailValidation/V2/XWebEmailValidation.wsdl

parsing WSDL...
generating code...
compiling code...

EmailValidation.java
ObjectFactory.java
package-info.java
ValidateEmailRequest.java
ValidateEmailResponse.java
XWebEmailValidationInterface.java

Essas classes geradas no exemplo são:

• A classe principal é EmailValidation.

• A interface com os métodos do serviço web é XWebEmailValidationInterface. Um objeto que implemente


esta interface é fornecido pelo método EmailValidation.getEmailValidation().

• ValidateEmailRequest representa os dados de entrada do método


XWebEmailValidationInterface.validateEmail().

• ValidateEmailResponse representa os dados de saída do métodos


XWebEmailValidationInterface.validateEmail().

• A classe ObjectFactory, de uso interno, para criar os objetos do tipo ValidateEmailRequest e


ValidateEmailResponse.

• package-info.java define o namespace do web service.

Para maiores informações veja Developing a JAX-WS client from a WSDL file.

9.4. Consumindo web services


No Framework, o acesso a um web service qualquer é sempre feito através de um bean gerenciado pelos
Spring, que é um proxy para o web service.

Nota
Um proxy é um objeto que representa uma referência ao serviço remoto, tornando o acesso
indireto, mas de maneira transparente para o usuário.

O proxy deve ser definido com as propriedades abaixo:

Tabela 9.4. Propiedade de JaxWsPortProxyFactoryBean

Framework Java Arquitetura Brasil 81


Web Services

Propriedade Descrição

serviceInterface Interface Java que o proxy deve implementar. É como os clientes verão o objeto.

wsdlDocumentUrl URL do web service que será acessado.

namespaceUri Namespace do web service.

serviceName Nome do serviço. Geralmente *EndpointPortService.

portName Nome da porta. Geralmente *EndpointPort.

lookupServiceOnStartup Indica se o serviço JAX-WS será verificado no início da aplicação. Caso seja
false, ele será do tipo "lazy", consultado apenas no primeiro acesso.

Para um cliente acessar um web service, basta declarar um bean que será o proxy do web service. No exemplo a
seguir fazemos a configuração de um proxy para o serviço Hello, e para o serviço EmailValidation, definido
anteriormente neste capítulo.

Arquivo META-INF/config/ws-clients.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- ======================================================================================= -->


<!-- Cliente HelloService -->
<!-- ======================================================================================= -->
<bean id="helloClient" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="serviceInterface" value="com.altec.bsbr.app.demo.service.HelloService"/>❶
<property name="wsdlDocumentUrl"
value="http://${hello.host}:${hello.port}/demo/HelloEndpointService/helloendpointservice.wsdl"
<property name="namespaceUri" value="http://webservice.demo.app.bsbr.altec.com/"/>
<property name="serviceName" value="HelloEndpointService"/>
<property name="portName" value="HelloEndpointPort"/>
<property name="lookupServiceOnStartup" value="false"/>
</bean>

<!-- ======================================================================================= -->


<!-- Cliente EmailValidation -->
<!-- ======================================================================================= -->
<bean id="emailValidationClient" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="serviceInterface"❷
value="com.altec.bsbr.app.abcAdmin.webclient.test.XWebEmailValidationInterface"/>
<property name="wsdlDocumentUrl"
value="http://ws.xwebservices.com/XWebEmailValidation/V2/XWebEmailValidation.wsdl"/>
<property name="namespaceUri" value="urn:ws-xwebservices-com:XWebEmailValidation:EmailValidation:v2"/>
<property name="serviceName" value="EmailValidation"/>
<property name="portName" value="EmailValidation"/>
<property name="lookupServiceOnStartup" value="false"/>
</bean>

</beans>

❶ Usamos a interface criada na própria a aplicação servidora. É a mesma que foi usada na declaração do
endpoint.
❷ Aqui, devemos usar a interface que foi criada pelo wsadmin.

As propriedades usadas no xml podem ficar definidas em arquivos separados para cada <runningMode> como
mostrado no exemplo a seguir:

Arquivo META-INF/config/desenv/ws-clients.properties:

hello.host=localhost
hello.port=8080

(1.13.6)
Web Services

Arquivo META-INF/config/prod/ws-clients.properties:

hello.host=server
hello.port=9080

Quando o web service precisar ser acessado pelo cliente, basta obter uma referência como se ele fosse um
serviço normal:

@Service
public class ExemploServiceImpl implements ExemploService {

@Autowired
private HelloService service;

@Autowired
private XWebEmailValidationInterface emailService;

public String exemplo(String name) {


return service.sayHello(name);
}

public String exemplo2(String email) {


ValidateEmailRequest req = new ValidateEmailRequest();
req.setEmail(email);

ValidateEmailResponse res = emailService.validateEmail(req);

return res.getStatus();
}

Dica
Se houver algum outro serviço local que também implemente a interface HelloService, será
necessário acrescentar a anotação @Qualifier("helloClient") para obter uma referência ao web
service cliente.

9.5. Expondo serviços para serem consumidos pelo WebCon


Consulte: http://bsbrsp2352/trac/wiki/ExpServicosWebCon

(1.13.6)
Capítulo 10. Segurança

10.1. Introdução
Este capítulo mostra como usar os recursos de segurança oferecidos pelo Framework: autenticação,
autorização, criptografia e auditoria.

10.2. Autenticação
A autenticação na rede corporativa acontence de forma transparente para os usuários, desde que tenha sido feito
login na estação com usuário/senha válidos para a rede Windows.

O Framework implementa autenticação que permite as aplicações Java fazerem parte da rede single sign on,
desde que acessadas a partir do Portal Corporativo.

O Portal autentica o usuário e envia para a aplicação Java um ticket se segurança assinado, contendo o nome do
usuário e o código do sistema sendo acessado. Com esses dados um servlet filter verifica a validade dos dados e
a autenticidade do usuário, criando uma HttpSession e permitindo que ele acesse o sistema.

10.2.1. Configuração da autenticação para diferentes runningModes.

A configuração da autenticação fica localizada no arquivo que está


localizado em
[Diretório_Raiz_Projeto]/src/META-INF/config/[runningMode]/authentication.xml. Abaixo estão
alguns exemplos de configuração do Filtro de autenticação:

• Para configurar a autenticação para utilizar


ticket utilize a classe
com.altec.bsbr.fw.security.authentication.filter.AuthFilter. Exemplo:

<?xml version="1.0" encoding="UTF-8"?>


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!--
========================================================================================================
--> <!-- Authorization Filter --> <!--
========================================================================================================
-->
<bean id="authFilter"
class="com.altec.bsbr.fw.security.authentication.filter.AuthFilter">
<property name="autenticationURL" value="[URL]" />❶
<property name="redirectURL" value="[URL]" />❷
<property name="timeout" value="[TIMEOUT]" />❸
<property name="firstPage" value="[URL]" />❹
</bean>
</beans>

❶ URL de validacao do ticket.


❷ URL de redirecionamento para obter ticket.
❸ Tempo máximo para esperar resposta da validação do dados.
❹ URL da primeira página da aplicação.

• Para configurar a autenticação para utilizar o Header Http enviado pelo IIS utilize a classe
com.altec.bsbr.fw.security.authentication.filter.SmartAuthFilter. Exemplo:

Framework Java Arquitetura Brasil 84


Segurança

<?xml version="1.0" encoding="UTF-8"?>


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!--
===========================================================================================================
--> <!-- Authorization Filter --> <!--
===========================================================================================================
-->
<bean id="authFilter"
class="com.altec.bsbr.fw.security.authentication.filter.SmartAuthFilter"/>
</beans>

• Para desabilitar a autenticação paratestes utilize a classe


com.altec.bsbr.fw.security.authentication.filter.DummyFilter. Exemplo:

<?xml version="1.0" encoding="UTF-8"?>


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!--
===========================================================================================================
--> <!-- Authorization Filter --> <!--
===========================================================================================================
-->
<bean id="authFilter"
class="com.altec.bsbr.fw.security.authentication.filter.DummyFilter"/>
</beans>

10.2.2. AuthFilter

O filtro com.altec.bsbr.fw.security.authentication.filter.AuthFilter é quem controla a autenticação


da aplicação web. É necessário configurá-lo no arquivo web.xml da aplicação. O exemplo a seguir mostra o
trecho de um arquivo web.xml configurando o AuthFilter:

<filter>❶
<filter-name>authFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>authFilter</param-value>
</init-param>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>authFilter</filter-name>
<url-pattern>/pages/*</url-pattern>❷
</filter-mapping>

❶ Definição do AuthFilter.
❷ Configuração do mapeamento do filtro. Determina qual o inicio da árvore de diretórios que devem ser
protegidos

Nota
Note que existem vários recursos que não devem ser protegidos, como arquivos CSSs, por
exemplo.

Framework Java Arquitetura Brasil 85


Segurança

10.2.3. SmartAuthFilter

Importante
O Filtro abaixo somete poderá ser usado caso o ambiente seja:

• Servidor Web IIS que esteja recebendo as requisições.

• O Browser seja internet explorer.

O filtro com.altec.bsbr.fw.security.authentication.filter.SmartAuthFilter controla o acesso a


autenticação de uma aplicação web e ele mesmo faz a checagem do usuário do windows, porém só pode ser
usado caso o servidor web que esteja recebendo as requisições sejam o IIS e o navegador seja internet explorer.
É necessário configurá-lo no arquivo web.xml da aplicação. O exemplo a seguir mostra o trecho de um arquivo
web.xml configurando o SmartAuthFilter:

<filter>❶
<filter-name>authFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>authFilter</param-value>
</init-param>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
<!--
Parametros usados por com.altec.bsbr.fw.security.authentication.filter.AuthFilter -->
<init-param>
<param-name>com.altec.bsbr.fw.authentication.modo</param-name>❷
<param-value>LOCAL</param-value>
</init-param>
<init-param>
<param-name>com.altec.bsbr.fw.authentication.sigla</param-name>❸
<param-value>SIGLA</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>authFilter</filter-name>
<url-pattern>/pages/*</url-pattern>❹
</filter-mapping>

❶ Definição do SmartAuthFilter.
❷ Mode de autenticação: LOCAL - valida usuario logado no windows diretamente no framework
❸ Sigla do sistema.
❹ Configuração do mapeamento do filtro. Determina qual o inicio da árvore de diretórios que devem ser
protegidos

Nota
Note que existem vários recursos que não devem ser protegidos, como arquivos CSSs, por
exemplo.

Com o uso destes filtros, a aplicação pode ser toda construída com a suposição de que o usuário já está
autenticado.

Para ter acesso a informações


da autenticação, deve ser usada a classe
com.altec.bsbr.fw.security.SecurityInfo, que possui informações como o nome do usuário e nome do
sistema:

Framework Java Arquitetura Brasil 86


Segurança

• String getUserName() - obtem o nome do usuário autenticado.

• String getLoginTimestamp() - obtem o instante em que foi feita a autenticação.

• String getSystemId() - obtem o codigo do sistema sendo acessado.

• String getRemoteAddr() - obtem o endereço IP do usuário.

Para acessar SecurityInfo deve ser usado o método estático getCurrent():

SecurityInfo secInfo = SecurityInfo.getCurrent(); String


usuario = secInfo.getUserName();

10.3. Autorização
A autorização foi desenvolvida para facilitar e aproveitar os recursos do MBS, sistema utilizado atualmente
para a autorização nas aplicações.

Com os recursos fornecidos pelo framework é possível criar menus diferenciados, baseados no perfil de acesso
do usuário, simplemente usando um componente JSF, ou restringir o acesso a métodos específicos da camada
de serviços com o uso de uma anotação.

10.3.1. Criação do menu personalizado

Caso a aplicação necessite de um menu hierárquico personalizado para cada usuário, deve ser usado o MBS.
Para tanto, é necessário configurar o MBS com as opções desejadas.

Existe uma planilha padrão para ser cadastrada no MBS, que deve ser preenchida com os dados de perfis,
hierarquia para o menu e funções (métodos de serviço) da aplicação.

Cada usuário do sistema deve ser associado a um perfil, e o menu e funções devem ser associados aos perfis,
assim, dependendo do perfil do usuário o menu apresentado é diferenciado, contendo somente as operações
permitidas.

A hierarquia do menu deve ter como "raíz" o nome da aplicação, e todos os itens do menu são "filhos" dela.
Todos os itens devem ter o nome do item pai, um nome único, uma descrição e uma URL. Caso não exista
URL associada a um item, ele simplesmente aparecerá no menu como um agrupamento de funções. As URLs
indicam qual página será chamada, no caso uma chamada para a servlet do ICEfaces, como relatorio.iface.
Exemplo de planilha:

Tabela 10.1. Planilha de cadastro no MBS

Nível Funções Descrição URL PerfilPerfilPerfil


Hierárquico

JAB - Aplicação de - A B C
referência

- JAB-PEDIDOS Pedidos /pages/pedidos.iface A B -

- JAB-ESTOQUE Estoque /pages/estoque.iface A - C

(1.13.6)
Segurança

Nível Funções Descrição URL PerfilPerfilPerfil


Hierárquico

- JAB-RELATORIO Relatórios - A B -

- JAB-RELATORIO1 Relatório Pedido 1 /pages/relatorios/rel_1.iface A B -

Para usar o menu obtido do MBS na aplicação web, veja a seção Menu de acesso configurado pelo MBS.

10.3.2. Autorização de serviços

Com o uso do Framework é possível fazer também autorização nos métodos da camada de serviços. Desse
modo podemos ter um controle mais granular da segurança de cada serviço, principalmente quando eles forem
chamados por outros sistemas e não pela camada web.

A autorização dos métodos de serviço será feita automaticamente se eles forem anotados com
com.altec.bsbr.fw.annotation.Authorize. A autorização será feita em um objeto do tipo SecurityInfo,
que deve ser passado como parâmetro do método do serviço. Abaixo segue um exemplo do uso de
SecurityInfo para indicar que o método de serviço deve ser autorizado:

@Service
public class TestServiceImpl implements TestService {
@Authorize
public String sayHello(SecurityInfo secInfo, String name) {
return "Hello " + name + "!";
}
}

Uma verificação de autorização será sempre feita, para saber se o usuário passado no parâmetro secInfo tem a
permissão de chamar o método. Caso ele não tenha permissão, será lançada a exceção
com.altec.bsbr.fw.security.authorization.AuthorizationException.

De modo análogo ao menu, os métodos devem ser listados na planilha, mas não devem ter URL nem item
"pai":

Tabela 10.2. Planilha de cadastro no MBS

Nível Funções (Máx: 64 Descrição URL PerfilPerfilPerfil


Hierárquico caracteres)

JAB JAB-TestServiceImpl.sayHello
Método para testes de - - B -
autorização de serviços

Importante
O valor do campo Funções da planílha não devem ter mais do que 64 caracteres. Ou seja, a soma
do Nome da Classe do Serviço + Nome do método + 1 NÃO deve ser maior do que 64 caracteres.

10.3.3. Configuração para acesso ao MBS

No diretório META-INF/conf deve existir um arquivo authorization.xml definindo os parâmetros de acesso ao

(1.13.6)
Segurança

MBS:

• url - endereço de conexão no web service do MBS.

• cacheSize - tamanho do cache de permissões de usuários.

• timeout - timeout em milisegundos do cache de permissões de usuários. (timeout default é 20 min)

Durante o desenvolvimento, pode ser inconveniente acessar sempre o MBS. Para isso, pode ser usada a classe
DummyAuthorization, que retorna sempre true para a autorização e possui um menu de exemplo, podendo ser
estendida de acordo com a conveniência do programador. Para usar este autorizador, basta colocar um arquivo
authorization.xml que usa o DummyAuthorization no diretório do running mode de desenvolvimento, e outro
authorization.xml com o MBSAuthorization no diretório dos running modes onde ele deve ser usado.

Arquivo META-INF/conf/prod/authorization.xml:

<!--
=======================================================================================
--> <!-- MBS --> <!--
=======================================================================================
-->
<bean class="com.altec.bsbr.fw.security.authorization.impl.MBSAuthorization">
<property name="url" value="http://wsdotnetdes.sb:81/mbs-ext/mbscomi.asmx"/>
<property name="cacheSize" value="1000"/>
<property name="timeout" value="1200000"/>
</bean>

Arquivo META-INF/conf/dev/authorization.xml:

<bean
class="com.altec.bsbr.fw.security.authorization.impl.DummyAuthorization">
</bean>

Nota
Se o programador precisar de algum uso avançado do MBS, o método
Authorization.getAuthorizationProvider() retorna uma instância de MBSCaller que pode ser
usada diretamente para chamar o web service do MBS.

10.4. Criptografia
Para as funcionalidades de criptografia, o Framework Java Altec Brasil se baseia no padrão Java Cryptography
Architecture suportado pelo Java 5 Standard Edition.

No entanto, para essa tarefa foi incluída a biblioteca open source Jasypt, que torna mais simples o uso de
capacidades de encriptação/decripatção, sem a necessidade de conhecimentos profundos de criptologia.

Os pacotes abaixo são usados para as tarefas mais comuns:

• Digesting, ou hash (org.jasypt.util.digest.*)

• Encriptação de senhas (digesting) (org.jasypt.util.password.*)

• Encriptação de textos (org.jasypt.util.text.*)

• Encriptação de números (org.jasypt.util.numeric.*)

Framework Java Arquitetura Brasil 89


Segurança

• Encriptação de binários (org.jasypt.util.binary.*)

Está fora do escopo deste documento explicar conceitos de criptografia ou mesmo documentar a biblioteca
Jasypt. O intuito é apresentar algumas das suas funcionalidades básicas. Maiores informações podem ser
obtidas abaixo:

• Site da Sun sobre Java SE Security: http://java.sun.com/javase/technologies/security

• Site oficial do Jasyp: http://www.jasypt.org

• Criptografia na Wikipédia: http://pt.wikipedia.org/wiki/Criptografia

• Documento Santander: Uso de la Criptografia / SC-NT-008-E

• Documento Santander: Elección de Componentes Criptográficos / SC-ET-020-E

• Documento Santander: Gestión de Claves Criptográficas / SC-ET-021-E

10.4.1. Digesting

A classe org.jasypt.util.digest.Digester executa o digest em nível binário (compatível com os gerados


por java.security.MessageDigest) de uma maneira thread-safe.

...
Digester digester = new Digester();
digester.setAlgorithm("SHA-1");
...
byte[] digest = digester.digest(message);
...

10.4.2. Encriptação de senhas (usando digesting)

Todas as classes aqui descritas implementam a interface org.jasypt.util.password.PasswordEncryptor e


podem ser usadas de modo intercambiável.

• org.jasypt.util.password.BasicPasswordEncryptor pode ser usada para encriptar senhas e


posteriormente verificar sua validade.

...
BasicPasswordEncryptor passwordEncryptor = new BasicPasswordEncryptor();
String encryptedPassword = passwordEncryptor.encryptPassword(userPassword);
...
if (passwordEncryptor.checkPassword(inputPassword, encryptedPassword)) {
// correto!
} else {
// senha incorreta!
}
...

• org.jasypt.util.password.StrongPasswordEncryptor é equivalente ao anterior, mas apresenta um nível


de segurança maior (com um maior custo computacional).

...
StrongPasswordEncryptor passwordEncryptor = new StrongPasswordEncryptor();
String encryptedPassword = passwordEncryptor.encryptPassword(userPassword);
...
if (passwordEncryptor.checkPassword(inputPassword, encryptedPassword)) {
// correto!

Framework Java Arquitetura Brasil 90


Segurança

} else {
// senha incorreta!
}
...

• org.jasypt.util.password.ConfigurablePasswordEncryptor permite ao desenvolvedor configurar qual


algoritimo e mecenismo de encriptação de senha, como descrito na documentação do Jasypt.

...
ConfigurablePasswordEncryptor passwordEncryptor = new ConfigurablePasswordEncryptor();
passwordEncryptor.setAlgorithm("SHA-1");
passwordEncryptor.setPlainDigest(true); String encryptedPassword =
passwordEncryptor.encryptPassword(userPassword);
...
if (passwordEncryptor.checkPassword(inputPassword, encryptedPassword)) {
// correto!
} else {
// senha incorreta!
}
...

10.4.3. Encriptação de texto

Todas as classes aqui descritas implementam a interface org.jasypt.util.text.TextEncryptor e podem ser


usadas de modo intercambiável.

• org.jasypt.util.text.BasicTextEncryptor permite a encriptação e decriptação de textos. Antes de ser


usado, ele precisa receber a senha que será usada.

... BasicTextEncryptor textEncryptor = new BasicTextEncryptor();


textEncryptor.setPassword(myEncryptionPassword);
...
String myEncryptedText = textEncryptor.encrypt(myText);
...
String plainText = textEncryptor.decrypt(myEncryptedText);
...

• org.jasypt.util.text.StrongTextEncryptor permite a encriptação e decriptação de textos usando


algoritmo forte. Antes de ser usado, ele precisa receber a senha que sera usada.

Dependendo do algoritmo escolhido, pode ser necessária a instalação do Java Cryptography Extension
(JCE) Unlimited Strength Jurisdiction Policy Files.

... StrongTextEncryptor textEncryptor = new StrongTextEncryptor();


textEncryptor.setPassword(myEncryptionPassword);
...
String myEncryptedText = textEncryptor.encrypt(myText);
...
String plainText = textEncryptor.decrypt(myEncryptedText);
...

10.4.4. Encriptação de números

Todas as classes aqui descritas implementam a interface org.jasypt.util.numeric.DecimalNumberEncryptor


ou org.jasypt.util.numeric.IntegerNumberEncryptor e podem ser usadas de modo intercambiável.

• org.jasypt.util.numeric.BasicIntegerNumberEncryptor permite a encriptação e decriptação de objetos

(1.13.6)
Segurança

BigInteger. Antes de ser usado, ele precisa receber a senha que sera usada.

...
BasicIntegerNumberEncryptor integerEncryptor = new BasicIntegerNumberEncryptor();
integerEncryptor.setPassword(myEncryptionPassword);
...
BigInteger myEncryptedNumber = textEncryptor.encrypt(myNumber);
...
BigInteger plainNumber = textEncryptor.decrypt(myEncryptedNumber);
...

• org.jasypt.util.numeric.StrongIntegerNumberEncryptor permite a encriptação e decriptação de


objetos BigInteger usando alogritmo forte. Antes de ser usado, ele precisa receber a senha que sera usada.

Dependendo do algoritmo escolhido, pode ser necessário a instalação do Java Cryptography Extension
(JCE) Unlimited Strength Jurisdiction Policy Files.

... StrongIntegerNumberEncryptor integerEncryptor =


new StrongIntegerNumberEncryptor();
integerEncryptor.setPassword(myEncryptionPassword);
...
BigInteger myEncryptedNumber = integerEncryptor.encrypt(myNumber);
...
BigInteger plainNumber = integerEncryptor.decrypt(myEncryptedNumber);
...

• org.jasypt.util.numeric.BasicDecimalNumberEncryptor permite a encriptação e decriptação de objetos


BigDecimal . Antes de ser usado, ele precisa receber a senha que sera usada.

... BasicIntegerNumberEncryptor decimalEncryptor =


new BasicIntegerNumberEncryptor();
decimalEncryptor.setPassword(myEncryptionPassword);
...
BigDecimal myEncryptedNumber = decimalEncryptor.encrypt(myNumber);
...
BigDecimal plainNumber = decimalEncryptor.decrypt(myEncryptedNumber);
...

• org.jasypt.util.numeric.StrongDecimalNumberEncryptor permite a encriptação e decriptação de


objetosBigDecimal usando alogritmo forte. Antes de ser usado, ele precisa receber a senha que sera usada.

Dependendo do algoritmo escolhido, pode ser necessário a instalação do Java Cryptography Extension
(JCE) Unlimited Strength Jurisdiction Policy Files.

...
StrongDecimalNumberEncryptor decimalEncryptor = new StrongDecimalNumberEncryptor();
decimalEncryptor.setPassword(myEncryptionPassword);
...
BigDecimal myEncryptedNumber = decimalEncryptor.encrypt(myNumber);
...
BigDecimal plainNumber = decimalEncryptor.decrypt(myEncryptedNumber);
...

10.4.5. Encriptação de binários

Todas as classes aqui descritas implementam a interface org.jasypt.util.binary.BinaryEncryptor e podem


ser usadas de modo intercambiável.

• org.jasypt.util.binary.BasicBinarytEncryptor permite a encriptação e decriptação de arrays de bytes.


Antes de ser usado, ele precisa receber a senha que sera usada.

(1.13.6)
Segurança

...
BasicBinaryEncryptor binaryEncryptor = new BasicBinaryEncryptor();
binaryEncryptor.setPassword(myEncryptionPassword);
...
byte[] myEncryptedBinary = binaryEncryptor.encrypt(myBinary);
...
String plainBinary = binaryEncryptor.decrypt(myEncryptedBinary);
...

• org.jasypt.util.binary.StrongBinaryEncryptor permite a encriptação e decriptação de arrays de bytes,


usando algoritmo forte. Antes de ser usado, ele precisa receber a senha que sera usada.

Dependendo do algoritmo escolhido, pode ser necessária a instalação do Java Cryptography Extension
(JCE) Unlimited Strength Jurisdiction Policy Files .

...
StrongBinaryEncryptor binaryEncryptor = new StrongBinaryEncryptor();
binaryEncryptor.setPassword(myEncryptionPassword);
...
String myEncryptedBinary = binaryEncryptor.encrypt(myBinary);
...
String plainBinary = binaryEncryptor.decrypt(myEncryptedBinary);
...

10.4.6. Algoritmos criptográficos

Importante
O gerenciamento de chaves e senhas está fora do escopo do Framework. Para sua utilização correta
a área de Segurança de Informação deve ser consultada.

Os algoritmos criptográficos aprovados pelo Grupo Santander são:

• AES, Triple-DES, IDEA, Blowfish e RC4 para encriptação simétrica

• RSA para encriptação assimétrica

• SHA-1 para hash sem chave

• AES para hash com chave

• RSA, DSA ou ECDSA para certificado digital

Atenção
Não usar outros algoritmos, como o DES ou MD5.

Para maiores informações, consulte o documento "Elección de Componentes Criptográficos SC-ET-020-E".

Tabela 10.3. Algoritmos criptográficos

Algoritmo Uso Tamanho de chave Vida útil esperada Período máximo


mínimo de revisão

AES Encriptação 128 bit 20 anos 5 anos

Triple-DES (2-key) Encriptação 112 (2 x 56) bit 5 anos 1 ano

Framework Java Arquitetura Brasil 93


Segurança

Algoritmo Uso Tamanho de chave Vida útil esperada Período máximo


mínimo de revisão

Triple-DES (3-key) Encriptação 168 (3 x 56) bit 10 anos 2 anos

IDEA Encriptação 128 bits 10 anos 5 anos

Blowfish Encriptação 128 bits 5 anos 2 anos

RC4-SSL Encriptação 128 bits 1 ano 1 ano

RSA-1024 Encriptação de 1024 bits 3 anos 1 ano


chaves

RSA-2048 Encriptação de 2048 bits 10 anos 2 anos


chaves (CA)

AES Hash com chave 128 bit 20 anos 5 anos

SAH-1 Hash sem chave 160 bit (Hash) 5 anos 1 ano

DSA Certificado digital 168 bit 3 anos 2 anos

RSA-1024 Certificado digital 1024 bit 3 anos 1 ano

RSA-2048 Certificado digital 2048 bit 10 anos 2 anos

ECDSA Certificado digital 112 bit 10 anos 2 anos

10.5. Auditoria

É importante observar que existe uma diferença entre Log de aplicação e Auditoria. Enquanto o log faz o
registro de informações sobre o ciclo de vida da aplicação e dados internos do sistema, a Auditoria tem o
objetivo de rastrear as operações de negócio realizadas por motivos de segurança, e contém informações sobre
acesso e uso por clientes de um determinado recurso do sistema.

Além disso, o conjunto de informações auditadas costuma ser armazenado em estruturas indexadas para
consultas e geração de relatórios.

Portanto, o destino dos dados de auditoria geralmente é diferente dos dados de Log. Ao passo que informações
de Log são importantes para os técnicos e desenvolvedores detectarem problemas, registros de auditoria
auxiliam gerentes e analistas de negócio e segurança determinarem os padrões de acesso a um determinado
recurso.

O Framework oferece uma


API para gravar informações de auditoria. A classe
com.altec.bsbr.fw.audit.AuditTrail é a responsável por receber os eventos de auditoria.

Assim como o Log manual, a auditoria manual é a oportunidade que o desenvolvedor tem de determinar os
pontos e conjunto de dados que deverão ser auditados fora do escopo do método de serviço. Para tanto, o
desenvolvedor deve utilizar a API de auditoria para fazer as chamadas adequadas e registrar as informações
pertinentes ao acesso e utilização de um determinado recurso.

As informações a serem
persistidas no evento de auditoria, ficam contidas na classe
com.altec.bsbr.fw.audit.AuditInfo. Esta classe é responsável por armazenar pares de [parâmetro, valor]

Framework Java Arquitetura Brasil 94


Segurança

que serão armazenado na forma de informações auditáveis.

A classe AuditInfo já possui algumas propriedades padrão, que devem ser seguidas por todas as aplicações:

• Canal (Exemplo: IB, Portal Java, ATM, etc).

• Tipo de terminal (Exemplo: Web, Celular, Client-Server, etc).

• Número do terminal (Exemplo: identificação do dispositivo, IP, Nome do host, etc).

• Nome do usuário – é preenchido pelo próprio Framework.

• Indicador de finalização correta ou com erro – é preenchido pelo próprio Framework.

• Data e hora da transação – é preenchido pelo Framework.

• Nome do serviço – é preenchido pelo Framework.

• Nome do método – é preenchido pelo Framework.

A aplicação deve dizer como os eventos de auditoria devem ser gravados, implementando a interface
com.altec.bsbr.fw.audit.AuditHandler, que deve pegar as propriedades presentes no objeto AuditInfo e
efetuarem a persistência dos valores como, por exemplo, colocando-os numa fila ou num banco de dados.

O exemplo a seguir simplesmente insere as informações numa tabela do banco de dados. Para tanto ela
simplesmente estende a classe GenericJdbcDao, e usa o objeto SimpleJdbcTemplate disponibilizado para
executar o insert.

@Repository public class DbAuditHandler extends GenericJdbcDao implements AuditHandler {


public void logEvent(AuditInfo props) {
Map<String, Object> parameters = new HashMap<String, Object>(6);
parameters.put("DATA_HORA", auditInfo.getDataHora().toDate());
parameters.put("SERVICO", auditInfo.getServico());
parameters.put("METODO", auditInfo.getMetodo());
parameters.put("CANAL", auditInfo.getCanal());
parameters.put("TIPO_TERMINAL", auditInfo.getTipoTerminal());
parameters.put("NUMERO_TERMINAL", auditInfo.getNumeroTerminal());
parameters.put("USUARIO", auditInfo.getUsuario());
getSimpleJdbcTemplate().update("insert into" + " audit_log (ID, DATA_HORA,
SERVICO, METODO, CANAL, TIPO_TERMINAL, NUMERO_TERMINAL, USUARIO)" +
"values (seq_id.nextval," + " :DATA_HORA, :SERVICO, :METODO, :CANAL, :TIPO_TERMINAL, :NUMERO_TERMINAL, :
}
}

Esse AuditHandler deve constar em um arquivo de configuração META-INF/config/audit.xml

<bean
class="com.altec.bsbr.app.demo.audit.DbAuditHandler"> <property
name="dataSource" ref="dataSource"/> </bean>

Dica
Durante o processo de desenvolvimento, pode ser conveniente usar um AuditHandler simplificado,
que apenas envia a saída para o arquivo de log comum. Nesse caso pode ser usado um arquivo para
produção (META-INF/config/prod/audit.xml) com o DbAuditHandler e um outro para
desenvolvimento (META-INF/config/dev/audit.xml) com o DefaultAuditHander, que apenas
coloca as informações de auditoria no log de arquivos normal.

<bean
class="com.altec.bsbr.fw.audit.DefaultAuditHandler"/>

(1.13.6)
Segurança

10.5.1. Auditoria manual

Para fazer gerar um evento de auditoria, é necessário obter uma instância de


com.altec.bsbr.fw.audit.AuditTrail através de um método estático. A aplicação precisa então criar um
objeto AuditInfo contendo as informações do evento e passa-la para o objeto de auditoria. Exemplo de uso:

AuditTrail audit = AuditTrail.getInstance(); AuditInfo


auditInfo = new AuditInfo(); auditInfo.setProperty("saldoAnterior",
oldValue); auditInfo.setProperty("saldoPosterior", newValue);
audit.log(auditInfo);

Internamente, a classe AuditTrail coloca os eventos de log numa fila para serem persistidos de maneira
assíncrona. Assim, a aplicação não precisa incorrer no custo de uma gravação no banco de dados para continuar
o processamento.

10.5.2. Auditoria automática

Os métodos da camada de serviço serão automaticamente auditados se possuirem a anotação


com.altec.bsbr.fw.annotation.Audit. O Framework espera que o método possua como parâmetro um
objeto do tipo AuditInfo.

Abaixo segue um exemplo do uso de @Audit para indicar que o método de serviço deve ser auditado:

@Service
public class TestServiceImpl implements TestService {
@Audit
public String sayHello(AuditInfo info, String name) {
return "Hello " + name + "!";
}
}

O chamador do serviço tem a obrigação de passar um objeto AuditInfo contendo os dados necessários. Caso o
método anotado com @Audit não possua nenhum parâmetro do tipo AuditInfo ou ele seja nulo, ocorrerá uma
exceção, e o método não será executado.

(1.13.6)
Capítulo 11. Interface Web

11.1. Introdução
A interface web está baseada nos seguintes frameworks JSF, ICEfaces com Facelets para componentes visuais
e templates, JasperReports para relatórios e Spring para integrar com a camada de serviços. Deste modo, o
Framework Santander Brasil oferece uma infra-estrutura básica para o desenvolvimento rápido e fácil
utilizando os Frameworks citados anteriormente.

O Framework tem como característica principal o desenvolvimento baseado nos padrões de interfaces gráficas
e em camadas. Portanto, o bom entendimento da interação de camadas torna-se imprescindível. Na figura a
seguir detalhamos num nível alto de abstração como a interface web interage com a camada de serviços.

11.2. Sobre o JSF


JSF é um Framework de desenvolvimento de aplicações web Java, baseado em componentes. Similar ao

Framework Java Arquitetura Brasil 97


Interface Web

framework de interface gráfica Java Swing, os componentes da interface fazem chamada a classes chamadas
Backing Beans, que atuam como fornecedores de dados aos componentes e respondem a eventos realizados nos
mesmos.

JSF é um padrão que está sendo amplamente utilizado em projetos de grande porte, além disso os principais
Servidores de Aplicação existentes possuem total suporte.

Figura 11.1. Iteração entre o browser, páginas e componentes (UI)

A figura acima descreve a iteração entre o Navegador (Browser) e uma aplicação JSF qualquer. Os
componentes da página jsp refletem o estado dos componentes UI que estão no servidor.

Para facilitar a criação e o desenho de novas telas JSF utiliza o padrão de tag libraries em arquivos jsp ou jspx.
Veja abaixo um exemplo de uso de tag libraries:

• Declaração em uma página jsp ou jspx é feita utilizando-se XML Namespaces. Com ela é possível incluir
componentes JSF e de terceiros nas páginas:

<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:jsp="http://java.sun.com/JSP/Page"❶
xmlns:ui="http://java.sun.com/jsf/facelets"❷
xmlns:h="http://java.sun.com/jsf/html"❸
xmlns:f="http://java.sun.com/jsf/core"❹
xmlns:ice="http://www.icesoft.com/icefaces/component"❺
version="2.0">
...
</html>

❶ Declaração das tags JSP, fazendo a ligação para jsp.


❷ Declaração das tags Facelets, fazendo a ligação para ui.
❸ Declaração das tags JSF HTML, fazendo a ligação para h.
❹ Declaração das tags JSF Code, fazendo a ligação para f.
❺ Declaração das tags do Icefaces, fazendo a ligação para ice.

• Uso dos componentes declarados anteriormente em páginas jsp e jspx:

...

Framework Java Arquitetura Brasil 98


Interface Web

<ice:outputText value="..."/>
<ice:commandButton action="..." actionListener="..."/>
...
<h:outputText value="..."/>
<h:outputLink value="..."/>
...

Com JSF é possível criar componentes ricos de uma maneira simples e confiável, porém é necessário um
esforço inicial que muitas vezes não temos em um projeto. Desta forma iremos utilizar componentes já prontos
do projeto Icefaces.org. Este projeto tem uma grande variedade de componentes ricos e com suporte a AJAX,
ou seja, são componentes que agregam funcionalidades de alta tecnologia as aplicações web.

Abaixo exemplificamos alguns componentes usando JSF com Icefaces:

• Componente de tabela:

Figura 11.2. Componente ice:dataTable

• Componente de árvore:

Framework Java Arquitetura Brasil 99


Interface Web

Figura 11.3. Componente ice:tree

• Componente de menu:

Figura 11.4. Componente ice:menuBar

(1.13.6)
Interface Web

• Componente de Gráficos:

Figura 11.5. Componente ice:outputChart

• Componente de Mapa:

(1.13.6)
Interface Web

Figura 11.6. Componente ice:GMap

Estes componentes podem ser facilmente customizados bastando criar uma nova folha de estilo.

Para uma lista completa de componentes acesse Icefaces.org.

11.3. Configurando a aplicação


Cada novo projeto deve ter sua própria estrutura de diretórios básica de um novo projeto de web Java. Esta
estrutura pode ser visualizada no arquivo web_blank.zip que será fornecido pela área de arquitetura do Banco
Santander.

Projeto/
web/
resources/
index.jsp -> Página inicial (faz um redirocionamento para a URL do ICEfaces)
css/ -> Estilo
images/ -> Imagens
pages/ -> Páginas JSPX
WEB-INF/
faces-config.xml
faces-navigation.xml
web.xml

Cada nova aplicação deve configurar alguns parâmetros padrão no arquivo web.xml. Abaixo segue um template
de um arquivo web.xml configurado para um projeto web padrão.

Primeiro, definimos o cabeçalho do arquivo e o nome da aplicação:

<?xml version="1.0" encoding="UTF-8"?>


<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"

Framework Java Arquitetura Brasil 102


Interface Web

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<display-name>ABC CD Online Application</display-name>

Depois, são definidos os parâmetros de configuração de uma aplicação JSF. O exemplo abaixo contem os
valores default, que devem ser alterados apenas se necessário.

<context-param>
<description>
The ServletContext init parameter consulted by the
StateManager to tell where the state should be saved. Valid
values are given as the values of the constants: client or
server.

If this parameter is not specified, the default value is the


value of the constant client.
</description>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>

<context-param>
<description>
Context initialization parameter name for a comma delimited
list of context-relative resource paths (in addition to
/WEB-INF/faces-config.xml which is loaded automatically if
it exists) containing JavaServer Faces configuration
information.
</description>
<param-name>javax.faces.CONFIG_FILES</param-name>
<param-value>
/WEB-INF/faces-config.xml, /WEB-INF/faces-navigation.xml
</param-value>
</context-param>

<context-param>
<description>
The value to use for the default extension if the webapp is
using url extension mapping.
</description>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.jspx</param-value>
</context-param>

<context-param>
<description>Special Debug Output for Development</description>
<param-name>facelets.DEVELOPMENT</param-name>
<param-value>true</param-value>
</context-param>

<context-param>
<description>
Set this flag to true, if you want the JavaServer Faces
Reference Implementation to validate the XML in your
faces-config.xml resources against the DTD. Default value is
false.
</description>
<param-name>com.sun.faces.validateXml</param-name>
<param-value>true</param-value>
</context-param>

<context-param>
<description>
Set this flag to true, if you want the JavaServer Faces
Reference Implementation to verify that all of the
application objects you have configured (components,
converters, renderers, and validators) can be successfully
created. Default value is false.
</description>
<param-name>com.sun.faces.verifyObjects</param-name>
<param-value>true</param-value>
</context-param>

Framework Java Arquitetura Brasil 103


Interface Web

A seguir, os parâmetros de configuração de uma aplicação JSF com ICEfaces. O exemplo abaixo contem os
valores default, que devem ser alterados apenas se necessário.

<context-param>
<description>
By default, ICEfaces runs in asynchronous update mode, which
provides support for ICEfaces unique server-initiated
rendering (server-push) capabilities. However, many
applications do not require the full capabilities provided
by asynchronous update mode. In these cases, it is
recommended that synchronous update mode be configured.

Synchronous update mode can be enabled application-wide


using the ICEfaces context parameter,
com.icesoft.faces.synchronousUpdate. Typically this is set
in the web.xml file of your web application.
</description>
<param-name>com.icesoft.faces.synchronousUpdate</param-name>
<param-value>true</param-value>
</context-param>

<context-param>
<description>
To allow multiple windows for a single application,
concurrent DOM views must be enabled. This is set through
the ICEfaces context parameter,
com.icesoft.faces.concurrentDOMViews.
</description>
<param-name>com.icesoft.faces.concurrentDOMViews</param-name>
<param-value>false</param-value>
</context-param>

<context-param>
<description>
To cause request scope to last only for the duration of a
single user event, "standard request scope" must be enabled.
This is set through the ICEfaces context parameter,
com.icesoft.faces.standardRequestScope.
</description>
<param-name>com.icesoft.faces.standardRequestScope</param-name>
<param-value>true</param-value>
</context-param>

<context-param>
<description>
Resources such as JavaScript and CSS files can be compressed
when sent to the browser. This can improve application load
time in certain deployments. This configuration works
independently from the web-server configuration.

The feature can be turned on application-wide using the


ICEfaces context parameter,
com.icesoft.faces.compressResources.
</description>
<param-name>com.icesoft.faces.compressResources</param-name>
<param-value>true</param-value>
</context-param>

<context-param>
<description>
The maximum file upload size can be specified in the web.xml
file of your web application
</description>
<param-name>com.icesoft.faces.uploadMaxFileSize</param-name>
<param-value>1048576</param-value>
</context-param>

<!-- Heartbeating actively monitors the asynchronous connection


state and reports the connection health as one of the
following states:

* Inactive - The connection is alive and there is no pending


activity.

* Active - The connection is alive and there is a request


pending.

(1.13.6)
Interface Web

* Caution - The connection heartbeat latency has exceeded


the configured threshold and that asynchronous updates from
the server may not be received in a timely manner.

* Disconnected - The connection has been lost, due either to


network or application error, such as session expiry, etc.

The Caution state occurs if heartbeats go missing, but


retries are in progress. If the retries fail, the connection
state will transition to Disconnected, and if a retry
succeeds, the connection state will return to Inactive. -->

<context-param>
<description>
When a connection is lost, ICEFaces can be configured to
redirect the browser to a custom error page. This feature
can be turned on application-wide using the ICEfaces context
parameter, com.icesoft.faces.connectionLostRedirectURI.
</description>
<param-name>com.icesoft.faces.connectionLostRedirectURI</param-name>
<param-value>/</param-value>
</context-param>

<context-param>
<description>
The connectionTimeout parameter defines how long, in
milliseconds, that the bridge will wait for a response from
the server for a user-initiated request before declaring the
connection lost. The default value is 60000 (60 seconds).
</description>
<param-name>com.icesoft.faces.connectionTimeout</param-name>
<param-value>60000</param-value>
</context-param>

Definir os listeners de configuração do Spring. O exemplo abaixo contem os valores default, que devem ser
alterados apenas se necessário.

<!-- Deve ser o primeiro listener no web.xml -->


<listener>
<listener-class>
org.springframework.web.util.IntrospectorCleanupListener
</listener-class>
</listener>

<listener>
<description>
Servlet 2.4+ listener that exposes the request to the
current thread, through both LocaleContextHolder and
RequestContextHolder. To be registered as listener in
web.xml.

Alternatively, Spring's RequestContextFilter and Spring's


DispatcherServlet also expose the same request context to
the current thread. In contrast to this listener, advanced
options are available there (e.g.
"threadContextInheritable").

This listener is mainly for use with third-party servlets,


e.g. the JSF FacesServlet. Within Spring's own web support,
DispatcherServlet's processing is perfectly sufficient.
</description>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>

Definir o listener de configuração do Framework:

<listener>
<listener-class>
com.altec.bsbr.fw.config.ContextLoaderListener
</listener-class>
</listener>

(1.13.6)
Interface Web

Definir o listener de configuração do ICEfaces:

<listener>
<listener-class>
com.icesoft.faces.util.event.servlet.ContextEventRepeater
</listener-class>
</listener>

Os servlets do ICEfaces. O exemplo abaixo contem os valores default, que devem ser alterados apenas se
necessário.

<servlet>
<description>
Don't remove this servlet. Websphere requires it.
</description>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet>
<description>
FacesServlet is a servlet that manages the request
processing lifecycle for web applications that are utilizing
JavaServer Faces to construct the user interface.
</description>
<servlet-name>Persistent Faces Servlet</servlet-name>
<servlet-class>
com.icesoft.faces.webapp.xmlhttp.PersistentFacesServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet>
<servlet-name>Blocking Servlet</servlet-name>
<servlet-class>
com.icesoft.faces.webapp.xmlhttp.BlockingServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

Servlet de imagem é um Servlet que ajuda a rederizar imagens em uma página web, se necessário. Para mais
informações consulte Servlet de Imagem. Para resabilitar o cache de imagens utilize "0" no parâmetro
com.altec.bsbr.fw.web.image.MaxCachedImages.

<servlet>
<servlet-name>Image Render</servlet-name>
<servlet-class>
com.altec.bsbr.fw.web.image.ImageServlet
</servlet-class>
<init-param>
<description>
Configures the cached images to the provided value.
Default value is 5. Use "0" (zero) to disable the cache.
</description>
<param-name>
com.altec.bsbr.fw.web.image.MaxCachedImages
</param-name>
<param-value>20</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>

Servlets de configuração do JasperReports (colocar apenas os necessários):

<servlet>
<servlet-name>Pdf Report Servlet</servlet-name>
<servlet-class>
net.sf.jasperreports.j2ee.servlets.PdfServlet

Framework Java Arquitetura Brasil 106


Interface Web

</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>

<servlet>
<servlet-name>Rtf Report Servlet</servlet-name>
<servlet-class>
net.sf.jasperreports.j2ee.servlets.RtfServlet
</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>

<servlet>
<servlet-name>Odt Report Servlet</servlet-name>
<servlet-class>
net.sf.jasperreports.j2ee.servlets.OdtServlet
</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>

<servlet>
<servlet-name>Xls Report Servlet</servlet-name>
<servlet-class>
net.sf.jasperreports.j2ee.servlets.XlsServlet
</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>

<servlet>
<servlet-name>Xml Report Servlet</servlet-name>
<servlet-class>
net.sf.jasperreports.j2ee.servlets.XmlServlet
</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>

Mapeamento dos servlets:

<servlet-mapping>
<servlet-name>Pdf Report Servlet</servlet-name>
<url-pattern>*.pdf</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>Odt Report Servlet</servlet-name>
<url-pattern>*.odt</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>Xsl Report Servlet</servlet-name>
<url-pattern>*.xls</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>Xml Report Servlet</servlet-name>
<url-pattern>*.xml</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>Rtf Report Servlet</servlet-name>
<url-pattern>*.rtf</url-pattern>
</servlet-mapping>

<!-- Persistent Faces Servlet Mapping -->


<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>Persistent Faces Servlet</servlet-name>
<url-pattern>*.iface</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>Persistent Faces Servlet</servlet-name>

Framework Java Arquitetura Brasil 107


Interface Web

<url-pattern>/xmlhttp/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>Blocking Servlet</servlet-name>
<url-pattern>/block/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>Image Render</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>

Configuração do timeout da sessão HTTP:

<session-config>
<!--
The session-timeout element defines the default
session timeout interval for all sessions created
in this web application. The specified timeout
must be expressed in a whole number of minutes.
If the timeout is 0 or less, the container ensures
the default behaviour of sessions is never to time
out. If this element is not specified, the container
must set its default timeout period.
-->
<session-timeout>15</session-timeout>
</session-config>

Configurações do arquivo welcome (primeira página a ser apresentada):

<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>

E por fim, o mapeamento de erros:

<error-page>
<error-code>500</error-code>
<location>/pages/error.iface</location>
</error-page>

</web-app>

11.4. Configurando JSF


Existem dois arquivos que devem ser adicionados a aplicação web para se utilizar o Framework:

• faces-config.xml: É o principal arquivo de configuração de uma implementação da API Java Server Faces
(JSF). Neste arquivo devem ser registrados os Converters, Backing Beans e Validators. Para um melhor
entendimento separamos a navegação do site em um outro arquivo.

• Converters: São usados para converter valores entre um formulário e o tipo definido em uma classe
Java.

• Backing Beans: São classes que irão interagir com a página .jspx, fornecendo dados, processando
formulários, processando cliques, mundaças na página, etc.

Nota

(1.13.6)
Interface Web

Só é necessário caso haja a necessidade de efetuar uma configuração prévia no Backing


Bean, pois o próprio Spring Framework se encarregará de registrá-lo, não havendo a
necessidade de fazer a declaração no faces-config.xml.

• Validators: São classes que irão fazer a validação dos dados que foram inseridos em um formulário.

• faces-navigation.xml: Neste arquivo deve ficar o controle de navegação do site.

Estes arquivos devem estar localizados no diretório WEB-INF da sua aplicação. Conforme mostrado abaixo:

[Raiz_Projeto]/
/src
/web/
WEB-INF/
faces-config.xml
faces-navigation.xml

Importante
Na inicialização da aplicação o Framework já adiciona as configurações básicas do JSF, como:
VariableResolver para resolver os Backing Beans via Spring, Converter para ExportOption.
Portanto, não há a necessidade de adicioná-los novamente.

Para obter maiores informações sobre JSF veja o site oficial.

11.4.1. Configurando Facelets

Facelets agregam suporte a templates ao JSF e uma série de funcionalidades que facilitam a criação de UIs,
componentes e templates.

Para criar um novo template basta criar um arquivo utilizando a tag <ui:insert name="nome_da_secao"/>.

O seguinte exemplo mostra um arquivo template.jspx com o title e body a serem definidos (opicionalmente)
pelas UI's que estenderem este template.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Facelets: Number Guess Tutorial</title>
<style type="text/css">
<!--
body {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: small;
}
-->
</style>
</head>

<body>
<h1>
<ui:insert name="title">Default Title</ui:insert>
</h1>
<p>
<ui:insert name="body">Default Body</ui:insert>
</p>
</body>
</html>

(1.13.6)
Interface Web

Para mais informações de como usar facelets veja Facelets.

11.4.2. Criando uma nova UI

UI ou User Interface
Interface com o usuário é o conjunto de características com as qual os utilizadores interagem com
as máquinas, dispositivos, programas de computador ou alguma outra ferramenta complexa.

O projeto de uma interface com o usuário afeta a quantidade de esforço que o usuário precisará
para prover as entradas ao sistema e para interpretar sua respectiva saída, além de quanto esforço
ele precisará para aprender o procedimento. A usabilidade é uma área do design que leva em
consideração a psicologia e a fisiologia dos usuários para tornar os sistemas mais efetivos,
eficientes e satisfatórios. Ela está principalmente associada as características da interface com o
usuário, mas também pode estar associada com a funcionalidade do produto.

Em ciência da computação e interação homem-computador, a interface com o usuário de um


programa de computador refere-se as informações gráficas, textuais e auditivas apresentadas ao
utilizador, e as sequências de controle (como comandos de teclado ou movimentos do mouse) para
interagir com o programa.

Para implementar uma UI deve-se seguir 3 passos básicos:

1. Criar o arquivo .jspx na estrutura de diretórios desejada dentro do diretório pages.

2. Criar o Backing Bean

3. Inserir as informações de navegação no arquivo faces-navigation.xml.

11.4.2.1. Criar o arquivo .jspx

Primeiro deve ser criado o arquivo .jspx na estrutura de diretórios desejada dentro do diretório pages.

Abaixo segue um exemplo de um arquivo .jspx usando um template.jspx já definido:

<?xml version="1.0" encoding="UTF-8"?>


<ui:composition xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ice="http://www.icesoft.com/icefaces/component"
template="template.jspx">

<ui:define name="body">
<h1>#{messageBBean.message}</h1>
</ui:define>

</ui:composition>

Para uma lista completa de componentes que podem ser utilizados veja:

• Facelets - agrega suporte a templates ao JSF e uma série de funcionalidades que facilitam a criação de UIs.

• Java Server Faces Home - componetes padrão.

• Icefaces.org - agrega suporte a AJAX ao JSF.

Framework Java Arquitetura Brasil 110


Interface Web

11.4.2.2. Criar o Backing Bean

Cada Backing Bean deve ser


configurado com a seguinte anotação
org.springframework.stereotype.Component (@Componente). Ele pode ter diferentes configurações de
escopo que podem ser especificadas usando-se a anotação org.springframework.context.annotation.Scope
(@Scope).

Escopos existentes:

• Request: Registrar um backing bean no escopo request fará com que o bean exista apenas durante um
request. Este escopo deve ser usado para todo caso onde o usuário não necessitará acessar as informações
do estado do Backing Bean em outros Beans ou páginas durante a navegação no site.

• Session: Registrar um backing bean no escopo session fará com que o bean exista apenas durante uma
session. Além disso, cada usuário terá uma instância diferente do objeto. Este escopo deve ser usado para os
casos onde a informação do estado de um Backing Bean deverá ser guardada para futuros acessos.

Importante
Alguns aplication servers necessitam serializar a sessão quando estão entrando em estado de
shutdown (parando) e com ela todos os objetos que nela estão, portanto é importante checar se
o Backing Bean pode ser serializado e se depois ele pode restaurar um estado válido
novamente. Atributos que não precisam ser serializados podem ser declarados como
transient.

Abaixo segue um exemplo de um Backing Bean:

@Component
@Scope("session")
public class MessageBBean extends BasicBBean {

@Autowired
private transient MessageService messageService;

...
}

Nota
Observe que no exemplo anterior o Backing Bean utiliza a seguinte nomenclatura [Nome]BBean e
esta será adotada como padrão usado no Framework.

O Backing Bean define e utiliza o serviço MessageService bastando anotar o atributo como @Autowired. Deste
modo o Framework se encarrega de injetar o serviço solicitado ao Bean.

Importante
Observe que no exemplo anterior o Backing Bean declara como transient o serviço declarado
(MessageService). É importante seguir esta prática para todos os beans que não são serializáveis e
que foram criados utilizando Spring, como neste exemplo o serviço. No Framework Spring todos
os beans que são proxy de alguma classe não podem ser serializados.

O Backing Bean não precisa ser adicionado ao faces-config.xml, pois ele é instanciado automaticamente pelo
Framework. Ele será criado como um bean no contexto do Spring, com o nome definido pela regra abaixo:

Tabela 11.1. Regra de definição de nome de backing beans

Framework Java Arquitetura Brasil 111


Interface Web

Nome da classe Nome do bean

com.altec...MessageBBean messageBBean (mesmo nome da classe, mas com a


primeira letra minúscula)

com.altec...ABCMessageBBean ABCMessageBBean (mesmo nome da classe)

Se o nome default não for satisfatório, é possível que se personalize o nome do seu Bean utilizando a seguinte
anotação: @Component("outroNomeBBean").

Desta maneira, os backing beans estarão disponíveis tanto para acesso através de outros beans quanto dentro
das páginas jspx.

O Backing Bean pode ser obtido usando-se a anotação @Autowired.

public class OutroBBean extends BasicBBean {


@Autowired
private MessageBBean messageBBean;
...
}

Seguindo a mesma regra abaixo mostramos como acessar um Backing Bean em uma página .jspx.

...
<input type="text" jsfc="h:inputText" value="#{messageBBean.text}" required="true"/>
<input type="button" jsfc="h:commandButton" value="Pesquisar" action="Pesquisar"
actionListener="#{messageBBean.pesquisar}"/>
...

11.4.2.3. Inserir as informações de navegação no arquivo faces-navigation.xml

A seguir, mostramos um exemplo:

<?xml version='1.0' encoding='UTF-8'?>


<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">

<faces-config>

<navigation-rule>
<description>Message Rules</description>
<from-view-id>/pages/message.jspx</from-view-id>
<navigation-case>
<from-outcome>Success</from-outcome>
<to-view-id>/pages/success.jspx</to-view-id>
</navigation-case>
</navigation-rule>

</faces-config>

11.5. BasicBBean
A classe básica para a criação de um Backing Bean chamada com.altec.bsbr.fw.web.jsf.BasicBBean
oferece vários métodos de infra-estrutura os quais facilitam a implementação de um Backing Bean. Abaixo
segue a lista de métodos/atributos definidos desta classe.

• getBind(String managedBeanName): Cria uma instância do Backing Bean de acordo com a EL passada

(1.13.6)
Interface Web

como parâmetro.

• addMessage(FacesMessage.Severity severity, String summary, String details): Adiciona uma


mensagem ao context JSF de acordo com a sua severidade.

• getFacesContext(): Atalho para o FacesContext corrente.

• getHttpRequest(): Atalho para o HttpServletRequest.

• getHttpResponse(): Atalho para o HttpServletResponse.

• getHttpSession(boolean create): Atalho para o HttpSession.

• getRequestAttribute(String attributeName): Atalho para recuperar um atributo do Request.

• getRequestParameter(String attributeName): Atalho para recuperar os parametros de um request.

• getSessionAttribute(String attributeName): Atalho para recuperar um atributo da Session.

• getAttribute(ActionEvent event, String attName): Recupera um atributo do enviado pelo evento.

• String SUCCESS: Atributo que já configura o bean para retornar as mensagens padrão "Success" para o
navigation controller.

• String ERROR: Atributo que já configura o bean para retornar as mensagens padrão "Error" para o
navigation controller.

Importante
O Framework JSF é bastante flexível e permite várias formas de comunicação entre a página e o
Backing Bean, as quais, devem permanecer da forma como foram idealizadas. Portanto, utilize os
métodos getHttpRequest(), getHttpResponse(), getHttpSession(boolean create),
getRequestAttribute(String attributeName), getSessionAttribute(String
attributeName), getRequestParameter(String paramName) com cuidado, apenas quando for
necessário comunicar com componentes de fora do contexto JSF, como um servlet.

11.6. CRUD
Em muitos projetos, grande parte das UI's tem o conceito de incluir, ler, editar, e excluir (CRUD,
Create-Read-Update-Delete). Para isso o Framework oferece algumas classes orientadas a estas características.

A classe com.altec.bsbr.fw.web.jsf.CrudServiceBBean<T,ID extends Serializable> é uma classe


genérica que permite criar facilmente uma UI com suporte aos métodos mais básicos (CRUD). Ela configura
um Backing Bean para que este possa ter funcionalidades de CRUD.

• save(T entity): Método que permite acessar o Serviço CRUD e salvar uma entidade qualquer.

• findAll(): Retorna uma lista de entidades do tipo especificado via Generics.

• get(ID id, boolean lock): Retorna uma instância da entidade do tipo especificado via Generics.

• remove(ID primaryKey): Remove uma entidade a partir do tipo especificado via Generics.

Esta classe é uma extensão de BasicBBean.

(1.13.6)
Interface Web

Abaixo está um exemplo de como usar CrudServiceBBean:

@Component
@Scope("request")
public class CrudPessoaBBean extends CrudServiceBBean<Pessoa, Long>
implements Serializable{
private Pessoa pessoa;

...

public String save() {


try {
save(pessoa); // Chamada direta ao método save.
return SUCCESS;
} catch (Exception e) {
e.printStackTrace();
return ERROR;
}
}

...
}

11.7. Relatórios com JasperReports


A classe com.altec.bsbr.fw.web.jsf.ReportBBean permite que um Backing Bean tenha suporte a relatórios.
Ela já possui configurada uma lista de opções de exportação de relatórios com os seguintes formatos PDF,
EXCEL, RTF, ODT, XML.

Para configurar está classe deve-se estende-la implementando os seguinte métodos:

• Map<String, Object> getReportParameters(): Este método provê os parâmetros para o relatório a ser
gerado.

• net.sf.jasperreports.engine.JRDataSource getJRDataSource(): Este método provê o conjunto de


dados que será utilizado pelo relatório.

• java.io.InputStream getReportStream(): Este método provê o relatório compilado utilizando-se o


iReport, ou seja, o .jasper.

Após isso basta chamar o método String render() dentro seu Backing Bean que o próprio framework irá
gerar e devolver o relatório gerado.

Esta classe também configura uma lista de opções de exportação. A qual pode ser acessada utilizando-se o
seguinte método: List<SelectItem> getListExportOptions().

A seguir, mostramos um exemplo de como utilizar as duas opções.

Arquivo .jspx:

...
<form jsfc="h:form">
...
<td><label jsfc="h:outputLabel" for="exportOption">
#{msg['label.export.option']} (*):</label></td>
<td>
<select id="exportOption" jsfc="h:selectOneMenu"
value="#{testReportBBean.exportOption}">
<f:selectItems value="#{testReportBBean.listExportOptions}"/>
</select>
<br/>
<h:message errorClass="error" for="exportOption"/>

Framework Java Arquitetura Brasil 114


Interface Web

</td>
...
<td></td>
<td><input type="submit" jsfc="h:commandButton"
action="#{testReportBBean.render}"
value="#{msg['button.render']}" />
<input type="submit" jsfc="h:commandButton" immediate="true"
action="Cancel"
value="#{msg['button.cancel']}"/>
</td>
...
</form>
...

Backing Bean:

@Component
@Scope("request")
public class TestReportBBean extends ReportBBean {

private final String reportPath = "path_to_report/test_report.jasper";

@Override
protected JRDataSource getJRDataSource() {
List<Product> products = new ArrayList<Product>();
for (int i = 0; i < 10; i++) {
Product product = new Product();
product.setId(i);
product.setName("test-" + i);
products.add(product);
}
return new JRBeanCollectionDataSource(products);
}

@Override
protected Map<String, Object> getReportParameters() {
return null;
}

@Override
protected InputStream getReportStream() {
return FindReport.getReport(reportPath);
}
}

No faces-navigation.xml:

...
<navigation-rule>
<display-name>Test Report Products</display-name>
<from-view-id>/pages/TestReport.jspx</from-view-id>

<navigation-case>
<from-outcome>PDF</from-outcome>
<to-view-id>/report.pdf</to-view-id>
<redirect/>
</navigation-case>
<navigation-case>
<from-outcome>EXCEL</from-outcome>
<to-view-id>/report.xls</to-view-id>
<redirect/>
</navigation-case>
<navigation-case>
<from-outcome>Cancel</from-outcome>
<to-view-id>/pages/Welcome.jspx</to-view-id>
</navigation-case>

</navigation-rule>
...

Framework Java Arquitetura Brasil 115


Interface Web

11.8. Menu de acesso configurado pelo MBS


Para configurar o menu é necessário que a aplicação WEB tenha feito as configurações de segurança descritas
na seção Segurança - Autorização e criar as classes que irão acessar o MBS descritos na seção Segurança -
Autorização Serviços .

Para construção do menu utilizamos o componente ice:tree o qual irá construir um árvode de links para as
páginas configuradas no MBS.

A partir da interface com.altec.bsbr.fw.security.authorization.Authorization é possível ter acesso ao


javax.swing.tree.TreeModel que deverá ser criado pelo serviço de autorização a ser usado.

Para maiores informações sobre o componente visual que renderiza a árvore do menu, veja ice:tree .

Para configurar o menu de acesso devemos seguir alguns passos descritos abaixo:

• Criar uma interface que ofereça o método para acessar o TreeModel passando o nome do usuário e o nome
do sistema.

Exemplo:

...
public interface MenuService {
public javax.swing.tree.TreeModel buildUserMenu(String user, String system);
}

• Criar uma classe de serviço que implemente a interface que foi criada. Fazendo @Autowire na interface
com.altec.bsbr.fw.security.authorization.Authorization.

...
@Service
public class MenuServiceImpl implements MenuService {
@Autowired
private Authorization authorization;
public javax.swing.tree.TreeModel buildUserMenu(String user, String system) {
return authorization.getMenuTree(user, system)
}
}

• Criar uma classe Backing Bean que acesse o serviço de menu adicionando a anotação @Autowired no
atributo do tipo da interface que foi criada.

Exemplo:

...
@Component
public class MenuBBean extends BasicBBean implements InitializingBean {
@Autowired
private MenuService menuService;❶

private TreeModel treeModel;❷

public void afterPropertiesSet() {


SecurityInfo securityInfo = SecurityInfo.getCurrent();
treeModel = menuService.buildUserMenu(securityInfo.getUserName(), securityInfo.getSystemId());
}

public TreeModel getTreeModel() {


return treeModel;
}
}

(1.13.6)
Interface Web

❶ Serviço que será usado para recuperar o treeModel.


❷ Atributo que será usado para renderizar o menu.

• Adicione a tag ice:tree a página .jspx.

Exemplo:

<form jsfc="h:form" class="common"><ice:tree id="menuTree"❶


value="#{menuBBean.treeModel}" var="node" hideRootNode="false"
hideNavigation="false">
<ice:treeNode>❷
<f:facet name="content">
<ice:panelGroup style="display: inline">
<ice:outputLink id="treeNode"
value="#{facesContext.externalContext.requestContextPath}#{node.userObject.menuItem.url}"
rendered="${not empty node.userObject.menuItem.url}">
#{node.userObject.menuItem.descricao}
</ice:outputLink>
<ice:outputLink id="treeNode"
value="#{facesContext.externalContext.requestContextPath}/pages/firstPage.iface"
rendered="${empty node.userObject.menuItem.url}">
#{node.userObject.menuItem.descricao}
</ice:outputLink>
</ice:panelGroup>
</f:facet>
</ice:treeNode>
</ice:tree></form>

❶ Tag ice:tree para configurar o menu.


❷ Tag ice:treeNode para configurar os nodes.

Para mais informações consulte:

• ICEfaces.org.

• ICEfaces components overview.

• ICEfaces Documentation.

11.9. Servlet de Imagem


O Servlet de imagem é utilizado para renderizar-se imagens em páginas web. Para utilizá-lo é necessário fazer a
declaração no web.xml conforme descrevemos na seção Configurando a aplicação.

Veja abaixo o exemplo de como utilizá-lo:

• Criar um componente que implemente a interface com.altec.bsbr.fw.web.image.ImageSupport. não


esqueça de acrescentar a anotação org.springframework.stereotype.Component.

...
@Component
public class ProductImage implements ImageSupport {

@Autowired
private transient ProdutoService produtoService;

public byte[] loadImage(String uniqueId) {


Long id = Long.valueOf(uniqueId);
return produtoService.getImageProduto(id);
}

(1.13.6)
Interface Web

• Declarar a função JSTL na página:

<?xml version="1.0" encoding="UTF-8"?>

<ui:composition xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ice="http://www.icesoft.com/icefaces/component"
xmlns:fn="http://www.santander.com.br/functions"❶
template="template.jspx">
...
</ui:composition>

❶ Declarar o XML Namespace http://www.santander.com.br/functions para apontar para fn.

• Utilizar na página jspx a função da seguinte forma:

<img src="#{fn:getImageUrl('productImage',❶
val.estoque.produto.codigo❷
)}"/>

❶ Nome do componente que criamos para fornecer os dados da imagem.


❷ Propriedade a qual o identificador, usado para encontrar a imagem, será retornado.

Framework Java Arquitetura Brasil 118


Capítulo 12. Batch

12.1. Introdução
O Framework prove algumas funcionalidades para ajudar o desenvolvimento de aplicações batch em Java. No
entanto elas deverão usar a infra-estrutura existente provida pelo Control-M para iniciar e controlar os
processos.

O framework tem um programa principal para iniciar processos batch, fornecendo uma infra-estrutura para que
a aplicação possa informar seu status de execução ao Control-M, através do código de saída do programa.

Elas poderão acessar todos os recursos oferecidos pelo framework, como controle dos serviços, mensageria,
persistência, acesso a web services, etc.

O framework possui um mecanismo de processamento de tarefas em batch em paralelo. Este mecanismo


consiste em um modelo padrão de produtor-transformação-consumidor onde existe uma fonte de dados que
chamamos de produtor (fila origem, arquivos, web-services, etc), um processo que transforma o dado e uma
fonte consumidora (arquivo, banco de dados, fila destino, etc).

Diagrama mostrando interações entre Produtor/Consumidor

Existem controladores de fluxo de processamento preperados para rodar tarefas de modo sequencial e paralelo,
de forma muito simples. São configuráveis, flexíveis, tem bom desempenho, minimizam os erros comuns de
programação sequencial e concorrente.

Os controladores de fluxo de processamento foram desenvolvidos para maximizar o desempenho em soluções


concorrentes, portanto, uma das formas mais natural de enxergar o paralelismo foi escolhida: Produtor /
Consumidor , onde as transformações ocorrem em paralelo, melhorando o desempenho. Os dados gerados pelo
Produtor , passam por uma determinada Tarefa que transforma os dados recebidos em dados prontos para o
Consumidor trabalhar.

Framework Java Arquitetura Brasil 119


Batch

12.2. Processamento
Um produtor pode ser qualquer objeto que implemente a interface
com.altec.bsbr.fw.batch.RecordProducer e tem a função de produzir os registros do processo batch. Cada
vez que o método next() for chamado, ele retornará mais um registro a ser processado.

public interface RecordProducer<T> {


boolean hasNext();
T next();
List<Parameter> getParameters();
void setParametes(List<Parameter> parameters);
}

Uma tarefa pode ser qualquer objeto que estenda a classe abstrata com.altec.bsbr.fw.batch.Task que tenha a
função de transformar a saída gerada pelo produtor (do tipo PARAM) em um objeto (do tipo RET) para ser
processado pelo consumidor. Nesta classe também é onde deve ser implementada a lógica de negócios do
processo batch.

A infra estrutura do Framework fará a chamada do método execute() passando como parâmetro o registro
fornecido pelo RecordProducer . Depois do processamento do método, o Framework passará o resultado para o
RecordConsumer .

public abstract class Task<PARAM, RET> implements Callable<RET> {


...
public abstract RET execute(PARAM data) throws Exception;
}

Um consumidor pode ser qualquer objeto que implemente a interface


com.altec.bsbr.fw.batch.RecordConsumer e tem a função consumir os registros após eles serem
processados, como gravar os dados em um arquivo ou banco de dados.

public interface RecordConsumer<V> {


void consume(V object);
void flush();
List<Parameter> getParameters();
void setParameters(List<Parameter> parameters);
}

Uma característica importante é o a capacidade de executar o processamento das Tasks em paralelo, podendo
aproveitar os recursos de múltiplas CPUs e múltiplos Cores.

Quando for necessário executar alguma incicialização ou finalização...

12.2.1. Criando um batch

Para se criar um processo batch, é necessário definir as classes a seguir.

• Produtor: responsável por transformar os dados de origem (seja de arquivos, banco de dados ou outra fonte
qualquer) em um tipo de objeto que represente algum sentido para as futuras tranformações. Um Produtor
deve implementar a interface RecordProducer , como mostrado no exemplo a seguir:

public class PokerProducer implements RecordProducer<FilePokerHand> {


private static final int KBYTES = 1024;
private DefaultDataInput pokerHandsDataInput;

public PokerProducer() throws DataException {


this.pokerHandsDataInput = new DefaultDataInput();

Framework Java Arquitetura Brasil 120


Batch

Mapper mapper = new DelimiterMapper(FilePokerHand.class);


mapper.setBufferSize(4 * KBYTES);
this.pokerHandsDataInput.setMapper(mapper);
}

public List<Parameter> getParameters() {


throw new UnsupportedOperationException();
}

public boolean hasNext() {


try {
return this.pokerHandsDataInput.hasNext();
} catch (DataException e) {
System.out.println(e.getMessage());
}
return false;
}

public FilePokerHand next() {


try {
return (FilePokerHand) this.pokerHandsDataInput.read();
} catch (DataException e) {
System.out.println(e.getMessage());
}
return null;
}

public void setParameters(List<Parameter> parameters) {


try {
this.pokerHandsDataInput.setReader(new FileReader(parameters.get(0).getParameter()));
} catch (FileNotFoundException e) {
System.out.println(e.getMessage());
} catch (DataException e) {
System.out.println(e.getMessage());
}
}
}

• Tarefa: responsável por transformar os dados de entrada em objetos prontos para serem consumidos. As
tarefas podem ser executadas em paralelo. Uma Tarefa deve implementar a interface Task, como mostrado
no exemplo a seguir:

public class PokerTask extends Task<Object, Object> {


private static final Logger logger = LoggerFactory.getLogger(PokerTask.class);

public Object execute(Object data) throws Exception {


FilePokerHand filePokerHand = (FilePokerHand) data;
if (logger.isTraceEnabled()) {
List<Card> cards = PokerUtil.getOrderedCards(filePokerHand.getPocket());
for(Card card : cards) {
logger.trace("Card: " + card.getId().getIdName() + " of " +
card.getSuite().getSuiteName());
}
}
return getPokerHand(filePokerHand.getPokerHand());
}

private PokerHand getPokerHand(Integer pokerHandId) {


return PokerHandFactory.create(pokerHandId);
}
}

DummyTask
Caso queira que o objeto produzido no RecordProducer seja consumido sem nenhuma
transformação para o RecordConsumer pode ser usada a task pertencente ao Framework
com.altec.bsbr.fw.batch.DummyTask que apenas repassa o conteúdo recebido para o
consumidor.

Framework Java Arquitetura Brasil 121


Batch

Obs.: ver o tópico Configuração .

• Consumidor: responsável pelo destino final dos dados(persistência, listagem, etc..)


processados/transfomados, pode existir um Consumer para todo o processamento ou um para cada Task.
Uma Consumer deve implementar a interface RecordConsumer, como mostrado no exemplo a seguir:

public class PokerConsumer implements RecordConsumer<Object> {


public void consume(Object object) {
((PokerHand) object).add();
}

public void flush() { }


public void setParameters(List<Parameter> parameters) { }
}

• Parâmetros : a classe Parameter define um meio para que o Spring injete os parametros nas
implementações de RecordProducer e RecordConsumer. Existem dois atributos na classe: parameter e
parameterType, sendo String e Integer respectivamente. O atributo parameter é o valor do parâmetro
que deseja passar, e o parameterType define se ele é de entrada (0) ou saída (1). Caso seja um parâmetro de
entrada será usado durante a execução do RecordProducer, caso seja de saída na execução do
RecordConsumer.

<!--
=======================================================================================
RecordProducer que gera os dados para o processo de batch
=======================================================================================
-->
<bean id="producer" class="com.altec.fw.bsbr.batch.teste.carga.poker.PokerProducer">
<property name="parameters"><ref bean="parameters"/></property>
</bean>
<bean id="parameters" class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list>
<ref bean="parameter1"/>
</list>
</property>
</bean>
<bean id="parameter1" class="com.altec.bsbr.fw.batch.Parameter">
<property name="parameter" value="Poker/test/data/poker-hand-testing.data.txt"/>
<property name="parameterType" value="0"/>
</bean>

• Handlers : os Handlers são executados antes e depois da pilha de execução do TaskManager. O


startHandler executa imediatamente antes da primeira task e o endHandler executa imediatamente depois
da execução de todas as tasks.

public class PokerHandler implements Handler {


private static final Logger logger = LoggerFactory.getLogger(PokerHandler.class);

public Object handle() {


logger.info("None: " + None.getInstance().pct() * 100 + " %");
logger.info("Pair: " + Pair.getInstance().pct() * 100 + " %");
logger.info("Two Pairs: " + TwoPairs.getInstance().pct() * 100 + " %");
logger.info("Three Of A Kind: " + ThreeOfAKind.getInstance().pct() * 100 + " %");
logger.info("Straight: " + Straight.getInstance().pct() * 100 + " %");
logger.info("Flush: " + Flush.getInstance().pct() * 100 + " %");
logger.info("Full House: " + FullHouse.getInstance().pct() * 100 + " %");
logger.info("Four Of A Kind: " + FourOfAKind.getInstance().pct() * 100 + " %");
logger.info("Straight Flush: " + StraightFlush.getInstance().pct() * 100 + " %");
logger.info("Royal Flush: " + RoyalFlush.getInstance().pct() * 100 + " %");
return null;
}
}

(1.13.6)
Batch

12.2.1.1. Como usar exceções?

Durante o processamento do batch, é possível indicar a ocorrência de alguma situação anormal através do
lançamento de exceções. Caso algum erro ocorra existem duas exceções para indicar a gravidade do erro:
BatchWarningException e BatchErrorException as duas são RuntimeException e podem receber um código
que será passado para o Control-M indicando qual erro ou aviso.

Caso uma BatchWarningException seja lançada o processamento continua e o aviso será logado.

Caso uma BatchErrorException seja lançada todo o processamento será interrompido e terminado com o
código de erro indicado ou com o código de erro padrão (que é 1).

12.2.2. Configuração

Configurando o arquivo batch.xml

Esse arquivo indica qual RecordProducer e RecordConsumer serão usados para esse processamento. Assim
como os parâmetros que as classes receberão. Os parâmetros podem ser passados no construtor da classe que
implementa as interfaces, ou usando o método setParameters(Parameters). Indica também quais os Handlers
serão usados, existem duas opções: startHandler e endHandler.

Dica
O arquivo batch.xml deve ficar no diretório: src

<!--
=======================================================================================
RecordProducer que gera os dados para o processo de batch
=======================================================================================
-->
<bean id="producer" class="com.altec.bsbr.fw.batch.PokerProducer"/>

<!--
=======================================================================================
RecordConsumer que consome os dados para o processo de batch
=======================================================================================
-->
<bean id="consumer" class="com.altec.bsbr.fw.batch.PokerConsumer"/>

<!--
=======================================================================================
Handlers
=======================================================================================
-->
<bean id="startHandler" class="com.altec.bsbr.fw.batch.DummyHandler"/>
<bean id="endHandler" class="com.altec.bsbr.fw.batch.DummyHandler"/>

Dica
A classe FromDatabaseProducer pode ser usada para gerar registros a partir de uma query no
banco de dados. A query é definida no batch.xml, sendo atribuída ao parâmetro query. O exemplo
a seguir mostra como:

<!--
=======================================================================================
RecordProducer que gera os dados para o processo de batch
=======================================================================================
-->
<bean id="producer" class="com.altec.bsbr.fw.batch.FromDatabaseProducer">
<property name="query" value="select * from jab.tb_pedi"/>
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.SingleConnectionDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>

(1.13.6)
Batch

<property name="url" value="jdbc:oracle:thin:@[hostname]:[port]:[SID]"/>


<property name="username" value="user"/>
<property name="password" value="pass"/>
<property name="autoCommit" value="false"/>
</bean>

Dica
A classe ToStdoutConsumer é útil durante o desenvolvimento, todos os valores dos atributos do
objeto de entrada no método consume(Object object) são listados na console.

<!--
=======================================================================================
RecordConsumer que consome os dados para o processo de batch
=======================================================================================
-->
<bean id="consumer" class="com.altec.bsbr.fw.batch.ToStdoutConsumer"/>

Configurando o arquivo batch.properties

Arquivo de configuração do TaskManager. Indica qual Task deve ser utilizada ( batchRunner.taskType ), qual
o tamanho do pool de threads deve ser usado ( batchRunner.poolSize ), de quantos em quantos registros os
controladores devem executar um flush (flush para arquivos, e commit para transações com banco, ou qualquer
outro controle a ser implementado no flush() da interface RecordConsumer ( batchRunner.flushFrequency )
e se a saída deve ou não ser compartilhada (batchRunner.sharedOutput ).

TaskManager

A classe Taskmanager controla todo o fluxo de execução para uma determinada tarefa. Pode executar as tasks
em paralelo (configuração no batch.properties ) ou em série. O processamento em série acontece a partir das
tasks os produtos gerados pelo produtor entram na fila de execução e os resultados das tasks, são enviados
para os consumidores. A configuração batchRunner.sharedOutput define se as saídas vão para um ponto
único, ou se elas podem ser tratadas em paralelo (por exemplo: arquivo -> saídas compartilhadas; banco de
dados -> saídas não compartilhadas). A configuração batchRunner.maxTasksRunning define qual a quantidade
máxima de tasks que podem ser inicializadas pelo producer, é importante que esta propriedade seja utilizada de
uma forma na qual o consumer consiga dar uma vazão maior do que o producer consegue produzir, para uma
quantidade ilimitada de tasks atribua -1 a esta variável. A configuraçção batchRunner.sleepPeriodInMilis
define o tempo em milisengundos na qual o task manager deve esperar para que continue produzir novas tasks,
ou seja, ele deve ser configurado de acordo com o tempo necessário que o consumer consiga executar sem
enfileirar as threads.

Dica
O arquivo batch.properties deve ficar no diretório: META-INF/config ou dentro do diretório do
runningMode: META-INF/config/[runningMode]/

12.2.3. Executando o batch

Como iniciar a aplicação

Para executar uma aplicação batch é necessário usar scripts de inicialização para carregar os jars necessários no
classpath e chamar o método main() da classe com.altec.bsbr.fw.batch.BatchRunner. Os scripts de
inicialização mudam de um sistema operacional para outro, a seguir um exemplo de script para o Windows:

@echo off setlocal


rem ===========================================================================

Framework Java Arquitetura Brasil 124


Batch

set JAVA_HOME=C:\Java\java❶
set FW_LIBS=C:\Java\workspace\Framework\fw\lib❷
set CLASSPATH=C:\Java\workspace\Framework\abcBatch\dist\abcBatch.jar❸
rem ===========================================================================

for /r %FW_LIBS%\provided %%x in (*.jar) do call cpappend.bat %%x ❹


for /r %FW_LIBS%\compile %%x in (*.jar) do call cpappend.bat %%x

rem echo CLASSPATH=%CLASSPATH%

set JAVA="%JAVA_HOME%\bin\java.exe"

%JAVA% -cp "%CLASSPATH%" -DrunningMode=prod❺ com.altec.bsbr.fw.batch.BatchRunner❻

exit /b %ERRORLEVEL%❼
endlocal

❶ Path do executavel java.


❷ Path das bibliotecas do Framework.
❸ Jar principal da aplicação batch.
❹ Construção do classpath com todas bibliotecas.
❺ Especifica o running mode.
❻ Indica a classe BatchRunner para ser executada.
❼ Devolve o código de erro da aplicação Java.

O código de retorno da aplicação batch em Java pode ser usada para definir o comportamento do Control-M. O
modo de obter o valor numérico do código de retorno da aplicação depende do shell que estiver sendo usado:

Tabela 12.1. Código de retorno de aplicação

Shell Variável

cmd.exe (Windows) %ERRORLEVEL%

bash (Unix) $?

12.2.4. Parâmetros do BatchRunner

A classe BatchRunner aceita os seguintes parâmetros:

• batchConfig: URL da localização do arquivo de configuração. Ex:


-DbatchConfig=file:/c:/sistema/configuracao/batch.xml

Nota
Este parâmetro sobre-escreve o batch.xml já existente no arquivo jar da aplicação.

12.3. Manipulando arquivos


O framework oferece algumas opções para facilitar a leitura e escrita de dados em arquivos, são bem simples de
usar, basta anotar um POJO (classe e atributos) com as anotações fornecidas e usar as classes utilitárias que
serão descritas a seguir.

12.3.1. DefaultDataInput

Framework Java Arquitetura Brasil 125


Batch

Implementação padrão da interface DataInput que baseada em um Mapper (classe que deternima como os
registros serão lidos dado um formato) retorna objetos populados com os dados no arquivo.

No exemplo a seguir o DefaultDataInput é preparado para ler um arquivo com campos separados por
delimitador, o tipo de registro é representado pela classe Cd.

...
DefaultDataInput titlesDataInput = new DefaultDataInput();
titlesDataInput.setMapper(new DefaultDelimiterMapper(Cd.class));
titlesDataInput.setReader(new BufferedReader(new FileReader(fileName), BUFFER_SIZE));
...

12.3.2. DefaultFileDataOutput

Implementação padrão da interface DataOutput para arquivos. Baseada em um Marshaller (classe que
deternima como os registros serão gerados dado um formato) retorna registros (ou registro) a partir de objetos
populados com os dados.

No exemplo a seguir o DefaultFileDataOutput é preparado para gravar um arquivo com campos separados
por delimitador, o tipo de registro é representado pela classe Cd.

...
DefaultFileDataOutput<Cd> dataOutput = new DefaultFileDataOutput<Cd>("test_csv.txt",
new DelimitedMarshaller<Cd>());
//save collection
dataOutput.save(getCd());

public Collection<Cd> getCd(){


Collection<Cd> result = new ArrayList<Cd>();
...
return result;
}
...

O método save() pode receber uma lista de objetos ou um simples objeto. Caso uma lista seja passada, o
retorno será um bloco de registros. Caso receba um unico objeto, um registro será retornado. Para a
FixedLenghtMarshaller o retorno do método save(), quando recebe uma lista é o conteúdo total do arquivo,
com header e trailler, caso existam.

Veja: Marshaller para saber quais marshallers poderão ser usados.

12.3.3. FlatfileContextDataOutput

Implementação Flatfile da interface ContextDataOutput para arquivos posicionais. Esta implementação possui
o suporte a customização e parametrização de header e trail.

Abaixo mostramos um exemplo de geração de um arquivo com os valores de uma collection:

...
//Instanciando a implementação Flatfile.
ContextDataOutput<Collection<Person>> contextDataOutput =
new FlatfileContextDataOutput<Collection<Person>>("C:/Temp/Test.txt");

//Configura-se qual o marshall que será usado.


contextDataOutput.setFlatfileDataMarshaller(
new FixedLengthFlatfileDataMarshaller<Collection<Person>>());

//Salvando uma lista de objetos pessoa em um arquivo.


List<Person> personList = ...;

(1.13.6)
Batch

contextDataOutput.save(personList);
...

Veja: Marshaller para saber quais marshallers poderão ser usados.

Abaixo mostramos um exemplo de geração de um arquivo com os valores de uma collection com um contexto
personalizado:

... //Da mesma forma que o exemplo anterior cria-se uma instancia do ContextDataOutput.
... //Definição da classe CustomMarshallContext
public class CustomMarshallContext implements MarshallContext {
public String param;

public String getParam() {


return param;
}

public void setParam(String param) {


this.param = param;
}
}

//Passando o context para o DataOutput CustomMarshallContext


marshallContext = new CustomMarshallContext();
marshallContext.setParam("Hello");
contextDataOutput.save(personList, marshallContext);
...

Veja: Exemplos de personalização de Header e Trail com customização.

12.3.3.1. @Close

Para encerrar com segurança os recursos utilizados na geração dos arquivos, o framework disponibiliza uma
anotação (com.altec.bsbr.fw.batch.annotation.Close), que deve ser aplicada em um método na classe
Consumer.

Abaixo mostramos um exemplo de encerramento dos recursos utilizando a anotação:

... //Inicialização, criação do contexto para ContextDataOutput

/*
* Implementação da interface RecordConsumer. O objeto T está demonstrado
* em uma estrutura genérica, substitua pelo seu objeto concreto em sua implementação.
*/
public void consume(T t) {
try {
contextDataOutput.save( t );
}
catch (DataException e) {
//Tratar a exececao
}
}

//Implementação da interface RecordConsumer


public void flush() {
try {
contextDataOutput.flush();
}
catch (DataException e) {
//Tratar a exececao
}
}

/* Método criado para encerrar os recursos com segurança.


* Deve-se utilizar a annotation @Close para que o framework identifique.
*/
@Close
public void close() {
try {

(1.13.6)
Batch

contextDataOutput.close();
}
catch (DataException e) {
//Tratar a exececao
}
}
...

12.4. Processamento de registros


O Framework já possui suporte para o processamento do formato com campos de tamanho fixo e CSV (comma
separated value).

12.4.1. CSV

Existe um conjunto de anotações, um Mapper e um Marshaller para facilitar o trabalho com registros de
campos separados por delimitadores.

12.4.1.1. Anotações

12.4.1.1.1. DelimitedFieldFile
Anotação de classe, que indica q a classe representa um registro que tem os campos separados por
delimitadores. O delimitador deve ser informado, conforme o exemplo:

...
@DelimitedFieldFile(delimiter = ",")
public class Cd {
...

12.4.1.1.2. DelimitedField
Anotação de atributo, que indica que o atributo é um dos campos do registro. Os seguintes atributos podem ser
indicados na anotação:

• name() - opcional: Se o nome do campo não é o nome do atributo na classe.

• position() - obrigatório: posição do campo no registro.

• converter() - opcional: implementação da Converter para converter o valor do campo para um tipo
especifico e vice-versa.

• validator() - opcional: implementação da Validator para validar o valor do campo.

...
@DelimitedField(position = 1)
private Integer code;

@DelimitedField(position = 2, converter = YearDateConverter.class)


private Date year;

@DelimitedField(position = 4, validator = TitleValidator.class)


private String title;
...

Framework Java Arquitetura Brasil 128


Batch

12.4.1.2. Mapper

A classe DelimitedMapper é uma implementação da interface Mapper, preparada para ler arquivos separados
por delimitadores, sendo o POJO passado para o construtor a representação de um registro.

12.4.1.3. Marshaller

A classe DelimitedMarshaller gera um arquivo baseado num POJO anotado com as anotações descritas
acima. Ao chamar o método marshaller, passando uma colecção de POJOs anotados, uma string com os
registros será retornada, caso um único objeto seja passado será retornada ums string com um único registro.

12.4.2. Registros de tamanho fixo

12.4.2.1. Anotações

12.4.2.1.1. FixedLenghtFieldFile
Identifica que o arquivo conterá registros com campos de tamanho fixo.

...
@FixedLenghtFieldFile()
public class Person {
...

• header() - opcional: implementação da interface Header que gera o cabeçalho para esse arquivo. Exemplo:

...
public class PersonHeader implements Header {
private String pattern = null;

public String changeValues(Object... values) throws MarshallException {


this.pattern = "1{0}{1}PERSONHEADER{2}";
return MessageFormat.format(this.pattern, values);
}

public void setPattern(String pattern) {


this.pattern = pattern;
}
}
...

• header() - opcional: implementação da interface ContextSupportHeader que gera o cabeçalho para esse
arquivo com suporte a parametrização. Exemplo:

...
public class PersonHeader implements ContextSupportHeader {
public String processHeader(MarshallContext marshallContext) throws MarshallException {
return "ProcessedSize = "+
((DataHolderMarshallContext<Collection<Person>>)marshallContext).getData().size();
}
}
...

Nota
Somente pode ser usado com a classe FixedLengthFlatfileDataMarshaller. Veja Marshaller.

• trail() - opcional: implementação da interface Trail que gera o rodapé para esse arquivo.

Framework Java Arquitetura Brasil 129


Batch

...
public class PersonTrail implements Trail {
private String pattern = null;

public String changeValues(Object... values) throws MarshallException {


this.pattern = "3{0}{1}PERSONTRAIL{2}";
return MessageFormat.format(this.pattern, values);
}

public void setPattern(String pattern) {


this.pattern = pattern;
}
}
...

• trail() - opcional: implementação da interface ContextSupportTrail que gera o rodapé para esse arquivo
com suporte a parametrização. Exemplo:

...
public class PersonTrail implements ContextSupportTrail {
public String processTrail(MarshallContext marshallContext) throws MarshallException {
return "ProcessedSize = "+
((DataHolderMarshallContext<Collection<Person>>)marshallContext).getData().size();
}
}
...

Nota
Somente pode ser usado com a classe FixedLengthFlatfileDataMarshaller. Veja Marshaller.

Dica
Header e Trailler só funcionam gerando arquivo, ou seja a classe FixedLenghtMarshaller gera o
Header e o Trailler. E FixedLengthFlatfileDataMarshaller gera o Header e o Trailler com
suporte a parametrização.

12.4.2.1.2. FixedLenghtField
Anotação de atributo que identifica os atributos que estarão no registro.

• position() - Posição do campo no registro.

• lenght() - Tamanho do campo no registro.

• paddingAlign() - Para qual lado devem estar os caracteres de preenchimento. O padrão é alinhar a
esquerda, e os valores aceitáveis são:

• Align.LEFT

• Align.RIGHT

• paddingChar() - Caracter a ser usado para o preenchimento.

• converter() - opcional: implementação da Converter para converter o valor do campo para um tipo
especifico e vice-versa.

• validator() - opcional: implementação da Validator para validar o valor do campo.

...

(1.13.6)
Batch

@FixedLenghtField(position = 1, lenght = 35, paddingAlign = Align.RIGHT, paddingChar = ' ')


private String firstName = null;

@FixedLenghtField(position = 2, lenght = 35, paddingAlign = Align.RIGHT, paddingChar = ' ')


private String lastName = null;
...

12.4.2.1.3. FixedLenghtFieldDetailId
Anotação de classe que permite criar um identificador para o registro de detalhe, muito comum em arquivos
com headers e traillers.

• id() - Identificador de registro.

...
@FixedLenghtFieldDetailId(id = "2")
public class Person {
...

12.4.2.2. Mapper

A classe FixedLenghtFieldMapper é uma implementação da interface Mapper, preparada para ler registros com
campos de tamanho fixo, sendo o POJO passado para o construtor a representação de um registro.

12.4.2.3. Marshaller

A classe FixedLengthFlatfileDataMarshaller<T> gera os registros (ou registro) da mesma forma que a


classe FixedLengthMarshaller porém possui 2 métodos marshall descritos abaixo:

• T: Tipo genério que pode ser uma Collection ou um Objeto.

• marshall(T obj, MarshallContext marshallContext): MarshallContext é uma interface que é utilizada


para parametrizar a criação do header e do trail, conforme detalhados anteriormente.

• marshall(T obj):este método invoca o método anterior passando um MarshallContext padrão chamado
DataHolderMarshallContext o qual encapsula o dado que foi passado para o método marshall, para
posteriomente ser acesado pelo ContextSupportHeader.processHeader() e
ContextSupportTrail.processTrail() detalhados anteriormente.

Veja: Criando arquivos com os resultados do Marshall.

A classe FixedLenghtMarshaller (deprecated) gera os registros(ou registro) baseada em um POJO anotado


com as anotações descritas acima. Ao chamar o método marshaller, passando uma colecção de POJOs
anotados, uma string com os registros será retornada, caso um único objeto seja passado será retornada ums
string com um único registro.

12.5. Configurando o banco de dados com autenticação no


MBS
Para configurar é necessário ter o nome do sistema, a frase e a url do banco de dados. Durante o processo de
abertura de conexão o framework irá obter as informações de usuário e senha do MBS.

(1.13.6)
Batch

Siga os passos abaixo para configurar um novo Datasource:

• No arquivo data_access.xml configure o DataSource da seguinte maneira:

...
<bean id="dataSource1" class="com.altec.bsbr.fw.jdbc.datasource.MbsUserCredentialDataSourceAdapter"
autowire-candidate="default">
<constructor-arg value="http://mbs_host:81/web_service"/>❶
<constructor-arg value="sistema"/>❷
<constructor-arg value="frase"/>❸
<property name="targetDataSource" ref="targetDataSource"/>❹
</bean>
<bean id="targetDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@host_db:1521:db" />❺
</bean>
...

❶ Host do servidor MBS.


❷ Nome do sistema.
❸ Frase do sistema.
❹ DataSource o qual utilizará autenticação do MBS.
❺ URL JDBC do banco de dados.

12.6. Configurando um pool de conexões com o banco de


dados
Semelhante ao disponível em aplicações web, o framework disponibiliza uma configuração para processos
batch se beneficiarem de um pool de conexões com o banco de dados.

Siga os passos abaixo para configurar um novo Datasource:

• No arquivo data_access.xml configure o DataSource da seguinte maneira:

...
<bean id="dataSource1" class="com.altec.bsbr.fw.jdbc.datasource.PoolingBatchDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@host_db:1521:db"/>❶
<property name="webService" value="http://mbs_host:81/web_service"/>❷
<property name="sistema" value="sistema"/>❸
<property name="frase" value="frase"/>❹
<property name="mbsAutentication" value="true"/>❺
<property name="paramMap"/>
<map>
<entry key="initialSize" value="initialSize"/>❻
<entry key="maxActive" value="maxActive"/>❼
</map/>
</property/>
</bean>
...

❶ URL JDBC do banco de dados.


❷ Host do servidor MBS.
❸ Nome do sistema.
❹ Frase do sistema.
❺ Ativa a autenticação com o MBS.
❻ Quantidade de conexões que devem ser iniciadas.
❼ Quantidade máxima de conexões ativas.

Framework Java Arquitetura Brasil 132


Capítulo 13. LDAP

13.1. Acesso a servidores LDAP


O Framework possui classes utilitárias que facilitam o acesso a servidores LDAP. Veja abaixo como se
configurar o acesso ao servidor LDAP.

• Crie o DTO que será usado para trafegar os dados entre as camadas. Exemplo:

package com.altec.bsbr.app.abcLdap.dto;
...
public class UserInfo {
public String nome;
...
// gets e sets
...
}

• Crie a classe de mapeamento que estenda de


org.springframework.ldap.core.simple.ParameterizedContextMapper. Exemplo:

package com.altec.bsbr.app.abcLdap.ldap.mapper;
...
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.simple.ParameterizedContextMapper;

import com.altec.bsbr.test.dto.UserInfo;

public class UserInfoMapper implements ParameterizedContextMapper<UserInfo> {


public UserInfo mapFromContext(Object ctx) {
DirContextAdapter adapter = (DirContextAdapter) ctx;
UserInfo info = new UserInfo();
info.setNome(adapter.getStringAttribute("cn"));
//System.out.println(info);
return info;
}
}

• Crie uma interface para o DAO que fara o acesso ao servidor LDAP. Exemplo:

package com.altec.bsbr.app.abcLdap.dao;
....
public interface UserInfoDao {
public List<UserInfo> findAll();
}

• Crie uma classe que estenda de com.altec.bsbr.fw.dao.ldap.GenericLdapDao.

package com.altec.bsbr.app.abcLdap.dao.impl;
import com.altec.bsbr.fw.dao.ldap.GenericLdapDao;
...

@Repository
public class UserInfoDaoImpl extends GenericLdapDao implements UserInfoDao {
private final int PAGE_SIZE = 500;

public List<UserInfo> findAll() {


final String filter = "(objectclass=user)";
return pagedSearch(filter, new UserInfoMapper(), PAGE_SIZE);
}
}

Framework Java Arquitetura Brasil 133


LDAP

• Anote a classe utilizando @Autowired de serviço para utilizar fazer o acesso ao DAO. Exemplo:

package com.altec.bsbr.app.abcLdap.service.impl;
...
@Service
public class UserInfoServiceImpl implements UserInfoService {
@Autowired
private UserInfoDao userInfoDao;
...
}

13.1.1. Configurando o servidor Ldap

Crie o ldap.xml no diretório META-INF/config/[runningMode]/ com as seguintes configurações:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/bea
http://www.springframework.org/schema/util http://www.springfr

<bean id="contextSource"
class="org.springframework.ldap.pool.factory.PoolingContextSource">
<property name="contextSource" ref="contextSourceTarget" />
</bean>

<bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource">


<property name="url" value="ldap://ldap_server:389" />❶
<property name="base" value="DC=com,DC=br,DC=app" />❷
<property name="userDn" value="usu" />❸
<property name="password" value="pass" />❹
<property name="pooled" value="true" />
<property name="baseEnvironmentProperties">
<map>
<entry key="java.naming.referral" value="follow"/>
<entry key="com.sun.jndi.ldap.connect.timeout" value="10000"/>❺
</map>
</property>
</bean>

<bean name="ldapTemplate" class="org.springframework.ldap.core.simple.SimpleLdapTemplate">


<constructor-arg type="org.springframework.ldap.core.ContextSource" ref="contextSourceTarget"/>
</bean>

</beans>

❶ Host e Porta do servidor LDAP


❷ Filtro Base.
❸ Usuário do servidor LDAP.
❹ Senha do servidor LDAP.
❺ Quanto tempo a thread atual ira esperar por uma conexão do pool.

13.1.2. Métodos da classe GenericLdapDao

A classe com.altec.bsbr.fw.dao.ldap.GenericLdapDao possui os seguintes métodos:

• pagedSearch(String filter, ParameterizedContextMapper<?> mapper, int pageSize): List<T>:


Executa uma busca páginada para casos em que o resultado esperado excede a quantidade máxima de
resultados retornados pelo LDAP server.

• search(String filter, ParameterizedContextMapper<?> mapper, PagedResultsCookie cookie, int

Framework Java Arquitetura Brasil 134


LDAP

pageSize): List<T>: Executa uma busca páginada para casos em que o resultado esperado excede a
quantidade máxima de resultados retornados pelo LDAP server.

• getSimpleLdapTemplate(): SimpleLdapTemplate: A instancia do SimpleLdapTemplate usada pelo


GenericLdapDao.

13.1.3. Utilizando um SimpleLdapTemplate específico

Para fornecer um SimpleLdapTemplate escífico sobre-escreva o método


setSimpleLdapTemplate(SimpleLdapTemplate). Exemplo:

...
@Repository
public class FooDaoImpl extends GenericLdapDao implements FooDao {
@Autowired
@Qualifier("mySimpleLdapTemplate")
@Override
public void setSimpleLdapTemplate(SimplaLdapTemplate simpleLdapTemplate) {
super.setSimpleLdapTemplate(simpleLdapTemplate);
}
}

Para maiores informações consulte:

• Spring Ldap

• Tips for LDAP users

• LDAP Naming Service Provider for JNDI

Framework Java Arquitetura Brasil 135


Capítulo 14. Classes utilitárias

14.1. Introdução
Este capítulo descreve o uso das várias classes utilitárias do Framework, que podem ser usadas no dia-a-dia de
programação em Java.

Está fora do escopo deste manual, documentar bibliotecas de terceiros, que são usadas pelo Framework. O
intuito é apenas apresentar algumas das suas funcionalidades básicas. Maiores informações podem ser obtidas
na documentação oficial de cada produto.

14.2. Manipulação de data e hora


Para a manipulação de valores do tipo data ou tempo, foi adotada a biblioteca Joda-Time, que possui uma API
mais amigável que java.util.Calendar e java.util.Date .

Esta é uma rápida introdução da biblioteca Joda-Time, e alguns dos recursos oferecidos. A documentação
completa está no guia do usuário .

14.2.1. Data e Horário

As principais classes incluidas no Joda-Time são:

• DateTime - substituto imutável para o JDK Calendar.

• DateMidnight - classe imutável que representa a data em que o tempo é forçado a meia-noite.

• LocalDate - classe imutável representando uma data local sem hora (e sem fuso horário).

• Local - classe imutável representando uma hora sem data (sem fuso horário).

• LocalDateTime - classe imutável representando uma data e hora locais (sem fuso horário).

Cada classe datetime fornece uma variedade de construtores. Estas incluem construtores com objetos, o que
permite construir, por exemplo, um DateTime a partir dos seguintes objetos:

• Date - um instante do JDK

• Calendar - um calendário JDK

• String - em formato ISO8601

• Long - em milisegundos

• qualquer classe datetime do Joda-Time

Esta lista é extensível. Em outras palavras o Joda-Time sacrifica um pouco de segurança de tipos pela
extensibilidade. Significa, porém, que a conversão a partir de um Date ou Calendar do JDK para uma classe
Joda-Time é fácil - basta passar a classe JDK no construtor.

Framework Java Arquitetura Brasil 136


Classes utilitárias

Cada classe datetime fornece métodos de acesso simples para campos datetime. Por exemplo, para acessar o
mês você pode usar:

...
DateTime dt = new DateTime();
int month = dt.getMonthOfYear();
...

Todas as principais classes datetime são imutáveis (como String) e não podem ser alteradas após a criação. No
entanto, métodos simples são fornecidos para alterar valores de campos em objetos recém criados. Por
exemplo, para definir o ano, ou adicionar 2 horas você pode usar:

...
DateTime dt = new DateTime();
DateTime year2000 = dt.withYear(2000);
DateTime twoHoursLater = dt.plusHours(2);
...

Além de métodos get básicos, cada classe datetime provee métodos que retornam propriedades (
DateTime.Property ) para cada campo. Estas proporcionam acesso a todo o manancial de funcionalidade do
Joda-Time. Por exemplo, para obter informações acerca de um mês ou ano:

...
DateTime dt = new DateTime();
String monthName = dt.monthOfYear().getAsText();
String frenchShortName = dt.monthOfYear().getAsShortText(Locale.FRENCH);
boolean isLeapYear = dt.year().isLeap();
DateTime rounded = dt.dayOfMonth().roundFloorCopy();
...

14.2.2. Intervalos e períodos de tempo

Joda-Time fornece suporte para intervalos e períodos de tempo.

Um intervalo é representado pela classe Interval . Ela possui um início e fim, e permite operações baseadas em
torno desse intervalo de tempo.

Um período de tempo é representada pela classe Period . Ela contém um período como 6 meses, 3 dias e 7
horas. Você pode criar uma Período diretamente, ou derivá-lo de um intervalo.

Uma duração de tempo é representada pela classe Duration . Esta detém uma duração exata em milisegundos.
Você pode criar uma duração diretamente, ou derivá-la de um intervalo.

Apesar de um período e uma duração parecerem semelhantes, elas funcionam de forma diferente. Considere,
por exemplo, adicionar um dia a um DateTime na mudança de horário de verão.

...
DateTime dt = new DateTime(2005, 3, 26, 12, 0, 0, 0);
DateTime plusPeriod = dt.plus(Period.days(1));
DateTime plusDuration = dt.plus(new Duration(24L*60L*60L*1000L));
...

Adicionar um período vai acrescentar 23 horas neste caso, e não 24 por causa da mudança do horário de verão,
assim o horário do resultado ainda será meio-dia. Adicionar uma duração irá acrescentar 24 horas não importa o
que, portanto, o horário do resultado será 13:00.

Framework Java Arquitetura Brasil 137


Classes utilitárias

14.2.3. Input and Output

A leitura da informação de data ou hora de fontes externas que têm o seu próprio formato personalizado é uma
exigência frequente para aplicações que tenham computações com datas. Escrever com um formato
personalizado é também um requisito comum.

Muitos formatos personalizados podem ser representados por formatos que especificam uma seqüência de
campos calendário junto com a representação (numérico, nome string, etc) e comprimento do campo. Por
exemplo o padrão "yyyy" representaria um ano com 4 dígitos. Outros formatos não são tão facilmente
representados. Por exemplo, o padrão "yy" para um dígito com dois anos não identifica unicamente o século a
que pertence. Na saída, isto não irá causar problemas, mas há um problema de interpretação na entrada.

Além disso, existem várias normas para serialização de data/hora de uso comum, em particular o ISO8601.
Estas também devem ser suportadas pela maior parte das aplicações.

Joda-time suporta estes diferentes requisitos através de uma arquitetura flexível. Vamos agora descrever os
vários elementos desta arquitetura.

14.2.3.1. Formatadores

Todo parse e impressão é realizado utilizando um objeto DateTimeFormatter . Dado um objeto fmt do tipo
DateTimeFormatter , o parsing é realizado da seguinte forma

...
String strInputDateTime;
// string is populated with a date time string in some fashion
...
DateTime dt = fmt.parseDateTime(strInputDateTime);
...

Assim, um objeto DateTime é retornado a partir do método de parse do formatter. Do mesmo modo, a saída é
realizada como

...
String strOutputDateTime = fmt.print(dt);
...

14.2.3.2. Formatadores Standard

O suporte para formatos padrão baseado no ISO8601 é fornecido pela ISODateTimeFormat classe. Isto
proporciona uma série de métodos de construção.

Por exemplo, se você quisesse usar o formato padrão ISO para datetime, que é yyyy-MM-dd'T'HH:mm:ss.SSSZ ,
você deve inicializar fmt como

...
DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
...

Depois, você poderia usar fmt , como descrito acima, para ler ou escrever objetos datetime neste formato.

14.2.3.3. Formatadores Customizados

Se você precisar de um formatter customizado que pode ser descrito em termos de um pattern, você pode usar o
método de fabricação fornecido pela classe DateTimeFormat . Assim, para obter um formatter para um ano de

Framework Java Arquitetura Brasil 138


Classes utilitárias

com 4 dígitos, mês com 2 dígitos, e dia do mês com 2 dígitos, ou seja, um formato yyyyMMdd você faria

...
DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyyMMdd");
...

O pattern é compatível com os padrões de data do JDK .

Pode haver a necessidade de fazer parse ou imprimir no formato de um determinado país (locale). Isto é
conseguido chamando o método withLocale de um formatter, que retorna outro formatter baseada no original.

...
DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyyMMdd");
DateTimeFormatter frenchFmt = fmt.withLocale(Locale.FRENCH);
DateTimeFormatter germanFmt = fmt.withLocale(Locale.GERMAN);
...

Formatadores são imutáveis, de modo que o original não é alterada pelo método withLocale .

14.2.3.4. Formatadores diferentes

Por último, se você tem um formato que não é facilmente representado por um pattern, o Joda-Time expõe uma
classe builder que pode ser usada para construir um formatter customizado que é definido através do programa.
Assim, se você quiser um formatter para imprimir e analisar datas na forma "22-Jan-65", você poderia fazer o
seguinte:

...
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendDayOfMonth(2)
.appendLiteral('-')
.appendMonthOfYearShortText()
.appendLiteral('-')
.appendTwoDigitYear(1956) // pivot = 1956
.toFormatter();
...

Cada método append adiciona um novo campo para ser analisado / impresso para o builder chamador e retorna
um novo builder. O último método toFormatter cria o formatter real que será usado.

O que é particularmente interessante sobre este formato é o "dois dígitos pro ano" ( appendTwoDigitYear() ).
Uma vez que a interpretação de um ano com 2 dígitos é ambígua, o método appendTwoDigitYear toma um
parâmetro extra que define o intervalo de 100 anos dos dois dígitos, indicando o ponto médio do intervalo.
Neste exemplo, a faixa será (1956 - 50) = 1906, a (1956 + 49) = 2005. Assim, 04 será 2004, mas 07 será 1907.
Este tipo de conversão não é possível com formato normal em patterns, destacando o poder da arquitetura de
formatação do Joda-time.

14.2.3.5. Acesso direto

Para simplificar o acesso ao formatter, são fornecidos métodos de acesso nas classes datetime.

...
DateTime dt = new DateTime();
String a = dt.toString();
String b = dt.toString("dd:MM:yy");
String c = dt.toString("EEE", Locale.FRENCH);
DateTimeFormatter fmt = ...;
String d = dt.toString(fmt);
...

(1.13.6)
Classes utilitárias

Cada um dos quatro resultados demonstram uma forma diferente de usar o formatadores. O resultado a é uma
string no padrão ISO8601 para o DateTime. O resultado b irá utilizar o padrão de saída 'dd:MM:yy' (note que
os padrões são guardados em cache internamente). O resultado c será a saída usando o padrão "EEE", em
francês. O resultado d usará o formatter especificado, e assim é o mesmo que fmt.print(dt) .

14.2.4. Interoperabilidade com JDK

A classe DateTime tem um construtor que leva um Object como entrada. Em especial, a este construtor pode
ser passado um Date do JDK, Calendar do JDK ou GregorianCalendar do JDK (Ele também aceita uma
String formatada em ISO8601, ou um objeto Long representando milisegundos). Esta é uma metade da
interoperabilidade com o JDK. A outra metade da interoperabilidade com o JDK é fornecida por métodos
DateTime que retornam objetos do JDK.

Assim conversão entre DateTime do Joda-time e Date do JDK, e pode ser realizado da seguinte forma

...
// from Joda to JDK
DateTime dt = new DateTime();
Date jdkDate = dt.toDate();

// from JDK to Joda


dt = new DateTime(jdkDate);
...

Do mesmo modo, para Calendar do JDK:

...
// from Joda to JDK
DateTime dt = new DateTime();
Calendar jdkCal = dt.toCalendar(Locale.CHINESE);

// from JDK to Joda


dt = new DateTime(jdkCal);
...

e GregorianCalendar do JDK:

...
// from Joda to JDK
DateTime dt = new DateTime();
GregorianCalendar jdkGCal = dt.toGregorianCalendar();

// from JDK to Joda


dt = new DateTime(jdkGCal);
...

14.3. Miscelânea
O projeto Apache fornece as bibliotecas open-source commons-lang e commons-collections para ajudar a
resolver problemas de programação do dia-a-dia, como manipulação de caracteres, Strings, arrays e coleções.

14.3.1. A biblioteca Commons Lang

14.3.1.1. Descrição

A biblioteca Commons Lang fornece adições um tanto quanto necessárias ao padrão java.lang da JDK. Ela

(1.13.6)
Classes utilitárias

contém componentes genéricos e reutilizáveis para o uso diário.

O pacote principal contem várias classes utilitárias, enquanto há vários sub-pacotes incluindo enums, exceção e
construtor. Usar as classes utilitárias é geralmente muito simples. São o equivalente a funções globais em uma
outra língua, uma coleção de métodos stand-alone, thread-safe e estáticos. Em contraste, sub-pacotes podem
conter interfaces que necessitem de implementações ou classes que podem precisar serem estendidas para obter
a funcionalidade total do código. Podem, no entanto, conter mais funções do tipo global.

Commons Lang procura suportar o Java 1.2 em diante - então, embora você possa ter visto características em
umas versões mais novas do Java, tais como métodos de separação e exceções aninhadas, o framework ainda
mantem versões não java.lang para usuários das versões anteriores de Java.

Você encontrará métodos depreciados ("deprecated") enquanto percorre a documentação do framework. Estes
métodos serão removidos na próxima grande versão.

Antes de começar, é uma boa hora para falar das classes Utils. Todas elas contêm construtores públicos vazios
com avisos para não utilizar. Isto pode parecer uma coisa estranha, mas isso permite que as ferramentas como o
Velocity acessem as classes como se fossem "beans". Em outras palavras, sim, nós conhecemos construtores
privados.

14.3.1.2. Manipulação de String - StringUtils, StringEscapeUtils, RandomStringUtils,


Tokenizer, WordUtils

Lang tem uma série de utilitários para String. O primeiro é StringUtils, com várias e várias funções que
ajustam, transformam, melhoram e tratam os java.lang.Strings. Além de StringUtils, tem uma série de outras
classes para manipulação de String: RandomStringUtils, StringEscapeUtils e Tokenizer. O nome da classe
RandomStringUtils fala por si só Ela oferece formas de gerar textos aleatórios, que podem ser utilizados como
senhas iniciais. StringEscapeUtils contém métodos para transformar textos Java, JavaScript, HTML, XML e
SQL, retirando carateres reservados. Tokenizer é uma melhor alternativa para java.util.StringTokenizer.

Essas classes são ideais para começar a utilizar esse framework. Métodos capitalize,
substringBetween/Before/After, split e join de StringUtils são bons para começar a usar. Se você usa muito
java.sql.Statements, StringEscapeUtils.escapeSql pode ser interessante.

Além destas classes, WordUtils é um outro manipulador de String. Ele funciona com Strings a nível da palavra,
por exemplo WordUtils.capitalize vai transformar em caixa alta a primeira letra cada palavra em um texto.
WordUtils também contém métodos para quebrar texto.

14.3.1.3. Manipulação de caracteres - CharSetUtils, CharSet, CharRange, CharUtils

Além de lidar com Strings, também é importante lidar com chars e Characters. CharUtils existe para esta
finalidade, enquanto CharSetUtils existe para ajustar e manipular as Strings como conjunto de caracteres.
Tenha cuidado, embora CharSetUtils receba um argumento do tipo String, este é somente um conjunto de
caracteres. Por exemplo, CharSetUtils.delete("testtest", "tr") removerá todos os t's e todos os r's da
String, e não apenas as String "tr".

CharRange e CharSet são ambos usados internamente por CharSetUtils e provavelmente serão usados
raramente.

14.3.1.4. Interação da JVM - SystemUtils, CharEncoding

SystemUtils é uma pequena classe simples que torna fácil descobrir informações sobre qual plataforma você
está. Para alguns, este é um mal necessário. Serve para eliminar alguns detalhes específicos da versão do JDK.

Framework Java Arquitetura Brasil 141


Classes utilitárias

if (SystemUtils.isJavaVersionAtLeast(1.3f)) { ... }

A classe CharEncoding é também utilizada para interagir com o ambiente Java e pode ser utilizado para ver que
codificações ("encoding") de caracteres são suportadas em um ambiente particular.

14.3.1.5. Serialização - SerializationUtils, SerializationException

Serialização não tem que ser tão difícil! Uma classe simples do util pode facilitar, alem disso fornece um
método para clonar um objeto deserializando e reserializando, um truque velho de Java.

14.3.1.6. Funções Variadas - ObjectUtils, ClassUtils, ArrayUtils, BooleanUtils

ObjectUtils contém funções úteis para Objetos, principalmente, implementações que tratam 'null' de forma
segura nos métodos de java.lang.Object.

ClassUtils é em grande parte um conjunto de métodos auxiliares para "reflection". Uma nota especial para a
ocultação dos comparadores no ClassUtils, úteis para classificar classes de objetos e pacotes pelo nome; porém
eles simplesmente ordenam alfabeticamente e não compreendem o método simples de classificação de java e
javax .

Em seguida, ArrayUtils. Este é um assunto extenso com muitos métodos e muitas sobrecargas de métodos de
modo que provavelmente merece um olhar detalhado aqui. Antes de começarmos, assuma que cada método
mencionado está sobrecarregado para todos os primitivos e para Object. Além disso, o 'xxx' denota um tipo
primitivo genérico, mas geralmente inclui também a classe Object.

• ArrayUtils fornece arrays vazios, com instância única ("singletons"), para todos os tipos basicos. Estes
serão largamente utilizados na API Collections com métodos toArray, mas também devem ser utilizados
com métodos que retornam um array vazio em caso de erro.

• add(xxx[], xxx) irá adicionar um tipo primitivo para um array, redimensionando o array como você
espera. Também suporta a classe Object.

• clone(xxx[]) clona um array de primitivos ou de Objects.

• contains(xxx[], xxx) procura por um primitivo ou um objeto em um array de primitivos ou de Objects.

• getLength(Object) retorna o comprimento de qualquer array ou IllegalArgumentException se o parâmetro


não for um array. hashCode(Object) , equals(Object, Object) , toString(Object)

• indexOf(xxx[], xxx) e indexOf(xxx[], xxx, int) são cópias dos métodos clássicos da classe String,
mas desta vez para arrays de primitivos e de Objects. Além disso, existe um conjunto de métodos do tipo
lastIndexOf .

• isEmpty(xxx[]) permite que você saiba se um array possui tamanho zero ou é nulo.

• isSameLength(xxx[], xxx[]) retorna verdadeiro se os arrays são do mesmo tamanho.

• Além dos métodos de adição, há também dois tipos de métodos de remoção. O primeiro tipo remove o valor
em um índice, remove(xxx[], int) , enquanto o segundo tipo remove o primeiro valor do array,
remove(xxx[], xxx) .

• Agora chegando no fim, o método reverse(xxx[]) reverte os valores do array.

• O método subarray(xxx[], int, int) cria um array extraído de um array maior.

Framework Java Arquitetura Brasil 142


Classes utilitárias

• A conversão de primitivo para primitivo é tratado pelos métodos toObject(xxx[]) e toPrimitive(Xxx[])


.

Por último, ArrayUtils.toMap(Object[]) é digna de nota especial. Não é somente um método


sobrecarregado para trabalhar com arrays, mas uma maneira simples de criar Maps a partir de literais.
Usando toMap

...
Map colorMap = MapUtils.toMap(new String[][] {{
{"RED", "#FF0000"},
{"GREEN", "#00FF00"},
{"BLUE", "#0000FF"}
});
...

Nossa última classe útil é BooleanUtils. Ele contém diversos métodos que tratam Booleanos, provavelmente o
de maior interesse é o método BooleanUtils.toBoolean(String) que transforma várias Strings
positivas/negativas em um objeto booleano, e não apenas true/false como Boolean.valueOf.

14.3.1.7. Exceções - IllegalClassException, IncompleteArgumentException,


NotImplementedException, NullArgumentException, UnhandledException

O framework Lang também tem uma série de exceções que nós achamos úteis. Todas estas exceções são
descendentes de RuntimeException, elas são apenas um pouco mais significativas do que
java.lang.IllegalArgumentException.

14.3.1.8. Texto

O pacote de texto fornece, entre outras classes, um substituto para StringBuffer nomeado StrBuilder , uma
classe para substituir variáveis dentro de uma String nomeada StrSubstitutor e um substituto para
StringTokenizer nomeado StrTokenizer . Mesmo não tendo ganhos, o prefixo Str tem sido utilizado para
garantir que não tenha conflito com qualquer padrão de classes Java atual ou futura.

14.3.1.9. Outros - BitField, Validate

Chegando ao final do nosso pacote, nós ficamos com um par de classes que não se encaixam em nenhum dos
tópicos até agora.

A classe de BitField fornece uma classe wrapper ao redor do clássico bitmask integer, enquanto que a classe
Validate pode ser utilizada para asserções (lembre-se, Java 1.2 também é suportado).

14.3.2. A biblioteca Commons Collections

Commons-Collections fornece um grande número de classes para ajudar o dia a dia de programação. Este
documento destaca algumas características chaves para você começar.

• Utilities para as coleções padrão.

• Maps

• Iteração em Maps

• Maps ordenados

(1.13.6)
Classes utilitárias

• Maps bidirecionais

• Queues e Buffers

• Bags

Commons-collections utiliza uma estratégia de sincronização semelhante ao Java collections padrão. A maioria
das diversas implementações de collections, maps e bags não são thread safe sem sincronização adicional. O
método synchronizeXXX adequado em Collections é uma forma que essas implementações podem ser
sincronizadas para uso em uma aplicação multithread.

Os javadocs da classe deverão indicar se uma determinada implementação é segura para acesso multithread
sem sincronização adicional. Onde não há nenhuma indicação explícita que a implementação é thread safe
então deve-se presumir que a sincronização é necessária.

14.3.2.1. Utilitários

Uma classe utilitária é fornecida para cada interface principal de collection. Assim, as interfaces Set e
SortedSet são fornecidas pela SetUtils . Estas classes fornecem métodos úteis para trabalhar com esse tipo de
collection.

A maioria dos métodos são encontrados em duas classes “raiz” de collection utility - CollectionUtils e
MapUtils . Como todas as outras interfaces collection estendem Collection ou Map estas utilities podem ser
usadas amplamente. Elas incluem intersecção, contagem, iteração, funções e operações de typecasting, entre
outras. As classes utility também fornecem o acesso a classes decorator em um modo similar à classe
Collections do JDK.

14.3.2.2. Mapas

14.3.2.2.1. Iteração em mapas


A interface Map do JDK sempre sofreu por ser difícil de iterar. Os usuários da API são forçados a iterar sobre
um EntrySet ou sobre o KeySet Commons-Collections fornece agora uma interface nova - MapIterator que
permite a iteração simples sobre maps.

...
IterableMap map = new HashedMap();
MapIterator it = map.mapIterator();
while (it.hasNext()) {
Object key = it.next();
Object value = it.getValue();

it.setValue(newValue);
}
...

14.3.2.2.2. Mapas ordenados


Uma nova interface é fornecida para os mapas que têm uma ordem mas não são ordenados - OrderedMap . Duas
implementações são fornecidas - LinkedMap e ListOrderedMap (um decorador). Esta interface suporta o map
iterator, e também permite iteração tanto adiante quanto para trás através do map.

...
OrderedMap map = new LinkedMap();
map.put("FIVE", "5");
map.put("SIX", "6");
map.put("SEVEN", "7");

(1.13.6)
Classes utilitárias

map.firstKey(); // returns "FIVE"


map.nextKey("FIVE"); // returns "SIX"
map.nextKey("SIX"); // returns "SEVEN"
...

14.3.2.2.3. Mapas bidirecionais


Uma nova hierarquia de interface foi adicionada para suportar mapas bidirecionais - BidiMap . Estes
representam mapas onde a chave pode consultar o valor e o valor pode consultar a chave com igual facilidade.

...
BidiMap bidi = new TreeBidiMap();
bidi.put("SIX", "6");
bidi.get("SIX"); // returns "6"
bidi.getKey("6"); // returns "SIX"
bidi.removeValue("6"); // removes the mapping
BidiMap inverse = bidi.inverseBidiMap(); // returns a map with keys and values swapped
...

Interfaces adicionais são fornecidas para mapas bidirecionais ordenados. Implementações são fornecidas para
cada tipo de mapa bidirecional.

14.3.2.3. Filas

Uma nova hierarquia de interface foi adicionada para suportar queues (filas) e buffers - Buffer . Estas
representam collections que tenham uma ordem de remoção bem definida.

...
Buffer buffer = new UnboundedFifoBuffer();
buffer.add("ONE");
buffer.add("TWO");
buffer.add("THREE");
buffer.remove(); // removes and returns the next in order, "ONE" as this is a FIFO
buffer.remove(); // removes and returns the next in order, "TWO" as this is a FIFO
...

Implementações são fornecidas para FIFO (queue), LIFO (stack) e Priority (remoção na ordem do comparador).

14.3.2.4. Bags

Uma nova hierarquia de interface foi adicionado para suportar bags - Bag . Estas representam collections onde
um certo número de cópias de cada elemento é armazenada.

...
Bag bag = new HashBag();
bag.add("ONE", 6); // add 6 copies of "ONE"
bag.remove("ONE", 2); // removes 2 copies of "ONE"
bag.getCount("ONE"); // returns 4, the number of copies in the bag (6 - 2)
...

Implementações são fornecidas para Bags ordenadas e desordenadas.

14.4. Validadores
O Framework fornece um conjunto de classes que implementam validação, que podem ser muito úteis. Esses
validadores ficam no package com.altec.bsbr.fw.validator e estão listados na tabela a seguir:

Framework Java Arquitetura Brasil 145


Classes utilitárias

Tabela 14.1. Validadores

Validator Descrição

EmailValidator Valida se o argumento é um endereço de email,


baseado em uma expressão regular.

NumberDigitsValidator Valida se a precisão de números inteiros ou


fracionários está dentro do limite máximo definido,
por exemplo se o número tem 2 casas decimais.

NumberRangeValidator Valida se o valor está entre uma faixa, sendo valor


minímo e valor máximo os limites da faixa.

StringDateTimeValidator Valida se a data está no padrão informado. O padrão


pode ser um
org.joda.time.format.DateTimeFormatter , ou
uma String que obedeça a esse formatter.

StringLengthValidator Verifica se uma string tem um determinado tamanho.


Usando valores minímo e máximo.

StringPatternValidator Dado uma regular expression valida um determinado


valor. Pode ser usada uma String ou um
java.util.regex.Pattern .

Algumas classes utilitárias do Framework, como as Mapper e Marshaller usam os validadores indicados nas
anotações automaticamente, como visto nas seções de arquitetura estendida e processamento de registros .

Mas os validadores podem ser usados a qualquer momento, basta usar uma instância do validador. Os exemplos
a seguir mostram como utilizar os validadores:

... private Validator emailValidator = new EmailValidator(); public


void sendSuporteEmail(String fromEmail, String conteudo) {
emailValidator.validate(fromEmail));

SimpleMailMessage msg = new SimpleMailMessage();
msg.setFrom(fromEmail); ... }

❶ Se fromEmail for inválido, lança a exceção ValidateException .

ou...

...
private Validator emailValidator = new EmailValidator();

public void sendSuporteEmail(String fromEmail, String conteudo) {


if (!emailValidator.isValid(fromEmail)){
throw new EmailInvalidoException("Email invalido: [" + fromEmail + "]");
}

SimpleMailMessage msg = new SimpleMailMessage();


msg.setFrom(fromEmail);
...
}

Framework Java Arquitetura Brasil 146


Classes utilitárias

14.4.1. Criando um validador

A interface do Validator é bastante simples:

package com.altec.bsbr.fw.validator;

import com.altec.bsbr.fw.record.exception.ValidateException;

public interface Validator {

void validate(Object value) throws ValidateException;

boolean isValid(Object value);

Os validadores estendem a classe abstrata BaseValidator . Assim, para criar outros validadores basta
estendê-la e implementar o método validate() .

Um recurso muito útil é o método reject() que recebe uma mensagem e um objeto e lança uma exceção
ValidateException com a mensagem e valor indicados. A seguir um exemplo de validador:

public class StringPatternValidator extends BaseValidator {

private Pattern pattern;

public StringPatternValidator(Pattern pattern) {


this.pattern = pattern;
}

public StringPatternValidator(String s) {
pattern = Pattern.compile(s);
}

public void validate(Object target) throws ValidateException {


if (target == null) {
reject("stringpattern.null.error", null);
return;
}
if (!String.class.equals(target.getClass())) {
reject("stringpattern.class.error", target);
return;
}

String string = (String) target;


Matcher matcher = pattern.matcher(string);

if (!matcher.matches()) {
reject("stringpattern.match.error", string);
}
}
}

14.5. Conversores
O Framework fornece um conjunto de classes para conversão de String em Objetos e vice-versa, que podem ser
muito úteis. Esses conversores ficam no package com.altec.bsbr.fw.converter e estão listados na tabela a
seguir:

Tabela 14.2. Conversores

Converter Descrição

NumberConverter Conversor base para qualquer conversor numérico.As

(1.13.6)
Classes utilitárias

Converter Descrição

especializações e suas descrições a seguir.

BigDecimalConverter Converte uma String para um BigDecimal e


vice-versa. O método setScale() permite alterar a
precisão(sendo a precisão padrão = 0 (zero)) e o
método setPattern() permite alterar a formatação do
valor em String dado um determinado formato (sendo
o formato padrão "0.00")

DoubleConverter Converte uma String para um BigDecimal e


vice-versa. O método setPattern() permite alterar a
formatação do valor em String dado um determinado
formato (sendo o formato padrão "0.00")

BooleanConverter Conversor base para Booleans. Existem algumas


especializações desse conversor no framework, as
descrições para cada uma pode ser lida nas linhas a
seguir.

OneZeroBooleanConverter Para qualquer String passada para o conversor ele


retornará true, para "1" e false para o resto. Para os
valores true e false, retornará "1" e "0",
respectivamente.

TFBooleanConverter Para qualquer String passada para o conversor ele


retornará true, para "T" e false para o resto. Para os
valores true e false, retornará "T" e "F",
respectivamente.

YNBooleanConverter Para qualquer String passada para o conversor ele


retornará true, para "Y" e false para o resto. Para os
valores true e false, retornará "Y" e "N",
respectivamente.

VFBooleanConverter Para qualquer String passada para o conversor ele


retornará true, para "V" e false para o resto. Para os
valores true e false, retornará "V" e "F",
respectivamente.

SNBooleanConverter Para qualquer String passada para o conversor ele


retornará true, para "S" e false para o resto. Para os
valores true e false, retornará "S" e "N",
respectivamente.

DateConverter Conversor base para qualquer conversor de datas(com


uso do SimpleDateFormat). As especializações e
descrições podem ser lidas nas linhas a seguir.

TimestampDateConverter Converte uma String no padrão


"yyyy-MM-dd-hh.mm.ss.ms" para um valor do tipo
java.util.Date e datas para a String com o mesmo
padrão.

YYYYMMDDDateConverter Converte uma String no padrão "yyyyMMdd" valor


do tipo java.util.Date e datas para a String com o
mesmo padrão.

(1.13.6)
Classes utilitárias

Algumas classes utilitárias do Framework, como as Mapper e Marshaller usam os conversores indicados nas
anotações automaticamente, como visto nas seções de arquitetura estendida e processamento de registros .

14.5.1. Criando um conversor

A interface do Converter é bastante simples:

package com.altec.bsbr.fw.converter;

import com.altec.bsbr.fw.record.exception.ConverterException;

public interface Converter<T> {

T parseValue(String value) throws ConverterException;

String formatValue(Object value) throws ConverterException;

Os conversores estendem a classe abstrata BaseConverter . Assim, para criar outros conversores basta
estendê-la e implementar os métodos parseValue() e formatValue ().

Um recurso muito útil é o método reject() que recebe uma mensagem e um objeto e lança uma exceção
ConverterException com a mensagem e valor indicados. A seguir um exemplo de conversor:

public class DateConverter extends BaseConverter<Date> {

private SimpleDateFormat sdf;

public void setPattern(String pattern) {


this.sdf = new SimpleDateFormat(pattern);
}

public String formatValue(Object value) throws ConverterException {


if (!(value instanceof Date)) {
throw new ConverterException("O objeto não é uma instância de java.util.Date", value == null
? "null"
: value.getClass().getName());
}
return sdf.format((Date) value);
}

public Date parseValue(String value) throws ConverterException {


if (null == this.sdf) {
throw new ConverterException("Use o método setPattern()", null);
}
try {
return sdf.parse(value);
}
catch (ParseException e) {
throw new ConverterException("Impossível converter o valor: [" + value + "]", e);
}
}
}

14.6. Manipulação de arquivos


Para a manipulação de valores do tipo data ou tempo, foi adotada a biblioteca Apache Commons IO, que possui
capacidade extra as das classes do JDK: Utilitários – métodos estáticos para tarefas comuns.

• Filtros – várias implementações de filtros de arquivos.

Framework Java Arquitetura Brasil 149


Classes utilitárias

• Comparadores – várias implementações de java.util.Comparator para arquivos.

• Streams – várias implementações de streams, readers e writers.

14.6.1. Commons IO

14.6.1.1. IOUtils

IOUtils contem os métodos utilitários que tratam a leitura, a escrita e a cópia. Os métodos trabalham em
InputStream , OutputStream , Reader e Writer .

Como um exemplo, considere a tarefa de ler bytes de um URL, e sua impressão. Isto é feito tipicamente da
seguinte forma:

...
InputStream in = new URL("http://jakarta.apache.org").openStream();
try {
InputStreamReader inR = new InputStreamReader( in );
BufferedReader buf = new BufferedReader(inR);
String line;
while ((line = buf.readLine()) != null) {
System.out.println(line);
}
} finally {
in.close();
}
...

Usando a classe IOUtils , poderia ser feito assim:

...
InputStream in = new URL( "http://jakarta.apache.org" ).openStream();
try {
System.out.println(IOUtils.toString(in));
} finally {
IOUtils.closeQuietly(in);
}
...

Em determinados domínios da aplicação, tais operações do IO são comuns, e esta classe pode economizar
muito tempo. E você pode confiar num código que está bem testado.

Para classes utilitárias como esta, flexibilidade e velocidade são de primordial importância. Entretanto você
deve igualmente compreender as limitações deste enfoque. Usar a técnica acima para ler um arquivo de 1GB
resultaria na tentativa de criar um objeto String de 1GB!

14.6.1.2. FileUtils

A classe FileUtils contem métodos utilitários para trabalhar com objetos de arquivo. Estes incluem a leitura,
escrita, cópia e comparação de arquivos.

Por exemplo para ler todas as linhas de um arquivo, linha a linha, você poderia usar:

...
File file = new File("/commons/io/project.properties");
List lines = FileUtils.readLines(file, "UTF-8");
...

14.6.1.3. FilenameUtils

Framework Java Arquitetura Brasil 150


Classes utilitárias

A classe FilenameUtils contem métodos utilitários para trabalhar com nomes de arquivo sem usar objetos da
classe File. A classe tem o objetivo de ser consistente entre Unix e Windows, de ajudar na transições entre estes
ambientes (tal como mover do ambiente de desenvolvimento para a produção).

Por exemplo, normalizar um nome de arquivo que remove segmentos de ponto duplos:

...
String filename = "C:/commons/io/../lang/project.xml";
String normalized = FilenameUtils.normalize(filename);
// result is "C:/commons/lang/project.xml"
...

14.6.1.4. FileSystemUtils

A classe FileSystemUtils contem métodos utilitários para trabalhar com o sistema de arquivo cuja
funcionalidade não é suportada pelo JDK. Atualmente, o único método é para obter o espaço livre em disco.
Observe que é utilizado um comando de linha e não código nativo.

Por exemplo para encontrar o espaço livre em disco:

...
long freeSpace = FileSystemUtils.freeSpace("C:/");
...

14.6.1.5. Streams

Os pacotes org.apache.commons.io.input e org.apache.commons.io.output contêm várias


implementações úteis de Streams. Incluindo:

• Null output stream - silenciosamente absorve todos os dados enviados a ele

• Tee output stream - envia dados de saída a dois streams em vez de um

• Byte array output stream - é uma versão mais rápida da classe JDK

• Counting streams - conta o número de bytes que passaram

• Proxy streams - delega para o método correto no proxy

• Lockable writer - permite sincronização da escrita com uso de arquivo de lock

Ver o pacote javadoc input ou output para maiores detalhes.

14.6.2. Commons codec

Codec é composta por um modesto conjunto de utilitários e um framework simples para codificação e
decodificação de dados tanto para textos quanto para dados binários.

14.6.2.1. Binary Encoders

Tabela 14.3. Binary Encoders

Base64 Fornece conteúdo-transferência-codificação Base64


como definido no RFC 2045 . Este codificador pode

(1.13.6)
Classes utilitárias

opcionalmente criar blocos de 76 caracteres de saída


de forma que haja adesão completa à RFC 2045.

Hex Converte um array de bytes em um array de


caracteres que representam os valores hexadecimais
de cada byte na mesma ordem do array original

BinaryCodec Traduz entre arrays de byte e strings de "0"s e "1"s.

14.6.2.2. Language Encoders

Tabela 14.4. Language Encoders

Soundex Implementação do algoritmo de Soundex (tipo


pesquisa fonética).

Metaphone Implementacão do algoritmo de Metaphone (outra


forma de pesquisa fonética).

Refined Soundex Implementação alternativa do algoritmo de Soundex.

Double Metaphone Implementação alternativa do algoritmo de


Metaphone.

14.6.2.3. Digest Encoders

Tabela 14.5. Digest Encoders

DigestUtils Fornece métodos estáticos simples para criar


codificações SHA ou MD5.

14.6.2.4. Network Encoders

Tabela 14.6. Network Encoders

URLCodec Implementa o esquema de codificação


www-form-urlencoded , também conhecido como
codificação URL.

QuotedPrintableCodec Codec para RFC 1521 MIME (Multipurpose Internet


Mail Extensions) Parte Um. Regras #3, #4 e #5 da
especificação ainda não estão implementadas

BCodec Idêntico à codificação Base64 definida por RFC 1521


e permite que um conjunto de caracteres seja
especificado.

QCodec Similar ao padrão conteúdo-transferência-codificação


definido no RFC 1521 e projetada para permitir texto
que contém principalmente carácteres ASCII para ser
decifrável em um terminal ASCII sem decodificação.

(1.13.6)
Classes utilitárias

14.6.3. Manipulação de arquivos formatados

O Framework possui uma série de classes para facilitar a manipulação de arquivos no formato CSV e com
registro de tamanho fixo. Elas estão descritas no capítulo de manipulação de arquivos batch .

14.7. Manipulação de XML


Para a manipulação de XML foram adotadas as APIs padrão Java, SAX e DOM já presentes no JDK. Essas
APIs devem ser usadas em circunstâncias diferentes, como explicado na tabela abaixo:

Tabela 14.7. DOM vs SAX

DOM SAX

Todo o documento é carregado em memória. Processa os elementos sequencialmente enquanto eles


são lidos.

Deve ser usado em documentos pequenos, onde Deve ser usado em documentos grandes, e o
grande parte dele precisa ser processada. documento pode ser processado em blocos.

API manipula uma árvore. API orientada a eventos

Mais flexível. Mais difícil de usar.

14.7.1. DOM

A API DOM se baseia na manipulação de elementos e atributos de um documento que representa o XML.

O exemplo abaixo mostra como ler o XML de um arquivo usando DOM:

import java.io.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.*;

public class BasicDom {


public static void main(String[] args) {
Document doc = parseXmlFile("infilename.xml", false);
}

// Parses an XML file and returns a DOM document.


// If validating is true, the contents is validated against the DTD
// specified in the file.
public static Document parseXmlFile(String filename, boolean validating) {
try {
// Create a builder factory
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(validating);

// Create the builder and parse the file


Document doc = factory.newDocumentBuilder().parse(new File(filename));
return doc;
} catch (SAXException e) {
// A parsing error occurred; the xml input is not valid
} catch (ParserConfigurationException e) {
} catch (IOException e) {
}
return null;
}
}

Framework Java Arquitetura Brasil 153


Classes utilitárias

Exemplo para visitar todos os nodes do XML:

// Obtem um documento DOM


Document doc = parseXmlFile("infilename.xml", true);

visit(doc, 0);

// This method visits all the nodes in a DOM tree


public static void visit(Node node, int level) {
// Process node

// If there are any children, visit each one


NodeList list = node.getChildNodes();
for (int i=0; i$lt;list.getLength(); i++) {
// Get child node
Node childNode = list.item(i);

// Visit child node


visit(childNode, level+1);
}
}

Exemplo de uso do XPath para selecionar elementos do XML:

// Obtem todos os elementos "nome" do documento


String xpath = "//nome";

// Obtem um documento DOM


Document doc = parseXmlFile("infilename.xml", false);

try {
// Get the matching elements
NodeList nodelist = org.apache.xpath.XPathAPI.selectNodeList(doc, xpath);

// Process the elements in the nodelist


for (int i=0; i<nodelist.getLength(); i++) {
// Get element
Element elem = (Element)nodelist.item(i);
}
} catch (javax.xml.transform.TransformerException e) {
}

14.7.2. SAX

A API SAX se baseia no tratamento de eventos que são disparados durante a leitura de um documento XML.

O exemplo abaixo mostra como ler o XML de um arquivo usando SAX:

import java.io.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

public class BasicSax {


public static void main(String[] args) {
// Create a handler to handle the SAX events generated during parsing
DefaultHandler handler = new MyHandler();

// Parse the file using the handler


parseXmlFile("infilename.xml", handler, false);
}

// DefaultHandler contain no-op implementations for all SAX events.


// This class should override methods to capture the events of interest.
static class MyHandler extends DefaultHandler {
}

// Parses an XML file using a SAX parser.


// If validating is true, the contents is validated against the DTD
// specified in the file.

Framework Java Arquitetura Brasil 154


Classes utilitárias

public static void parseXmlFile(String filename, DefaultHandler handler, boolean validating) {


try {
// Create a builder factory
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(validating);

// Create the builder and parse the file


factory.newSAXParser().parse(new File(filename), handler);
} catch (SAXException e) {
// A parsing error occurred; the xml input is not valid
} catch (ParserConfigurationException e) {
} catch (IOException e) {
}
}
}

Exemplo que obtem os atributos de um elemento durante o parse do XML:

// Cria um handler para os eventos SAX


DefaultHandler handler = new MyHandler();

// Parse an XML file using SAX;


parseXmlFile("infilename.xml", handler, true);

// This class listens for startElement SAX events


static class MyHandler extends DefaultHandler {
// This method is called when an element is encountered
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts) {
// Get the number of attribute
int length = atts.getLength();

// Process each attribute


for (int i=0; i<length; i++) {
// Get names and values for each attribute
String name = atts.getQName(i);
String value = atts.getValue(i);

// The following methods are valid only if the parser is namespace-aware

// The uri of the attribute's namespace


String nsUri = atts.getURI(i);

// This is the name without the prefix


String lName = atts.getLocalName(i);
}
}
}

14.8. Envio de e-mail


Para o envio de e-mail de maneira simples, foi adotada a biblioteca do Spring, que possui a classe
org.springframework.mail.javamail.JavaMailSender .

Quando a aplicação for utilizar um Mail Provider definido no WebSphere, um objeto JavaMailSenderImpl
deve ser definido num arquivo de configuração, apontando para uma mail session tal como registrado no
servidor de aplicações. Exemplo:

• WebSphere - META-INF/config/<runningMode>/mail.xml obtemos uma mail session através de um lookup


JNDI no Websphere.

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"

(1.13.6)
Classes utilitárias

xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">

<!-- ======================================================================================= -->


<!-- Mail Sender -->
<!-- ======================================================================================= -->

<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">


<property name="session" ref="mailSession"/>
</bean>

<jee:jndi-lookup id="mailSession" jndi-name="mail/gmail"/>

</beans>

Para obter a instância do JavaMailSender basta usar a injeção de dependências do Spring. Exemplo de uso:

@Service
public class MailServiceImpl implements MailService {

@Autowired
private JavaMailSender sender;

public void sendSuporteEmail(String fromEmail, String conteudo) {

// criamos a mensagem
MimeMessage message = sender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message);
helper.setFrom(fromEmail);
helper.setTo("test@host.com");
helper.setText(conteudo);

// colocamos um anexo
FileSystemResource file = new FileSystemResource(new File("logo.jpg"));
helper.addAttachment("ABC.jpg", file);

// enviamos a mensagem
sender.send(message);
}

Para obter maiores informações, inclusive de como enviar arquivos anexos ou usar templates, consulte a
documentação do Spring para e-mail.

(1.13.6)
Capítulo 15. Gerenciamento e monitoração

15.1. Introdução
Este capítulo mostra algumas características do Framework que facilitam o gerenciamento e monitoração de
aplicações construídas com ele.

A capacidade de gerenciamento de componentes do Framework é feita através da tecnologia JMX (Java


Management Extensions).

15.1.1. JMX

JMX é um padrão Java que permite instrumentar aplicações para que elas sejam gerenciadas remotamente.
Com ela é possível monitorar um sistema e verificar ou alterar o valor de parâmetros de configuração.

A entidade básica que expõe informação de gerência é o MBean (Managed Bean). Portanto o MBean é usado
para instrumentar um recurso que se quer gerenciar, expondo uma interface para um recurso, que pode ser
manipulado usando um agente JMX.

Ferramentas de gerenciamento compatíveis com o padrão JMX (como o JConsole presente no JDK ou o Tivoli
Monitoring da IBM) podem ser usadas para monitorar e configurar MBeans.

15.2. Gerenciamento padrão


O Framework constrói automaticamente uma árvore JMX para monitoração e visualização de elementos da
aplicação. Essas informações são descritas a seguir.

15.2.1. Monitoração de serviços

A camada de negócio é o núcleo da lógica da aplicação. Como tanto, esta camada contém os pontos críticos de
performance e disponibilidade nos quais as requisições se concentram. Desta forma, as interfaces de serviço da
camada de negócio são as fortes candidatas a monitoração.

Todos os serviços implementados com o Framework são automaticamente monitorados e algumas informações
básicas sobre seu uso são coletadas. Para cada método definido na interface de negócio do serviço estão
disponíveis as propriedades da tabela a seguir.

Tabela 15.1. Propriedades disponíveis dos serviços

Propriedade Descrição

Hits Quantidade de acessos

LastValue Tempo da última chamada do método (em milisegundos)

Min Tempo mínimo de execução (em milisegundos)

Max Tempo máximo de execução (em milisegundos)

Avg Tempo médio de execução (em milisegundos)

Framework Java Arquitetura Brasil 157


Gerenciamento e monitoração

Propriedade Descrição

Total Tempo total acumulado de execução (em milisegundos)

StdDev Desvio padrão do tempo de execução (em milisegundos)

FirstAccess Data do primeiro acesso

LastAccess Data do último acesso

Quando o Framework detecta um serviço, é criado um MBean relativo a cada um de seus métodos. Esse
MBean é registrado automaticamente no MBeanServer disponível (do servidor de aplicações ou JDK).

A regra para geração de ObjectName do MBean é a seguinte:

• O domain é definido como o nome da aplicação, tal qual definido no arquivo


META-INF/config/application.properties

• O type tem o valor fixo ServiceStats

• O name tem o nome completo da classe e do método do serviço

• As propriedades cell, node e process são acrescentadas pelo WebSphere de acordo com o servidor onde o
serviço está instalado.

Um exemplo de tal MBean numa instância do WebSphere Application Server, teria o ObjectName:

[demo:type=ServiceStats,name=com.altec.bsbr.app.demo.service.TestServiceImpl.findAll,
cell=bsbrsp311Node01Cell,node=bsbrsp311Node01,process=server1]

Observando esse MBean referente


ao método findAll da classe
com.altec.bsbr.app.demo.service.TestServiceImpl, podemos saber por exemplo, com que frequencia ele é
chamado e qual seu tempo médio de execução.

Framework Java Arquitetura Brasil 158


Gerenciamento e monitoração

Figura 15.1. Tela do JConsole mostrando estatísticas da chamada do serviço sayHello

Todas as informações coletadas durante a execução da aplicação, são armazendas em memória, e serão
perdidas após a aplicação ser parada.

15.3. Monitoração de versão


Além de informações de monitoração, o Framework disponibiliza também, MBeans para visualização de
informações gerais da aplicação como:

• Versão da aplicação.

• Versão do Framework usado pela aplicação.

Esses MBeans podem ser consultados na árvore JMX via uma interface de monitoração como JConsole. O
MBean com nome ApplicationVersionInfo guarda as seguintes informações referentes a aplicação:

• Título da aplicação

• Nome da aplicação

• Pacote de distribuição

• Fornecedor da aplicação

Framework Java Arquitetura Brasil 159


Gerenciamento e monitoração

Importante
Esses dados são obtidos a partir do arquivo de propriedades
META-INF/config/application.properties empacotado na aplicação. Portanto, é essencial que
ele seja preenchido corretamente.

Figura 15.2. Tela do JConsole mostrando a versão da aplicação demo

15.4. Exportando informações para gerenciamento


O Framework permite que qualquer aplicação crie MBeans para que alguma de suas características internas
sejam visíveis ou gerenciáveis através de uma ferramenta JMX.

Para exportar um objeto como MBean, basta criar uma classe Java qualquer no pacote mbean, e anotá-la com
org.springframework.jmx.export.annotation.ManagedResource. Os métodos que devem ser expostos
devem ter as anotações org.springframework.jmx.export.annotation.ManagedOperation ou
org.springframework.jmx.export.annotation.ManagedAttribute.

Criando a classe exemplo abaixo, ela será automaticamente registrada no MBeanServer do servidor de
aplicações, e exportará a operação sayHello.

package com.altec.bsbr.app.demo.mbean;

@ManagedResource
public class HelloMBean implements HelloService {

@Autowired
private HelloService service;

@ManagedOperation
public String sayHello(String name) {
return service.sayHello(name);
}

(1.13.6)
Gerenciamento e monitoração

Para maiores informações sobre as anotações de managed beans, consulte o manual do Spring.

15.5. Uso do wsadmin com MBeans


Os componentes JMX também podem ser gerenciados pelo wsadmin, ferramenta de linha de comando do
WebSphere.

Abaixo podemos ver alguns comando para manipular MBeans gerados pelo Framework:

wsadmin>$AdminControl queryNames abcOnline:*


abcOnline:cell=bsbrsp311Node01Cell,name=applicationVersionInfo,type=ApplicationVersionInfo,...
...
abcOnline:cell=bsbrsp311Node01Cell,name=frameworkVersionInfo,type=FrameworkVersionInfo,...
abcOnline:cell=bsbrsp311Node01Cell,name=testMBean,type=TestMBean,node=bsbrsp311Node01,process=server1

wsadmin>$AdminControl queryNames abcOnline:type=FrameworkVersionInfo,*


abcOnline:cell=bsbrsp311Node01Cell,name=frameworkVersionInfo,type=FrameworkVersionInfo,
node=bsbrsp311Node01,process=server1

wsadmin>set fw [$AdminControl queryNames abcOnline:cell=bsbrsp311Node01Cell,name=frameworkVersionInfo,


type=FrameworkVersionInfo,node=bsbrsp311Node01,process=server1]
abcOnline:cell=bsbrsp311Node01Cell,name=frameworkVersionInfo,type=FrameworkVersionInfo,
node=bsbrsp311Node01,process=server1

wsadmin>$Help attributes $fw


Attribute Type Access
Name java.lang.String RO
Version java.lang.String RO
Vendor java.lang.String RO
Title java.lang.String RO
Pkg java.lang.String RO

wsadmin>$AdminControl getAttribute $fw Version


1.13.6

wsadmin>$Help operations $fw


Operation
java.lang.String getTitle()
java.lang.String getName()
java.lang.String getPkg()
java.lang.String getVersion()
java.lang.String getVendor()

wsadmin>$AdminControl invoke $fw getTitle


Framework Java Arquitetura Brasil

Para maiores informações de como usar o wsadmin, consulte o WebSphere Application Server V6 System
Management & Configuration Handbook.

(1.13.6)
Capítulo 16. Testes Unitários

16.1. Introdução
Em programação de computadores, o uso de testes unitários é um método de testes que verifica se unidades
individuais de código fonte estão funcionando apropriadamente. Uma unidade é a menor parte testável de uma
aplicação. Em programação orientada a objetos, a menor parte testável é um método, o qual pode pertencer a
uma classe base, super classe, classe abstrata e uma classe derivada.

É importante que cada caso de teste seja independente dos outros. Para isso, quando o objeto testado depende
de outros, é necessário o uso de objetos falsos (mock objects) os quais tem a responsabilidade de fazer o
isolamento entre os testes. Testes unitários são tipicamente feitos pelos desenvolvedores para asegurar que o
código escrito atenderá os requisitos da aplicação desenvolvida.

16.2. Objetivo
O principal objetivo dos testes unitários é isolar cada parte da aplicação afim de certificar que estão todas
corretas. Um teste unitário deve ser categorico ao testar uma unidade de código, ou seja, deve testar todos os
contextos possíveis onde tal unidade de código poderá estar sujeita.

16.3. Benefícios

• Facilidade de manutenção

Testes unitários permitem que um programador refatore um código em um momento posterior e ainda
asegurar que o módulo ainda funcionará corretamente (Testes de Regressão). O procedimento é escrever
casos de testes para todas as funções e métodos, de tal forma que sempre que uma mudança causar uma
falha, está será rapidamente identificada.

• Simplifica a integração

Testes unitários ajudam a eliminar códigos desnecessários ou duvidosos ao se condificar a integração de


duas metades (cliente e o serviço), tornando assim a união das metades muito mais simples e menos
dolorosa.

• Acrescenta a documentação

Testes unitários provêem uma documentação viva do sistema. Para os desenvolvedores afim de encontrar
facilmente uma documentação de como usar determinados componentes, classes utilitárias, regras de
negócio, iteração com classes, etc. podem achá-las nos testes unitários, os quais fornecerão uma ótima
descrição de como usar tal API e em quais contextos um determinado método ou classe foram desenhados.

16.4. Como criar testes unitários


O Framework foi idealizado de tal forma que facilite o desenvolvimento de testes unitários. Ou seja, usando
interfaces é possível criar implementações falsas as quais apenas permitem testar o código feito antes de que se
faça a integração da implementação verdadeira. No Framework, os Serviços, Dao's, MessagingGateway's, etc.

Framework Java Arquitetura Brasil 162


Testes Unitários

foram desenhados utilizando-se interfaces para que sejam fácilmente substituidos afim de permitir que os testes
tenham o máximo de isolamento possível.

O Framework JUnit versão 4.4 é o que será usado para rodar os testes unitários.

Para criar uma classe de teste precisamos seguir os passos descritos abaixo:

1. Criar o diretório src-test na raiz de diretórios do projeto. Veja o exemplo abaixo:

[Raiz_Projeto]/
src/
src-test/❶
lib/
ear/

❶ Diretório que deve ser criado.

2. Criar a classe de teste dentro do diretório src-test. Veja abaixo o exemplo:

[Raiz-Projeto]/
src/
com.altec.bsbr.app.projetox.util.format/
FormataData.java❶
src-test/
com.altec.bsbr.app.projetox.util.format.test/
FormataDataTest.java❷
lib/
ear/

❶ Classe do projeto a qual iremos testar.


❷ Classe de teste.

Veja o exemplo abaixo da classe FormataData.

...
public class FormataData {
public String formatDate(java.util.Date date) {
...
}
}

Teste Unitário da classe FormataData.

...
public class FormataDataTest {
...

@org.junit.Test❶
public void testFormatDate() throws Exception {

final java.util.Date data =


new SimpleDateFormat("dd/MM/yyyy").parse("12/01/2000");

String formatedDate = formataData.formatDate(data);

org.junit.Assert.assertTrue("Data inválida!", "12/01/2000", formatedDate);


}
...
}

❶ Anotação @org.junit.Test usada para assinar um método e informar o Framework que tal método
deve ser executado como test unitário.

Framework Java Arquitetura Brasil 163


Testes Unitários

Para mais informações sobre como criar testes unitários acesse:

JUnit.org

JUnit 4 in 60 Seconds

3. Agora, para executar o teste, utilizamos a ferramenta de build Ant o qual irá compilar os testes e
executa-los criando um relatório Html dos resultados dos testes. Veja abaixo os passos para executar o
teste unitário utilizando o Ant no Eclipse.

a. Clique no menu Window -> Show View -> Ant.

Figura 16.1. Menu Window - Show View

b. Clique no ícone para adicionar o build.xml do projeto.

Framework Java Arquitetura Brasil 164


Testes Unitários

Figura 16.2. Build adicionado

c. Após adicionado o build.xml clique 2 vezes na target test-html.

4. O relatório dos testes estará disponível no diretório


[Raiz_projeto]/temp/test-reports/html/index.html.

(1.13.6)
Testes Unitários

Figura 16.3. Resultado dos testes executados no abcOnline

(1.13.6)
Parte III. Aplicação de Referência
Esta seção detalha a construção de uma aplicação de referência usando o Framework JAB.

• Capítulo 17. A aplicação de referência

• Capítulo 18. Arquitetura e implementação

Framework Java Arquitetura Brasil 167


Capítulo 17. A aplicação de referência

17.1. Introdução
O Framework possui uma aplicação de referência para exemplificar seu uso. Essa aplicação de referência
contempla vários recursos do Framework, possibilitando por exemplo, a visibilidade na forma de
desenvolvimento de futuras aplicações. Este capítulo faz uma descrição funcional da aplicação de referência.

17.2. ABC-CD Online


A Loja ABC-CD Online é um sistema composto pelo site de vendas denominado ABC-Online e pelo módulo
administrativo ABC-Admin. O primeiro é um site de vendas de CDs online, e suas funcionalidades são permitir
a venda online e facilitar a escolha de produtos para o cliente. O segundo é um subsistema de administração do
site de vendas, cujas funcionalidades são o controle e gerenciamento de pedidos, controle de estoque e emissão
de relatórios gerenciais.

17.2.1. ABC-Online

O ABC-Online é o site destinado ao usuário (cliente da loja), organizado na seguinte estrutura:

• Home - página organizada por categorias musicais, e para cada categoria estão disponibilizados os produtos
com seus respectivos detalhes;

• Cadastro - página de cadastro do usuário;

• Login - página que permite ao usuário inserir seu dados de login para o acesso do cliente na loja. Após
logado, o cliente poderá visualizar o pedido, concluir a compra e selecionar a forma de pagamento desejada;

• Carrinho - página onde são listados os produtos selecionados pelo usuário. É nesta página que o usuário
também conclui a compra de produtos;

• Suporte - página disponível para solicitação de suporte via e-mail.

Framework Java Arquitetura Brasil 168


A aplicação de referência

Figura 17.1. Cenário do sistema ABC-Online

Descrição do modelo de caso de uso do ABC-Online:

• Cadastro de Cliente: A loja disponibiliza uma tela para cadastro do cliente, informando alguns dados
pessoais, como nome, endereço (incluindo cidade e estado), e-mail e o cadastro de senha de acesso.

• Login de Acesso: Para toda compra, o usuário deverá efetuar o login informando seu endereço de e-mail e a
sua senha cadastrada.

Framework Java Arquitetura Brasil 169


A aplicação de referência

• Busca de Produtos: Para facilitar a busca de produtos, o usuário poderá dispor do uso da Busca disponível
na página principal da loja.

• Adicionar Produtos no Carrinho: Ao identificar um produto de interessse, o usuário deve escolher a opção
de adicionar os produtos no carrinho.

• Finalizar Pedido: Uma vez que os produtos estejam no carrinho, para concluir a compra dos mesmos o
usuário deverá optar por finalizar o pedido.

• Pagamento: O usuário terá a opção de escolhar a forma de pagamento de seu pedido, as opções são: cartão
de crédito ou débito e boleto bancário.

• Solicitar Suporte: O usuário poderá soliciar os serviços de suporte da loja. Basta o cliente informar o e-mail,
telefone e a descrição do serviço.

17.2.2. ABC-Admin

O ABC-Admin é o módulo destinado ao trabalho dos administradores do site, organizado na seguinte estrutura:

• Controle de Estoque

• Controle de Status de Pedidos

• Emissão de Relatórios Gerenciais


O módulo também possui uma estrutura para o processamento em batch para o tratamento de pedido.

Framework Java Arquitetura Brasil 170


A aplicação de referência

Figura 17.2. Cenário do sistema ABC-Admin

Descrição do modelo de caso de uso do ABC-Admin:

• Login de Acesso: O processo de login é de acordo com o perfil administrativo do usuário, sendo um
administrador geral, administrador do estoque ou acompanhamento de pedidos.

• Acompanhamento de Pedido: O usuário poderá acompanhar os pedidos fazendo consultas por status de
pedido.

• Tratamento de Pedido: O tratamento de pedido é feito por um processamento em batch para a mudança
de status do pedido. Os status se resumem a dois tipos, Pedido Realizado e Pedido Entregue.

• Pedido Realizado: é o primeiro status o qual um pedido deve assumir, após o pagamento realizado
pelo clinete na Loja ABC-Online.

• Pedido Entregue: é o segundo status o qual um pedido deve deve assumir, após a entrega do pedido
ao cliente.

• Emissão de Relatórios: É um recurso da aplicação para emitir relatórios para o controle da quantidade de
produtos no estoque, de status dos pedidos e da quantidade de vendas por período. Os relatórios podem ser
exportados em formato PDF ou XLS.

• Consulta Estoque: permite ao usuário analisar a quantidade de produtos no estoque. Os produtos serão
listados em ordem decrescente de quantidade.

(1.13.6)
Capítulo 18. Arquitetura e implementação

18.1. Introdução
Este capítulo detalha a arquitetura e implementação da aplicação de referência do Framework.

18.2. ABC CD Online


A arquitetura da aplicação foi baseada no padrão do Framework, dividindo a aplicação em camadas:

• Camada de Persistência: a aplicação utiliza a classe abstrata


com.altec.bsbr.fw.dao.jpa.GenericHibernateJpaDao e a classe
com.altec.bsbr.fw.dao.jpa.CrudJpaDao do Framework.

• Camada de Negócio: a aplicação segue as regras de criação de serviços do Framework, utilizando anotações
que serão controladas pelo Spring.

• Camada Web: utiliza JSF.

18.2.1. Camada de Persistência

A camada de persistência de dados da aplicaçao ABC-Online encontra-se no pacote


com.altec.bsbr.app.abc.dao. O diagrama a seguir mostra a camada com as respectivas implementações dos
DAOs da aplicação.

Figura 18.1. Diagrama de Classe da camada de persistência do sistema ABC-Online

Framework Java Arquitetura Brasil 172


Arquitetura e implementação

Interfaces:

• EstoqueDao

• LoginDao

• PopulateTablesDao

• ClienteDao

• PedidoDao

• ProdutoDao

Classes de Implementação:

• ClienteDaoImpl: A classe estende GenericHibernateJpaDao<Cliente, Long>, implementa o método


login(Cliente cliente) e retorna uma instância do Cliente (utilizando o método findOneByCriteria) no
processo de login.

• EstoqueDaoImpl: A classe estende GenericHibernateJpaDao<Estoque, Long>, implementando os


métodos:

• List<Estoque> findByCategoria(Categoria categoria): retorna uma lista de produtos do estoque


de acordo com a categoria informada.

• Estoque findEstoqueById(Estoque estoque, boolean lock): retorna o código de um produto no


estoque.

• List<Estoque> findByDescription(String description): retorna uma lista de produtos do estoque


após informar a descrição (palavra chave) como parâmetro.

• PopulateTablesDaoImpl: A classe faz a persistência utilizando a classe CrudJpaDao, implementando o


seguinte método:

• populate(): Método que popula informações dos produtos, como código, nome do CD, artista, data de
lançamento e categoria.

• PedidoDaoImpl: A classe estende GenericHibernateJpaDao<Pedido, Long>, implementa o método


findPedidosByCliente(Cliente cliente) e retorna uma instância do Cliente (utilizando o método
findByCriteria) na localização de pedidos do cliente.

• ProdutoDaoImpl: A classe estende GenericHibernateJpaDao<Produto, Long>, implementando os


seguintes métodos:

• getImage(final Long codigoProduto): chama uma imagem do Produto (utilizando o método


findOneUsingCallback).

• Estoque getProdutoWithPartesProduto(final Long codigoProduto): retorna as partes de


informação do produto (utilizando o método findOneUsingCallback).

18.2.2. Camada de Serviço

Framework Java Arquitetura Brasil 173


Arquitetura e implementação

A camada de negocio da aplicaçao ABC-Online encontra-se no pacote com.altec.bsbr.app.abc.service. O


diagrama a seguir mostra as interfaces com as respectivas classes de implementação.

Figura 18.2. Diagrama de Classe de Serviços do sistema ABC-Online

Interfaces:

• EstoqueService

• LoginException

• LoginService

• MailService

• PedidoException

• PedidoService

• PopulateTablesService

• ProdutoService

• TestService

Classe de Implementação:

• ProdutoServiceImpl: utiliza a classe com.altec.bsbr.app.abc.dao.ProdutoDao para fazer a persistência,

Framework Java Arquitetura Brasil 174


Arquitetura e implementação

implementando os métodos:

• getImageProduto(Long codigoProduto): retorna a imagem do produto chamando o método


getProdutoWithPartesProduto(codigoProduto) do serviço ProdutoDao.

• Produto getProdutoWithPartesProduto(Long codigoProduto): retorna as partes de informação do


produto, chamando o método getProdutoWithPartesProduto (codigoProduto) do
serviçoProdutoDao.

• findByDescription : realiza a busca informando a descrição do produto;

• EstoqueServiceImpl: utiliza a classe com.altec.bsbr.app.abc.dao.EstoqueDao para fazer a persistência,


implementando os métodos:

• findByCategoria: realiza a busca de produtos por categoria.

• findEstoqueById: realiza a busca através do código do produto.

• findByDescription: realiza a busca informando a descrição do produto;

• LoginServiceImpl: utiliza a classe com.altec.bsbr.app.abc.dao.LoginDao para fazer a persistência,


implementando o método findOneByCriteria para fazer o login do usuário.

• MailServiceImpl: utiliza a classe SimpleMailMessage e a interface JavaMailSender do Spring, para envio


de e-mail. Esta classe implementa o método sendSuporteEmail para a solicitação de suporte da aplicação.

• PedidoServiceImpl: utiliza a classe com.altec.bsbr.fw.dao.jpa.CrudJpaDao para fazer a persistência, a


classe implementa o método criarPedido passando como parâmentro o cliente, a forma de pagamento e a
lista de produtos (CDs) para a fazer os pedidos na loja.

• PopulateTablesServiceImpl: utiliza a classe com.altec.bsbr.app.abc.dao.PopulateTablesDao para


fazer a persistência, implementando o método populate() para popular informações dos produtos.

• TestServiceImpl: classe utilizada para teste, que implementa o método test(String name) que retorna
uma string.

18.2.3. Camada Web

A camada web da aplicaçao ABC-Online encontra-se no pacote com.altec.bsbr.app.abc.web. O diagrama a


seguir mostra os Backing Beans criados:

(1.13.6)
Arquitetura e implementação

Figura 18.3. Diagrama de Classe dos BBeans do sistema ABC-Online

Backing beans do JSF

Os Backing Beans encontram-se no pacote com.altec.bsbr.app.abc.web.jsf. Abaixo estão listados os


Bbeans da aplicação:

• BuscaBBean: classe que faz a busca de produtos pelo site, informando uma palavra-chave.

• CarrinhoBBean: classe onde são adicionados os produtos selecionados pelo usuário. A classe implementa
os principais métodos:

• adicionarProduto(ActionEvent event): método utilizado para adicionar produtos no carrinho.

• removerProduto(ActionEvent event): método utilizado para remover produtos no carrinho.

• finalizarCompra(ActionEvent event): método para finalização da compra.

• atualizarCarrinho(ActionEvent event): método para atualização do carrinho.

• cleanUp(): método para esvaziar o carrinho.

• CategoriaBBean: a classe lista todas a categorias musicais (existentes no estoque) que serão exibidos na
página inicial da aplicação.

• ClienteBBean: a classe para fazer o cadastro do cliente e também utilizada para autorização de login.

(1.13.6)
Arquitetura e implementação

• DetalhesCDBBean: a classe exibe os detalhes do produto que além do título, autor e ano de lançamento do
CD, são exibidos: o preço e a faixa musical do CD.

• FirstPageBBean: a classe exibe na página principal a classificação dos produtos por categoria musical.

• ImprimirPedidoBBean: a classe que imprime o pedido do cliente, após pagamento.

• LoginBBean: Página de login para acesso do cliente a loja. A classe implementa os principais métodos:

• login(): método para efetuar o acesso do cliente.

• isAutorizado(): método para autorizar o acesso.

• isPagPendente(): método retorna os pedidos com pagamentos pendentes ao cliente (caso este tiver
pendência).

• checkCliente(Cliente cliente): método verifica a autorização do cliente.

• PagamentoBBean: classe para efetuar pagamento.

• PopulateTablesBBean: utiliza a classe com.altec.bsbr.app.abc.dao.PopulateTablesService para fazer


a persistência, implementando o método populate() para popular informações dos produtos.

• SuporteBBean: classe para solicitação de suporte, informando e-mail, telefone para contato com o cliente e
a descrição do serviço.

• PedidosEfetuadosBBean: classe responsável por listar pedidos efetuados pelo cliente, utilizando os
métodos void search(ActionEvent event) para a busca dos pedidos por cliente.

18.3. ABC-Admin

18.3.1. Camada de Persistência

A camada de persistência
de dados da aplicação ABC-Admin encontra-se no pacote
com.altec.bsbr.app.abcAdmin.dao. O diagrama a seguir mostra a camada com as respectivas
implementações dos DAOs da aplicação.

Framework Java Arquitetura Brasil 177


Arquitetura e implementação

Figura 18.4. Diagrama de Classe da camada de persistência do sistema ABC-Admin

Interfaces:

• EstoqueDao

• PedidoDao

Classes de Implementação:

• EstoqueDaoImpl: a classe estende GenericHibernateJpaDao<Estoque, Long> para fazer a persistência,


implementando o método findByDescription, retorna uma lista de produtos do estoque após informar a
descrição.

• EstoqueJdbcDaoImpl: realiza a consulta sobre a quantidade do produto no estoque, e também de


informações do mesmo.

• PedidoDaoImpl: utiliza a classe GenericHibernateJpaDao<Pedido, Long>, implementando os principais


métodos:

• List<Pedido> findByDescription(final String text, final Date fromDate, final Date


toDate): método que localiza os pedidos realizados informando a descrição o e período (data início e
data final). O retorno é um lista de pedidos.

• List<Pedido> findByStatus(final StatusPedido status): método que retorna uma lista de pedidos
por status.

18.3.2. Camada de Serviço

A camada de negócio da aplicação ABC-Admin encontra-se no pacote

Framework Java Arquitetura Brasil 178


Arquitetura e implementação

com.altec.bsbr.app.abcAdmin.service. O diagrama a seguir mostra as interfaces com as respectivas classes


de implementação.

Figura 18.5. Diagrama de Classe de Serviços do sistema ABC-Admin

Interfaces:

• EstoqueService

• HelloService

• MenuItemHolder

• MenuService

• PedidoService

Classes de Implementação:

• EstoqueServiceImpl: serviço que retorna uma lista de pedidos.

• HelloServiceImpl: é um exemplo para teste.

• MenuServiceImpl: o serviço lista todos os acessos permitidos ao usuário. A classe chama o método
buildUserMenu(String user, String system) que retorna uma instância de Authorization com a
construção do menu autorizado ao usuário logado.

• PedidoServiceImpl: serviço localiza pedidos por período (data início e data final) e pedidos por status
(pedidos realizados e pedidos entregues).

(1.13.6)
Arquitetura e implementação

18.3.3. Camada Web

A camada web da aplicação ABC-Admin encontra-se no pacote com.altec.bsbr.app.abcAdmin.web. O


diagrama a seguir mostra os Backing Beans criados:

Figura 18.6. Diagrama de Classe dos BBeans do sistema ABC-Admin

Backing beans do JSF

Os Backing Beans encontram-se no pacote com.altec.bsbr.app.abcAdmin.web.jsf. Abaixo estão listados os


Bbeans da aplicação:

• AcompanhamentoPedidoBBean: a classe permite localizar pedidos informando a descrição e o período (data


início e data final), retornando uma listagem dos pedidos com os respectivos status.

• ConsultaEstoqueBBean: a classe informa a quantidade de produtos existentes no estoque.

• FirstPageBBean: a classe renderiza o menu de acordo com a tipo de perfil do usuário logado.

• HelloServiceBBean: gera mensagem de saudação, usada para testes.

• IntegracaoAeaBBean: classe que faz a comunicação síncrona (requisição e resposta) com a Arquitetura
Estendida Altair, fazendo a transformação entre objetos Java e o formato da AEA.

• RelatorioClienteBBean: a classe permite a emissão de relatório de clientes.

• RelatorioEstoqueBBean: a classe permite a emissão de relatório dos produtos no estoque.

(1.13.6)
Arquitetura e implementação

• RelatorioPedidoBBean: a classe permite a emissão de relatório dos pedidos realizados e entregues.

• RelatorioVendasEfetuadasBBean: a classe permite a emissão de relatório de vendas efetuadas por período.

• TestEJBBBean: a classe é um exemplo para EJB, que permite calcular dois números resultado na soma dos
mesmo.

• WebServiceBBean: a classe utiliza web service para validar endereço de e-mail, teste de serviço e busca de
cd através do código do produto.

18.4. Aplicações Batch ABC CD Online

18.4.1. Tratamento de Pedido

A aplicação batch realiza a mudança de status de pedidos no sistema ABC Admin. No processo são utilizados
as classes PedidoTask e ProcessaPedidoConsumer, ambos encontram-se no pacote
com.altec.bsbr.app.abcAdmin.batch.

O processo batch usa o padrão produtor-transformação-consumidor, onde tanto o produtor como o consumidor
usam o banco de dados.

O Produtor utilizado para gerar os dados é indicado no batch.xml (package abcBatch.src.batch.xml), onde a
classe FromDatabaseProducer é utilizada para gerar os registros a partir de uma consulta na tabela de Pedido
localizando os pedidos com status de Pedido Realizados.

Figura 18.7. Diagrama de classe da task PedidoTask

• PedidoTask:a classe faz a chamada do método execute() recebendo um objeto contendo as colunas do
ResultSet (fornecido pelo RecordProducer) dos pedidos com status de Pedido Realizado, e devolve apenas

Framework Java Arquitetura Brasil 181


Arquitetura e implementação

o código dos pedidos.

• Task<Objet, BigDecimal>:classe padrão do Framework, responsável por transformar os dados de entrada em


objetos prontos para serem consumidos. A tarefa Pedidotask deve implementar a classe Task.

Figura 18.8. Diagrama de classe da task PedidoTask

Abaixo estão listados as classes envolvidas na tarefa:

• PedidoTask:a classe faz a chamada do método execute() recebendo um objeto contendo as colunas do
ResultSet (fornecido pelo RecordProducer) dos pedidos com status de Pedido Realizado, e devolve apenas
o código dos pedidos.

• Task<Objet, BigDecimal>:classe padrão do Framework, responsável por transformar os dados de entrada em


objetos prontos para serem consumidos. A tarefa Pedidotask deve implementar a classe Task.

Framework Java Arquitetura Brasil 182


Arquitetura e implementação

Figura 18.9. Diagrama de classe do consumidor ProcessaPedidoConsumer

Abaixo estão listados as classes envolvidas no consumo dos registros:

• ProcessaPedidoConsumer: implementa a interface com.altec.bsbr.fw.batch.RecordConsumer,


implementando os métodos:

• consume(BigDecimal codigoPedido): recebe o código do pedido e executa a mudança de status para


Pedido Entregue.

• flush(): o método faz o commit no banco de dados.

• RecordConsumer<BigDecimal>: classe padrão do Framework, responsável por consumir os registros após


eles serem processados, que neste caso será gravar todos os Pedidos Entregues no banco de dados. A classe
ProcessaPedidosConsumer deve implementar a interface RecordConsumer.

• GenericJdbcDao: Utiliza recursos jdbc para fazer update dos Pedidos Realizados para Pedidos Entregues na
tabela Pedidos.

18.4.2. Processamento Batch para Cds

O processo é representado pelos pojos Cd e Track que serão lidos pelo Produtor (FromFileProducer) e
processados por uma Task (CdtoProdutoTask) e consumidos pelo Consumidor (DatabaseConsumer).

A aplicaçao batch realiza a atualização da informações do Cd no sistema ABC Admin. No processo são
utilizados as classes FromFilesProducer (Produtor), CdtoProdutoTask (Tarefa) e DatabaseConsumer
(Consumidor), as classes encontram-se no pacote com.altec.bsbr.app.abcProductsDataLoader.

(1.13.6)
Arquitetura e implementação

Figura 18.10. Diagrama da classe Cd

A classe Cd representa o objeto Produto, contendo informações como:

• Código

• Nome do Artista

• Título do Cd

• Imagem da Capa do Cd

• Gênero Músical

(1.13.6)
Arquitetura e implementação

• Quantidade do Produto no Estoque

Figura 18.11. Diagrama da classe Track

A Classe Track representa o objeto ParteProduto, contendo os detalhes do Produto como:

• Ordem da música

• Descrição

Framework Java Arquitetura Brasil 185


Arquitetura e implementação

Figura 18.12. Diagrama de classe do produtor FromFilesProducer

• FromFilesProducer: implementa um produtor com a função de produzir os registros do Cd (Produto) e da


Track (Partes do Produto).

• next(): o metodo retornará mais um registro a ser processado, cada vez que o método for chamado.

• RecordProducer: interface padrão do Framework a qual a classe FromFileProducer deve implementar.

Figura 18.13. Diagrama da classe CdtoProdutoTask

Framework Java Arquitetura Brasil 186


Arquitetura e implementação

• CdtoProdutoTask:
a classe faz a chamada do método execute() recebendo o Cd e retornando as atualizações
das informações do Produto - getProduto (Cd cd), do produto no Estoque - getEstoque(Cd data) e da
Parte do Produto - getPartesProduto.

• getEstoque(Cd data): insere as informações do produto como o preço e a quantidade do produto no


estoque (atualizando a tabela Estoque).

• getProdutoFrom(Cd cd): insere as informações do cd como o nome, título, ano de lançamento, autor,
etc, atualizando a tabela Produto e Categoria

• getPartesproduto(Cd cd): insere as partes do cd, como a descriçao e a ordem das músicas do Cd,
atualizando a tabela ParteProduto.

• Task<Cd, Object>: classe padrão do Framework, responsável por transformar os dados de entrada em
objetos prontos para serem consumidos. A tarefa CdtoProdutoTask deve implementar a classe Task.

Figura 18.14. Diagrama de classe do consumidor DatabaseConsumer

• DatabaseConsumer: implementa a interface com.altec.bsbr.fw.batch.RecordConsumer, implementando


os métodos:

• consume(Object[ ] objects): verifica o gênero musical do Cd na tabela Categoria e insere as


informações do produto na tabela Produto.

• insertEstoque(Estoque estoque, Long produtoID): atualiza as informações do Cd na tabela Estoque.

• insertCd(Produto objetct): atualiza as informações do Cd na tabela Produto.

• insertTracks(Produto objetct): insere os detalhes do Cd na tabela ParteProduto.

(1.13.6)
Arquitetura e implementação

• checkGenre(Produto produto): verifica o gênero musical do Cd na tabela Categoria.

• flush(): o método faz o commit no banco de dados.

• RecordConsumer<Object>: classe padrão do Framework, responsável por consumir os registros após eles
serem processados (processados pelo CdtoProdutoTask) , que neste caso deverá gravar as informações do
Cd nas tabelas envolvidas. A classe ProcessaPedidosConsumer deve implementar a interface RecordConsumer.

• GenericJdbcDao: Utiliza recursos jdbc do Framework para fazer os updates nas tabelas.

(1.13.6)
Apêndice A. Referências
A.1. Referências
Referências bibliográficas e internéticas.

• Apache Ant 1.7.1 – ferramenta de build. [http://ant.apache.org/]

• Slf4j 1.5.3 – proporciona uma fachada genérica para vários outras bibliotecas de log. Proporciona uma
mecanismo plugável de integração com os logs mais comuns utilizados. [http://www.slf4j.org/]

• Logback 0.9.9 – implementação de Log mais madura e considerada uma evolução ao log4j.
[http://logback.qos.ch/]

• Spring 2.5.5 – framework vastamente difundido usado como um “container leve”. Proporciona mecanismo
produtivo para desacoplamento entre as camadas da aplicação, executando de forma automática injeção de
dependência e integração com diversos serviços de aplicações corporativas como JTA, JPA, EJB.
[http://www.springframework.org/]

• Hibernate 3.3.1 – implementação JPA da RedHat. [http://hibernate.org/]

• ehcache 1.5.0 – biblioteca utilizada para implementar soluções de cache. [http://ehcache.sourceforge.net/]

• ICEFaces 1.7 – implementação de componentes Java Server Faces, com suporte a Ajax.
[http://www.icefaces.org/]

• JasperReports 3.0.1 – API para desenvolvimento de relatórios em java.


[http://www2.jasperforge.org/plugins/project/project_home.php?group_id=102]

• Jamon 2.7 – biblioteca que disponibiliza uma API para registro de acesso e monitoramento a métodos da
camada de serviços da aplicação. [http://jamonapi.sourceforge.net/]

• Jasypt 1.5 – biblioteca que simplifica o uso de rotina criptográficas. [http://www.jasypt.org/]

• Joda-time 1.5.2 – proporciona uma forma mais madura e avançada que a API Java para tratamento de
data/hora e manipulação de Calendários. [http://joda-time.sourceforge.net/]

• Apache Commons – bibliotecas com várias classes utilitárias que simplificam tarefas de programação
comuns:

• Lang 2.4 [http://commons.apache.org/lang/]

• Collections 3.2.1 [http://commons.apache.org/collections/]

• IO 1.4 [http://commons.apache.org/io/]

• Codec 1.3 [http://commons.apache.org/codec/]

• Beanutils 1.7 [http://commons.apache.org/beanutils/]

• HttpClient 3.1 [http://hc.apache.org/httpclient-3.x/index.html]

Framework Java Arquitetura Brasil 189

Вам также может понравиться